public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] macro: Allow the repetition of metavars when expanding repetitions
@ 2022-07-22 13:34 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-07-22 13:34 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:09855d5c0eb14a9b976a98ae4ec9ab012eebaa51

commit 09855d5c0eb14a9b976a98ae4ec9ab012eebaa51
Author: Arthur Cohen <arthur.cohen@embecosm.com>
Date:   Wed Jul 20 13:49:53 2022 +0200

    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.

Diff:
---
 gcc/rust/expand/rust-macro-expand.cc            | 14 +++++--
 gcc/rust/expand/rust-macro-expand.h             | 56 +++++++++++++++++++------
 gcc/rust/expand/rust-macro-substitute-ctx.cc    |  7 +++-
 gcc/testsuite/rust/compile/macro-issue1400-2.rs | 32 ++++++++++++++
 gcc/testsuite/rust/compile/macro-issue1400.rs   | 33 +++++++++++++++
 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 189d377ccc4..f96c28834dd 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 a5825249f33..51d7516f1c5 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 6f16214a2d8..1031cea483d 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 00000000000..ba7b61b0b16
--- /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 00000000000..971bd778054
--- /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}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-22 13:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-22 13:34 [gcc/devel/rust/master] macro: Allow the repetition of metavars when expanding repetitions Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).