aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2022-07-20 13:49:53 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2022-07-20 15:08:51 +0200
commit09855d5c0eb14a9b976a98ae4ec9ab012eebaa51 (patch)
treed3cb79c22ffa2c662d29394c84111771f032a26a /gcc
parent3f5fc214f4a53ac6c90e421814fcf049e56d3dc9 (diff)
downloadgcc-09855d5c0eb14a9b976a98ae4ec9ab012eebaa51.zip
gcc-09855d5c0eb14a9b976a98ae4ec9ab012eebaa51.tar.gz
gcc-09855d5c0eb14a9b976a98ae4ec9ab012eebaa51.tar.bz2
macro: Allow the repetition of metavars when expanding repetitions
When expanding repeating metavars, we have to allow the repetition of non-repeating metavars as well: ``` macro_rules! foo { ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( impl $Trait for $Ty { fn bar() -> i32 { 14 } } )+ } } trait Foo { fn bar() -> i32; } trait Bar { fn bar() -> i32; } trait Baz { fn bar() -> i32; } trait Qux { fn bar() -> i32; } struct S; foo!{(Foo, Bar, Baz, Qux) for S} ``` This is valid, as the $Ty metavar is not a repetition. However, this should fail to compile: ``` macro_rules! foo { // note the repetition here now ( ( $( $Trait: ident ),+ ) for $($Ty: ident)+ ) => { $( impl $Trait for $Ty { fn bar() -> i32 { 14 } } )+ } } trait Foo { fn bar() -> i32; } trait Bar { fn bar() -> i32; } trait Baz { fn bar() -> i32; } trait Qux { fn bar() -> i32; } struct S; foo!{(Foo, Bar, Baz, Qux) for S} ``` Obviously, if we were to specify as many $Ty as $Trait then there would be no issue, but that behavior is already handled.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc14
-rw-r--r--gcc/rust/expand/rust-macro-expand.h56
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.cc7
-rw-r--r--gcc/testsuite/rust/compile/macro-issue1400-2.rs32
-rw-r--r--gcc/testsuite/rust/compile/macro-issue1400.rs33
5 files changed, 123 insertions, 19 deletions
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 189d377..f96c288 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -83,10 +83,15 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
if (did_match_rule)
{
+ // FIXME: ARTHUR: Comment
// Debugging
- // for (auto &kv : matched_fragments)
- // rust_debug ("[fragment]: %s (%ld)", kv.first.c_str (),
- // kv.second.get_fragments ().size ());
+ for (auto &kv : matched_fragments)
+ rust_debug ("[fragment]: %s (%ld - %s)", kv.first.c_str (),
+ kv.second.get_fragments ().size (),
+ kv.second.get_kind ()
+ == MatchedFragmentContainer::Kind::Repetition
+ ? "repetition"
+ : "metavar");
matched_rule = &rule;
break;
@@ -621,7 +626,8 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
// matched fragment get the offset in the token stream
size_t offs_end = source.get_offs ();
- sub_stack.insert_fragment (
+ // FIXME: ARTHUR: Here we want to append?
+ sub_stack.append_fragment (
MatchedFragment (fragment->get_ident (), offs_begin,
offs_end));
}
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index a582524..51d7516 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -76,8 +76,17 @@ struct MatchedFragment
class MatchedFragmentContainer
{
public:
- MatchedFragmentContainer (std::vector<MatchedFragment> fragments)
- : fragments (fragments)
+ // Does the container refer to a simple metavariable, different from a
+ // repetition repeated once
+ enum class Kind
+ {
+ MetaVar,
+ Repetition,
+ };
+
+ MatchedFragmentContainer (std::vector<MatchedFragment> fragments,
+ Kind kind = Kind::Repetition)
+ : fragments (fragments), kind (kind)
{}
/**
@@ -94,7 +103,7 @@ public:
*/
static MatchedFragmentContainer one (MatchedFragment fragment)
{
- return MatchedFragmentContainer ({fragment});
+ return MatchedFragmentContainer ({fragment}, Kind::MetaVar);
}
/**
@@ -103,6 +112,8 @@ public:
void add_fragment (MatchedFragment fragment)
{
fragments.emplace_back (fragment);
+
+ kind = Kind::Repetition;
}
size_t get_match_amount () const { return fragments.size (); }
@@ -112,20 +123,28 @@ public:
}
// const std::string &get_fragment_name () const { return fragment_name; }
- bool is_single_fragment () const { return get_match_amount () == 1; }
+ bool is_single_fragment () const
+ {
+ // FIXME: Is that valid?
+ return get_match_amount () == 1 && kind == Kind::MetaVar;
+ }
+
const MatchedFragment get_single_fragment () const
{
- rust_assert (get_match_amount () == 1);
+ rust_assert (is_single_fragment ());
return fragments[0];
}
+ const Kind &get_kind () const { return kind; }
+
private:
/**
* Fragments matched `match_amount` times. This can be an empty vector
* in case having zero matches is allowed (i.e ? or * operators)
*/
std::vector<MatchedFragment> fragments;
+ Kind kind;
};
class SubstitutionScope
@@ -156,15 +175,26 @@ public:
auto it = current_map.find (fragment.fragment_ident);
if (it == current_map.end ())
- {
- current_map.insert (
- {fragment.fragment_ident, MatchedFragmentContainer::one (fragment)});
- }
+ current_map.insert (
+ {fragment.fragment_ident, MatchedFragmentContainer::one (fragment)});
else
- {
- auto &frags = it->second;
- frags.add_fragment (fragment);
- }
+ gcc_unreachable ();
+ }
+
+ /**
+ * Append a new matched fragment to a repetition into the current substitution
+ * map
+ */
+ void append_fragment (MatchedFragment fragment)
+ {
+ auto &current_map = stack.back ();
+ auto it = current_map.find (fragment.fragment_ident);
+
+ if (it == current_map.end ())
+ current_map.insert (
+ {fragment.fragment_ident, MatchedFragmentContainer ({fragment})});
+ else
+ it->second.add_fragment (fragment);
}
void insert_matches (std::string key, MatchedFragmentContainer matches)
diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc
index 6f16214..1031cea 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.cc
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc
@@ -74,7 +74,9 @@ SubstituteCtx::check_repetition_amount (size_t pattern_start,
is_valid = false;
}
- size_t repeat_amount = it->second.get_match_amount ();
+ auto &fragment = it->second;
+
+ size_t repeat_amount = fragment.get_match_amount ();
if (!first_fragment_found)
{
first_fragment_found = true;
@@ -82,7 +84,8 @@ SubstituteCtx::check_repetition_amount (size_t pattern_start,
}
else
{
- if (repeat_amount != expected_repetition_amount)
+ if (repeat_amount != expected_repetition_amount
+ && !fragment.is_single_fragment ())
{
rust_error_at (
frag_token->get_locus (),
diff --git a/gcc/testsuite/rust/compile/macro-issue1400-2.rs b/gcc/testsuite/rust/compile/macro-issue1400-2.rs
new file mode 100644
index 0000000..ba7b61b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macro-issue1400-2.rs
@@ -0,0 +1,32 @@
+macro_rules! foo {
+ ( ( $( $Trait: ident ),+ ) for $($Ty: ident)* ) => {
+ $(
+ impl $Trait for $Ty {
+ // { dg-error "different amount of matches used in merged repetitions: expected 4, got 1" "" { target *-*-* } .-1 }
+ fn bar() -> i32 {
+ 14
+ }
+ }
+ )+
+ }
+}
+
+trait Foo {
+ fn bar() -> i32;
+}
+
+trait Bar {
+ fn bar() -> i32;
+}
+
+trait Baz {
+ fn bar() -> i32;
+}
+
+trait Qux {
+ fn bar() -> i32;
+}
+
+struct S;
+
+foo! {(Foo, Bar, Baz, Qux) for S}
diff --git a/gcc/testsuite/rust/compile/macro-issue1400.rs b/gcc/testsuite/rust/compile/macro-issue1400.rs
new file mode 100644
index 0000000..971bd77
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macro-issue1400.rs
@@ -0,0 +1,33 @@
+// { dg-additional-options "-w" }
+
+macro_rules! foo {
+ ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
+ $(
+ impl $Trait for $Ty {
+ fn bar() -> i32 {
+ 14
+ }
+ }
+ )+
+ }
+}
+
+trait Foo {
+ fn bar() -> i32;
+}
+
+trait Bar {
+ fn bar() -> i32;
+}
+
+trait Baz {
+ fn bar() -> i32;
+}
+
+trait Qux {
+ fn bar() -> i32;
+}
+
+struct S;
+
+foo! {(Foo, Bar, Baz, Qux) for S}