@@ -6,7 +6,6 @@ use rustc_hir::attrs::diagnostic::{
66 Directive , FilterFormatString , Flag , FormatArg , FormatString , LitOrArg , Name , NameValue ,
77 OnUnimplementedCondition , Piece , Predicate ,
88} ;
9- use rustc_hir:: lints:: FormatWarning ;
109use rustc_macros:: Diagnostic ;
1110use rustc_parse_format:: {
1211 Argument , FormatSpec , ParseError , ParseMode , Parser , Piece as RpfPiece , Position ,
@@ -19,9 +18,8 @@ use thin_vec::{ThinVec, thin_vec};
1918
2019use crate :: context:: { AcceptContext , Stage } ;
2120use crate :: errors:: {
22- DisallowedPlaceholder , DisallowedPositionalArgument , IgnoredDiagnosticOption ,
23- InvalidFormatSpecifier , MalFormedDiagnosticAttributeLint , MissingOptionsForDiagnosticAttribute ,
24- NonMetaItemDiagnosticAttribute , WrappedParserError ,
21+ FormatWarning , IgnoredDiagnosticOption , MalFormedDiagnosticAttributeLint ,
22+ MissingOptionsForDiagnosticAttribute , NonMetaItemDiagnosticAttribute , WrappedParserError ,
2523} ;
2624use crate :: parser:: { ArgParser , MetaItemListParser , MetaItemOrLitParser , MetaItemParser } ;
2725
@@ -88,6 +86,29 @@ impl Mode {
8886 Self :: DiagnosticOnUnmatchArgs => DEFAULT ,
8987 }
9088 }
89+
90+ fn allowed_format_arguments ( & self ) -> & ' static str {
91+ match self {
92+ Self :: RustcOnUnimplemented => {
93+ "see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented> for allowed format arguments"
94+ }
95+ Self :: DiagnosticOnUnimplemented => {
96+ "only `Self` and generics of the trait are allowed as a format argument"
97+ }
98+ Self :: DiagnosticOnConst => {
99+ "only `Self` and generics of the implementation are allowed as a format argument"
100+ }
101+ Self :: DiagnosticOnMove => {
102+ "only `This`, `Self` and generics of the type are allowed as a format argument"
103+ }
104+ Self :: DiagnosticOnUnknown => {
105+ "only `This` is allowed as a format argument, referring to the failed import"
106+ }
107+ Self :: DiagnosticOnUnmatchArgs => {
108+ "only `This` is allowed as a format argument, referring to the macro's name"
109+ }
110+ }
111+ }
91112}
92113
93114fn merge_directives < S : Stage > (
@@ -257,22 +278,13 @@ fn parse_directive_items<'p, S: Stage>(
257278 match parse_format_string ( input. name , snippet, input. span , mode) {
258279 Ok ( ( f, warnings) ) => {
259280 for warning in warnings {
260- let ( FormatWarning :: InvalidSpecifier { span, .. }
261- | FormatWarning :: PositionalArgument { span, .. }
262- | FormatWarning :: DisallowedPlaceholder { span } ) = warning;
281+ let ( FormatWarning :: InvalidSpecifier { span }
282+ | FormatWarning :: PositionalArgument { span }
283+ | FormatWarning :: IndexedArgument { span }
284+ | FormatWarning :: DisallowedPlaceholder { span, .. } ) = warning;
263285 cx. emit_dyn_lint (
264286 MALFORMED_DIAGNOSTIC_FORMAT_LITERALS ,
265- move |dcx, level| match warning {
266- FormatWarning :: PositionalArgument { .. } => {
267- DisallowedPositionalArgument . into_diag ( dcx, level)
268- }
269- FormatWarning :: InvalidSpecifier { .. } => {
270- InvalidFormatSpecifier . into_diag ( dcx, level)
271- }
272- FormatWarning :: DisallowedPlaceholder { .. } => {
273- DisallowedPlaceholder . into_diag ( dcx, level)
274- }
275- } ,
287+ move |dcx, level| warning. into_diag ( dcx, level) ,
276288 span,
277289 ) ;
278290 }
@@ -422,38 +434,74 @@ fn parse_arg(
422434 is_source_literal: bool ,
423435) -> FormatArg {
424436 let span = slice_span ( input_span, arg. position_span . clone ( ) , is_source_literal) ;
425- if matches!( mode, Mode :: DiagnosticOnUnknown ) {
426- warnings. push ( FormatWarning :: DisallowedPlaceholder { span } ) ;
427- return FormatArg :: AsIs ( sym:: empty_braces) ;
428- }
429437
430438 match arg. position {
431439 // Something like "hello {name}"
432440 Position :: ArgumentNamed ( name) => match ( mode, Symbol :: intern ( name) ) {
433- // Only `#[rustc_on_unimplemented]` can use these
434- ( Mode :: RustcOnUnimplemented { .. } , sym:: ItemContext ) => FormatArg :: ItemContext ,
435- ( Mode :: RustcOnUnimplemented { .. } | Mode :: DiagnosticOnUnmatchArgs , sym:: This ) => {
436- FormatArg :: This
441+ ( Mode :: RustcOnUnimplemented , sym:: ItemContext ) => FormatArg :: ItemContext ,
442+
443+ // Like `{This}`, but sugared.
444+ // FIXME(mejrs) maybe rename/rework this or something
445+ // if we want to apply this to other attrs?
446+ ( Mode :: RustcOnUnimplemented , sym:: Trait ) => FormatArg :: Trait ,
447+
448+ // Some diagnostic attributes can use `{This}` to refer to the annotated item.
449+ // For those that don't, we continue and maybe use it as a generic parameter.
450+ //
451+ // FIXME(mejrs) `DiagnosticOnUnimplemented` is intentionally not here;
452+ // that requires lang approval which is best kept for a standalone PR.
453+ (
454+ Mode :: RustcOnUnimplemented
455+ | Mode :: DiagnosticOnUnknown
456+ | Mode :: DiagnosticOnMove
457+ | Mode :: DiagnosticOnUnmatchArgs ,
458+ sym:: This ,
459+ ) => FormatArg :: This ,
460+
461+ // `{Self}`; the self type.
462+ // - For trait declaration attributes that's the type that does not implement it.
463+ // - for trait impl attributes, the implemented for type.
464+ // - For ADT attributes, that's the type (which will be identical to `{This}`)
465+ // - For everything else it doesn't make sense.
466+ (
467+ Mode :: RustcOnUnimplemented
468+ | Mode :: DiagnosticOnUnimplemented
469+ | Mode :: DiagnosticOnMove
470+ | Mode :: DiagnosticOnConst ,
471+ kw:: SelfUpper ,
472+ ) => FormatArg :: SelfUpper ,
473+
474+ // Generic parameters.
475+ // FIXME(mejrs) unfortunately, all the "special" symbols above might fall through,
476+ // but at this time we are not aware of what generic parameters the trait actually has.
477+ // If we find `ItemContext` or something we have to assume that's a generic parameter.
478+ // We lint against that in `check_attr.rs` though.
479+ (
480+ Mode :: RustcOnUnimplemented
481+ | Mode :: DiagnosticOnUnimplemented
482+ | Mode :: DiagnosticOnMove
483+ | Mode :: DiagnosticOnConst ,
484+ generic_param,
485+ ) => FormatArg :: GenericParam { generic_param, span } ,
486+
487+ // Generics are explicitly not allowed, we print those back as is.
488+ ( Mode :: DiagnosticOnUnknown | Mode :: DiagnosticOnUnmatchArgs , as_is) => {
489+ warnings. push ( FormatWarning :: DisallowedPlaceholder {
490+ span,
491+ attr : mode. as_str ( ) ,
492+ allowed : mode. allowed_format_arguments ( ) ,
493+ } ) ;
494+ return FormatArg :: AsIs ( Symbol :: intern ( & format ! ( "{{{as_is}}}" ) ) ) ;
437495 }
438- ( Mode :: RustcOnUnimplemented { .. } , sym:: Trait ) => FormatArg :: Trait ,
439- // Any attribute can use these
440- ( _, kw:: SelfUpper ) => FormatArg :: SelfUpper ,
441- ( _, generic_param) => FormatArg :: GenericParam { generic_param, span } ,
442496 } ,
443497
444498 // `{:1}` and `{}` are ignored
445499 Position :: ArgumentIs ( idx) => {
446- warnings. push ( FormatWarning :: PositionalArgument {
447- span,
448- help : format ! ( "use `{{{idx}}}` to print a number in braces" ) ,
449- } ) ;
500+ warnings. push ( FormatWarning :: IndexedArgument { span } ) ;
450501 FormatArg :: AsIs ( Symbol :: intern ( & format ! ( "{{{idx}}}" ) ) )
451502 }
452503 Position :: ArgumentImplicitlyIs ( _) => {
453- warnings. push ( FormatWarning :: PositionalArgument {
454- span,
455- help : String :: from ( "use `{{}}` to print empty braces" ) ,
456- } ) ;
504+ warnings. push ( FormatWarning :: PositionalArgument { span } ) ;
457505 FormatArg :: AsIs ( sym:: empty_braces)
458506 }
459507 }
@@ -473,7 +521,7 @@ fn warn_on_format_spec(
473521 . as_ref ( )
474522 . map ( |inner| slice_span ( input_span, inner. clone ( ) , is_source_literal) )
475523 . unwrap_or ( input_span) ;
476- warnings. push ( FormatWarning :: InvalidSpecifier { span, name : spec . ty . into ( ) } )
524+ warnings. push ( FormatWarning :: InvalidSpecifier { span } )
477525 }
478526}
479527
0 commit comments