Skip to content

Commit d12d295

Browse files
powerboat9P-E-P
authored andcommitted
Detect macros with duplicate metavariable bindings
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]>
1 parent b940d2c commit d12d295

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

gcc/rust/expand/rust-macro-expand.cc

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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 (

gcc/rust/expand/rust-macro-expand.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ struct MacroExpander
300300
: cfg (cfg), crate (crate), session (session),
301301
sub_stack (SubstitutionScope ()),
302302
expanded_fragment (AST::Fragment::create_error ()),
303-
has_changed_flag (false), resolver (Resolver::Resolver::get ()),
303+
has_changed_flag (false), had_duplicate_error (false),
304+
resolver (Resolver::Resolver::get ()),
304305
mappings (Analysis::Mappings::get ())
305306
{}
306307

@@ -512,6 +513,9 @@ struct MacroExpander
512513
tl::optional<AST::MacroRulesDefinition &> last_def;
513514
tl::optional<AST::MacroInvocation &> last_invoc;
514515

516+
// used to avoid emitting excess errors
517+
bool had_duplicate_error;
518+
515519
public:
516520
Resolver::Resolver *resolver;
517521
Analysis::Mappings &mappings;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
macro_rules! foo {
2+
($a:ident, $a:ident) => {0} // { dg-error "duplicate matcher binding" }
3+
}
4+
5+
fn main() {
6+
foo!(a, b);
7+
}

0 commit comments

Comments
 (0)