aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorOwen Avery <powerboat9.gamer@gmail.com>2023-06-03 17:40:18 -0400
committerCohenArthur <arthur.cohen@embecosm.com>2023-06-30 08:01:24 +0000
commit40b4f94e9597627fa57d77a87fd8ac0a187f4a7d (patch)
tree3b833bb32b48b85a273b086af22694ece30ae8e6 /gcc
parent7af86eaaffec8cab5ad80e242480fe9f6c1ffaa6 (diff)
downloadgcc-40b4f94e9597627fa57d77a87fd8ac0a187f4a7d.zip
gcc-40b4f94e9597627fa57d77a87fd8ac0a187f4a7d.tar.gz
gcc-40b4f94e9597627fa57d77a87fd8ac0a187f4a7d.tar.bz2
Improve macro repetition handling
gcc/rust/ChangeLog: * expand/rust-macro-expand.cc (MacroExpander::match_matcher): Remove append_fragment inside repetitions. (MacroExpander::match_n_matches): Use sub_stack push/pop to handle repetitions. (MatchedFragmentContainer::add_fragment): Add MatchedFragmentContainer accepting version. * expand/rust-macro-expand.h (MatchedFragmentContainer::add_fragment): Likewise. (MatchedFragmentContainerRepetition::add_fragment): Likewise. (SubstititionScope::append_fragment): Likewise. gcc/testsuite/ChangeLog: * rust/compile/macro56.rs: New test. Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc36
-rw-r--r--gcc/rust/expand/rust-macro-expand.h34
-rw-r--r--gcc/testsuite/rust/compile/macro56.rs9
3 files changed, 63 insertions, 16 deletions
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 7cacb39..e313e1a 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -501,14 +501,9 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
// matched fragment get the offset in the token stream
size_t offs_end = source.get_offs ();
- if (in_repetition)
- sub_stack.append_fragment (
- MatchedFragment (fragment->get_ident ().as_string (),
- offs_begin, offs_end));
- else
- sub_stack.insert_metavar (
- MatchedFragment (fragment->get_ident ().as_string (),
- offs_begin, offs_end));
+ sub_stack.insert_metavar (
+ MatchedFragment (fragment->get_ident ().as_string (), offs_begin,
+ offs_end));
}
break;
@@ -598,6 +593,7 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
if (!match_token (parser, *rep.get_sep ()))
break;
+ sub_stack.push ();
bool valid_current_match = false;
for (auto &match : matches)
{
@@ -612,13 +608,7 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
// matched fragment get the offset in the token stream
size_t offs_end = source.get_offs ();
- // The main difference with match_matcher happens here: Instead
- // of inserting a new fragment, we append to one. If that
- // fragment does not exist, then the operation is similar to
- // `insert_fragment` with the difference that we are not
- // creating a metavariable, but a repetition of one, which is
- // really different.
- sub_stack.append_fragment (
+ sub_stack.insert_metavar (
MatchedFragment (fragment->get_ident ().as_string (),
offs_begin, offs_end));
}
@@ -645,6 +635,12 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
break;
}
}
+ auto old_stack = sub_stack.pop ();
+
+ // nest metavars into repetitions
+ for (auto &ent : old_stack)
+ sub_stack.append_fragment (ent.first, std::move (ent.second));
+
// If we've encountered an error once, stop trying to match more
// repetitions
if (!valid_current_match)
@@ -1201,6 +1197,16 @@ MatchedFragmentContainer::add_fragment (MatchedFragment fragment)
.add_fragment (fragment);
}
+void
+MatchedFragmentContainer::add_fragment (
+ std::unique_ptr<MatchedFragmentContainer> fragment)
+{
+ rust_assert (!is_single_fragment ());
+
+ return static_cast<MatchedFragmentContainerRepetition &> (*this)
+ .add_fragment (std::move (fragment));
+}
+
std::unique_ptr<MatchedFragmentContainer>
MatchedFragmentContainer::zero ()
{
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index 19e71f7..e566d5d 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -111,6 +111,11 @@ public:
*/
void add_fragment (MatchedFragment fragment);
+ /**
+ * Add a matched fragment to the container
+ */
+ void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment);
+
// const std::string &get_fragment_name () const { return fragment_name; }
bool is_single_fragment () const { return get_kind () == Kind::MetaVar; }
@@ -155,7 +160,15 @@ public:
*/
void add_fragment (MatchedFragment fragment)
{
- fragments.emplace_back (metavar (fragment));
+ add_fragment (metavar (fragment));
+ }
+
+ /**
+ * Add a matched fragment to the container
+ */
+ void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment)
+ {
+ fragments.emplace_back (std::move (fragment));
}
virtual Kind get_kind () const { return Kind::Repetition; }
@@ -227,6 +240,25 @@ public:
it->second->add_fragment (fragment);
}
+ /**
+ * Append a new matched fragment to a repetition into the current substitution
+ * map
+ */
+ void append_fragment (std::string ident,
+ std::unique_ptr<MatchedFragmentContainer> fragment)
+ {
+ auto &current_map = stack.back ();
+ auto it = current_map.find (ident);
+
+ if (it == current_map.end ())
+ it = current_map
+ .emplace (ident, std::unique_ptr<MatchedFragmentContainer> (
+ new MatchedFragmentContainerRepetition ()))
+ .first;
+
+ it->second->add_fragment (std::move (fragment));
+ }
+
void insert_matches (std::string key,
std::unique_ptr<MatchedFragmentContainer> matches)
{
diff --git a/gcc/testsuite/rust/compile/macro56.rs b/gcc/testsuite/rust/compile/macro56.rs
new file mode 100644
index 0000000..bf42a64
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macro56.rs
@@ -0,0 +1,9 @@
+macro_rules! check {
+ (a, b, c ; x, y, z; e, r; a) => {}
+}
+
+macro_rules! foo {
+ ($($($i:ident),*);*) => {check!($($($i),*);*);}
+}
+
+foo!(a, b, c ; x, y, z; e, r; a);