gccrs: expansion: Only add fragments if the matcher succeeded

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.
This commit is contained in:
Arthur Cohen 2025-04-08 14:41:16 +02:00
parent 76477f9655
commit cb23182fa2
2 changed files with 88 additions and 7 deletions

View file

@ -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

View file

@ -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| -> () {
};
}