@@ -21,7 +21,8 @@ pub(super) fn failed_to_match_macro(
2121 sp : Span ,
2222 def_span : Span ,
2323 name : Ident ,
24- arg : TokenStream ,
24+ attr_args : Option < & TokenStream > ,
25+ body : & TokenStream ,
2526 rules : & [ MacroRule ] ,
2627) -> ( Span , ErrorGuaranteed ) {
2728 debug ! ( "failed to match macro" ) ;
@@ -35,7 +36,11 @@ pub(super) fn failed_to_match_macro(
3536 // diagnostics.
3637 let mut tracker = CollectTrackerAndEmitter :: new ( psess. dcx ( ) , sp) ;
3738
38- let try_success_result = try_match_macro ( psess, name, & arg, rules, & mut tracker) ;
39+ let try_success_result = if let Some ( attr_args) = attr_args {
40+ try_match_macro_attr ( psess, name, attr_args, body, rules, & mut tracker)
41+ } else {
42+ try_match_macro ( psess, name, body, rules, & mut tracker)
43+ } ;
3944
4045 if try_success_result. is_ok ( ) {
4146 // Nonterminal parser recovery might turn failed matches into successful ones,
@@ -53,7 +58,7 @@ pub(super) fn failed_to_match_macro(
5358
5459 let Some ( BestFailure { token, msg : label, remaining_matcher, .. } ) = tracker. best_failure
5560 else {
56- if !rules. iter ( ) . any ( |rule| matches ! ( rule, MacroRule :: Func { .. } ) ) {
61+ if attr_args . is_none ( ) && !rules. iter ( ) . any ( |rule| matches ! ( rule, MacroRule :: Func { .. } ) ) {
5762 let mut err = psess. dcx ( ) . struct_span_err ( sp, "invoked macro has no invocation rules" ) ;
5863 if !def_head_span. is_dummy ( ) {
5964 err. span_label ( def_head_span, "this macro has no rules to invoke" ) ;
@@ -92,10 +97,12 @@ pub(super) fn failed_to_match_macro(
9297 }
9398
9499 // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
95- if let Some ( ( arg, comma_span) ) = arg. add_comma ( ) {
100+ if attr_args. is_none ( )
101+ && let Some ( ( body, comma_span) ) = body. add_comma ( )
102+ {
96103 for rule in rules {
97104 let MacroRule :: Func { lhs, .. } = rule else { continue } ;
98- let parser = parser_from_cx ( psess, arg . clone ( ) , Recovery :: Allowed ) ;
105+ let parser = parser_from_cx ( psess, body . clone ( ) , Recovery :: Allowed ) ;
99106 let mut tt_parser = TtParser :: new ( name) ;
100107
101108 if let Success ( _) =
@@ -118,70 +125,6 @@ pub(super) fn failed_to_match_macro(
118125 ( sp, guar)
119126}
120127
121- pub ( super ) fn failed_to_match_macro_attr (
122- psess : & ParseSess ,
123- sp : Span ,
124- def_span : Span ,
125- name : Ident ,
126- args : TokenStream ,
127- body : TokenStream ,
128- rules : & [ MacroRule ] ,
129- ) -> ErrorGuaranteed {
130- // An error occurred, try the expansion again, tracking the expansion closely for better
131- // diagnostics.
132- let mut tracker = CollectTrackerAndEmitter :: new ( psess. dcx ( ) , sp) ;
133-
134- let result = try_match_macro_attr ( psess, name, & args, & body, rules, & mut tracker) ;
135- if result. is_ok ( ) {
136- // Nonterminal parser recovery might turn failed matches into successful ones,
137- // but for that it must have emitted an error already
138- assert ! (
139- tracker. dcx. has_errors( ) . is_some( ) ,
140- "Macro matching returned a success on the second try"
141- ) ;
142- }
143-
144- if let Some ( ( _, guar) ) = tracker. result {
145- // An irrecoverable error occurred and has been emitted.
146- return guar;
147- }
148-
149- let Some ( BestFailure { token, msg : label, remaining_matcher, .. } ) = tracker. best_failure
150- else {
151- return psess. dcx ( ) . span_delayed_bug ( sp, "failed to match a macro attr" ) ;
152- } ;
153-
154- let span = token. span . substitute_dummy ( sp) ;
155-
156- let mut err = psess. dcx ( ) . struct_span_err ( span, parse_failure_msg ( & token, None ) ) ;
157- err. span_label ( span, label) ;
158- if !def_span. is_dummy ( ) && !psess. source_map ( ) . is_imported ( def_span) {
159- err. span_label ( psess. source_map ( ) . guess_head_span ( def_span) , "when calling this macro" ) ;
160- }
161-
162- annotate_doc_comment ( & mut err, psess. source_map ( ) , span) ;
163-
164- if let Some ( span) = remaining_matcher. span ( ) {
165- err. span_note ( span, format ! ( "while trying to match {remaining_matcher}" ) ) ;
166- } else {
167- err. note ( format ! ( "while trying to match {remaining_matcher}" ) ) ;
168- }
169-
170- if let MatcherLoc :: Token { token : expected_token } = & remaining_matcher
171- && ( matches ! ( expected_token. kind, token:: OpenInvisible ( _) )
172- || matches ! ( token. kind, token:: OpenInvisible ( _) ) )
173- {
174- err. note ( "captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens" ) ;
175- err. note ( "see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information" ) ;
176-
177- if !def_span. is_dummy ( ) && !psess. source_map ( ) . is_imported ( def_span) {
178- err. help ( "try using `:tt` instead in the macro definition" ) ;
179- }
180- }
181-
182- err. emit ( )
183- }
184-
185128/// The tracker used for the slow error path that collects useful info for diagnostics.
186129struct CollectTrackerAndEmitter < ' dcx , ' matcher > {
187130 dcx : DiagCtxtHandle < ' dcx > ,
0 commit comments