]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: expand: Add new ExpandVisitor class
authorArthur Cohen <arthur.cohen@embecosm.com>
Mon, 20 Mar 2023 03:17:04 +0000 (04:17 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:28:38 +0000 (18:28 +0100)
This class takes care of actually performing the macro expansion by calling
into the MacroExpander for each node of a given AST, leaving the job of
cfg-stripping nodes to the AttrVisitor.

gcc/rust/ChangeLog:

* Make-lang.in: Add new object file.
* expand/rust-attribute-visitor.cc (AttrVisitor::go): Visit all items of a
crate.
(AttrVisitor::expand_struct_fields): Do not perform macro expansion anymore.
(AttrVisitor::expand_function_params): Likewise.
(AttrVisitor::expand_generic_args): Likewise.
(AttrVisitor::expand_qualified_path_type): Likewise.
(AttrVisitor::expand_self_param): Likewise.
(AttrVisitor::expand_trait_function_decl): Likewise.
(AttrVisitor::expand_trait_method_decl): Likewise.
(AttrVisitor::visit): Likewise.
(AttrVisitor::maybe_expand_expr): Remove function.
(AttrVisitor::maybe_expand_type): Likewise.
* expand/rust-attribute-visitor.h: Do not keep MacroExpander inside AttrVisitor
anymore.
* expand/rust-macro-expand.h (struct MacroExpander): Turn ContextType into an
enum class for more type safety.
* expand/rust-macro-expand.cc (MacroExpander::expand_crate): Use new ContextType
API.
* rust-session-manager.cc (Session::expansion): Call into ExpandVisitor.
* expand/rust-expand-visitor.cc: New file.
* expand/rust-expand-visitor.h: New file.

gcc/testsuite/ChangeLog:

* rust/compile/macro49.rs: New test.
* rust/compile/macro50.rs: New test.

gcc/rust/Make-lang.in
gcc/rust/expand/rust-attribute-visitor.cc
gcc/rust/expand/rust-attribute-visitor.h
gcc/rust/expand/rust-expand-visitor.cc [new file with mode: 0644]
gcc/rust/expand/rust-expand-visitor.h [new file with mode: 0644]
gcc/rust/expand/rust-macro-expand.cc
gcc/rust/expand/rust-macro-expand.h
gcc/rust/rust-session-manager.cc
gcc/testsuite/rust/compile/macro49.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/macro50.rs [new file with mode: 0644]

index 8f4839042df14d8514d293905e1c857ff891cc42..083a44e336929f60ed51e7afcf2607187da4d775 100644 (file)
@@ -82,6 +82,7 @@ GRS_OBJS = \
     rust/rust-compile-resolve-path.o \
     rust/rust-macro-expand.o \
     rust/rust-attribute-visitor.o \
+       rust/rust-expand-visitor.o \
     rust/rust-macro-invoc-lexer.o \
     rust/rust-macro-substitute-ctx.o \
     rust/rust-macro-builtins.o \
index cad07a48c54dd6e18a71a564196ae90d8ffe186d..6178428576731fc99bb2394e0c7b444d0feb0b7d 100644 (file)
@@ -141,6 +141,20 @@ AttrVisitor::go (AST::Crate &crate)
       crate.strip_crate ();
       // TODO: maybe create warning here? probably not desired behaviour
     }
+
+  auto &items = crate.items;
+
+  for (auto it = items.begin (); it != items.end ();)
+    {
+      auto &item = *it;
+      item->accept_vis (*this);
+
+      if (item->is_marked_for_strip ())
+       it = items.erase (it);
+      else
+       it++;
+    }
+
   // expand module attributes?
 }
 
@@ -160,20 +174,14 @@ AttrVisitor::expand_struct_fields (std::vector<AST::StructField> &fields)
          continue;
        }
 
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       // expand sub-types of type, but can't strip type itself
       auto &type = field.get_field_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
 
-      expander.pop_context ();
-
       // if nothing else happens, increment
       ++it;
     }
@@ -209,8 +217,6 @@ AttrVisitor::expand_tuple_fields (std::vector<AST::TupleField> &fields)
 void
 AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
 {
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   for (auto it = params.begin (); it != params.end ();)
     {
       auto &param = *it;
@@ -233,8 +239,6 @@ AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
       auto &type = param.get_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
@@ -242,8 +246,6 @@ AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
       // increment
       ++it;
     }
-
-  expander.pop_context ();
 }
 
 void
