@@ -321,7 +321,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
321
321
}
322
322
323
323
#[ derive( Clone , Debug ) ]
324
- pub struct OnUnimplementedFormatString ( Symbol , Span ) ;
324
+ pub struct OnUnimplementedFormatString {
325
+ symbol : Symbol ,
326
+ span : Span ,
327
+ is_diagnostic_namespace_variant : bool ,
328
+ }
325
329
326
330
#[ derive( Debug ) ]
327
331
pub struct OnUnimplementedDirective {
@@ -401,6 +405,14 @@ impl IgnoredDiagnosticOption {
401
405
}
402
406
}
403
407
408
+ #[ derive( LintDiagnostic ) ]
409
+ #[ diag( trait_selection_unknown_format_parameter_for_on_unimplemented_attr) ]
410
+ #[ help]
411
+ pub struct UnknownFormatParameterForOnUnimplementedAttr {
412
+ argument_name : Symbol ,
413
+ trait_name : Symbol ,
414
+ }
415
+
404
416
impl < ' tcx > OnUnimplementedDirective {
405
417
fn parse (
406
418
tcx : TyCtxt < ' tcx > ,
@@ -414,8 +426,14 @@ impl<'tcx> OnUnimplementedDirective {
414
426
let mut item_iter = items. iter ( ) ;
415
427
416
428
let parse_value = |value_str, value_span| {
417
- OnUnimplementedFormatString :: try_parse ( tcx, item_def_id, value_str, span, value_span)
418
- . map ( Some )
429
+ OnUnimplementedFormatString :: try_parse (
430
+ tcx,
431
+ item_def_id,
432
+ value_str,
433
+ value_span,
434
+ is_diagnostic_namespace_variant,
435
+ )
436
+ . map ( Some )
419
437
} ;
420
438
421
439
let condition = if is_root {
@@ -552,15 +570,15 @@ impl<'tcx> OnUnimplementedDirective {
552
570
IgnoredDiagnosticOption :: maybe_emit_warning (
553
571
tcx,
554
572
item_def_id,
555
- directive. message . as_ref ( ) . map ( |f| f. 1 ) ,
556
- aggr. message . as_ref ( ) . map ( |f| f. 1 ) ,
573
+ directive. message . as_ref ( ) . map ( |f| f. span ) ,
574
+ aggr. message . as_ref ( ) . map ( |f| f. span ) ,
557
575
"message" ,
558
576
) ;
559
577
IgnoredDiagnosticOption :: maybe_emit_warning (
560
578
tcx,
561
579
item_def_id,
562
- directive. label . as_ref ( ) . map ( |f| f. 1 ) ,
563
- aggr. label . as_ref ( ) . map ( |f| f. 1 ) ,
580
+ directive. label . as_ref ( ) . map ( |f| f. span ) ,
581
+ aggr. label . as_ref ( ) . map ( |f| f. span ) ,
564
582
"label" ,
565
583
) ;
566
584
IgnoredDiagnosticOption :: maybe_emit_warning (
@@ -573,8 +591,8 @@ impl<'tcx> OnUnimplementedDirective {
573
591
IgnoredDiagnosticOption :: maybe_emit_warning (
574
592
tcx,
575
593
item_def_id,
576
- directive. parent_label . as_ref ( ) . map ( |f| f. 1 ) ,
577
- aggr. parent_label . as_ref ( ) . map ( |f| f. 1 ) ,
594
+ directive. parent_label . as_ref ( ) . map ( |f| f. span ) ,
595
+ aggr. parent_label . as_ref ( ) . map ( |f| f. span ) ,
578
596
"parent_label" ,
579
597
) ;
580
598
IgnoredDiagnosticOption :: maybe_emit_warning (
@@ -634,7 +652,7 @@ impl<'tcx> OnUnimplementedDirective {
634
652
item_def_id,
635
653
value,
636
654
attr. span ,
637
- attr . span ,
655
+ is_diagnostic_namespace_variant ,
638
656
) ?) ,
639
657
notes : Vec :: new ( ) ,
640
658
parent_label : None ,
@@ -712,7 +730,12 @@ impl<'tcx> OnUnimplementedDirective {
712
730
// `with_no_visible_paths` is also used when generating the options,
713
731
// so we need to match it here.
714
732
ty:: print:: with_no_visible_paths!(
715
- OnUnimplementedFormatString ( v, cfg. span) . format(
733
+ OnUnimplementedFormatString {
734
+ symbol: v,
735
+ span: cfg. span,
736
+ is_diagnostic_namespace_variant: false
737
+ }
738
+ . format(
716
739
tcx,
717
740
trait_ref,
718
741
& options_map
@@ -760,20 +783,19 @@ impl<'tcx> OnUnimplementedFormatString {
760
783
tcx : TyCtxt < ' tcx > ,
761
784
item_def_id : DefId ,
762
785
from : Symbol ,
763
- err_sp : Span ,
764
786
value_span : Span ,
787
+ is_diagnostic_namespace_variant : bool ,
765
788
) -> Result < Self , ErrorGuaranteed > {
766
- let result = OnUnimplementedFormatString ( from, value_span) ;
767
- result. verify ( tcx, item_def_id, err_sp) ?;
789
+ let result = OnUnimplementedFormatString {
790
+ symbol : from,
791
+ span : value_span,
792
+ is_diagnostic_namespace_variant,
793
+ } ;
794
+ result. verify ( tcx, item_def_id) ?;
768
795
Ok ( result)
769
796
}
770
797
771
- fn verify (
772
- & self ,
773
- tcx : TyCtxt < ' tcx > ,
774
- item_def_id : DefId ,
775
- span : Span ,
776
- ) -> Result < ( ) , ErrorGuaranteed > {
798
+ fn verify ( & self , tcx : TyCtxt < ' tcx > , item_def_id : DefId ) -> Result < ( ) , ErrorGuaranteed > {
777
799
let trait_def_id = if tcx. is_trait ( item_def_id) {
778
800
item_def_id
779
801
} else {
@@ -782,7 +804,7 @@ impl<'tcx> OnUnimplementedFormatString {
782
804
} ;
783
805
let trait_name = tcx. item_name ( trait_def_id) ;
784
806
let generics = tcx. generics_of ( item_def_id) ;
785
- let s = self . 0 . as_str ( ) ;
807
+ let s = self . symbol . as_str ( ) ;
786
808
let parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
787
809
let mut result = Ok ( ( ) ) ;
788
810
for token in parser {
@@ -792,32 +814,48 @@ impl<'tcx> OnUnimplementedFormatString {
792
814
Position :: ArgumentNamed ( s) => {
793
815
match Symbol :: intern ( s) {
794
816
// `{ThisTraitsName}` is allowed
795
- s if s == trait_name => ( ) ,
796
- s if ALLOWED_FORMAT_SYMBOLS . contains ( & s) => ( ) ,
817
+ s if s == trait_name && !self . is_diagnostic_namespace_variant => ( ) ,
818
+ s if ALLOWED_FORMAT_SYMBOLS . contains ( & s)
819
+ && !self . is_diagnostic_namespace_variant =>
820
+ {
821
+ ( )
822
+ }
797
823
// So is `{A}` if A is a type parameter
798
824
s if generics. params . iter ( ) . any ( |param| param. name == s) => ( ) ,
799
825
s => {
800
- result = Err ( struct_span_err ! (
801
- tcx. sess,
802
- span,
803
- E0230 ,
804
- "there is no parameter `{}` on {}" ,
805
- s,
806
- if trait_def_id == item_def_id {
807
- format!( "trait `{trait_name}`" )
808
- } else {
809
- "impl" . to_string( )
810
- }
811
- )
812
- . emit ( ) ) ;
826
+ if self . is_diagnostic_namespace_variant {
827
+ tcx. emit_spanned_lint (
828
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
829
+ tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
830
+ self . span ,
831
+ UnknownFormatParameterForOnUnimplementedAttr {
832
+ argument_name : s,
833
+ trait_name,
834
+ } ,
835
+ ) ;
836
+ } else {
837
+ result = Err ( struct_span_err ! (
838
+ tcx. sess,
839
+ self . span,
840
+ E0230 ,
841
+ "there is no parameter `{}` on {}" ,
842
+ s,
843
+ if trait_def_id == item_def_id {
844
+ format!( "trait `{trait_name}`" )
845
+ } else {
846
+ "impl" . to_string( )
847
+ }
848
+ )
849
+ . emit ( ) ) ;
850
+ }
813
851
}
814
852
}
815
853
}
816
854
// `{:1}` and `{}` are not to be used
817
855
Position :: ArgumentIs ( ..) | Position :: ArgumentImplicitlyIs ( _) => {
818
856
let reported = struct_span_err ! (
819
857
tcx. sess,
820
- span,
858
+ self . span,
821
859
E0231 ,
822
860
"only named substitution parameters are allowed"
823
861
)
@@ -856,45 +894,50 @@ impl<'tcx> OnUnimplementedFormatString {
856
894
. collect :: < FxHashMap < Symbol , String > > ( ) ;
857
895
let empty_string = String :: new ( ) ;
858
896
859
- let s = self . 0 . as_str ( ) ;
897
+ let s = self . symbol . as_str ( ) ;
860
898
let parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
861
899
let item_context = ( options. get ( & sym:: ItemContext ) ) . unwrap_or ( & empty_string) ;
862
900
parser
863
901
. map ( |p| match p {
864
- Piece :: String ( s) => s,
902
+ Piece :: String ( s) => s. to_owned ( ) ,
865
903
Piece :: NextArgument ( a) => match a. position {
866
- Position :: ArgumentNamed ( s ) => {
867
- let s = Symbol :: intern ( s ) ;
904
+ Position :: ArgumentNamed ( arg ) => {
905
+ let s = Symbol :: intern ( arg ) ;
868
906
match generic_map. get ( & s) {
869
- Some ( val) => val,
870
- None if s == name => & trait_str,
907
+ Some ( val) => val. to_string ( ) ,
908
+ None if self . is_diagnostic_namespace_variant => {
909
+ format ! ( "{{{arg}}}" )
910
+ }
911
+ None if s == name => trait_str. clone ( ) ,
871
912
None => {
872
913
if let Some ( val) = options. get ( & s) {
873
- val
914
+ val. clone ( )
874
915
} else if s == sym:: from_desugaring {
875
916
// don't break messages using these two arguments incorrectly
876
- & empty_string
877
- } else if s == sym:: ItemContext {
878
- item_context
917
+ String :: new ( )
918
+ } else if s == sym:: ItemContext
919
+ && !self . is_diagnostic_namespace_variant
920
+ {
921
+ item_context. clone ( )
879
922
} else if s == sym:: integral {
880
- "{integral}"
923
+ String :: from ( "{integral}" )
881
924
} else if s == sym:: integer_ {
882
- "{integer}"
925
+ String :: from ( "{integer}" )
883
926
} else if s == sym:: float {
884
- "{float}"
927
+ String :: from ( "{float}" )
885
928
} else {
886
929
bug ! (
887
930
"broken on_unimplemented {:?} for {:?}: \
888
931
no argument matching {:?}",
889
- self . 0 ,
932
+ self . symbol ,
890
933
trait_ref,
891
934
s
892
935
)
893
936
}
894
937
}
895
938
}
896
939
}
897
- _ => bug ! ( "broken on_unimplemented {:?} - bad format arg" , self . 0 ) ,
940
+ _ => bug ! ( "broken on_unimplemented {:?} - bad format arg" , self . symbol ) ,
898
941
} ,
899
942
} )
900
943
. collect ( )
0 commit comments