@@ -112,9 +112,13 @@ MacroExpander::expand_decl_macro (location_t invoc_locus,
112112
113113 if (matched_rule == nullptr )
114114 {
115- rich_location r (line_table, invoc_locus);
116- r.add_range (rules_def.get_locus ());
117- rust_error_at (r, " Failed to match any rule within macro" );
115+ if (!had_duplicate_error)
116+ {
117+ rich_location r (line_table, invoc_locus);
118+ r.add_range (rules_def.get_locus ());
119+ rust_error_at (r, " Failed to match any rule within macro" );
120+ }
121+ had_duplicate_error = false ;
118122 return AST::Fragment::create_error ();
119123 }
120124
@@ -535,6 +539,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
535539
536540 const MacroInvocLexer &source = parser.get_token_source ();
537541
542+ std::unordered_map<std::string, location_t > duplicate_check;
543+
538544 for (auto &match : matcher.get_matches ())
539545 {
540546 size_t offs_begin = source.get_offs ();
@@ -548,6 +554,21 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
548554 if (!match_fragment (parser, *fragment))
549555 return false ;
550556
557+ auto duplicate_result = duplicate_check.insert (
558+ std::make_pair (fragment->get_ident ().as_string (),
559+ fragment->get_ident ().get_locus ()));
560+
561+ if (!duplicate_result.second )
562+ {
563+ // TODO: add range labels?
564+ rich_location r (line_table,
565+ fragment->get_ident ().get_locus ());
566+ r.add_range (duplicate_result.first ->second );
567+ rust_error_at (r, " duplicate matcher binding" );
568+ had_duplicate_error = true ;
569+ return false ;
570+ }
571+
551572 // matched fragment get the offset in the token stream
552573 size_t offs_end = source.get_offs ();
553574 sub_stack.insert_metavar (
0 commit comments