@@ -367,6 +367,23 @@ pub struct UnknownFormatParameterForOnUnimplementedAttr {
367
367
trait_name : Symbol ,
368
368
}
369
369
370
+ #[ derive( LintDiagnostic ) ]
371
+ #[ diag( trait_selection_disallowed_positional_argument) ]
372
+ #[ help]
373
+ pub struct DisallowedPositionalArgument ;
374
+
375
+ #[ derive( LintDiagnostic ) ]
376
+ #[ diag( trait_selection_invalid_format_specifier) ]
377
+ #[ help]
378
+ pub struct InvalidFormatSpecifier ;
379
+
380
+ #[ derive( LintDiagnostic ) ]
381
+ #[ diag( trait_selection_wrapped_parser_error) ]
382
+ pub struct WrappedParserError {
383
+ description : String ,
384
+ label : String ,
385
+ }
386
+
370
387
impl < ' tcx > OnUnimplementedDirective {
371
388
fn parse (
372
389
tcx : TyCtxt < ' tcx > ,
@@ -758,64 +775,99 @@ impl<'tcx> OnUnimplementedFormatString {
758
775
let trait_name = tcx. item_name ( trait_def_id) ;
759
776
let generics = tcx. generics_of ( item_def_id) ;
760
777
let s = self . symbol . as_str ( ) ;
761
- let parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
778
+ let mut parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
762
779
let mut result = Ok ( ( ) ) ;
763
- for token in parser {
780
+ for token in & mut parser {
764
781
match token {
765
782
Piece :: String ( _) => ( ) , // Normal string, no need to check it
766
- Piece :: NextArgument ( a) => match a. position {
767
- Position :: ArgumentNamed ( s) => {
768
- match Symbol :: intern ( s) {
769
- // `{ThisTraitsName}` is allowed
770
- s if s == trait_name && !self . is_diagnostic_namespace_variant => ( ) ,
771
- s if ALLOWED_FORMAT_SYMBOLS . contains ( & s)
772
- && !self . is_diagnostic_namespace_variant =>
773
- {
774
- ( )
775
- }
776
- // So is `{A}` if A is a type parameter
777
- s if generics. params . iter ( ) . any ( |param| param. name == s) => ( ) ,
778
- s => {
779
- if self . is_diagnostic_namespace_variant {
780
- tcx. emit_node_span_lint (
781
- UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
782
- tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
783
- self . span ,
784
- UnknownFormatParameterForOnUnimplementedAttr {
785
- argument_name : s,
786
- trait_name,
787
- } ,
788
- ) ;
789
- } else {
790
- result = Err ( struct_span_code_err ! (
791
- tcx. dcx( ) ,
792
- self . span,
793
- E0230 ,
794
- "there is no parameter `{}` on {}" ,
795
- s,
796
- if trait_def_id == item_def_id {
797
- format!( "trait `{trait_name}`" )
798
- } else {
799
- "impl" . to_string( )
800
- }
801
- )
802
- . emit ( ) ) ;
783
+ Piece :: NextArgument ( a) => {
784
+ let format_spec = a. format ;
785
+ if self . is_diagnostic_namespace_variant
786
+ && ( format_spec. ty_span . is_some ( )
787
+ || format_spec. width_span . is_some ( )
788
+ || format_spec. precision_span . is_some ( )
789
+ || format_spec. fill_span . is_some ( ) )
790
+ {
791
+ tcx. emit_node_span_lint (
792
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
793
+ tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
794
+ self . span ,
795
+ InvalidFormatSpecifier ,
796
+ ) ;
797
+ }
798
+ match a. position {
799
+ Position :: ArgumentNamed ( s) => {
800
+ match Symbol :: intern ( s) {
801
+ // `{ThisTraitsName}` is allowed
802
+ s if s == trait_name && !self . is_diagnostic_namespace_variant => ( ) ,
803
+ s if ALLOWED_FORMAT_SYMBOLS . contains ( & s)
804
+ && !self . is_diagnostic_namespace_variant =>
805
+ {
806
+ ( )
807
+ }
808
+ // So is `{A}` if A is a type parameter
809
+ s if generics. params . iter ( ) . any ( |param| param. name == s) => ( ) ,
810
+ s => {
811
+ if self . is_diagnostic_namespace_variant {
812
+ tcx. emit_node_span_lint (
813
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
814
+ tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
815
+ self . span ,
816
+ UnknownFormatParameterForOnUnimplementedAttr {
817
+ argument_name : s,
818
+ trait_name,
819
+ } ,
820
+ ) ;
821
+ } else {
822
+ result = Err ( struct_span_code_err ! (
823
+ tcx. dcx( ) ,
824
+ self . span,
825
+ E0230 ,
826
+ "there is no parameter `{}` on {}" ,
827
+ s,
828
+ if trait_def_id == item_def_id {
829
+ format!( "trait `{trait_name}`" )
830
+ } else {
831
+ "impl" . to_string( )
832
+ }
833
+ )
834
+ . emit ( ) ) ;
835
+ }
803
836
}
804
837
}
805
838
}
839
+ // `{:1}` and `{}` are not to be used
840
+ Position :: ArgumentIs ( ..) | Position :: ArgumentImplicitlyIs ( _) => {
841
+ if self . is_diagnostic_namespace_variant {
842
+ tcx. emit_node_span_lint (
843
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
844
+ tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
845
+ self . span ,
846
+ DisallowedPositionalArgument ,
847
+ ) ;
848
+ } else {
849
+ let reported = struct_span_code_err ! (
850
+ tcx. dcx( ) ,
851
+ self . span,
852
+ E0231 ,
853
+ "only named generic parameters are allowed"
854
+ )
855
+ . emit ( ) ;
856
+ result = Err ( reported) ;
857
+ }
858
+ }
806
859
}
807
- // `{:1}` and `{}` are not to be used
808
- Position :: ArgumentIs ( ..) | Position :: ArgumentImplicitlyIs ( _) => {
809
- let reported = struct_span_code_err ! (
810
- tcx. dcx( ) ,
811
- self . span,
812
- E0231 ,
813
- "only named generic parameters are allowed"
814
- )
815
- . emit ( ) ;
816
- result = Err ( reported) ;
817
- }
818
- } ,
860
+ }
861
+ }
862
+ }
863
+ if self . is_diagnostic_namespace_variant {
864
+ for e in parser. errors {
865
+ tcx. emit_node_span_lint (
866
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
867
+ tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
868
+ self . span ,
869
+ WrappedParserError { description : e. description , label : e. label } ,
870
+ ) ;
819
871
}
820
872
}
821
873
@@ -853,9 +905,9 @@ impl<'tcx> OnUnimplementedFormatString {
853
905
let empty_string = String :: new ( ) ;
854
906
855
907
let s = self . symbol . as_str ( ) ;
856
- let parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
908
+ let mut parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
857
909
let item_context = ( options. get ( & sym:: ItemContext ) ) . unwrap_or ( & empty_string) ;
858
- parser
910
+ let constructed_message = ( & mut parser)
859
911
. map ( |p| match p {
860
912
Piece :: String ( s) => s. to_owned ( ) ,
861
913
Piece :: NextArgument ( a) => match a. position {
@@ -895,9 +947,20 @@ impl<'tcx> OnUnimplementedFormatString {
895
947
}
896
948
}
897
949
}
950
+ Position :: ArgumentImplicitlyIs ( _) if self . is_diagnostic_namespace_variant => {
951
+ String :: from ( "{}" )
952
+ }
953
+ Position :: ArgumentIs ( idx) if self . is_diagnostic_namespace_variant => {
954
+ format ! ( "{{{idx}}}" )
955
+ }
898
956
_ => bug ! ( "broken on_unimplemented {:?} - bad format arg" , self . symbol) ,
899
957
} ,
900
958
} )
901
- . collect ( )
959
+ . collect ( ) ;
960
+ if self . is_diagnostic_namespace_variant && !parser. errors . is_empty ( ) {
961
+ String :: from ( s)
962
+ } else {
963
+ constructed_message
964
+ }
902
965
}
903
966
}
0 commit comments