aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-07-22 09:55:16 +0000
committerGitHub <noreply@github.com>2022-07-22 09:55:16 +0000
commitdc9981eb31327b7564e350d3997458f567db33d7 (patch)
treeabfbd4b9c9c1ca38122ee7ad9ed65a0c688f0544 /gcc
parent4a8c733b470eb6b7b52722c8694af9395d7cffe1 (diff)
parentd3926e6a87abd10aebd8f41749c00efbfeef1936 (diff)
downloadgcc-dc9981eb31327b7564e350d3997458f567db33d7.zip
gcc-dc9981eb31327b7564e350d3997458f567db33d7.tar.gz
gcc-dc9981eb31327b7564e350d3997458f567db33d7.tar.bz2
Merge #1405
1405: Allow repeating metavars alongside repetitions r=CohenArthur a=CohenArthur Fixes #1400 Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc23
-rw-r--r--gcc/rust/expand/rust-macro-expand.h61
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.cc9
-rw-r--r--gcc/testsuite/rust/compile/macro-issue1400-2.rs32
-rw-r--r--gcc/testsuite/rust/compile/macro-issue1400.rs33
5 files changed, 133 insertions, 25 deletions
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index e27adf5..1d57e39 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -83,10 +83,14 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
if (did_match_rule)
{
- // Debugging
- // for (auto &kv : matched_fragments)
- // rust_debug ("[fragment]: %s (%ld)", kv.first.c_str (),
- // kv.second.get_fragments ().size ());
+ // // Debugging
+ // 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;
@@ -481,7 +485,7 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
// matched fragment get the offset in the token stream
size_t offs_end = source.get_offs ();
- sub_stack.insert_fragment (
+ sub_stack.insert_metavar (
MatchedFragment (fragment->get_ident (), offs_begin, offs_end));
}
break;
@@ -586,7 +590,14 @@ 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 (
+
+ // 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 (
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 2c3380b..341c5a4 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)
{}
/**
@@ -92,9 +101,9 @@ public:
/**
* Create a valid fragment matched one time
*/
- static MatchedFragmentContainer one (MatchedFragment fragment)
+ static MatchedFragmentContainer metavar (MatchedFragment fragment)
{
- return MatchedFragmentContainer ({fragment});
+ return MatchedFragmentContainer ({fragment}, Kind::MetaVar);
}
/**
@@ -102,6 +111,8 @@ public:
*/
void add_fragment (MatchedFragment fragment)
{
+ rust_assert (!is_single_fragment ());
+
fragments.emplace_back (fragment);
}
@@ -112,20 +123,27 @@ 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
+ {
+ 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
@@ -148,23 +166,34 @@ public:
}
/**
- * Insert a new matched fragment into the current substitution map
+ * Insert a new matched metavar into the current substitution map
*/
- void insert_fragment (MatchedFragment fragment)
+ void insert_metavar (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::one (fragment)});
- }
+ current_map.insert ({fragment.fragment_ident,
+ MatchedFragmentContainer::metavar (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..9592d2d 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 (),
@@ -152,7 +155,7 @@ SubstituteCtx::substitute_repetition (
sub_fragment = kv_match.second.get_fragments ()[i];
sub_map.insert (
- {kv_match.first, MatchedFragmentContainer::one (sub_fragment)});
+ {kv_match.first, MatchedFragmentContainer::metavar (sub_fragment)});
}
auto substitute_context = SubstituteCtx (input, new_macro, sub_map);
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}