From 2983beb0d9101a8bf31890951f4a4094bd603f08 Mon Sep 17 00:00:00 2001 From: Owen Avery Date: Wed, 7 Jun 2023 12:26:37 -0400 Subject: [PATCH] Insert empty repeated metavars for nested repetitions gcc/rust/ChangeLog: * expand/rust-macro-expand.cc (MacroExpander::match_repetition_skipped_metavars): New. (MacroExpander::match_repetition): Use new method. * expand/rust-macro-expand.h (MacroExpander::match_repetition_skipped_metavars): New. gcc/testsuite/ChangeLog: * rust/compile/macro-issue2268.rs: New test. Signed-off-by: Owen Avery --- gcc/rust/expand/rust-macro-expand.cc | 75 ++++++++++++++----- gcc/rust/expand/rust-macro-expand.h | 5 ++ gcc/testsuite/rust/compile/macro-issue2268.rs | 5 ++ 3 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/rust/compile/macro-issue2268.rs diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index a45c13f89b9a..729d92889f4d 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -669,6 +669,62 @@ MacroExpander::match_n_matches (Parser &parser, return res; } +/* + * Helper function for defining unmatched repetition metavars + */ +void +MacroExpander::match_repetition_skipped_metavars (AST::MacroMatch &match) +{ + // We have to handle zero fragments differently: They will not have been + // "matched" but they are still valid and should be inserted as a special + // case. So we go through the stack map, and for every fragment which doesn't + // exist, insert a zero-matched fragment. + switch (match.get_macro_match_type ()) + { + case AST::MacroMatch::MacroMatchType::Fragment: + match_repetition_skipped_metavars ( + static_cast (match)); + break; + case AST::MacroMatch::MacroMatchType::Repetition: + match_repetition_skipped_metavars ( + static_cast (match)); + break; + case AST::MacroMatch::MacroMatchType::Matcher: + match_repetition_skipped_metavars ( + static_cast (match)); + break; + case AST::MacroMatch::MacroMatchType::Tok: + break; + } +} + +void +MacroExpander::match_repetition_skipped_metavars ( + AST::MacroMatchFragment &fragment) +{ + auto &stack_map = sub_stack.peek (); + auto it = stack_map.find (fragment.get_ident ()); + + if (it == stack_map.end ()) + sub_stack.insert_matches (fragment.get_ident (), + MatchedFragmentContainer::zero ()); +} + +void +MacroExpander::match_repetition_skipped_metavars ( + AST::MacroMatchRepetition &rep) +{ + for (auto &match : rep.get_matches ()) + match_repetition_skipped_metavars (*match); +} + +void +MacroExpander::match_repetition_skipped_metavars (AST::MacroMatcher &rep) +{ + for (auto &match : rep.get_matches ()) + match_repetition_skipped_metavars (*match); +} + bool MacroExpander::match_repetition (Parser &parser, AST::MacroMatchRepetition &rep) @@ -703,24 +759,7 @@ MacroExpander::match_repetition (Parser &parser, res ? "successfully" : "unsuccessfully", (unsigned long) match_amount); - // We have to handle zero fragments differently: They will not have been - // "matched" but they are still valid and should be inserted as a special - // case. So we go through the stack map, and for every fragment which doesn't - // exist, insert a zero-matched fragment. - auto &stack_map = sub_stack.peek (); - for (auto &match : rep.get_matches ()) - { - if (match->get_macro_match_type () - == AST::MacroMatch::MacroMatchType::Fragment) - { - auto fragment = static_cast (match.get ()); - auto it = stack_map.find (fragment->get_ident ()); - - if (it == stack_map.end ()) - sub_stack.insert_matches (fragment->get_ident (), - MatchedFragmentContainer::zero ()); - } - } + match_repetition_skipped_metavars (rep); return res; } diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index d8c8147a0d28..988a9df0f3b5 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -304,6 +304,11 @@ struct MacroExpander bool match_token (Parser &parser, AST::Token &token); + void match_repetition_skipped_metavars (AST::MacroMatch &); + void match_repetition_skipped_metavars (AST::MacroMatchFragment &); + void match_repetition_skipped_metavars (AST::MacroMatchRepetition &); + void match_repetition_skipped_metavars (AST::MacroMatcher &); + bool match_repetition (Parser &parser, AST::MacroMatchRepetition &rep); diff --git a/gcc/testsuite/rust/compile/macro-issue2268.rs b/gcc/testsuite/rust/compile/macro-issue2268.rs new file mode 100644 index 000000000000..4bd9c101c73f --- /dev/null +++ b/gcc/testsuite/rust/compile/macro-issue2268.rs @@ -0,0 +1,5 @@ +macro_rules! foo { + ($(+ $($a:ident)*)*) => {$($($a)*)*} +} + +foo!();