Change:
The following code will cause the compiler to fail: Playground link: It should error that the inner matcher can match an empty string and reject it, just as it does if is used in place of .
The fix should be very easy, since this was already fixed for repetitions in (original bug: ): Looks like just needs to be checked against , too.
cc
Note that with on the outside, this errors properly, although with inconsistent error messages: if the inner repetition uses only, the error is "repetition matches empty token tree", but it seems that if any of the repetitions are , then the error is "multiple successful parses".
The behaviour in my previous comment is because the check for "repetition matches empty token tree" is done at definition time, but does not catch ; this is caught at expansion time however. Ideally all of this will be moved to definition time and the expansion-time check should probably be a) corrected to address the first comment and b) possibly become an ICE, since it should never be encountered since the RFC 550 rules should eliminate all ambiguity at definition time?
Hmm... I don't really remember how most of this code works... Just grepping, but it looks like there are a couple of other places we might want to look at:
I've opened

Discussion:
match *seq_tt { TokenTree::MetaVarDecl(_, _, id) => id.name == "vis", TokenTree::Sequence(_, ref sub_seq) => <del> sub_seq.op == quoted::KleeneOp::ZeroOrMore, </del> <ins> sub_seq.op == quoted::KleeneOp::ZeroOrMore || sub_seq.op == quoted::KleeneOp::ZeroOrOne, </ins> _ => false, } }) {

} // Reverse scan: Sequence comes before `first`. <del> if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore { </del> <ins> if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore || seq_rep.op == quoted::KleeneOp::ZeroOrOne { </ins> // If sequence is potentially empty, then // union them (preserving first emptiness). first.add_all(&TokenSet { maybe_empty: true, ..subfirst });

