(root)/
gcc-13.2.0/
gcc/
rust/
util/
rust-inline-visitor.h
       1  // Copyright (C) 2021-2023 Free Software Foundation, Inc.
       2  
       3  // This file is part of GCC.
       4  
       5  // GCC is free software; you can redistribute it and/or modify it under
       6  // the terms of the GNU General Public License as published by the Free
       7  // Software Foundation; either version 3, or (at your option) any later
       8  // version.
       9  
      10  // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11  // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13  // for more details.
      14  
      15  // You should have received a copy of the GNU General Public License
      16  // along with GCC; see the file COPYING3.  If not see
      17  // <http://www.gnu.org/licenses/>.
      18  
      19  // An improved implementation of the inline visitor.
      20  // Original idea from https://members.accu.org/index.php/articles/2021
      21  
      22  #ifndef RUST_INLINE_VISITOR
      23  #define RUST_INLINE_VISITOR
      24  
      25  namespace Rust {
      26  
      27  // Wrapper for the target Visitor we're matching against.
      28  // Consumes the final nullptr of the _args linked list.
      29  template <typename TargetVisitor> struct EmptyVisitor : TargetVisitor
      30  {
      31    EmptyVisitor (std::nullptr_t ptr) {}
      32  
      33    using TargetVisitor::visit;
      34  };
      35  
      36  // Wrapper for a (possibly incomplete) Visitor.
      37  template <typename BaseVisitor, typename Args> struct VisitorWrapper
      38  {
      39    // Lambdas are stored in _args as a linked list and passed to the actual
      40    // visitor when end_visitor() is called.
      41    Args _args;
      42  
      43    // The actual visitor being created.
      44    // Each visitor inherits from the last one and implements one more visit().
      45    template <typename T, typename F> struct Visitor : BaseVisitor
      46    {
      47      F _f;
      48  
      49      Visitor (std::pair<F, Args> &&args)
      50        : BaseVisitor (std::move (args.second)), _f (std::move (args.first))
      51      {}
      52  
      53      using BaseVisitor::visit;
      54      virtual void visit (T &t) final override { _f (t); }
      55    };
      56  
      57    VisitorWrapper (Args &&args) : _args (std::move (args)) {}
      58  
      59    // Add another visit() method to the visitor.
      60    // _args will be moved over, so don't keep the old wrapper around.
      61    template <typename T, typename F>
      62    VisitorWrapper<Visitor<T, F>, std::pair<F, Args>> on (F &&f)
      63    {
      64      return VisitorWrapper<Visitor<T, F>, std::pair<F, Args>> (
      65        std::make_pair (std::move (f), std::move (_args)));
      66    }
      67  
      68    // Returns the finished visitor.
      69    // NOTE: The reference implementation has a bug that exposes this method even
      70    // when BaseVisitor is still an abstract class. The C++11 standard states that
      71    // "An abstract class shall not be used [...] as a function return type". GCC
      72    // rejects the buggy code as expected, but Clang accepts the code as long as
      73    // the method is not actually called. Maybe this is a bug in Clang?
      74    template <typename T = BaseVisitor>
      75    typename std::enable_if<std::is_constructible<T, Args>::value, T>::type
      76    end_visitor ()
      77    {
      78      return T (std::move (_args));
      79    }
      80  };
      81  
      82  // The entry point.
      83  template <typename TargetVisitor>
      84  VisitorWrapper<EmptyVisitor<TargetVisitor>, std::nullptr_t>
      85  begin_visitor ()
      86  {
      87    return VisitorWrapper<EmptyVisitor<TargetVisitor>, std::nullptr_t> (nullptr);
      88  }
      89  
      90  } // namespace Rust
      91  
      92  #endif