@@ -21,7 +21,8 @@ pub(super) fn failed_to_match_macro(
21
21
sp : Span ,
22
22
def_span : Span ,
23
23
name : Ident ,
24
- arg : TokenStream ,
24
+ attr_args : Option < & TokenStream > ,
25
+ body : & TokenStream ,
25
26
rules : & [ MacroRule ] ,
26
27
) -> ( Span , ErrorGuaranteed ) {
27
28
debug ! ( "failed to match macro" ) ;
@@ -35,7 +36,11 @@ pub(super) fn failed_to_match_macro(
35
36
// diagnostics.
36
37
let mut tracker = CollectTrackerAndEmitter :: new ( psess. dcx ( ) , sp) ;
37
38
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
+ } ;
39
44
40
45
if try_success_result. is_ok ( ) {
41
46
// Nonterminal parser recovery might turn failed matches into successful ones,
@@ -53,7 +58,7 @@ pub(super) fn failed_to_match_macro(
53
58
54
59
let Some ( BestFailure { token, msg : label, remaining_matcher, .. } ) = tracker. best_failure
55
60
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 { .. } ) ) {
57
62
let mut err = psess. dcx ( ) . struct_span_err ( sp, "invoked macro has no invocation rules" ) ;
58
63
if !def_head_span. is_dummy ( ) {
59
64
err. span_label ( def_head_span, "this macro has no rules to invoke" ) ;
@@ -92,10 +97,12 @@ pub(super) fn failed_to_match_macro(
92
97
}
93
98
94
99
// 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
+ {
96
103
for rule in rules {
97
104
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 ) ;
99
106
let mut tt_parser = TtParser :: new ( name) ;
100
107
101
108
if let Success ( _) =
@@ -118,70 +125,6 @@ pub(super) fn failed_to_match_macro(
118
125
( sp, guar)
119
126
}
120
127
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
-
185
128
/// The tracker used for the slow error path that collects useful info for diagnostics.
186
129
struct CollectTrackerAndEmitter < ' dcx , ' matcher > {
187
130
dcx : DiagCtxtHandle < ' dcx > ,
0 commit comments