@@ -252,8 +254,6 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
   // lifetime args can't be expanded
   // FIXME: Can we have macro invocations for lifetimes?
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   // expand type args - strip sub-types only
   for (auto &arg : args.get_generic_args ())
     {
@@ -262,7 +262,6 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
          case AST::GenericArg::Kind::Type: {
            auto &type = arg.get_type ();
            type->accept_vis (*this);
-           maybe_expand_type (type);
 
            if (type->is_marked_for_strip ())
              rust_error_at (type->get_locus (),
@@ -272,7 +271,6 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
          case AST::GenericArg::Kind::Const: {
            auto &expr = arg.get_expression ();
            expr->accept_vis (*this);
-           maybe_expand_expr (expr);
 
            if (expr->is_marked_for_strip ())
              rust_error_at (expr->get_locus (),
@@ -289,8 +287,6 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
        }
     }
 
-  expander.pop_context ();
-
   // FIXME: Can we have macro invocations in generic type bindings?
   // expand binding args - strip sub-types only
   for (auto &binding : args.get_binding_args ())
@@ -307,15 +303,9 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
 void
 AttrVisitor::expand_qualified_path_type (AST::QualifiedPathType &path_type)
 {
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   auto &type = path_type.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
-  expander.pop_context ();
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
@@ -353,17 +343,12 @@ AttrVisitor::AttrVisitor::expand_closure_params (
 
       if (param.has_type_given ())
        {
-         expander.push_context (MacroExpander::ContextType::TYPE);
          auto &type = param.get_type ();
          type->accept_vis (*this);
 
-         maybe_expand_type (type);
-
          if (type->is_marked_for_strip ())
            rust_error_at (type->get_locus (),
                           "cannot strip type in this position");
-
-         expander.pop_context ();
        }
 
       // increment if found nothing else so far
@@ -376,17 +361,12 @@ AttrVisitor::expand_self_param (AST::SelfParam &self_param)
 {
   if (self_param.has_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
       auto &type = self_param.get_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
   /* TODO: maybe check for invariants being violated - e.g. both type and
    * lifetime? */
@@ -413,18 +393,12 @@ AttrVisitor::expand_trait_function_decl (AST::TraitFunctionDecl &decl)
 
   if (decl.has_return_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &return_type = decl.get_return_type ();
       return_type->accept_vis (*this);
 
-      maybe_expand_type (return_type);
-
       if (return_type->is_marked_for_strip ())
        rust_error_at (return_type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 
   if (decl.has_where_clause ())
@@ -449,18 +423,12 @@ AttrVisitor::expand_trait_method_decl (AST::TraitMethodDecl &decl)
 
   if (decl.has_return_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &return_type = decl.get_return_type ();
       return_type->accept_vis (*this);
 
-      maybe_expand_type (return_type);
-
       if (return_type->is_marked_for_strip ())
        rust_error_at (return_type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 
   if (decl.has_where_clause ())
@@ -525,7 +493,6 @@ AttrVisitor::visit (AST::MacroInvocation &macro_invoc)
   // I don't think any macro token trees can be stripped in any way
 
   // TODO: maybe have cfg! macro stripping behaviour here?
-  expander.expand_invoc (macro_invoc, macro_invoc.has_semicolon ());
 }
 
 void
@@ -575,18 +542,12 @@ AttrVisitor::visit (AST::TypePathSegmentFunction &segment)
 
   if (type_path_function.has_return_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &return_type = type_path_function.get_return_type ();
       return_type->accept_vis (*this);
 
-      maybe_expand_type (return_type);
-
       if (return_type->is_marked_for_strip ())
        rust_error_at (return_type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 }
 void
@@ -745,13 +706,11 @@ AttrVisitor::visit (AST::ArithmeticOrLogicalExpr &expr)
    * with outer expr */
   auto &l_expr = expr.get_left_expr ();
   l_expr->accept_vis (*this);
-  maybe_expand_expr (l_expr);
 
   /* should syntactically not have outer attributes, though this may
    * not have worked in practice */
   auto &r_expr = expr.get_right_expr ();
   r_expr->accept_vis (*this);
-  maybe_expand_expr (r_expr);
 
   // ensure that they are not marked for strip
   if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -774,13 +733,11 @@ AttrVisitor::visit (AST::ComparisonExpr &expr)
    * with outer expr */
   auto &l_expr = expr.get_left_expr ();
   l_expr->accept_vis (*this);
-  maybe_expand_expr (l_expr);
 
   /* should syntactically not have outer attributes, though this may
    * not have worked in practice */
   auto &r_expr = expr.get_right_expr ();
   r_expr->accept_vis (*this);
-  maybe_expand_expr (r_expr);
 
   // ensure that they are not marked for strip
   if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -803,13 +760,11 @@ AttrVisitor::visit (AST::LazyBooleanExpr &expr)
    * with outer expr */
   auto &l_expr = expr.get_left_expr ();
   l_expr->accept_vis (*this);
-  maybe_expand_expr (l_expr);
 
   /* should syntactically not have outer attributes, though this may
    * not have worked in practice */
   auto &r_expr = expr.get_right_expr ();
   r_expr->accept_vis (*this);
-  maybe_expand_expr (r_expr);
 
   // ensure that they are not marked for strip
   if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -859,13 +814,11 @@ AttrVisitor::visit (AST::AssignmentExpr &expr)
    * with outer expr */
   auto &l_expr = expr.get_left_expr ();
   l_expr->accept_vis (*this);
-  maybe_expand_expr (l_expr);
 
   /* should syntactically not have outer attributes, though this may
    * not have worked in practice */
   auto &r_expr = expr.get_right_expr ();
   r_expr->accept_vis (*this);
-  maybe_expand_expr (r_expr);
 
   // ensure that they are not marked for strip
   if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -888,13 +841,11 @@ AttrVisitor::visit (AST::CompoundAssignmentExpr &expr)
    * with outer expr */
   auto &l_expr = expr.get_left_expr ();
   l_expr->accept_vis (*this);
-  maybe_expand_expr (l_expr);
 
   /* should syntactically not have outer attributes, though this may
    * not have worked in practice */
   auto &r_expr = expr.get_right_expr ();
   r_expr->accept_vis (*this);
-  maybe_expand_expr (r_expr);
 
   // ensure that they are not marked for strip
   if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -1238,29 +1189,6 @@ AttrVisitor::visit (AST::CallExpr &expr)
   // FIXME: Arthur: Figure out how to refactor this - This is similar to
   // expanding items in the crate or stmts in blocks
   expand_pointer_allow_strip (expr.get_params ());
-  auto &params = expr.get_params ();
-  for (auto it = params.begin (); it != params.end ();)
-    {
-      auto &stmt = *it;
-
-      stmt->accept_vis (*this);
-
-      auto final_fragment = expander.take_expanded_fragment ();
-      if (final_fragment.should_expand ())
-       {
-         // Remove the current expanded invocation
-         it = params.erase (it);
-         for (auto &node : final_fragment.get_nodes ())
-           {
-             it = params.insert (it, node.take_expr ());
-             it++;
-           }
-       }
-      else if (stmt->is_marked_for_strip ())
-       it = params.erase (it);
-      else
-       it++;
-    }
 }
 void
 AttrVisitor::visit (AST::MethodCallExpr &expr)
@@ -1356,13 +1284,7 @@ AttrVisitor::visit (AST::BlockExpr &expr)
       return;
     }
 
-  std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
-    = [] (AST::SingleASTNode node) { return node.take_stmt (); };
-
-  expand_macro_children (MacroExpander::ContextType::BLOCK,
-                        expr.get_statements (), extractor);
-
-  expander.push_context (MacroExpander::ContextType::BLOCK);
+  expand_pointer_allow_strip (expr.get_statements ());
 
   // strip tail expression if exists - can actually fully remove it
   if (expr.has_tail_expr ())
@@ -1370,12 +1292,10 @@ AttrVisitor::visit (AST::BlockExpr &expr)
       auto &tail_expr = expr.get_tail_expr ();
 
       tail_expr->accept_vis (*this);
-      maybe_expand_expr (tail_expr);
 
       if (tail_expr->is_marked_for_strip ())
        expr.strip_tail_expr ();
     }
-  expander.pop_context ();
 }
 
 void
@@ -1393,19 +1313,13 @@ AttrVisitor::visit (AST::ClosureExprInnerTyped &expr)
    * allowed by spec */
   expand_closure_params (expr.get_params ());
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   // can't strip return type, but can strip sub-types
   auto &type = expr.get_return_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   // can't strip expression itself, but can strip sub-expressions
   auto &definition_block = expr.get_definition_block ();
   definition_block->accept_vis (*this);
@@ -1737,7 +1651,6 @@ AttrVisitor::visit (AST::IfExpr &expr)
   // can't strip condition expr itself, but can strip sub-expressions
   auto &condition_expr = expr.get_condition_expr ();
   condition_expr->accept_vis (*this);
-  maybe_expand_expr (condition_expr);
   if (condition_expr->is_marked_for_strip ())
     rust_error_at (condition_expr->get_locus (),
                   "cannot strip expression in this position - outer "
@@ -1765,7 +1678,6 @@ AttrVisitor::visit (AST::IfExprConseqElse &expr)
   // can't strip condition expr itself, but can strip sub-expressions
   auto &condition_expr = expr.get_condition_expr ();
   condition_expr->accept_vis (*this);
-  maybe_expand_expr (condition_expr);
   if (condition_expr->is_marked_for_strip ())
     rust_error_at (condition_expr->get_locus (),
                   "cannot strip expression in this position - outer "
@@ -1801,7 +1713,6 @@ AttrVisitor::visit (AST::IfExprConseqIf &expr)
   // can't strip condition expr itself, but can strip sub-expressions
   auto &condition_expr = expr.get_condition_expr ();
   condition_expr->accept_vis (*this);
-  maybe_expand_expr (condition_expr);
   if (condition_expr->is_marked_for_strip ())
     rust_error_at (condition_expr->get_locus (),
                   "cannot strip expression in this position - outer "
@@ -1837,7 +1748,6 @@ AttrVisitor::visit (AST::IfExprConseqIfLet &expr)
   // can't strip condition expr itself, but can strip sub-expressions
   auto &condition_expr = expr.get_condition_expr ();
   condition_expr->accept_vis (*this);
-  maybe_expand_expr (condition_expr);
   if (condition_expr->is_marked_for_strip ())
     rust_error_at (condition_expr->get_locus (),
                   "cannot strip expression in this position - outer "
@@ -2156,17 +2066,12 @@ AttrVisitor::visit (AST::TypeParam &param)
 
   if (param.has_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
       auto &type = param.get_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 }
 void
@@ -2179,18 +2084,12 @@ AttrVisitor::visit (AST::TypeBoundWhereClauseItem &item)
 {
   // for lifetimes shouldn't require
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   auto &type = item.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   // don't strip directly, only components of bounds
   for (auto &bound : item.get_type_param_bounds ())
     bound->accept_vis (*this);
@@ -2221,18 +2120,12 @@ AttrVisitor::visit (AST::Method &method)
 
   if (method.has_return_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &return_type = method.get_return_type ();
       return_type->accept_vis (*this);
 
-      maybe_expand_type (return_type);
-
       if (return_type->is_marked_for_strip ())
        rust_error_at (return_type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 
   if (method.has_where_clause ())
@@ -2339,18 +2232,12 @@ AttrVisitor::visit (AST::Function &function)
 
   if (function.has_return_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &return_type = function.get_return_type ();
       return_type->accept_vis (*this);
 
-      maybe_expand_type (return_type);
-
       if (return_type->is_marked_for_strip ())
        rust_error_at (return_type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 
   if (function.has_where_clause ())
@@ -2406,10 +2293,6 @@ AttrVisitor::visit (AST::StructStruct &struct_item)
 
   if (struct_item.has_where_clause ())
     expand_where_clause (struct_item.get_where_clause ());
-
-  /* strip struct fields if required - this is presumably
-   * allowed by spec */
-  expand_struct_fields (struct_item.get_fields ());
 }
 void
 AttrVisitor::visit (AST::TupleStruct &tuple_struct)
@@ -2550,19 +2433,13 @@ AttrVisitor::visit (AST::ConstantItem &const_item)
       return;
     }
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   // strip any sub-types
   auto &type = const_item.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   /* strip any internal sub-expressions - expression itself isn't
    * allowed to have external attributes in this position so can't be
    * stripped. */
@@ -2584,19 +2461,13 @@ AttrVisitor::visit (AST::StaticItem &static_item)
       return;
     }
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   // strip any sub-types
   auto &type = static_item.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   /* strip any internal sub-expressions - expression itself isn't
    * allowed to have external attributes in this position so can't be
    * stripped. */
@@ -2670,19 +2541,13 @@ AttrVisitor::visit (AST::TraitItemConst &item)
       return;
     }
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   // strip any sub-types
   auto &type = item.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   /* strip any internal sub-expressions - expression itself isn't
    * allowed to have external attributes in this position so can't be
    * stripped */
@@ -2747,11 +2612,7 @@ AttrVisitor::visit (AST::Trait &trait)
   if (trait.has_where_clause ())
     expand_where_clause (trait.get_where_clause ());
 
-  std::function<std::unique_ptr<AST::TraitItem> (AST::SingleASTNode)> extractor
-    = [] (AST::SingleASTNode node) { return node.take_trait_item (); };
-
-  expand_macro_children (MacroExpander::ContextType::TRAIT,
-                        trait.get_trait_items (), extractor);
+  expand_pointer_allow_strip (trait.get_trait_items ());
 }
 void
 AttrVisitor::visit (AST::InherentImpl &impl)
@@ -2776,26 +2637,16 @@ AttrVisitor::visit (AST::InherentImpl &impl)
   for (auto &param : impl.get_generic_params ())
     param->accept_vis (*this);
 
-  expander.push_context (MacroExpander::ContextType::ITEM);
-
   auto &type = impl.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   if (impl.has_where_clause ())
     expand_where_clause (impl.get_where_clause ());
 
-  std::function<std::unique_ptr<AST::InherentImplItem> (AST::SingleASTNode)>
-    extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); };
-
-  expand_macro_children (MacroExpander::ContextType::IMPL,
-                        impl.get_impl_items (), extractor);
+  expand_pointer_allow_strip (impl.get_impl_items ());
 }
 void
 AttrVisitor::visit (AST::TraitImpl &impl)
@@ -2820,18 +2671,12 @@ AttrVisitor::visit (AST::TraitImpl &impl)
   for (auto &param : impl.get_generic_params ())
     param->accept_vis (*this);
 
-  expander.push_context (MacroExpander::ContextType::ITEM);
-
   auto &type = impl.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
 
-  expander.pop_context ();
-
   auto &trait_path = impl.get_trait_path ();
   visit (trait_path);
   if (trait_path.is_marked_for_strip ())
@@ -2841,12 +2686,7 @@ AttrVisitor::visit (AST::TraitImpl &impl)
   if (impl.has_where_clause ())
     expand_where_clause (impl.get_where_clause ());
 
-  std::function<std::unique_ptr<AST::TraitImplItem> (AST::SingleASTNode)>
-    extractor
-    = [] (AST::SingleASTNode node) { return node.take_trait_impl_item (); };
-
-  expand_macro_children (MacroExpander::ContextType::TRAIT_IMPL,
-                        impl.get_impl_items (), extractor);
+  expand_pointer_allow_strip (impl.get_impl_items ());
 }
 
 void
@@ -2873,17 +2713,11 @@ AttrVisitor::visit (AST::ExternalStaticItem &item)
       return;
     }
 
-  expander.push_context (MacroExpander::ContextType::TYPE);
-
   auto &type = item.get_type ();
   type->accept_vis (*this);
 
-  maybe_expand_type (type);
-
   if (type->is_marked_for_strip ())
     rust_error_at (type->get_locus (), "cannot strip type in this position");
-
-  expander.pop_context ();
 }
 
 void
@@ -2916,19 +2750,13 @@ AttrVisitor::visit (AST::ExternalFunctionItem &item)
          continue;
        }
 
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &type = param.get_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
 
-      expander.pop_context ();
-
       // increment if nothing else happens
       ++it;
     }
@@ -2941,18 +2769,12 @@ AttrVisitor::visit (AST::ExternalFunctionItem &item)
 
   if (item.has_return_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &return_type = item.get_return_type ();
       return_type->accept_vis (*this);
 
-      maybe_expand_type (return_type);
-
       if (return_type->is_marked_for_strip ())
        rust_error_at (return_type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 
   if (item.has_where_clause ())
@@ -2978,12 +2800,7 @@ AttrVisitor::visit (AST::ExternBlock &block)
       return;
     }
 
-  std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)>
-    extractor
-    = [] (AST::SingleASTNode node) { return node.take_external_item (); };
-
-  expand_macro_children (MacroExpander::ContextType::EXTERN,
-                        block.get_extern_items (), extractor);
+  expand_pointer_allow_strip (block.get_extern_items ());
 }
 
 // I don't think it would be possible to strip macros without expansion
@@ -3327,18 +3144,12 @@ AttrVisitor::visit (AST::LetStmt &stmt)
   // similar for type
   if (stmt.has_type ())
     {
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &type = stmt.get_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
-
-      expander.pop_context ();
     }
 
   /* strip any internal sub-expressions - expression itself isn't
@@ -3353,8 +3164,6 @@ AttrVisitor::visit (AST::LetStmt &stmt)
        rust_error_at (init_expr->get_locus (),
                       "cannot strip expression in this position - outer "
                       "attributes not allowed");
-
-      maybe_expand_expr (init_expr);
     }
 }
 void
@@ -3531,19 +3340,13 @@ AttrVisitor::visit (AST::BareFunctionType &type)
          continue;
        }
 
-      expander.push_context (MacroExpander::ContextType::TYPE);
-
       auto &type = param.get_type ();
       type->accept_vis (*this);
 
-      maybe_expand_type (type);
-
       if (type->is_marked_for_strip ())
        rust_error_at (type->get_locus (),
                       "cannot strip type in this position");
 
-      expander.pop_context ();
-
       // increment if nothing else happens
       ++it;
     }
@@ -3566,21 +3369,4 @@ AttrVisitor::visit (AST::BareFunctionType &type)
   // no where clause, apparently
 }
 
-void
-AttrVisitor::maybe_expand_expr (std::unique_ptr<AST::Expr> &expr)
-{
-  auto final_fragment = expander.take_expanded_fragment ();
-  if (final_fragment.should_expand ()
-      && final_fragment.is_expression_fragment ())
-    expr = final_fragment.take_expression_fragment ();
-}
-
-void
-AttrVisitor::maybe_expand_type (std::unique_ptr<AST::Type> &type)
-{
-  auto final_fragment = expander.take_expanded_fragment ();
-  if (final_fragment.should_expand () && final_fragment.is_type_fragment ())
-    type = final_fragment.take_type_fragment ();
-}
-
 } // namespace Rust
index 1ad425ae970df301e6559842076a09c07a04c52e..734d607afd3bf9f644cf1a2a3984b5cede4ff390 100644 (file)
@@ -25,12 +25,8 @@ namespace Rust {
 class AttrVisitor : public AST::ASTVisitor
 {
 private:
-  MacroExpander &expander;
-  void maybe_expand_expr (std::unique_ptr<AST::Expr> &expr);
-  void maybe_expand_type (std::unique_ptr<AST::Type> &expr);
-
 public:
-  AttrVisitor (MacroExpander &expander) : expander (expander) {}
+  AttrVisitor () {}
 
   /* Run the AttrVisitor on an entire crate */
   void go (AST::Crate &crate);
@@ -47,58 +43,10 @@ public:
   void expand_trait_method_decl (AST::TraitMethodDecl &decl);
 
   /**
-   * Expand a set of values, erasing them if they are marked for strip, and
-   * replacing them with expanded macro nodes if necessary.
-   * This function is slightly different from `expand_pointer_allow_strip` as
-   * it can only be called in certain expansion contexts - where macro
-   * invocations are allowed.
+   * Expand a set of values, erasing them if they are marked for strip.
    *
-   * @param ctx Context to use for macro expansion
    * @param values Iterable reference over values to replace or erase
-   * @param extractor Function to call when replacing values with the content
-   *           of an expanded AST node
    */
-  template <typename T, typename U>
-  void expand_macro_children (MacroExpander::ContextType ctx, T &values,
-                             std::function<U (AST::SingleASTNode)> extractor)
-  {
-    expander.push_context (ctx);
-
-    for (auto it = values.begin (); it != values.end ();)
-      {
-       auto &value = *it;
-
-       // mark for stripping if required
-       value->accept_vis (*this);
-
-       auto final_fragment = expander.take_expanded_fragment ();
-
-       if (final_fragment.should_expand ())
-         {
-           it = values.erase (it);
-           for (auto &node : final_fragment.get_nodes ())
-             {
-               auto new_node = extractor (node);
-               if (new_node != nullptr && !new_node->is_marked_for_strip ())
-                 {
-                   it = values.insert (it, std::move (new_node));
-                   it++;
-                 }
-             }
-         }
-       else if (value->is_marked_for_strip ())
-         {
-           it = values.erase (it);
-         }
-       else
-         {
-           ++it;
-         }
-      }
-
-    expander.pop_context ();
-  }
-
   template <typename T> void expand_pointer_allow_strip (T &values)
   {
     for (auto it = values.begin (); it != values.end ();)
@@ -108,13 +56,9 @@ public:
        // mark for stripping if required
        value->accept_vis (*this);
        if (value->is_marked_for_strip ())
-         {
-           it = values.erase (it);
-         }
+         it = values.erase (it);
        else
-         {
-           ++it;
-         }
+         ++it;
       }
   }
 
diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc
new file mode 100644 (file)
index 0000000..2a5dc79
--- /dev/null
@@ -0,0 +1,1340 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-expand-visitor.h"
+
+namespace Rust {
+
+/* Expand all of the macro invocations currently contained in a crate */
+void
+ExpandVisitor::go (AST::Crate &crate)
+{
+  expander.push_context (MacroExpander::ContextType::ITEM);
+
+  // expand attributes recursively and strip items if required
+  //  AttrVisitor attr_visitor (*this);
+  auto &items = crate.items;
+  for (auto it = items.begin (); it != items.end ();)
+    {
+      auto &item = *it;
+      item->accept_vis (*this);
+
+      auto fragment = expander.take_expanded_fragment ();
+      if (fragment.should_expand ())
+       {
+         // Remove the current expanded invocation
+         it = items.erase (it);
+         for (auto &node : fragment.get_nodes ())
+           {
+             it = items.insert (it, node.take_item ());
+             it++;
+           }
+       }
+      else
+       it++;
+    }
+
+  expander.pop_context ();
+}
+
+void
+ExpandVisitor::maybe_expand_expr (std::unique_ptr<AST::Expr> &expr)
+{
+  // FIXME: ARTHUR: Why isn't there a ContextType::EXPR? We can only
+  // reach `parse_expr` once in MacroExpander::transcribe_rule(), but it
+  // would make things clearer wouldn't it?
+  expr->accept_vis (*this);
+
+  auto final_fragment = expander.take_expanded_fragment ();
+  if (final_fragment.should_expand ()
+      && final_fragment.is_expression_fragment ())
+    expr = final_fragment.take_expression_fragment ();
+}
+
+void
+ExpandVisitor::maybe_expand_type (std::unique_ptr<AST::Type> &type)
+{
+  expander.push_context (MacroExpander::ContextType::TYPE);
+
+  type->accept_vis (*this);
+  auto final_fragment = expander.take_expanded_fragment ();
+  if (final_fragment.should_expand () && final_fragment.is_type_fragment ())
+    type = final_fragment.take_type_fragment ();
+
+  expander.pop_context ();
+}
+
+// FIXME: Can this be refactored into a `scoped` method? Which takes a
+// ContextType as parameter and a lambda? And maybe just an std::vector<T>&?
+void
+ExpandVisitor::expand_struct_fields (std::vector<AST::StructField> &fields)
+{
+  for (auto &field : fields)
+    maybe_expand_type (field.get_field_type ());
+}
+
+void
+ExpandVisitor::expand_tuple_fields (std::vector<AST::TupleField> &fields)
+{
+  for (auto &field : fields)
+    maybe_expand_type (field.get_field_type ());
+}
+
+// FIXME: This can definitely be refactored with the method above
+void
+ExpandVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
+{
+  for (auto &param : params)
+    maybe_expand_type (param.get_type ());
+}
+
+void
+ExpandVisitor::expand_generic_args (AST::GenericArgs &args)
+{
+  for (auto &arg : args.get_generic_args ())
+    {
+      switch (arg.get_kind ())
+       {
+       case AST::GenericArg::Kind::Type:
+         maybe_expand_type (arg.get_type ());
+         break;
+       case AST::GenericArg::Kind::Const:
+         maybe_expand_expr (arg.get_expression ());
+         break;
+       default:
+         break;
+         // FIXME: Figure out what to do here if there is ambiguity. Since the
+         // resolver comes after the expansion, we need to figure out a way to
+         // strip ambiguous values here
+         // TODO: ARTHUR: Probably add a `mark_as_strip` method to `GenericArg`
+         // or something. This would clean up this whole thing
+       }
+    }
+
+  // FIXME: Can we have macro invocations in generic type bindings?
+  // expand binding args - strip sub-types only
+  // FIXME: ARTHUR: This needs a test! Foo<Item = macro!()>
+  for (auto &binding : args.get_binding_args ())
+    maybe_expand_type (binding.get_type ());
+}
+
+void
+ExpandVisitor::expand_qualified_path_type (AST::QualifiedPathType &path_type)
+{
+  maybe_expand_type (path_type.get_type ());
+
+  // FIXME: ARTHUR: Can we do macro expansion in there? Needs a test!
+  if (path_type.has_as_clause ())
+    path_type.get_as_type_path ().accept_vis (*this);
+}
+
+void
+ExpandVisitor::expand_closure_params (std::vector<AST::ClosureParam> &params)
+{
+  for (auto &param : params)
+    if (param.has_type_given ())
+      maybe_expand_type (param.get_type ());
+}
+
+void
+ExpandVisitor::expand_self_param (AST::SelfParam &self_param)
+{
+  if (self_param.has_type ())
+    maybe_expand_type (self_param.get_type ());
+
+  /* TODO: maybe check for invariants being violated - e.g. both type and
+   * lifetime? */
+}
+
+void
+ExpandVisitor::expand_where_clause (AST::WhereClause &where_clause)
+{
+  for (auto &item : where_clause.get_items ())
+    visit (item);
+}
+
+void
+ExpandVisitor::expand_trait_function_decl (AST::TraitFunctionDecl &decl)
+{
+  // just expand sub-stuff - can't actually strip generic params themselves
+  for (auto &param : decl.get_generic_params ())
+    visit (param);
+
+  /* strip function parameters if required - this is specifically
+   * allowed by spec */
+  expand_function_params (decl.get_function_params ());
+
+  if (decl.has_return_type ())
+    maybe_expand_type (decl.get_return_type ());
+
+  if (decl.has_where_clause ())
+    expand_where_clause (decl.get_where_clause ());
+}
+
+void
+ExpandVisitor::expand_trait_method_decl (AST::TraitMethodDecl &decl)
+{
+  for (auto &param : decl.get_generic_params ())
+    visit (param);
+
+  /* assuming you can't strip self param - wouldn't be a method
+   * anymore. spec allows outer attrs on self param, but doesn't
+   * specify whether cfg is used. */
+  expand_self_param (decl.get_self_param ());
+
+  /* strip function parameters if required - this is specifically
+   * allowed by spec */
+  expand_function_params (decl.get_function_params ());
+
+  if (decl.has_return_type ())
+
+    maybe_expand_type (decl.get_return_type ());
+
+  if (decl.has_where_clause ())
+    expand_where_clause (decl.get_where_clause ());
+}
+
+void
+ExpandVisitor::visit (AST::Token &)
+{}
+
+void
+ExpandVisitor::visit (AST::DelimTokenTree &)
+{}
+
+void
+ExpandVisitor::visit (AST::AttrInputMetaItemContainer &)
+{}
+
+void
+ExpandVisitor::visit (AST::IdentifierExpr &ident_expr)
+{}
+
+void
+ExpandVisitor::visit (AST::Lifetime &)
+{}
+
+void
+ExpandVisitor::visit (AST::LifetimeParam &)
+{}
+
+void
+ExpandVisitor::visit (AST::ConstGenericParam &)
+{}
+
+void
+ExpandVisitor::visit (AST::MacroInvocation &macro_invoc)
+{
+  // TODO: Can we do the AST fragment replacing here? Probably not, right?
+  expander.expand_invoc (macro_invoc, macro_invoc.has_semicolon ());
+}
+
+void
+ExpandVisitor::visit (AST::PathInExpression &path)
+{
+  for (auto &segment : path.get_segments ())
+    if (segment.has_generic_args ())
+      expand_generic_args (segment.get_generic_args ());
+}
+
+void
+ExpandVisitor::visit (AST::TypePathSegment &)
+{}
+
+void
+ExpandVisitor::visit (AST::TypePathSegmentGeneric &segment)
+{}
+
+void
+ExpandVisitor::visit (AST::TypePathSegmentFunction &segment)
+{
+  auto &type_path_function = segment.get_type_path_function ();
+
+  for (auto &type : type_path_function.get_params ())
+    visit (type);
+
+  if (type_path_function.has_return_type ())
+    maybe_expand_type (type_path_function.get_return_type ());
+}
+
+void
+ExpandVisitor::visit (AST::TypePath &path)
+{
+  for (auto &segment : path.get_segments ())
+    visit (segment);
+}
+
+void
+ExpandVisitor::visit (AST::QualifiedPathInExpression &path)
+{
+  expand_qualified_path_type (path.get_qualified_path_type ());
+
+  for (auto &segment : path.get_segments ())
+    if (segment.has_generic_args ())
+      expand_generic_args (segment.get_generic_args ());
+}
+
+void
+ExpandVisitor::visit (AST::QualifiedPathInType &path)
+{
+  expand_qualified_path_type (path.get_qualified_path_type ());
+
+  // this shouldn't strip any segments, but can strip inside them
+  for (auto &segment : path.get_segments ())
+    visit (segment);
+}
+
+void
+ExpandVisitor::visit (AST::LiteralExpr &expr)
+{}
+
+void
+ExpandVisitor::visit (AST::AttrInputLiteral &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaItemLitExpr &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaItemPathLit &)
+{}
+
+void
+ExpandVisitor::visit (AST::BorrowExpr &expr)
+{
+  visit (expr.get_borrowed_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::DereferenceExpr &expr)
+{
+  visit (expr.get_dereferenced_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ErrorPropagationExpr &expr)
+{
+  visit (expr.get_propagating_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::NegationExpr &expr)
+{
+  visit (expr.get_negated_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ArithmeticOrLogicalExpr &expr)
+{
+  maybe_expand_expr (expr.get_left_expr ());
+  maybe_expand_expr (expr.get_right_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ComparisonExpr &expr)
+{
+  maybe_expand_expr (expr.get_left_expr ());
+  maybe_expand_expr (expr.get_right_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::LazyBooleanExpr &expr)
+{
+  maybe_expand_expr (expr.get_left_expr ());
+  maybe_expand_expr (expr.get_right_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::TypeCastExpr &expr)
+{
+  visit (expr.get_casted_expr ());
+
+  visit (expr.get_type_to_cast_to ());
+}
+
+void
+ExpandVisitor::visit (AST::AssignmentExpr &expr)
+{
+  maybe_expand_expr (expr.get_left_expr ());
+  maybe_expand_expr (expr.get_right_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::CompoundAssignmentExpr &expr)
+{
+  maybe_expand_expr (expr.get_left_expr ());
+  maybe_expand_expr (expr.get_right_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::GroupedExpr &expr)
+{
+  visit (expr.get_expr_in_parens ());
+}
+
+void
+ExpandVisitor::visit (AST::ArrayElemsValues &elems)
+{
+  for (auto &elem : elems.get_values ())
+    visit (elem);
+}
+
+void
+ExpandVisitor::visit (AST::ArrayElemsCopied &elems)
+{
+  visit (elems.get_elem_to_copy ());
+  visit (elems.get_num_copies ());
+}
+
+void
+ExpandVisitor::visit (AST::ArrayExpr &expr)
+{
+  visit (expr.get_array_elems ());
+}
+
+void
+ExpandVisitor::visit (AST::ArrayIndexExpr &expr)
+{
+  visit (expr.get_array_expr ());
+  visit (expr.get_index_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::TupleExpr &expr)
+{
+  for (auto &element : expr.get_tuple_elems ())
+    visit (element);
+}
+
+void
+ExpandVisitor::visit (AST::TupleIndexExpr &expr)
+{
+  visit (expr.get_tuple_expr ());
+
+  // We can't have macro invocations for tuple indexes, right? Need a test!
+}
+
+void
+ExpandVisitor::visit (AST::StructExprStruct &expr)
+{}
+
+void
+ExpandVisitor::visit (AST::StructExprFieldIdentifier &)
+{}
+
+void
+ExpandVisitor::visit (AST::StructExprFieldIdentifierValue &field)
+{
+  visit (field.get_value ());
+}
+
+void
+ExpandVisitor::visit (AST::StructExprFieldIndexValue &field)
+{
+  visit (field.get_value ());
+}
+
+void
+ExpandVisitor::visit (AST::StructExprStructFields &expr)
+{
+  for (auto &field : expr.get_fields ())
+    visit (field);
+
+  if (expr.has_struct_base ())
+    visit (expr.get_struct_base ().get_base_struct ());
+}
+
+void
+ExpandVisitor::visit (AST::StructExprStructBase &expr)
+{
+  visit (expr.get_struct_base ().get_base_struct ());
+}
+
+void
+ExpandVisitor::visit (AST::CallExpr &expr)
+{
+  visit (expr.get_function_expr ());
+
+  for (auto &param : expr.get_params ())
+    maybe_expand_expr (param);
+}
+
+void
+ExpandVisitor::visit (AST::MethodCallExpr &expr)
+{
+  visit (expr.get_receiver_expr ());
+
+  for (auto &param : expr.get_params ())
+    maybe_expand_expr (param);
+}
+
+void
+ExpandVisitor::visit (AST::FieldAccessExpr &expr)
+{
+  visit (expr.get_receiver_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ClosureExprInner &expr)
+{
+  expand_closure_params (expr.get_params ());
+
+  visit (expr.get_definition_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::BlockExpr &expr)
+{
+  std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
+    = [] (AST::SingleASTNode node) { return node.take_stmt (); };
+
+  expand_macro_children (MacroExpander::ContextType::BLOCK,
+                        expr.get_statements (), extractor);
+
+  expander.push_context (MacroExpander::ContextType::BLOCK);
+
+  if (expr.has_tail_expr ())
+    maybe_expand_expr (expr.get_tail_expr ());
+
+  expander.pop_context ();
+}
+
+void
+ExpandVisitor::visit (AST::ClosureExprInnerTyped &expr)
+{
+  expand_closure_params (expr.get_params ());
+
+  maybe_expand_type (expr.get_return_type ());
+
+  visit (expr.get_definition_block ());
+}
+
+void
+ExpandVisitor::visit (AST::ContinueExpr &expr)
+{}
+
+void
+ExpandVisitor::visit (AST::BreakExpr &expr)
+{
+  if (expr.has_break_expr ())
+    visit (expr.get_break_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::RangeFromToExpr &expr)
+{
+  visit (expr.get_from_expr ());
+  visit (expr.get_to_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::RangeFromExpr &expr)
+{
+  visit (expr.get_from_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::RangeToExpr &expr)
+{
+  visit (expr.get_to_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::RangeFullExpr &)
+{}
+
+void
+ExpandVisitor::visit (AST::RangeFromToInclExpr &expr)
+{
+  visit (expr.get_from_expr ());
+  visit (expr.get_to_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::RangeToInclExpr &expr)
+{
+  visit (expr.get_to_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ReturnExpr &expr)
+{
+  if (expr.has_returned_expr ())
+    visit (expr.get_returned_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::UnsafeBlockExpr &expr)
+{
+  visit (expr.get_block_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::LoopExpr &expr)
+{
+  visit (expr.get_loop_block ());
+}
+
+void
+ExpandVisitor::visit (AST::WhileLoopExpr &expr)
+{
+  visit (expr.get_predicate_expr ());
+  visit (expr.get_loop_block ());
+}
+
+void
+ExpandVisitor::visit (AST::WhileLetLoopExpr &expr)
+{
+  for (auto &pattern : expr.get_patterns ())
+    visit (pattern);
+
+  visit (expr.get_scrutinee_expr ());
+  visit (expr.get_loop_block ());
+}
+
+void
+ExpandVisitor::visit (AST::ForLoopExpr &expr)
+{
+  visit (expr.get_pattern ());
+  visit (expr.get_iterator_expr ());
+  visit (expr.get_loop_block ());
+}
+
+void
+ExpandVisitor::visit (AST::IfExpr &expr)
+{
+  maybe_expand_expr (expr.get_condition_expr ());
+
+  visit (expr.get_if_block ());
+}
+
+void
+ExpandVisitor::visit (AST::IfExprConseqElse &expr)
+{
+  maybe_expand_expr (expr.get_condition_expr ());
+
+  visit (expr.get_if_block ());
+  visit (expr.get_else_block ());
+}
+
+void
+ExpandVisitor::visit (AST::IfExprConseqIf &expr)
+{
+  maybe_expand_expr (expr.get_condition_expr ());
+
+  visit (expr.get_if_block ());
+  visit (expr.get_conseq_if_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::IfExprConseqIfLet &expr)
+{
+  maybe_expand_expr (expr.get_condition_expr ());
+
+  visit (expr.get_if_block ());
+  visit (expr.get_conseq_if_let_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::IfLetExpr &expr)
+{
+  maybe_expand_expr (expr.get_value_expr ());
+
+  visit (expr.get_if_block ());
+}
+
+void
+ExpandVisitor::visit (AST::IfLetExprConseqElse &expr)
+{
+  maybe_expand_expr (expr.get_value_expr ());
+
+  visit (expr.get_if_block ());
+  visit (expr.get_else_block ());
+}
+
+void
+ExpandVisitor::visit (AST::IfLetExprConseqIf &expr)
+{
+  maybe_expand_expr (expr.get_value_expr ());
+
+  visit (expr.get_if_block ());
+  visit (expr.get_conseq_if_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::IfLetExprConseqIfLet &expr)
+{
+  maybe_expand_expr (expr.get_value_expr ());
+
+  visit (expr.get_if_block ());
+  visit (expr.get_conseq_if_let_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::MatchExpr &expr)
+{
+  visit (expr.get_scrutinee_expr ());
+
+  for (auto &match_case : expr.get_match_cases ())
+    {
+      auto &arm = match_case.get_arm ();
+
+      for (auto &pattern : arm.get_patterns ())
+       visit (pattern);
+
+      if (arm.has_match_arm_guard ())
+       visit (arm.get_guard_expr ());
+
+      visit (match_case.get_expr ());
+    }
+}
+
+void
+ExpandVisitor::visit (AST::AwaitExpr &expr)
+{
+  visit (expr.get_awaited_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::AsyncBlockExpr &expr)
+{
+  visit (expr.get_block_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::TypeParam &param)
+{
+  for (auto &bound : param.get_type_param_bounds ())
+    visit (bound);
+
+  if (param.has_type ())
+    maybe_expand_type (param.get_type ());
+}
+
+void
+ExpandVisitor::visit (AST::LifetimeWhereClauseItem &)
+{}
+
+void
+ExpandVisitor::visit (AST::TypeBoundWhereClauseItem &item)
+{
+  maybe_expand_type (item.get_type ());
+
+  for (auto &bound : item.get_type_param_bounds ())
+    visit (bound);
+}
+
+void
+ExpandVisitor::visit (AST::Method &method)
+{
+  for (auto &param : method.get_generic_params ())
+    visit (param);
+
+  expand_self_param (method.get_self_param ());
+  expand_function_params (method.get_function_params ());
+
+  if (method.has_return_type ())
+    visit (method.get_return_type ());
+
+  if (method.has_where_clause ())
+    expand_where_clause (method.get_where_clause ());
+
+  visit (method.get_definition ());
+}
+
+void
+ExpandVisitor::visit (AST::Module &module)
+{
+  if (module.get_kind () == AST::Module::ModuleKind::LOADED)
+    for (auto &item : module.get_items ())
+      visit (item);
+}
+
+void
+ExpandVisitor::visit (AST::ExternCrate &crate)
+{}
+
+void
+ExpandVisitor::visit (AST::UseTreeGlob &)
+{}
+
+void
+ExpandVisitor::visit (AST::UseTreeList &)
+{}
+
+void
+ExpandVisitor::visit (AST::UseTreeRebind &)
+{}
+
+void
+ExpandVisitor::visit (AST::UseDeclaration &use_decl)
+{}
+
+void
+ExpandVisitor::visit (AST::Function &function)
+{
+  for (auto &param : function.get_generic_params ())
+    visit (param);
+
+  expand_function_params (function.get_function_params ());
+
+  if (function.has_return_type ())
+    maybe_expand_type (function.get_return_type ());
+
+  if (function.has_where_clause ())
+    expand_where_clause (function.get_where_clause ());
+
+  visit (function.get_definition ());
+}
+
+void
+ExpandVisitor::visit (AST::TypeAlias &type_alias)
+{
+  visit (type_alias.get_type_aliased ());
+}
+
+void
+ExpandVisitor::visit (AST::StructStruct &struct_item)
+{
+  for (auto &generic : struct_item.get_generic_params ())
+    visit (generic);
+
+  if (struct_item.has_where_clause ())
+    expand_where_clause (struct_item.get_where_clause ());
+
+  expand_struct_fields (struct_item.get_fields ());
+}
+
+void
+ExpandVisitor::visit (AST::TupleStruct &tuple_struct)
+{
+  for (auto &generic : tuple_struct.get_generic_params ())
+    visit (generic);
+
+  if (tuple_struct.has_where_clause ())
+    expand_where_clause (tuple_struct.get_where_clause ());
+
+  expand_tuple_fields (tuple_struct.get_fields ());
+}
+
+void
+ExpandVisitor::visit (AST::EnumItem &item)
+{}
+
+void
+ExpandVisitor::visit (AST::EnumItemTuple &item)
+{
+  expand_tuple_fields (item.get_tuple_fields ());
+}
+
+void
+ExpandVisitor::visit (AST::EnumItemStruct &item)
+{
+  expand_struct_fields (item.get_struct_fields ());
+}
+
+void
+ExpandVisitor::visit (AST::EnumItemDiscriminant &item)
+{
+  visit (item.get_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::Enum &enum_item)
+{
+  for (auto &generic : enum_item.get_generic_params ())
+    visit (generic);
+
+  for (auto &variant : enum_item.get_variants ())
+    visit (variant);
+}
+
+void
+ExpandVisitor::visit (AST::Union &union_item)
+{
+  for (auto &generic : union_item.get_generic_params ())
+    visit (generic);
+
+  expand_struct_fields (union_item.get_variants ());
+}
+
+void
+ExpandVisitor::visit (AST::ConstantItem &const_item)
+{
+  maybe_expand_type (const_item.get_type ());
+
+  visit (const_item.get_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::StaticItem &static_item)
+{
+  maybe_expand_type (static_item.get_type ());
+
+  visit (static_item.get_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::TraitItemFunc &item)
+{
+  expand_trait_function_decl (item.get_trait_function_decl ());
+
+  if (item.has_definition ())
+    visit (item.get_definition ());
+}
+
+void
+ExpandVisitor::visit (AST::TraitItemMethod &item)
+{
+  expand_trait_method_decl (item.get_trait_method_decl ());
+
+  if (item.has_definition ())
+    visit (item.get_definition ());
+}
+
+void
+ExpandVisitor::visit (AST::TraitItemConst &const_item)
+{
+  maybe_expand_type (const_item.get_type ());
+
+  if (const_item.has_expr ())
+    visit (const_item.get_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::TraitItemType &item)
+{
+  for (auto &type : item.get_type_param_bounds ())
+    visit (type);
+}
+
+void
+ExpandVisitor::visit (AST::Trait &trait)
+{
+  for (auto &generic : trait.get_generic_params ())
+    visit (generic);
+
+  for (auto &bound : trait.get_type_param_bounds ())
+    visit (bound);
+
+  if (trait.has_where_clause ())
+    expand_where_clause (trait.get_where_clause ());
+
+  expander.push_context (MacroExpander::ContextType::TRAIT);
+
+  std::function<std::unique_ptr<AST::TraitItem> (AST::SingleASTNode)> extractor
+    = [] (AST::SingleASTNode node) { return node.take_trait_item (); };
+
+  expand_macro_children (MacroExpander::ContextType::TRAIT,
+                        trait.get_trait_items (), extractor);
+
+  expander.pop_context ();
+}
+
+void
+ExpandVisitor::visit (AST::InherentImpl &impl)
+{
+  // just expand sub-stuff - can't actually strip generic params themselves
+  for (auto &generic : impl.get_generic_params ())
+    visit (generic);
+
+  // FIXME: Is that correct? How do we test that?
+  expander.push_context (MacroExpander::ContextType::ITEM);
+
+  maybe_expand_type (impl.get_type ());
+
+  expander.pop_context ();
+
+  if (impl.has_where_clause ())
+    expand_where_clause (impl.get_where_clause ());
+
+  std::function<std::unique_ptr<AST::InherentImplItem> (AST::SingleASTNode)>
+    extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); };
+
+  expand_macro_children (MacroExpander::ContextType::IMPL,
+                        impl.get_impl_items (), extractor);
+}
+
+void
+ExpandVisitor::visit (AST::TraitImpl &impl)
+{
+  // just expand sub-stuff - can't actually strip generic params themselves
+  for (auto &param : impl.get_generic_params ())
+    visit (param);
+
+  // FIXME: Is that correct? How do we test that?
+  expander.push_context (MacroExpander::ContextType::ITEM);
+
+  maybe_expand_type (impl.get_type ());
+
+  expander.pop_context ();
+
+  visit (impl.get_trait_path ());
+
+  if (impl.has_where_clause ())
+    expand_where_clause (impl.get_where_clause ());
+
+  std::function<std::unique_ptr<AST::TraitImplItem> (AST::SingleASTNode)>
+    extractor
+    = [] (AST::SingleASTNode node) { return node.take_trait_impl_item (); };
+
+  expand_macro_children (MacroExpander::ContextType::TRAIT_IMPL,
+                        impl.get_impl_items (), extractor);
+}
+
+void
+ExpandVisitor::visit (AST::ExternalTypeItem &item)
+{}
+
+void
+ExpandVisitor::visit (AST::ExternalStaticItem &static_item)
+{
+  maybe_expand_type (static_item.get_type ());
+}
+
+void
+ExpandVisitor::visit (AST::ExternalFunctionItem &item)
+{
+  for (auto &param : item.get_generic_params ())
+    visit (param);
+
+  // FIXME: Should this work? What is the difference between NamedFunctionParam
+  // and FunctionParam?
+  // expand_function_params (item.get_function_params ());
+
+  for (auto &param : item.get_function_params ())
+    maybe_expand_type (param.get_type ());
+
+  if (item.has_return_type ())
+    maybe_expand_type (item.get_return_type ());
+
+  if (item.has_where_clause ())
+    expand_where_clause (item.get_where_clause ());
+}
+
+void
+ExpandVisitor::visit (AST::ExternBlock &block)
+{
+  std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)>
+    extractor
+    = [] (AST::SingleASTNode node) { return node.take_external_item (); };
+
+  expand_macro_children (MacroExpander::ContextType::EXTERN,
+                        block.get_extern_items (), extractor);
+}
+
+// I don't think it would be possible to strip macros without expansion
+void
+ExpandVisitor::visit (AST::MacroMatchFragment &)
+{}
+
+void
+ExpandVisitor::visit (AST::MacroMatchRepetition &)
+{}
+
+void
+ExpandVisitor::visit (AST::MacroMatcher &)
+{}
+
+void
+ExpandVisitor::visit (AST::MacroRulesDefinition &rules_def)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaItemPath &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaItemSeq &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaWord &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaNameValueStr &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaListPaths &)
+{}
+
+void
+ExpandVisitor::visit (AST::MetaListNameValueStr &)
+{}
+
+void
+ExpandVisitor::visit (AST::LiteralPattern &)
+{}
+
+void
+ExpandVisitor::visit (AST::IdentifierPattern &pattern)
+{
+  if (pattern.has_pattern_to_bind ())
+    visit (pattern.get_pattern_to_bind ());
+}
+
+void
+ExpandVisitor::visit (AST::WildcardPattern &)
+{}
+
+void
+ExpandVisitor::visit (AST::RestPattern &)
+{}
+
+void
+ExpandVisitor::visit (AST::RangePatternBoundLiteral &)
+{}
+
+void
+ExpandVisitor::visit (AST::RangePatternBoundPath &bound)
+{
+  visit (bound.get_path ());
+}
+
+void
+ExpandVisitor::visit (AST::RangePatternBoundQualPath &bound)
+{
+  visit (bound.get_qualified_path ());
+}
+
+void
+ExpandVisitor::visit (AST::RangePattern &pattern)
+{
+  visit (pattern.get_lower_bound ());
+  visit (pattern.get_upper_bound ());
+}
+
+void
+ExpandVisitor::visit (AST::ReferencePattern &pattern)
+{
+  visit (pattern.get_referenced_pattern ());
+}
+
+void
+ExpandVisitor::visit (AST::StructPatternFieldTuplePat &field)
+{
+  visit (field.get_index_pattern ());
+}
+
+void
+ExpandVisitor::visit (AST::StructPatternFieldIdentPat &field)
+{
+  visit (field.get_ident_pattern ());
+}
+
+void
+ExpandVisitor::visit (AST::StructPatternFieldIdent &field)
+{}
+
+void
+ExpandVisitor::visit (AST::StructPattern &pattern)
+{
+  visit (pattern.get_path ());
+
+  for (auto &inner :
+       pattern.get_struct_pattern_elems ().get_struct_pattern_fields ())
+    visit (inner);
+}
+
+void
+ExpandVisitor::visit (AST::TupleStructItemsNoRange &tuple_items)
+{
+  for (auto &pattern : tuple_items.get_patterns ())
+    visit (pattern);
+}
+
+void
+ExpandVisitor::visit (AST::TupleStructItemsRange &tuple_items)
+{
+  for (auto &lower_pattern : tuple_items.get_lower_patterns ())
+    visit (lower_pattern);
+  for (auto &upper_pattern : tuple_items.get_upper_patterns ())
+    visit (upper_pattern);
+}
+
+void
+ExpandVisitor::visit (AST::TupleStructPattern &pattern)
+{
+  visit (pattern.get_path ());
+
+  if (pattern.has_items ())
+    visit (pattern.get_items ());
+}
+
+void
+ExpandVisitor::visit (AST::TuplePatternItemsMultiple &tuple_items)
+{
+  for (auto &pattern : tuple_items.get_patterns ())
+    visit (pattern);
+}
+
+void
+ExpandVisitor::visit (AST::TuplePatternItemsRanged &tuple_items)
+{
+  for (auto &pattern : tuple_items.get_lower_patterns ())
+    visit (pattern);
+  for (auto &pattern : tuple_items.get_upper_patterns ())
+    visit (pattern);
+}
+
+void
+ExpandVisitor::visit (AST::TuplePattern &pattern)
+{
+  if (pattern.has_tuple_pattern_items ())
+    visit (pattern.get_items ());
+}
+
+void
+ExpandVisitor::visit (AST::GroupedPattern &pattern)
+{
+  visit (pattern.get_pattern_in_parens ());
+}
+
+void
+ExpandVisitor::visit (AST::SlicePattern &pattern)
+{
+  for (auto &item : pattern.get_items ())
+    visit (item);
+}
+
+void
+ExpandVisitor::visit (AST::AltPattern &pattern)
+{
+  for (auto &alt : pattern.get_alts ())
+    visit (alt);
+}
+
+void
+ExpandVisitor::visit (AST::EmptyStmt &)
+{}
+
+void
+ExpandVisitor::visit (AST::LetStmt &stmt)
+{
+  visit (stmt.get_pattern ());
+
+  if (stmt.has_type ())
+    maybe_expand_type (stmt.get_type ());
+
+  if (stmt.has_init_expr ())
+    maybe_expand_expr (stmt.get_init_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ExprStmtWithoutBlock &stmt)
+{
+  visit (stmt.get_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::ExprStmtWithBlock &stmt)
+{
+  visit (stmt.get_expr ());
+}
+
+void
+ExpandVisitor::visit (AST::TraitBound &bound)
+{
+  visit (bound.get_type_path ());
+}
+
+void
+ExpandVisitor::visit (AST::ImplTraitType &type)
+{
+  for (auto &bound : type.get_type_param_bounds ())
+    visit (bound);
+}
+
+void
+ExpandVisitor::visit (AST::TraitObjectType &type)
+{
+  for (auto &bound : type.get_type_param_bounds ())
+    visit (bound);
+}
+
+void
+ExpandVisitor::visit (AST::ParenthesisedType &type)
+{
+  visit (type.get_type_in_parens ());
+}
+
+void
+ExpandVisitor::visit (AST::ImplTraitTypeOneBound &type)
+{
+  visit (type.get_trait_bound ());
+}
+
+void
+ExpandVisitor::visit (AST::TraitObjectTypeOneBound &type)
+{
+  visit (type.get_trait_bound ());
+}
+
+void
+ExpandVisitor::visit (AST::TupleType &type)
+{
+  for (auto &elem : type.get_elems ())
+    visit (elem);
+}
+
+void
+ExpandVisitor::visit (AST::NeverType &)
+{}
+
+void
+ExpandVisitor::visit (AST::RawPointerType &type)
+{
+  visit (type.get_type_pointed_to ());
+}
+
+void
+ExpandVisitor::visit (AST::ReferenceType &type)
+{
+  visit (type.get_type_referenced ());
+}
+
+void
+ExpandVisitor::visit (AST::ArrayType &type)
+{
+  visit (type.get_elem_type ());
+}
+
+void
+ExpandVisitor::visit (AST::SliceType &type)
+{
+  visit (type.get_elem_type ());
+}
+
+void
+ExpandVisitor::visit (AST::InferredType &)
+{}
+
+void
+ExpandVisitor::visit (AST::BareFunctionType &type)
+{
+  for (auto &param : type.get_function_params ())
+    maybe_expand_type (param.get_type ());
+
+  if (type.has_return_type ())
+    visit (type.get_return_type ());
+}
+
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-expand-visitor.h b/gcc/rust/expand/rust-expand-visitor.h
new file mode 100644 (file)
index 0000000..e832d4a
--- /dev/null
@@ -0,0 +1,320 @@
+// Copyright (C) 2020-2023 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-visitor.h"
+#include "rust-macro-expand.h"
+
+namespace Rust {
+
+class ExpandVisitor : public AST::ASTVisitor
+{
+public:
+  ExpandVisitor (MacroExpander &expander) : expander (expander) {}
+
+  /* Expand all of the macro invocations currently contained in a crate */
+  void go (AST::Crate &crate);
+
+  /* Maybe expand a macro invocation in lieu of an expression */
+  void maybe_expand_expr (std::unique_ptr<AST::Expr> &expr);
+
+  /* Maybe expand a macro invocation in lieu of a type */
+  void maybe_expand_type (std::unique_ptr<AST::Type> &type);
+
+  /**
+   * Expand all macro invocations in lieu of types within a vector of struct
+   * fields
+   */
+  void expand_struct_fields (std::vector<AST::StructField> &fields);
+
+  /**
+   * Expand all macro invocations in lieu of types within a vector of tuple
+   * fields
+   */
+  void expand_tuple_fields (std::vector<AST::TupleField> &fields);
+
+  /**
+   * Expand all macro invocations in lieu of types within a list of function
+   * parameters
+   */
+  void expand_function_params (std::vector<AST::FunctionParam> &params);
+
+  /**
+   * Expand all macro invocations in lieu of types within a list of generic
+   * arguments
+   */
+  void expand_generic_args (AST::GenericArgs &args);
+
+  /**
+   * Expand a macro invocation in lieu of a qualified path type
+   */
+  void expand_qualified_path_type (AST::QualifiedPathType &path_type);
+
+  void expand_closure_params (std::vector<AST::ClosureParam> &params);
+  void expand_self_param (AST::SelfParam &self_param);
+  void expand_where_clause (AST::WhereClause &where_clause);
+  void expand_trait_function_decl (AST::TraitFunctionDecl &decl);
+  void expand_trait_method_decl (AST::TraitMethodDecl &decl);
+
+  /**
+   * Expand a set of values, erasing them if they are marked for strip, and
+   * replacing them with expanded macro nodes if necessary.
+   * This function is slightly different from `expand_pointer_allow_strip` as
+   * it can only be called in certain expansion contexts - where macro
+   * invocations are allowed.
+   *
+   * @param ctx Context to use for macro expansion
+   * @param values Iterable reference over values to replace or erase
+   * @param extractor Function to call when replacing values with the content
+   *           of an expanded AST node
+   */
+  template <typename T, typename U>
+  void expand_macro_children (MacroExpander::ContextType ctx, T &values,
+                             std::function<U (AST::SingleASTNode)> extractor)
+  {
+    expander.push_context (ctx);
+
+    for (auto it = values.begin (); it != values.end ();)
+      {
+       auto &value = *it;
+
+       // Perform expansion
+       value->accept_vis (*this);
+
+       auto final_fragment = expander.take_expanded_fragment ();
+
+       // FIXME: Is that correct? It seems *extremely* dodgy
+       if (final_fragment.should_expand ())
+         {
+           it = values.erase (it);
+           for (auto &node : final_fragment.get_nodes ())
+             {
+               auto new_node = extractor (node);
+               if (new_node != nullptr)
+                 {
+                   it = values.insert (it, std::move (new_node));
+                   it++;
+                 }
+             }
+         }
+       else
+         {
+           ++it;
+         }
+      }
+
+    expander.pop_context ();
+  }
+
+  // TODO: See if possible to make more specialization for Impl items, Block
+  // stmts etc? This could allow us to remove expand_macro_children or at least
+  // its extractor parameter
+  /**
+   * These functions allow to easily visit `std::unique_ptr`s as well as
+   * _replace_ them when necessary, e.g when expanding macro invocations in a
+   * list of expressions or types. The most generic version of the function will
+   * simply call the visitor again on the pointer, but there are two
+   * specializations for `std::unique_ptr<Expr>` and `std::unique_ptr<Type>` to
+   * enable replacing as well.
+   */
+  template <typename T> void visit (std::unique_ptr<T> &value)
+  {
+    value->accept_vis (*this);
+  }
+
+  template <typename T> void visit (std::unique_ptr<AST::Expr> &expr)
+  {
+    maybe_expand_expr (expr);
+  }
+
+  template <typename T> void visit (std::unique_ptr<AST::Type> &type)
+  {
+    maybe_expand_type (type);
+  }
+
+  void visit (AST::Token &) override;
+  void visit (AST::DelimTokenTree &) override;
+  void visit (AST::AttrInputMetaItemContainer &) override;
+  void visit (AST::IdentifierExpr &ident_expr) override;
+  void visit (AST::Lifetime &) override;
+  void visit (AST::LifetimeParam &) override;
+  void visit (AST::ConstGenericParam &) override;
+
+  void visit (AST::MacroInvocation &macro_invoc) override;
+
+  void visit (AST::PathInExpression &path) override;
+  void visit (AST::TypePathSegment &) override;
+  void visit (AST::TypePathSegmentGeneric &segment) override;
+  void visit (AST::TypePathSegmentFunction &segment) override;
+  void visit (AST::TypePath &path) override;
+  void visit (AST::QualifiedPathInExpression &path) override;
+  void visit (AST::QualifiedPathInType &path) override;
+
+  void visit (AST::LiteralExpr &expr) override;
+  void visit (AST::AttrInputLiteral &) override;
+  void visit (AST::MetaItemLitExpr &) override;
+  void visit (AST::MetaItemPathLit &) override;
+  void visit (AST::BorrowExpr &expr) override;
+  void visit (AST::DereferenceExpr &expr) override;
+  void visit (AST::ErrorPropagationExpr &expr) override;
+  void visit (AST::NegationExpr &expr) override;
+  void visit (AST::ArithmeticOrLogicalExpr &expr) override;
+  void visit (AST::ComparisonExpr &expr) override;
+  void visit (AST::LazyBooleanExpr &expr) override;
+  void visit (AST::TypeCastExpr &expr) override;
+  void visit (AST::AssignmentExpr &expr) override;
+  void visit (AST::CompoundAssignmentExpr &expr) override;
+  void visit (AST::GroupedExpr &expr) override;
+  void visit (AST::ArrayElemsValues &elems) override;
+  void visit (AST::ArrayElemsCopied &elems) override;
+  void visit (AST::ArrayExpr &expr) override;
+  void visit (AST::ArrayIndexExpr &expr) override;
+  void visit (AST::TupleExpr &expr) override;
+  void visit (AST::TupleIndexExpr &expr) override;
+  void visit (AST::StructExprStruct &expr) override;
+  void visit (AST::StructExprFieldIdentifier &) override;
+  void visit (AST::StructExprFieldIdentifierValue &field) override;
+
+  void visit (AST::StructExprFieldIndexValue &field) override;
+  void visit (AST::StructExprStructFields &expr) override;
+  void visit (AST::StructExprStructBase &expr) override;
+  void visit (AST::CallExpr &expr) override;
+  void visit (AST::MethodCallExpr &expr) override;
+  void visit (AST::FieldAccessExpr &expr) override;
+  void visit (AST::ClosureExprInner &expr) override;
+
+  void visit (AST::BlockExpr &expr) override;
+
+  void visit (AST::ClosureExprInnerTyped &expr) override;
+  void visit (AST::ContinueExpr &expr) override;
+  void visit (AST::BreakExpr &expr) override;
+  void visit (AST::RangeFromToExpr &expr) override;
+  void visit (AST::RangeFromExpr &expr) override;
+  void visit (AST::RangeToExpr &expr) override;
+  void visit (AST::RangeFullExpr &) override;
+  void visit (AST::RangeFromToInclExpr &expr) override;
+  void visit (AST::RangeToInclExpr &expr) override;
+  void visit (AST::ReturnExpr &expr) override;
+  void visit (AST::UnsafeBlockExpr &expr) override;
+  void visit (AST::LoopExpr &expr) override;
+  void visit (AST::WhileLoopExpr &expr) override;
+  void visit (AST::WhileLetLoopExpr &expr) override;
+  void visit (AST::ForLoopExpr &expr) override;
+  void visit (AST::IfExpr &expr) override;
+  void visit (AST::IfExprConseqElse &expr) override;
+  void visit (AST::IfExprConseqIf &expr) override;
+  void visit (AST::IfExprConseqIfLet &expr) override;
+  void visit (AST::IfLetExpr &expr) override;
+  void visit (AST::IfLetExprConseqElse &expr) override;
+  void visit (AST::IfLetExprConseqIf &expr) override;
+  void visit (AST::IfLetExprConseqIfLet &expr) override;
+  void visit (AST::MatchExpr &expr) override;
+  void visit (AST::AwaitExpr &expr) override;
+  void visit (AST::AsyncBlockExpr &expr) override;
+  void visit (AST::TypeParam &param) override;
+  void visit (AST::LifetimeWhereClauseItem &) override;
+  void visit (AST::TypeBoundWhereClauseItem &item) override;
+  void visit (AST::Method &method) override;
+  void visit (AST::Module &module) override;
+  void visit (AST::ExternCrate &crate) override;
+  void visit (AST::UseTreeGlob &) override;
+  void visit (AST::UseTreeList &) override;
+  void visit (AST::UseTreeRebind &) override;
+  void visit (AST::UseDeclaration &use_decl) override;
+  void visit (AST::Function &function) override;
+  void visit (AST::TypeAlias &type_alias) override;
+  void visit (AST::StructStruct &struct_item) override;
+  void visit (AST::TupleStruct &tuple_struct) override;
+  void visit (AST::EnumItem &item) override;
+  void visit (AST::EnumItemTuple &item) override;
+  void visit (AST::EnumItemStruct &item) override;
+  void visit (AST::EnumItemDiscriminant &item) override;
+  void visit (AST::Enum &enum_item) override;
+  void visit (AST::Union &union_item) override;
+  void visit (AST::ConstantItem &const_item) override;
+  void visit (AST::StaticItem &static_item) override;
+  void visit (AST::TraitItemFunc &item) override;
+  void visit (AST::TraitItemMethod &item) override;
+  void visit (AST::TraitItemConst &item) override;
+  void visit (AST::TraitItemType &item) override;
+  void visit (AST::Trait &trait) override;
+  void visit (AST::InherentImpl &impl) override;
+  void visit (AST::TraitImpl &impl) override;
+  void visit (AST::ExternalTypeItem &item) override;
+  void visit (AST::ExternalStaticItem &item) override;
+  void visit (AST::ExternalFunctionItem &item) override;
+  void visit (AST::ExternBlock &block) override;
+
+  // I don't think it would be possible to strip macros without expansion
+  void visit (AST::MacroMatchFragment &) override;
+  void visit (AST::MacroMatchRepetition &) override;
+  void visit (AST::MacroMatcher &) override;
+  void visit (AST::MacroRulesDefinition &rules_def) override;
+  void visit (AST::MetaItemPath &) override;
+  void visit (AST::MetaItemSeq &) override;
+  void visit (AST::MetaWord &) override;
+  void visit (AST::MetaNameValueStr &) override;
+  void visit (AST::MetaListPaths &) override;
+  void visit (AST::MetaListNameValueStr &) override;
+  void visit (AST::LiteralPattern &) override;
+  void visit (AST::IdentifierPattern &pattern) override;
+  void visit (AST::WildcardPattern &) override;
+  void visit (AST::RestPattern &) override;
+  void visit (AST::RangePatternBoundLiteral &) override;
+  void visit (AST::RangePatternBoundPath &bound) override;
+  void visit (AST::RangePatternBoundQualPath &bound) override;
+  void visit (AST::RangePattern &pattern) override;
+  void visit (AST::ReferencePattern &pattern) override;
+  void visit (AST::StructPatternFieldTuplePat &field) override;
+  void visit (AST::StructPatternFieldIdentPat &field) override;
+  void visit (AST::StructPatternFieldIdent &field) override;
+  void visit (AST::StructPattern &pattern) override;
+  void visit (AST::TupleStructItemsNoRange &tuple_items) override;
+  void visit (AST::TupleStructItemsRange &tuple_items) override;
+  void visit (AST::TupleStructPattern &pattern) override;
+  void visit (AST::TuplePatternItemsMultiple &tuple_items) override;
+  void visit (AST::TuplePatternItemsRanged &tuple_items) override;
+  void visit (AST::TuplePattern &pattern) override;
+  void visit (AST::GroupedPattern &pattern) override;
+  void visit (AST::SlicePattern &pattern) override;
+  void visit (AST::AltPattern &pattern) override;
+
+  void visit (AST::EmptyStmt &) override;
+  void visit (AST::LetStmt &stmt) override;
+  void visit (AST::ExprStmtWithoutBlock &stmt) override;
+  void visit (AST::ExprStmtWithBlock &stmt) override;
+
+  void visit (AST::TraitBound &bound) override;
+  void visit (AST::ImplTraitType &type) override;
+  void visit (AST::TraitObjectType &type) override;
+  void visit (AST::ParenthesisedType &type) override;
+  void visit (AST::ImplTraitTypeOneBound &type) override;
+  void visit (AST::TraitObjectTypeOneBound &type) override;
+  void visit (AST::TupleType &type) override;
+  void visit (AST::NeverType &) override;
+  void visit (AST::RawPointerType &type) override;
+  void visit (AST::ReferenceType &type) override;
+  void visit (AST::ArrayType &type) override;
+  void visit (AST::SliceType &type) override;
+  void visit (AST::InferredType &) override;
+  void visit (AST::BareFunctionType &type) override;
+
+private:
+  MacroExpander &expander;
+};
+
+} // namespace Rust
index 5a16d4352b61d9b7d2e6094d2f5c8838b9f79052..45ea0762c032c91d13a03bd675d0eaf4025f1272 100644 (file)
@@ -26,6 +26,7 @@
 #include "rust-early-name-resolver.h"
 
 namespace Rust {
+
 AST::Fragment
 MacroExpander::expand_decl_macro (Location invoc_locus,
                                  AST::MacroInvocData &invoc,
@@ -297,18 +298,15 @@ MacroExpander::expand_crate ()
   // TODO: does cfg apply for inner attributes? research.
   // the apparent answer (from playground test) is yes
 
-  push_context (ITEM);
+  push_context (ContextType::ITEM);
 
   // expand attributes recursively and strip items if required
-  AttrVisitor attr_visitor (*this);
+  //  AttrVisitor attr_visitor (*this);
   auto &items = crate.items;
   for (auto it = items.begin (); it != items.end ();)
     {
       auto &item = *it;
 
-      // mark for stripping if required
-      item->accept_vis (attr_visitor);
-
       auto fragment = take_expanded_fragment ();
       if (fragment.should_expand ())
        {
index 03d05d6bc864bf36899149155e98bc58352d1c5f..ceac8e60405770a6f4ff2d67a00694d17190bc57 100644 (file)
@@ -213,7 +213,7 @@ private:
 // Object used to store shared data (between functions) for macro expansion.
 struct MacroExpander
 {
-  enum ContextType
+  enum class ContextType
   {
     ITEM,
     BLOCK,
index 639b45a34dc72bd796893fffeb6abb94cd87b58c..23889649d51bf20b377b169070c64bd81b22e337 100644 (file)
@@ -40,6 +40,8 @@
 #include "rust-extern-crate.h"
 #include "rust-attributes.h"
 #include "rust-early-name-resolver.h"
+#include "rust-attribute-visitor.h"
+#include "rust-expand-visitor.h"
 
 #include "diagnostic.h"
 #include "input.h"
@@ -846,10 +848,9 @@ Session::expansion (AST::Crate &crate)
 
   while (!fixed_point_reached && iterations < cfg.recursion_limit)
     {
-      /* We need to name resolve macros and imports here */
+      AttrVisitor ().go (crate);
       Resolver::EarlyNameResolver ().go (crate);
-
-      expander.expand_crate ();
+      ExpandVisitor (expander).go (crate);
 
       fixed_point_reached = !expander.has_changed ();
       expander.reset_changed_state ();
diff --git a/gcc/testsuite/rust/compile/macro49.rs b/gcc/testsuite/rust/compile/macro49.rs
new file mode 100644 (file)
index 0000000..0900f7c
--- /dev/null
@@ -0,0 +1,9 @@
+macro_rules! closure {
+    () => {{
+        14 + 15
+    }};
+}
+
+fn main() {
+    let _ = || closure!();
+}
diff --git a/gcc/testsuite/rust/compile/macro50.rs b/gcc/testsuite/rust/compile/macro50.rs
new file mode 100644 (file)
index 0000000..e85afa7
--- /dev/null
@@ -0,0 +1,10 @@
+macro_rules! foo {
+    () => {
+        u32
+    };
+}
+
+fn main() {
+    let _a = 15i32;
+    let _b = _a as foo!();
+}