gccrs: macros: Handle matchers properly in repetitions
authorArthur Cohen <arthur.cohen@embecosm.com>
Mon, 29 Aug 2022 10:51:33 +0000 (12:51 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 31 Jan 2023 13:16:49 +0000 (14:16 +0100)
gcc/rust/ChangeLog:

* expand/rust-macro-expand.cc (MacroExpander::match_matcher): Handle
fragments differently based on whether or not we are currently trying
to match a matcher in a repetition context.
(MacroExpander::match_n_matches): Use new `in_repetition` argument
properly when calling `match_matcher`.
* expand/rust-macro-expand.h (MacroExpander::match_matcher): Allow
passing extra `in_repetition` bool argument

gcc/testsuite/ChangeLog:

* rust/compile/macro43.rs: New test.

gcc/rust/expand/rust-macro-expand.cc
gcc/rust/expand/rust-macro-expand.h
gcc/testsuite/rust/compile/macro43.rs [new file with mode: 0644]

index a214ca9..df258bd 100644 (file)
@@ -435,7 +435,7 @@ MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser,
 
 bool
 MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
-                             AST::MacroMatcher &matcher)
+                             AST::MacroMatcher &matcher, bool in_repetition)
 {
   if (depth_exceeds_recursion_limit ())
     {
@@ -485,8 +485,12 @@ 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_metavar (
-             MatchedFragment (fragment->get_ident (), offs_begin, offs_end));
+           if (in_repetition)
+             sub_stack.append_fragment (
+               MatchedFragment (fragment->get_ident (), offs_begin, offs_end));
+           else
+             sub_stack.insert_metavar (
+               MatchedFragment (fragment->get_ident (), offs_begin, offs_end));
          }
          break;
 
@@ -509,7 +513,7 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
            AST::MacroMatcher *m
              = static_cast<AST::MacroMatcher *> (match.get ());
            expansion_depth++;
-           if (!match_matcher (parser, *m))
+           if (!match_matcher (parser, *m, in_repetition))
              {
                expansion_depth--;
                return false;
@@ -619,7 +623,7 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
              case AST::MacroMatch::MacroMatchType::Matcher: {
                AST::MacroMatcher *m
                  = static_cast<AST::MacroMatcher *> (match.get ());
-               valid_current_match = match_matcher (parser, *m);
+               valid_current_match = match_matcher (parser, *m, true);
              }
              break;
            }
index 97a0269..bef1402 100644 (file)
@@ -273,7 +273,7 @@ struct MacroExpander
                         AST::MacroMatchRepetition &rep);
 
   bool match_matcher (Parser<MacroInvocLexer> &parser,
-                     AST::MacroMatcher &matcher);
+                     AST::MacroMatcher &matcher, bool in_repetition = false);
 
   /**
    * Match any amount of matches
diff --git a/gcc/testsuite/rust/compile/macro43.rs b/gcc/testsuite/rust/compile/macro43.rs
new file mode 100644 (file)
index 0000000..c7bf50a
--- /dev/null
@@ -0,0 +1,64 @@
+macro_rules! nonzero_integers {
+    ( $( $Ty: ident($Int: ty); )+ ) => {
+        $(
+            /// An integer that is known not to equal zero.
+            ///
+            /// This enables some memory layout optimization.
+            /// For example, `Option<NonZeroU32>` is the same size as `u32`:
+            ///
+            /// ```rust
+            /// use std::mem::size_of;
+            /// assert_eq!(size_of::<Option<std::num::NonZeroU32>>(), size_of::<u32>());
+            /// ```
+            #[stable(feature = "nonzero", since = "1.28.0")]
+            #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+            #[repr(transparent)]
+            pub struct $Ty(NonZero<$Int>);
+
+            impl $Ty {
+                /// Create a non-zero without checking the value.
+                ///
+                /// # Safety
+                ///
+                /// The value must not be zero.
+                #[stable(feature = "nonzero", since = "1.28.0")]
+                #[inline]
+                pub const unsafe fn new_unchecked(n: $Int) -> Self {
+                    $Ty(NonZero(n))
+                }
+
+                /// Create a non-zero if the given value is not zero.
+                #[stable(feature = "nonzero", since = "1.28.0")]
+                #[inline]
+                pub fn new(n: $Int) -> Option<Self> {
+                    if n != 0 {
+                        Some($Ty(NonZero(n)))
+                    } else {
+                        None
+                    }
+                }
+
+                /// Returns the value as a primitive type.
+                #[stable(feature = "nonzero", since = "1.28.0")]
+                #[inline]
+                pub fn get(self) -> $Int {
+                    self.0 .0
+                }
+
+            }
+
+            impl_nonzero_fmt! { // { dg-error "unknown macro" }
+                (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
+            }
+        )+
+    }
+}
+
+nonzero_integers! {
+    NonZeroU8(u8);
+    NonZeroU16(u16);
+    NonZeroU32(u32);
+    NonZeroU64(u64);
+    NonZeroU128(u128);
+    NonZeroUsize(usize);
+}