assert!(first.maybe_empty); first.add_all(subfirst); <del> if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore { </del> <ins> if subfirst.maybe_empty || seq_rep.op == quoted::KleeneOp::ZeroOrMore || seq_rep.op == quoted::KleeneOp::ZeroOrOne { </ins> // continue scanning for more first // tokens, but also make sure we // restore empty-tracking state

#![allow(unused_macros)] <ins> // Tests that repetition matchers cannot match the empty token tree (since that would be // ambiguous). // edition:2018 </ins> macro_rules! foo { ( $()* ) => {}; //~^ ERROR repetition matches empty token tree ( $()+ ) => {}; //~^ ERROR repetition matches empty token tree <ins> ( $()? ) => {}; //~^ ERROR repetition matches empty token tree </ins> ( $(),* ) => {}; // PASS ( $(),+ ) => {}; // PASS <ins> // `?` cannot have a separator... </ins> ( [$()*] ) => {}; //~^ ERROR repetition matches empty token tree ( [$()+] ) => {}; //~^ ERROR repetition matches empty token tree <ins> ( [$()?] ) => {}; //~^ ERROR repetition matches empty token tree </ins> ( [$(),*] ) => {}; // PASS ( [$(),+] ) => {}; // PASS <ins> // `?` cannot have a separator... </ins> ( $($()* $(),* $(a)* $(a),* )* ) => {}; //~^ ERROR repetition matches empty token tree ( $($()* $(),* $(a)* $(a),* )+ ) => {}; //~^ ERROR repetition matches empty token tree <ins> ( $($()* $(),* $(a)* $(a),* )? ) => {}; //~^ ERROR repetition matches empty token tree ( $($()? $(),* $(a)? $(a),* )* ) => {}; //~^ ERROR repetition matches empty token tree ( $($()? $(),* $(a)? $(a),* )+ ) => {}; //~^ ERROR repetition matches empty token tree ( $($()? $(),* $(a)? $(a),* )? ) => {}; //~^ ERROR repetition matches empty token tree </ins> ( $(a     $(),* $(a)* $(a),* )* ) => {}; // PASS ( $($(a)+ $(),* $(a)* $(a),* )+ ) => {}; // PASS <ins> ( $($(a)+ $(),* $(a)* $(a),* )? ) => {}; // PASS ( $(a     $(),* $(a)? $(a),* )* ) => {}; // PASS ( $($(a)+ $(),* $(a)? $(a),* )+ ) => {}; // PASS ( $($(a)+ $(),* $(a)? $(a),* )? ) => {}; // PASS </ins> ( $(a $()+)* ) => {}; //~^ ERROR repetition matches empty token tree ( $(a $()*)+ ) => {}; //~^ ERROR repetition matches empty token tree <ins> ( $(a $()+)? ) => {}; //~^ ERROR repetition matches empty token tree ( $(a $()?)+ ) => {}; //~^ ERROR repetition matches empty token tree </ins> } // --- Original Issue --- // macro_rules! make_vec {

let _ = make_vec![a 1, a 2, a 3]; } // --- Minified Issue --- // macro_rules! m { <del> ( $()* ) => {} </del> <ins> ( $()* ) => {}; </ins> //~^ ERROR repetition matches empty token tree }

error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:4:8 </del> <ins> --> $DIR/issue-5067.rs:9:8 </ins> | LL |     ( $()* ) => {}; |        ^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:6:8 </del> <ins> --> $DIR/issue-5067.rs:11:8 </ins> | LL |     ( $()+ ) => {}; |        ^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:12:9 </del> <ins> --> $DIR/issue-5067.rs:13:8 | LL |     ( $()? ) => {}; |        ^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:18:9 </ins> | LL |     ( [$()*] ) => {}; |         ^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:14:9 </del> <ins> --> $DIR/issue-5067.rs:20:9 </ins> | LL |     ( [$()+] ) => {}; |         ^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:20:8 </del> <ins> --> $DIR/issue-5067.rs:22:9 | LL |     ( [$()?] ) => {}; |         ^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:27:8 </ins> | LL |     ( $($()* $(),* $(a)* $(a),* )* ) => {}; |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:22:8 </del> <ins> --> $DIR/issue-5067.rs:29:8 </ins> | LL |     ( $($()* $(),* $(a)* $(a),* )+ ) => {}; |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:28:12 </del> <ins> --> $DIR/issue-5067.rs:31:8 | LL |     ( $($()* $(),* $(a)* $(a),* )? ) => {}; |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:33:8 | LL |     ( $($()? $(),* $(a)? $(a),* )* ) => {}; |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:35:8 | LL |     ( $($()? $(),* $(a)? $(a),* )+ ) => {}; |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:37:8 | LL |     ( $($()? $(),* $(a)? $(a),* )? ) => {}; |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:47:12 </ins> | LL |     ( $(a $()+)* ) => {}; |            ^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:30:12 </del> <ins> --> $DIR/issue-5067.rs:49:12 </ins> | LL |     ( $(a $()*)+ ) => {}; |            ^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:38:18 </del> <ins> --> $DIR/issue-5067.rs:51:12 | LL |     ( $(a $()+)? ) => {}; |            ^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:53:12 | LL |     ( $(a $()?)+ ) => {}; |            ^^ error: repetition matches empty token tree --> $DIR/issue-5067.rs:60:18 </ins> | LL |     (a $e1:expr $($(, a $e2:expr)*)*) => ([$e1 $($(, $e2)*)*]); |                  ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree <del> --> $DIR/issue-5067.rs:50:8 </del> <ins> --> $DIR/issue-5067.rs:71:8 </ins> | <del> LL |     ( $()* ) => {} </del> <ins> LL |     ( $()* ) => {}; </ins> |        ^^ <del> error: aborting due to 10 previous errors </del> <ins> error: aborting due to 18 previous errors </ins>

<ins> // Regression test for #57597. // // Make sure that nested matchers work correctly rather than causing an infinite loop or crash. // edition:2018 macro_rules! foo1 { ($($($i:ident)?)+) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo2 { ($($($i:ident)?)*) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo3 { ($($($i:ident)?)?) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo4 { ($($($($i:ident)?)?)?) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo5 { ($($($($i:ident)*)?)?) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo6 { ($($($($i:ident)?)*)?) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo7 { ($($($($i:ident)?)?)*) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo8 { ($($($($i:ident)*)*)?) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo9 { ($($($($i:ident)?)*)*) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo10 { ($($($($i:ident)?)*)+) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo11 { ($($($($i:ident)+)?)*) => {}; //~^ ERROR repetition matches empty token tree } macro_rules! foo12 { ($($($($i:ident)+)*)?) => {}; //~^ ERROR repetition matches empty token tree } fn main() { foo1!(); foo2!(); foo3!(); foo4!(); foo5!(); foo6!(); foo7!(); foo8!(); foo9!(); foo10!(); foo11!(); foo12!(); } </ins>

<ins> error: repetition matches empty token tree --> $DIR/issue-57597.rs:8:7 | LL |     ($($($i:ident)?)+) => {}; |       ^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:13:7 | LL |     ($($($i:ident)?)*) => {}; |       ^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:18:7 | LL |     ($($($i:ident)?)?) => {}; |       ^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:23:7 | LL |     ($($($($i:ident)?)?)?) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:28:7 | LL |     ($($($($i:ident)*)?)?) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:33:7 | LL |     ($($($($i:ident)?)*)?) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:38:7 | LL |     ($($($($i:ident)?)?)*) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:43:7 | LL |     ($($($($i:ident)*)*)?) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:48:7 | LL |     ($($($($i:ident)?)*)*) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:53:7 | LL |     ($($($($i:ident)?)*)+) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:58:7 | LL |     ($($($($i:ident)+)?)*) => {}; |       ^^^^^^^^^^^^^^^^^^ error: repetition matches empty token tree --> $DIR/issue-57597.rs:63:7 | LL |     ($($($($i:ident)+)*)?) => {}; |       ^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors </ins>