From: Owen Avery <[email protected]>

gcc/rust/ChangeLog:

        * expand/rust-macro-expand.cc
        (MacroExpander::expand_eager_invocations): Handle errors during
        eager expansion.
        (MacroExpander::expand_invoc): Avoid expanding macros which have
        pending eager invocations and return error fragments in more
        cases.

gcc/testsuite/ChangeLog:

        * rust/compile/macros/builtin/eager4.rs: New test.

Signed-off-by: Owen Avery <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/0cbc65882f623c0f6908732e9b645b466223d3ee

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4647

 gcc/rust/expand/rust-macro-expand.cc          | 46 ++++++++++++-------
 .../rust/compile/macros/builtin/eager4.rs     | 11 +++++
 2 files changed, 41 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/eager4.rs

diff --git a/gcc/rust/expand/rust-macro-expand.cc 
b/gcc/rust/expand/rust-macro-expand.cc
index 8f9008020..c06290cdf 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -186,8 +186,9 @@ MacroExpander::expand_eager_invocations 
(AST::MacroInvocation &invoc)
 
   // we want to build a substitution map - basically, associating a `start` and
   // `end` index for each of the pending macro invocations
-  std::map<std::pair<size_t, size_t>, std::unique_ptr<AST::MacroInvocation> &>
-    substitution_map;
+  std::map<std::pair<size_t, size_t>, AST::MacroInvocation *> substitution_map;
+
+  auto &pending = invoc.get_pending_eager_invocations ();
 
   for (size_t i = 0; i < stream.size (); i++)
     {
@@ -199,20 +200,29 @@ MacroExpander::expand_eager_invocations 
(AST::MacroInvocation &invoc)
       // offset and store them in the substitution map. Otherwise, we skip one
       // token and try parsing again
       if (invocation)
-       substitution_map.insert (
-         {{i, parser.get_token_source ().get_offs ()},
-          invoc.get_pending_eager_invocations ()[current_pending++]});
+       substitution_map.insert ({{i, parser.get_token_source ().get_offs ()},
+                                 pending[current_pending++].get ()});
       else
        parser.skip_token (stream[i]->get_id ());
     }
 
+  auto pending_it = pending.begin ();
   size_t current_idx = 0;
   for (auto kv : substitution_map)
     {
-      auto &to_expand = kv.second;
+      AST::MacroInvocation *to_expand = kv.second;
       expand_invoc (*to_expand, AST::InvocKind::Expr);
 
       auto fragment = take_expanded_fragment ();
+
+      if (fragment.is_error ())
+       {
+         // skip expansion of this macro
+         // leave current_idx as-is, and continue
+         pending_it++;
+         continue;
+       }
+
       auto &new_tokens = fragment.get_tokens ();
 
       auto start = kv.first.first;
@@ -233,6 +243,7 @@ MacroExpander::expand_eager_invocations 
(AST::MacroInvocation &invoc)
        new_stream.emplace_back (tok->clone_token ());
 
       current_idx = end;
+      pending_it = pending.erase (pending_it);
     }
 
   // Once all of that is done, we copy the last remaining tokens from the
@@ -243,7 +254,6 @@ MacroExpander::expand_eager_invocations 
(AST::MacroInvocation &invoc)
   auto new_dtt
     = AST::DelimTokenTree (dtt.get_delim_type (), std::move (new_stream));
 
-  invoc.get_pending_eager_invocations ().clear ();
   invoc.get_invoc_data ().set_delim_tok_tree (new_dtt);
 }
 
@@ -263,6 +273,13 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
       push_context (ContextType::EXPR);
       expand_eager_invocations (invoc);
       pop_context ();
+
+      // if we have pending eager invocations still, don't expand
+      if (!invoc.get_pending_eager_invocations ().empty ())
+       {
+         set_expanded_fragment (AST::Fragment::create_error ());
+         return;
+       }
     }
 
   AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
@@ -314,7 +331,11 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
   // If there's no rule associated with the invocation, we can simply return
   // early. The early name resolver will have already emitted an error.
   if (!rules_def)
-    return;
+    {
+      // error fragment
+      set_expanded_fragment (std::move (fragment));
+      return;
+    }
 
   auto rdef = rules_def.value ();
 
@@ -331,14 +352,7 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
   else
     fragment
       = expand_decl_macro (invoc.get_locus (), invoc_data, *rdef, semicolon);
-  // fix: if the expansion is failing, we must replace the marco with an empty
-  // error or node
-  // makes sure that it doesn't panic on Rouge macro (it -> Lowering Phase)
-  // added the parsing errors in gcc/testsuite/rust/compile/issue-4213.rs
-  if (fragment.is_error ())
-    {
-      fragment = AST::Fragment::create_empty ();
-    }
+
   set_expanded_fragment (std::move (fragment));
 }
 
diff --git a/gcc/testsuite/rust/compile/macros/builtin/eager4.rs 
b/gcc/testsuite/rust/compile/macros/builtin/eager4.rs
new file mode 100644
index 000000000..7b02b1129
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/eager4.rs
@@ -0,0 +1,11 @@
+#![feature(no_core)]
+#![feature(rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! concat {
+    ($($e:expr),* $(,)?) => {{ /* built in */ }}
+}
+
+// { dg-error "could not resolve" "" { target *-*-* } .+1 }
+pub const X: &'static str = concat!("A", stringify!(B), "C", stringify!(D), 
"E");

base-commit: 2190c42144381c879e5264d4d8cb812207a9172d
-- 
2.54.0

Reply via email to