From: Owen Avery <[email protected]>

This is imperfect, as invalid macro definitions should be detected
regardless of whether a macro is used or not.

gcc/rust/ChangeLog:

        * expand/rust-macro-expand.cc
        (MacroExpander::expand_decl_macro): Prevent excess errors.
        (MacroExpander::match_matcher): Detect duplicate metavariable
        names.
        * expand/rust-macro-expand.h (MacroExpander::MacroExpander):
        Initialize field had_duplicate_error.
        (MacroExpander::had_duplicate_error): New field.

gcc/testsuite/ChangeLog:

        * rust/compile/macros/mbe/macro-duplicate-binding.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/d12d295e2fa83df08362e0467e64f6dc12e22779

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

 gcc/rust/expand/rust-macro-expand.cc          | 27 ++++++++++++++++---
 gcc/rust/expand/rust-macro-expand.h           |  6 ++++-
 .../macros/mbe/macro-duplicate-binding.rs     |  7 +++++
 3 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 
gcc/testsuite/rust/compile/macros/mbe/macro-duplicate-binding.rs

diff --git a/gcc/rust/expand/rust-macro-expand.cc 
b/gcc/rust/expand/rust-macro-expand.cc
index 3848328ce..aeea4c780 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -112,9 +112,13 @@ MacroExpander::expand_decl_macro (location_t invoc_locus,
 
   if (matched_rule == nullptr)
     {
-      rich_location r (line_table, invoc_locus);
-      r.add_range (rules_def.get_locus ());
-      rust_error_at (r, "Failed to match any rule within macro");
+      if (!had_duplicate_error)
+       {
+         rich_location r (line_table, invoc_locus);
+         r.add_range (rules_def.get_locus ());
+         rust_error_at (r, "Failed to match any rule within macro");
+       }
+      had_duplicate_error = false;
       return AST::Fragment::create_error ();
     }
 
@@ -535,6 +539,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> 
&parser,
 
   const MacroInvocLexer &source = parser.get_token_source ();
 
+  std::unordered_map<std::string, location_t> duplicate_check;
+
   for (auto &match : matcher.get_matches ())
     {
       size_t offs_begin = source.get_offs ();
@@ -548,6 +554,21 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> 
&parser,
            if (!match_fragment (parser, *fragment))
              return false;
 
+           auto duplicate_result = duplicate_check.insert (
+             std::make_pair (fragment->get_ident ().as_string (),
+                             fragment->get_ident ().get_locus ()));
+
+           if (!duplicate_result.second)
+             {
+               // TODO: add range labels?
+               rich_location r (line_table,
+                                fragment->get_ident ().get_locus ());
+               r.add_range (duplicate_result.first->second);
+               rust_error_at (r, "duplicate matcher binding");
+               had_duplicate_error = true;
+               return false;
+             }
+
            // matched fragment get the offset in the token stream
            size_t offs_end = source.get_offs ();
            sub_stack.insert_metavar (
diff --git a/gcc/rust/expand/rust-macro-expand.h 
b/gcc/rust/expand/rust-macro-expand.h
index 7c8389aaf..cda4292cd 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -300,7 +300,8 @@ struct MacroExpander
     : cfg (cfg), crate (crate), session (session),
       sub_stack (SubstitutionScope ()),
       expanded_fragment (AST::Fragment::create_error ()),
-      has_changed_flag (false), resolver (Resolver::Resolver::get ()),
+      has_changed_flag (false), had_duplicate_error (false),
+      resolver (Resolver::Resolver::get ()),
       mappings (Analysis::Mappings::get ())
   {}
 
@@ -512,6 +513,9 @@ private:
   tl::optional<AST::MacroRulesDefinition &> last_def;
   tl::optional<AST::MacroInvocation &> last_invoc;
 
+  // used to avoid emitting excess errors
+  bool had_duplicate_error;
+
 public:
   Resolver::Resolver *resolver;
   Analysis::Mappings &mappings;
diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-duplicate-binding.rs 
b/gcc/testsuite/rust/compile/macros/mbe/macro-duplicate-binding.rs
new file mode 100644
index 000000000..96276e9ed
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-duplicate-binding.rs
@@ -0,0 +1,7 @@
+macro_rules! foo {
+    ($a:ident, $a:ident) => {0} // { dg-error "duplicate matcher binding" }
+}
+
+fn main() {
+    foo!(a, b);
+}

base-commit: b940d2c51ba04f6c224642e777aacf4b2931be6b
-- 
2.52.0

Reply via email to