@@ -8,7 +8,7 @@ use crate::diagnostics::utils::{
8
8
report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
9
9
Applicability , FieldInfo , FieldInnerTy , HasFieldMap , SetOnce ,
10
10
} ;
11
- use proc_macro2:: { Ident , TokenStream } ;
11
+ use proc_macro2:: { Ident , Span , TokenStream } ;
12
12
use quote:: { format_ident, quote} ;
13
13
use std:: collections:: HashMap ;
14
14
use std:: str:: FromStr ;
@@ -156,16 +156,20 @@ impl DiagnosticDeriveBuilder {
156
156
let name = name. as_str ( ) ;
157
157
let meta = attr. parse_meta ( ) ?;
158
158
159
- let is_help_or_note = matches ! ( name, "help" | "note" ) ;
159
+ let is_help_note_or_warn = matches ! ( name, "help" | "note" | "warn_ ") ;
160
160
161
161
let nested = match meta {
162
162
// Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
163
163
// `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
164
164
Meta :: List ( MetaList { ref nested, .. } ) => nested,
165
165
// Subdiagnostics without spans can be applied to the type too, and these are just
166
166
// paths: `#[help]` and `#[note]`
167
- Meta :: Path ( _) if is_help_or_note => {
168
- let fn_name = proc_macro2:: Ident :: new ( name, attr. span ( ) ) ;
167
+ Meta :: Path ( _) if is_help_note_or_warn => {
168
+ let fn_name = if name == "warn_" {
169
+ Ident :: new ( "warn" , attr. span ( ) )
170
+ } else {
171
+ Ident :: new ( name, attr. span ( ) )
172
+ } ;
169
173
return Ok ( quote ! { #diag. #fn_name( rustc_errors:: fluent:: _subdiag:: #fn_name) ; } ) ;
170
174
}
171
175
_ => throw_invalid_attr ! ( attr, & meta) ,
@@ -177,9 +181,11 @@ impl DiagnosticDeriveBuilder {
177
181
"error" => self . kind . set_once ( ( DiagnosticDeriveKind :: Error , span) ) ,
178
182
"warning" => self . kind . set_once ( ( DiagnosticDeriveKind :: Warn , span) ) ,
179
183
"lint" => self . kind . set_once ( ( DiagnosticDeriveKind :: Lint , span) ) ,
180
- "help" | "note" => ( ) ,
184
+ "help" | "note" | "warn_" => ( ) ,
181
185
_ => throw_invalid_attr ! ( attr, & meta, |diag| {
182
- diag. help( "only `error`, `warning`, `help` and `note` are valid attributes" )
186
+ diag. help(
187
+ "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes" ,
188
+ )
183
189
} ) ,
184
190
}
185
191
@@ -188,22 +194,24 @@ impl DiagnosticDeriveBuilder {
188
194
let mut nested_iter = nested. into_iter ( ) ;
189
195
if let Some ( nested_attr) = nested_iter. next ( ) {
190
196
// Report an error if there are any other list items after the path.
191
- if is_help_or_note && nested_iter. next ( ) . is_some ( ) {
197
+ if is_help_note_or_warn && nested_iter. next ( ) . is_some ( ) {
192
198
throw_invalid_nested_attr ! ( attr, & nested_attr, |diag| {
193
- diag. help( "`help` and `note` struct attributes can only have one argument" )
199
+ diag. help(
200
+ "`help`, `note` and `warn_` struct attributes can only have one argument" ,
201
+ )
194
202
} ) ;
195
203
}
196
204
197
205
match nested_attr {
198
- NestedMeta :: Meta ( Meta :: Path ( path) ) if is_help_or_note => {
206
+ NestedMeta :: Meta ( Meta :: Path ( path) ) if is_help_note_or_warn => {
199
207
let fn_name = proc_macro2:: Ident :: new ( name, attr. span ( ) ) ;
200
208
return Ok ( quote ! { #diag. #fn_name( rustc_errors:: fluent:: #path) ; } ) ;
201
209
}
202
210
NestedMeta :: Meta ( Meta :: Path ( path) ) => {
203
211
self . slug . set_once ( ( path. clone ( ) , span) ) ;
204
212
}
205
213
NestedMeta :: Meta ( meta @ Meta :: NameValue ( _) )
206
- if !is_help_or_note
214
+ if !is_help_note_or_warn
207
215
&& meta. path ( ) . segments . last ( ) . unwrap ( ) . ident . to_string ( ) == "code" =>
208
216
{
209
217
// don't error for valid follow-up attributes
@@ -347,10 +355,12 @@ impl DiagnosticDeriveBuilder {
347
355
report_error_if_not_applied_to_span ( attr, & info) ?;
348
356
Ok ( self . add_spanned_subdiagnostic ( binding, ident, parse_quote ! { _subdiag:: label } ) )
349
357
}
350
- "note" | "help" => {
351
- let path = match name {
352
- "note" => parse_quote ! { _subdiag:: note } ,
353
- "help" => parse_quote ! { _subdiag:: help } ,
358
+ "note" | "help" | "warn_" => {
359
+ let warn_ident = Ident :: new ( "warn" , Span :: call_site ( ) ) ;
360
+ let ( ident, path) = match name {
361
+ "note" => ( ident, parse_quote ! { _subdiag:: note } ) ,
362
+ "help" => ( ident, parse_quote ! { _subdiag:: help } ) ,
363
+ "warn_" => ( & warn_ident, parse_quote ! { _subdiag:: warn } ) ,
354
364
_ => unreachable ! ( ) ,
355
365
} ;
356
366
if type_matches_path ( & info. ty , & [ "rustc_span" , "Span" ] ) {
@@ -387,10 +397,10 @@ impl DiagnosticDeriveBuilder {
387
397
"suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
388
398
return self . generate_inner_field_code_suggestion ( attr, info) ;
389
399
}
390
- "label" | "help" | "note" => ( ) ,
400
+ "label" | "help" | "note" | "warn_" => ( ) ,
391
401
_ => throw_invalid_attr ! ( attr, & meta, |diag| {
392
402
diag. help(
393
- "only `label`, `note`, `help ` or `suggestion{,_short,_hidden,_verbose}` are \
403
+ "only `label`, `help`, ` note`, `warn ` or `suggestion{,_short,_hidden,_verbose}` are \
394
404
valid field attributes",
395
405
)
396
406
} ) ,
@@ -419,7 +429,14 @@ impl DiagnosticDeriveBuilder {
419
429
Ok ( self . add_spanned_subdiagnostic ( binding, ident, msg) )
420
430
}
421
431
"note" | "help" if type_is_unit ( & info. ty ) => Ok ( self . add_subdiagnostic ( ident, msg) ) ,
422
- "note" | "help" => report_type_error ( attr, "`Span` or `()`" ) ?,
432
+ // `warn_` must be special-cased because the attribute `warn` already has meaning and
433
+ // so isn't used, despite the diagnostic API being named `warn`.
434
+ "warn_" if type_matches_path ( & info. ty , & [ "rustc_span" , "Span" ] ) => Ok ( self
435
+ . add_spanned_subdiagnostic ( binding, & Ident :: new ( "warn" , Span :: call_site ( ) ) , msg) ) ,
436
+ "warn_" if type_is_unit ( & info. ty ) => {
437
+ Ok ( self . add_subdiagnostic ( & Ident :: new ( "warn" , Span :: call_site ( ) ) , msg) )
438
+ }
439
+ "note" | "help" | "warn_" => report_type_error ( attr, "`Span` or `()`" ) ?,
423
440
_ => unreachable ! ( ) ,
424
441
}
425
442
}
0 commit comments