Change:
is not valid lifetime, so using specifier should not cause local ambiguity. Example: cc tracking issue for $:lifetime matcher:
The problem is that currently a lifetime "may start with anything" because we haven't spelled out the rules. Edit , and insert the case into the function. You may also want to review this function to see if any case did not consider and recent syntax additions.
I'd like to take this issue
I'm on a train right now with limited connectivity, so I cant push my PR, but I have a change that I've compiled and tested, and I'm not sure if it's working correctly, I could use some more background. I this to maybeginwith, compiled and set as a custom toolchain all good so far I created a new cargo bin project (I didn't see any tests for macro_parser or any test dirs in the libsyntax directory, not sure if there's a better way to do this) and made the main function define that macro and use it, as in the original example. With nightly it showed the expected ambiguity error. Then I used rustup overrides with my custom toolchain and rebuilt, and it compiled with no errors. Is this the expected behavior when parsing the macro? I'm unclear on how the macro parser works in rust. Is it that, before adding this branch, when parsing they both matched the specifier. But after adding the bit that says "no that ain't a lifetime," it no longer gets caught by that arm of the macro, and when parsing the , it just skips it and doesn't complain? I guess I was expecting it to say something like "lifetimes cant start with #" instead of the local ambiguity, not for it to just stop being an error. Also, you mentioned reviewing the rest of the function to see if other things didn't consider lifetime or other new syntax additions, but I'm not sure what other syntax additions there are to consider.
Yes this is the expected behavior. When returns false, the parser knows that is definitely not a and thus stop matching against . The original template expects a next, which it matched, and thus everything goes fine. This is similar to the behavior of Basically to check the interaction with all other fragment specifiers, e.g. Interpolated lifetimes are encoded as which I don't see listed in the function. But maybe adding a case is sufficient to disambiguate the above examples. (For new syntax I'd like to reserve alongside in , though that would be off-topic and could also be a breaking change.)
apparently not

Discussion:
Token::Interpolated(ref nt) => may_be_ident(&nt.0), _ => false, }, <ins> "lifetime" => match *token { Token::Lifetime(_) => true, Token::Interpolated(ref nt) => match nt.0 { token::NtLifetime(_) | token::NtTT(_) => true, _ => false, }, _ => false, }, </ins> _ => match *token { token::CloseDelim(_) => false, _ => true,

fn main() { m!(a); <del> //~^ ERROR expected a lifetime, found `a` </del> <ins> //~^ ERROR no rules expected the token `a` </ins> }

//}}} <ins> //{{{ issue 50903 ============================================================== macro_rules! foo_50903 { ($($lif:lifetime ,)* #) => {}; } foo_50903!('a, 'b, #); foo_50903!('a, #); foo_50903!(#); //}}} //{{{ issue 51477 ============================================================== macro_rules! foo_51477 { ($lifetime:lifetime) => { "last token is lifetime" }; ($other:tt) => { "last token is other" }; ($first:tt $($rest:tt)*) => { foo_51477!($($rest)*) }; } fn test_51477() { assert_eq!("last token is lifetime", foo_51477!('a)); assert_eq!("last token is other", foo_51477!(@)); assert_eq!("last token is lifetime", foo_51477!(@ {} 'a)); } //}}} </ins> //{{{ some more tests ========================================================== macro_rules! test_block {

test_meta_block!(windows {}); <ins> macro_rules! test_lifetime { (1. $($l:lifetime)* $($b:block)*) => {}; (2. $($b:block)* $($l:lifetime)*) => {}; } test_lifetime!(1. 'a 'b {} {}); test_lifetime!(2. {} {} 'a 'b); </ins> //}}} fn main() {

test_40569(); test_35650(); test_24189(); <ins> test_51477(); </ins> }