@@ -14,7 +14,9 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
1414use rustc_ast_pretty:: pprust;
1515use rustc_attr:: { self as attr, TransparencyError } ;
1616use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
17- use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , DiagnosticMessage } ;
17+ use rustc_errors:: {
18+ Applicability , Diagnostic , DiagnosticBuilder , DiagnosticMessage , ErrorGuaranteed ,
19+ } ;
1820use rustc_feature:: Features ;
1921use rustc_lint_defs:: builtin:: {
2022 RUST_2021_INCOMPATIBLE_OR_PATTERNS , SEMICOLON_IN_EXPRESSIONS_FROM_MACROS ,
@@ -33,7 +35,7 @@ use std::borrow::Cow;
3335use std:: collections:: hash_map:: Entry ;
3436use std:: { mem, slice} ;
3537
36- use super :: macro_parser:: NamedParseResult ;
38+ use super :: macro_parser:: { NamedMatches , NamedParseResult } ;
3739
3840pub ( crate ) struct ParserAnyMacro < ' a > {
3941 parser : Parser < ' a > ,
@@ -253,9 +255,87 @@ fn expand_macro<'cx>(
253255 trace_macros_note ( & mut cx. expansions , sp, msg) ;
254256 }
255257
256- // Which arm's failure should we report? (the one furthest along)
257- let mut best_failure: Option < ( Token , & str ) > = None ;
258+ // Track nothing for the best performance
259+ let try_success_result = try_match_macro ( sess, name, & arg, lhses, & mut NoopTracker ) ;
260+
261+ match try_success_result {
262+ Ok ( ( i, named_matches) ) => {
263+ let ( rhs, rhs_span) : ( & mbe:: Delimited , DelimSpan ) = match & rhses[ i] {
264+ mbe:: TokenTree :: Delimited ( span, delimited) => ( & delimited, * span) ,
265+ _ => cx. span_bug ( sp, "malformed macro rhs" ) ,
266+ } ;
267+ let arm_span = rhses[ i] . span ( ) ;
268+
269+ let rhs_spans = rhs. tts . iter ( ) . map ( |t| t. span ( ) ) . collect :: < Vec < _ > > ( ) ;
270+ // rhs has holes ( `$id` and `$(...)` that need filled)
271+ let mut tts = match transcribe ( cx, & named_matches, & rhs, rhs_span, transparency) {
272+ Ok ( tts) => tts,
273+ Err ( mut err) => {
274+ err. emit ( ) ;
275+ return DummyResult :: any ( arm_span) ;
276+ }
277+ } ;
278+
279+ // Replace all the tokens for the corresponding positions in the macro, to maintain
280+ // proper positions in error reporting, while maintaining the macro_backtrace.
281+ if rhs_spans. len ( ) == tts. len ( ) {
282+ tts = tts. map_enumerated ( |i, tt| {
283+ let mut tt = tt. clone ( ) ;
284+ let mut sp = rhs_spans[ i] ;
285+ sp = sp. with_ctxt ( tt. span ( ) . ctxt ( ) ) ;
286+ tt. set_span ( sp) ;
287+ tt
288+ } ) ;
289+ }
290+
291+ if cx. trace_macros ( ) {
292+ let msg = format ! ( "to `{}`" , pprust:: tts_to_string( & tts) ) ;
293+ trace_macros_note ( & mut cx. expansions , sp, msg) ;
294+ }
295+
296+ let mut p = Parser :: new ( sess, tts, false , None ) ;
297+ p. last_type_ascription = cx. current_expansion . prior_type_ascription ;
298+
299+ if is_local {
300+ cx. resolver . record_macro_rule_usage ( node_id, i) ;
301+ }
302+
303+ // Let the context choose how to interpret the result.
304+ // Weird, but useful for X-macros.
305+ return Box :: new ( ParserAnyMacro {
306+ parser : p,
307+
308+ // Pass along the original expansion site and the name of the macro
309+ // so we can print a useful error message if the parse of the expanded
310+ // macro leaves unparsed tokens.
311+ site_span : sp,
312+ macro_ident : name,
313+ lint_node_id : cx. current_expansion . lint_node_id ,
314+ is_trailing_mac : cx. current_expansion . is_trailing_mac ,
315+ arm_span,
316+ is_local,
317+ } ) ;
318+ }
319+ Err ( ( ) ) => {
320+ todo ! ( "Retry macro invocation while tracking diagnostics info and emit error" ) ;
321+
322+ return DummyResult :: any ( sp) ;
323+ }
324+ }
325+
326+ DummyResult :: any ( sp)
327+ }
258328
329+ /// Try expanding the macro. Returns the index of the sucessful arm and its named_matches if it was successful,
330+ /// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors
331+ /// correctly.
332+ fn try_match_macro < ' matcher , T : Tracker < ' matcher > > (
333+ sess : & ParseSess ,
334+ name : Ident ,
335+ arg : & TokenStream ,
336+ lhses : & ' matcher [ Vec < MatcherLoc > ] ,
337+ track : & mut T ,
338+ ) -> Result < ( usize , NamedMatches ) , ( ) > {
259339 // We create a base parser that can be used for the "black box" parts.
260340 // Every iteration needs a fresh copy of that parser. However, the parser
261341 // is not mutated on many of the iterations, particularly when dealing with
@@ -277,7 +357,6 @@ fn expand_macro<'cx>(
277357 // this situation.)
278358 // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
279359 let parser = parser_from_cx ( sess, arg. clone ( ) ) ;
280-
281360 // Try each arm's matchers.
282361 let mut tt_parser = TtParser :: new ( name) ;
283362 for ( i, lhs) in lhses. iter ( ) . enumerate ( ) {
@@ -287,115 +366,36 @@ fn expand_macro<'cx>(
287366 // are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
288367 let mut gated_spans_snapshot = mem:: take ( & mut * sess. gated_spans . spans . borrow_mut ( ) ) ;
289368
290- match tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , lhs, & mut NoopTracker ) {
369+ let result = tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , lhs, track) ;
370+
371+ track. after_arm ( & result) ;
372+
373+ match result {
291374 Success ( named_matches) => {
292375 // The matcher was `Success(..)`ful.
293376 // Merge the gated spans from parsing the matcher with the pre-existing ones.
294377 sess. gated_spans . merge ( gated_spans_snapshot) ;
295378
296- let ( rhs, rhs_span) : ( & mbe:: Delimited , DelimSpan ) = match & rhses[ i] {
297- mbe:: TokenTree :: Delimited ( span, delimited) => ( & delimited, * span) ,
298- _ => cx. span_bug ( sp, "malformed macro rhs" ) ,
299- } ;
300- let arm_span = rhses[ i] . span ( ) ;
301-
302- let rhs_spans = rhs. tts . iter ( ) . map ( |t| t. span ( ) ) . collect :: < Vec < _ > > ( ) ;
303- // rhs has holes ( `$id` and `$(...)` that need filled)
304- let mut tts = match transcribe ( cx, & named_matches, & rhs, rhs_span, transparency) {
305- Ok ( tts) => tts,
306- Err ( mut err) => {
307- err. emit ( ) ;
308- return DummyResult :: any ( arm_span) ;
309- }
310- } ;
311-
312- // Replace all the tokens for the corresponding positions in the macro, to maintain
313- // proper positions in error reporting, while maintaining the macro_backtrace.
314- if rhs_spans. len ( ) == tts. len ( ) {
315- tts = tts. map_enumerated ( |i, tt| {
316- let mut tt = tt. clone ( ) ;
317- let mut sp = rhs_spans[ i] ;
318- sp = sp. with_ctxt ( tt. span ( ) . ctxt ( ) ) ;
319- tt. set_span ( sp) ;
320- tt
321- } ) ;
322- }
323-
324- if cx. trace_macros ( ) {
325- let msg = format ! ( "to `{}`" , pprust:: tts_to_string( & tts) ) ;
326- trace_macros_note ( & mut cx. expansions , sp, msg) ;
327- }
328-
329- let mut p = Parser :: new ( sess, tts, false , None ) ;
330- p. last_type_ascription = cx. current_expansion . prior_type_ascription ;
331-
332- if is_local {
333- cx. resolver . record_macro_rule_usage ( node_id, i) ;
334- }
335-
336- // Let the context choose how to interpret the result.
337- // Weird, but useful for X-macros.
338- return Box :: new ( ParserAnyMacro {
339- parser : p,
340-
341- // Pass along the original expansion site and the name of the macro
342- // so we can print a useful error message if the parse of the expanded
343- // macro leaves unparsed tokens.
344- site_span : sp,
345- macro_ident : name,
346- lint_node_id : cx. current_expansion . lint_node_id ,
347- is_trailing_mac : cx. current_expansion . is_trailing_mac ,
348- arm_span,
349- is_local,
350- } ) ;
379+ return Ok ( ( i, named_matches) ) ;
351380 }
352- Failure ( token, msg) => match best_failure {
353- Some ( ( ref best_token, _) ) if best_token. span . lo ( ) >= token. span . lo ( ) => { }
354- _ => best_failure = Some ( ( token, msg) ) ,
355- } ,
356- Error ( err_sp, ref msg) => {
357- let span = err_sp. substitute_dummy ( sp) ;
358- cx. struct_span_err ( span, & msg) . emit ( ) ;
359- return DummyResult :: any ( span) ;
381+ Failure ( _, _) => {
382+ // Try the next arm
383+ }
384+ Error ( _, _) => {
385+ // We haven't emitted an error yet
386+ return Err ( ( ) ) ;
387+ }
388+ ErrorReported ( _) => {
389+ return Err ( ( ) ) ;
360390 }
361- ErrorReported ( _) => return DummyResult :: any ( sp) ,
362391 }
363392
364393 // The matcher was not `Success(..)`ful.
365394 // Restore to the state before snapshotting and maybe try again.
366395 mem:: swap ( & mut gated_spans_snapshot, & mut sess. gated_spans . spans . borrow_mut ( ) ) ;
367396 }
368- drop ( parser) ;
369-
370- let ( token, label) = best_failure. expect ( "ran no matchers" ) ;
371- let span = token. span . substitute_dummy ( sp) ;
372- let mut err = cx. struct_span_err ( span, & parse_failure_msg ( & token) ) ;
373- err. span_label ( span, label) ;
374- if !def_span. is_dummy ( ) && !cx. source_map ( ) . is_imported ( def_span) {
375- err. span_label ( cx. source_map ( ) . guess_head_span ( def_span) , "when calling this macro" ) ;
376- }
377- annotate_doc_comment ( & mut err, sess. source_map ( ) , span) ;
378- // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
379- if let Some ( ( arg, comma_span) ) = arg. add_comma ( ) {
380- for lhs in lhses {
381- let parser = parser_from_cx ( sess, arg. clone ( ) ) ;
382- if let Success ( _) = tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , lhs, & mut NoopTracker ) {
383- if comma_span. is_dummy ( ) {
384- err. note ( "you might be missing a comma" ) ;
385- } else {
386- err. span_suggestion_short (
387- comma_span,
388- "missing comma here" ,
389- ", " ,
390- Applicability :: MachineApplicable ,
391- ) ;
392- }
393- }
394- }
395- }
396- err. emit ( ) ;
397- cx. trace_macros_diag ( ) ;
398- DummyResult :: any ( sp)
397+
398+ Err ( ( ) )
399399}
400400
401401// Note that macro-by-example's input is also matched against a token tree:
@@ -477,28 +477,29 @@ pub fn compile_declarative_macro(
477477 let parser = Parser :: new ( & sess. parse_sess , body, true , rustc_parse:: MACRO_ARGUMENTS ) ;
478478 let mut tt_parser =
479479 TtParser :: new ( Ident :: with_dummy_span ( if macro_rules { kw:: MacroRules } else { kw:: Macro } ) ) ;
480- let argument_map = match tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , & argument_gram, & mut NoopTracker ) {
481- Success ( m) => m,
482- Failure ( token, msg) => {
483- let s = parse_failure_msg ( & token) ;
484- let sp = token. span . substitute_dummy ( def. span ) ;
485- let mut err = sess. parse_sess . span_diagnostic . struct_span_err ( sp, & s) ;
486- err. span_label ( sp, msg) ;
487- annotate_doc_comment ( & mut err, sess. source_map ( ) , sp) ;
488- err. emit ( ) ;
489- return dummy_syn_ext ( ) ;
490- }
491- Error ( sp, msg) => {
492- sess. parse_sess
493- . span_diagnostic
494- . struct_span_err ( sp. substitute_dummy ( def. span ) , & msg)
495- . emit ( ) ;
496- return dummy_syn_ext ( ) ;
497- }
498- ErrorReported ( _) => {
499- return dummy_syn_ext ( ) ;
500- }
501- } ;
480+ let argument_map =
481+ match tt_parser. parse_tt ( & mut Cow :: Borrowed ( & parser) , & argument_gram, & mut NoopTracker ) {
482+ Success ( m) => m,
483+ Failure ( token, msg) => {
484+ let s = parse_failure_msg ( & token) ;
485+ let sp = token. span . substitute_dummy ( def. span ) ;
486+ let mut err = sess. parse_sess . span_diagnostic . struct_span_err ( sp, & s) ;
487+ err. span_label ( sp, msg) ;
488+ annotate_doc_comment ( & mut err, sess. source_map ( ) , sp) ;
489+ err. emit ( ) ;
490+ return dummy_syn_ext ( ) ;
491+ }
492+ Error ( sp, msg) => {
493+ sess. parse_sess
494+ . span_diagnostic
495+ . struct_span_err ( sp. substitute_dummy ( def. span ) , & msg)
496+ . emit ( ) ;
497+ return dummy_syn_ext ( ) ;
498+ }
499+ ErrorReported ( _) => {
500+ return dummy_syn_ext ( ) ;
501+ }
502+ } ;
502503
503504 let mut valid = true ;
504505
0 commit comments