@@ -22,7 +22,7 @@ use rustc_lint_defs::builtin::{
2222 RUST_2021_INCOMPATIBLE_OR_PATTERNS , SEMICOLON_IN_EXPRESSIONS_FROM_MACROS ,
2323} ;
2424use rustc_lint_defs:: BuiltinLintDiagnostics ;
25- use rustc_parse:: parser:: Parser ;
25+ use rustc_parse:: parser:: { Parser , Recovery } ;
2626use rustc_session:: parse:: ParseSess ;
2727use rustc_session:: Session ;
2828use rustc_span:: edition:: Edition ;
@@ -219,6 +219,8 @@ pub(super) trait Tracker<'matcher> {
219219
220220 /// For tracing.
221221 fn description ( ) -> & ' static str ;
222+
223+ fn recovery ( ) -> Recovery ;
222224}
223225
224226/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization.
@@ -230,6 +232,9 @@ impl<'matcher> Tracker<'matcher> for NoopTracker {
230232 fn description ( ) -> & ' static str {
231233 "none"
232234 }
235+ fn recovery ( ) -> Recovery {
236+ Recovery :: Forbidden
237+ }
233238}
234239
235240/// Expands the rules based macro defined by `lhses` and `rhses` for a given
@@ -330,15 +335,20 @@ fn expand_macro<'cx>(
330335 let mut tracker = CollectTrackerAndEmitter :: new ( cx, sp) ;
331336
332337 let try_success_result = try_match_macro ( sess, name, & arg, lhses, & mut tracker) ;
333- assert ! ( try_success_result. is_err( ) , "Macro matching returned a success on the second try" ) ;
338+
339+ if try_success_result. is_ok ( ) {
340+ // Nonterminal parser recovery might turn failed matches into successful ones,
341+ // but for that it must have emitted an error already
342+ tracker. cx . sess . delay_span_bug ( sp, "Macro matching returned a success on the second try" ) ;
343+ }
334344
335345 if let Some ( result) = tracker. result {
336346 // An irrecoverable error occurred and has been emitted.
337347 return result;
338348 }
339349
340350 let Some ( ( token, label, remaining_matcher) ) = tracker. best_failure else {
341- return tracker . result . expect ( "must have encountered Error or ErrorReported" ) ;
351+ return DummyResult :: any ( sp ) ;
342352 } ;
343353
344354 let span = token. span . substitute_dummy ( sp) ;
@@ -360,7 +370,7 @@ fn expand_macro<'cx>(
360370 // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
361371 if let Some ( ( arg, comma_span) ) = arg. add_comma ( ) {
362372 for lhs in lhses {
363- let parser = parser_from_cx ( sess, arg. clone ( ) ) ;
373+ let parser = parser_from_cx ( sess, arg. clone ( ) , Recovery :: Allowed ) ;
364374 let mut tt_parser = TtParser :: new ( name) ;
365375
366376 if let Success ( _) =
@@ -406,7 +416,12 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
406416 fn after_arm ( & mut self , result : & NamedParseResult ) {
407417 match result {
408418 Success ( _) => {
409- unreachable ! ( "should not collect detailed info for successful macro match" ) ;
419+ // Nonterminal parser recovery might turn failed matches into successful ones,
420+ // but for that it must have emitted an error already
421+ self . cx . sess . delay_span_bug (
422+ self . root_span ,
423+ "should not collect detailed info for successful macro match" ,
424+ ) ;
410425 }
411426 Failure ( token, msg) => match self . best_failure {
412427 Some ( ( ref best_token, _, _) ) if best_token. span . lo ( ) >= token. span . lo ( ) => { }
@@ -432,6 +447,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
432447 fn description ( ) -> & ' static str {
433448 "detailed"
434449 }
450+
451+ fn recovery ( ) -> Recovery {
452+ Recovery :: Allowed
453+ }
435454}
436455
437456impl < ' a , ' cx > CollectTrackerAndEmitter < ' a , ' cx , ' _ > {
@@ -477,7 +496,7 @@ fn try_match_macro<'matcher, T: Tracker<'matcher>>(
477496 // 68836 suggests a more comprehensive but more complex change to deal with
478497 // this situation.)
479498 // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
480- let parser = parser_from_cx ( sess, arg. clone ( ) ) ;
499+ let parser = parser_from_cx ( sess, arg. clone ( ) , T :: recovery ( ) ) ;
481500 // Try each arm's matchers.
482501 let mut tt_parser = TtParser :: new ( name) ;
483502 for ( i, lhs) in lhses. iter ( ) . enumerate ( ) {
@@ -1559,8 +1578,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
15591578 }
15601579}
15611580
1562- fn parser_from_cx ( sess : & ParseSess , tts : TokenStream ) -> Parser < ' _ > {
1563- Parser :: new ( sess, tts, true , rustc_parse:: MACRO_ARGUMENTS )
1581+ fn parser_from_cx ( sess : & ParseSess , tts : TokenStream , recovery : Recovery ) -> Parser < ' _ > {
1582+ Parser :: new ( sess, tts, true , rustc_parse:: MACRO_ARGUMENTS ) . recovery ( recovery )
15641583}
15651584
15661585/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
0 commit comments