From: Arthur Cohen <arthur.cohen@embecosm.com>
gcc/rust/ChangeLog:
* expand/rust-macro-expand.cc (MacroExpander::match_n_matches): Do not
insert fragments and substack fragments if the matcher failed.
gcc/testsuite/ChangeLog:
* rust/compile/macros/mbe/macro-issue3708.rs: New test.
---
gcc/rust/expand/rust-macro-expand.cc | 15 ++--
.../compile/macros/mbe/macro-issue3708.rs | 80 +++++++++++++++++++
2 files changed, 88 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs
@@ -621,9 +621,10 @@ 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_metavar (
- MatchedFragment (fragment->get_ident ().as_string (),
- offs_begin, offs_end));
+ if (valid_current_match)
+ sub_stack.insert_metavar (
+ MatchedFragment (fragment->get_ident ().as_string (),
+ offs_begin, offs_end));
}
break;
@@ -650,15 +651,15 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser,
}
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)
break;
+ // nest metavars into repetitions
+ for (auto &ent : old_stack)
+ sub_stack.append_fragment (ent.first, std::move (ent.second));
+
match_amount++;
// Break early if we notice there's too many expressions already
new file mode 100644
@@ -0,0 +1,80 @@
+// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" }
+
+macro_rules! impl_fn_for_zst {
+ ($(
+ $( #[$attr: meta] )*
+ struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
+ |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
+ $body: block;
+ )+) => {
+ $(
+ $( #[$attr] )*
+ struct $Name;
+
+ impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
+ #[inline]
+ extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
+ $body
+ }
+ }
+
+ impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
+ #[inline]
+ extern "rust-call" fn call_mut(
+ &mut self,
+ ($( $arg, )*): ($( $ArgTy, )*)
+ ) -> $ReturnTy {
+ Fn::call(&*self, ($( $arg, )*))
+ }
+ }
+
+ impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
+ type Output = $ReturnTy;
+
+ #[inline]
+ extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
+ Fn::call(&self, ($( $arg, )*))
+ }
+ }
+ )+
+ }
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "fn"]
+pub trait Fn<Args>: FnMut<Args> {
+ /// Performs the call operation.
+ #[unstable(feature = "fn_traits", issue = "29625")]
+ extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[must_use = "closures are lazy and do nothing unless called"]
+pub trait FnMut<Args>: FnOnce<Args> {
+ /// Performs the call operation.
+ #[unstable(feature = "fn_traits", issue = "29625")]
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args> {
+ /// The returned type after the call operator is used.
+ #[lang = "fn_once_output"]
+ #[stable(feature = "fn_once_output", since = "1.12.0")]
+ type Output;
+
+ /// Performs the call operation.
+ #[unstable(feature = "fn_traits", issue = "29625")]
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+impl_fn_for_zst! {
+ #[derive(Copy)]
+ struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> () {
+ };
+}