@@ -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 ,
@@ -713,7 +731,12 @@ impl<'tcx> OnUnimplementedDirective {
713
731
// `with_no_visible_paths` is also used when generating the options,
714
732
// so we need to match it here.
715
733
ty:: print:: with_no_visible_paths!(
716
- OnUnimplementedFormatString ( v, cfg. span) . format(
734
+ OnUnimplementedFormatString {
735
+ symbol: v,
736
+ span: cfg. span,
737
+ is_diagnostic_namespace_variant: false
738
+ }
739
+ . format(
717
740
tcx,
718
741
trait_ref,
719
742
& options_map
@@ -761,20 +784,19 @@ impl<'tcx> OnUnimplementedFormatString {
761
784
tcx : TyCtxt < ' tcx > ,
762
785
item_def_id : DefId ,
763
786
from : Symbol ,
764
- err_sp : Span ,
765
787
value_span : Span ,
788
+ is_diagnostic_namespace_variant : bool ,
766
789
) -> Result < Self , ErrorGuaranteed > {
767
- let result = OnUnimplementedFormatString ( from, value_span) ;
768
- result. verify ( tcx, item_def_id, err_sp) ?;
790
+ let result = OnUnimplementedFormatString {
791
+ symbol : from,
792
+ span : value_span,
793
+ is_diagnostic_namespace_variant,
794
+ } ;
795
+ result. verify ( tcx, item_def_id) ?;
769
796
Ok ( result)
770
797
}
771
798
772
- fn verify (
773
- & self ,
774
- tcx : TyCtxt < ' tcx > ,
775
- item_def_id : DefId ,
776
- span : Span ,
777
- ) -> Result < ( ) , ErrorGuaranteed > {
799
+ fn verify ( & self , tcx : TyCtxt < ' tcx > , item_def_id : DefId ) -> Result < ( ) , ErrorGuaranteed > {
778
800
let trait_def_id = if tcx. is_trait ( item_def_id) {
779
801
item_def_id
780
802
} else {
@@ -783,7 +805,7 @@ impl<'tcx> OnUnimplementedFormatString {
783
805
} ;
784
806
let trait_name = tcx. item_name ( trait_def_id) ;
785
807
let generics = tcx. generics_of ( item_def_id) ;
786
- let s = self . 0 . as_str ( ) ;
808
+ let s = self . symbol . as_str ( ) ;
787
809
let parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
788
810
let mut result = Ok ( ( ) ) ;
789
811
for token in parser {
@@ -793,32 +815,48 @@ impl<'tcx> OnUnimplementedFormatString {
793
815
Position :: ArgumentNamed ( s) => {
794
816
match Symbol :: intern ( s) {
795
817
// `{ThisTraitsName}` is allowed
796
- s if s == trait_name => ( ) ,
797
- s if ALLOWED_FORMAT_SYMBOLS . contains ( & s) => ( ) ,
818
+ s if s == trait_name && !self . is_diagnostic_namespace_variant => ( ) ,
819
+ s if ALLOWED_FORMAT_SYMBOLS . contains ( & s)
820
+ && !self . is_diagnostic_namespace_variant =>
821
+ {
822
+ ( )
823
+ }
798
824
// So is `{A}` if A is a type parameter
799
825
s if generics. params . iter ( ) . any ( |param| param. name == s) => ( ) ,
800
826
s => {
801
- result = Err ( struct_span_err ! (
802
- tcx. sess,
803
- span,
804
- E0230 ,
805
- "there is no parameter `{}` on {}" ,
806
- s,
807
- if trait_def_id == item_def_id {
808
- format!( "trait `{trait_name}`" )
809
- } else {
810
- "impl" . to_string( )
811
- }
812
- )
813
- . emit ( ) ) ;
827
+ if self . is_diagnostic_namespace_variant {
828
+ tcx. emit_spanned_lint (
829
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES ,
830
+ tcx. local_def_id_to_hir_id ( item_def_id. expect_local ( ) ) ,
831
+ self . span ,
832
+ UnknownFormatParameterForOnUnimplementedAttr {
833
+ argument_name : s,
834
+ trait_name,
835
+ } ,
836
+ ) ;
837
+ } else {
838
+ result = Err ( struct_span_err ! (
839
+ tcx. sess,
840
+ self . span,
841
+ E0230 ,
842
+ "there is no parameter `{}` on {}" ,
843
+ s,
844
+ if trait_def_id == item_def_id {
845
+ format!( "trait `{trait_name}`" )
846
+ } else {
847
+ "impl" . to_string( )
848
+ }
849
+ )
850
+ . emit ( ) ) ;
851
+ }
814
852
}
815
853
}
816
854
}
817
855
// `{:1}` and `{}` are not to be used
818
856
Position :: ArgumentIs ( ..) | Position :: ArgumentImplicitlyIs ( _) => {
819
857
let reported = struct_span_err ! (
820
858
tcx. sess,
821
- span,
859
+ self . span,
822
860
E0231 ,
823
861
"only named substitution parameters are allowed"
824
862
)
@@ -857,45 +895,50 @@ impl<'tcx> OnUnimplementedFormatString {
857
895
. collect :: < FxHashMap < Symbol , String > > ( ) ;
858
896
let empty_string = String :: new ( ) ;
859
897
860
- let s = self . 0 . as_str ( ) ;
898
+ let s = self . symbol . as_str ( ) ;
861
899
let parser = Parser :: new ( s, None , None , false , ParseMode :: Format ) ;
862
900
let item_context = ( options. get ( & sym:: ItemContext ) ) . unwrap_or ( & empty_string) ;
863
901
parser
864
902
. map ( |p| match p {
865
- Piece :: String ( s) => s,
903
+ Piece :: String ( s) => s. to_owned ( ) ,
866
904
Piece :: NextArgument ( a) => match a. position {
867
- Position :: ArgumentNamed ( s ) => {
868
- let s = Symbol :: intern ( s ) ;
905
+ Position :: ArgumentNamed ( arg ) => {
906
+ let s = Symbol :: intern ( arg ) ;
869
907
match generic_map. get ( & s) {
870
- Some ( val) => val,
871
- None if s == name => & trait_str,
908
+ Some ( val) => val. to_string ( ) ,
909
+ None if self . is_diagnostic_namespace_variant => {
910
+ format ! ( "{{{arg}}}" )
911
+ }
912
+ None if s == name => trait_str. clone ( ) ,
872
913
None => {
873
914
if let Some ( val) = options. get ( & s) {
874
- val
915
+ val. clone ( )
875
916
} else if s == sym:: from_desugaring {
876
917
// don't break messages using these two arguments incorrectly
877
- & empty_string
878
- } else if s == sym:: ItemContext {
879
- item_context
918
+ String :: new ( )
919
+ } else if s == sym:: ItemContext
920
+ && !self . is_diagnostic_namespace_variant
921
+ {
922
+ item_context. clone ( )
880
923
} else if s == sym:: integral {
881
- "{integral}"
924
+ String :: from ( "{integral}" )
882
925
} else if s == sym:: integer_ {
883
- "{integer}"
926
+ String :: from ( "{integer}" )
884
927
} else if s == sym:: float {
885
- "{float}"
928
+ String :: from ( "{float}" )
886
929
} else {
887
930
bug ! (
888
931
"broken on_unimplemented {:?} for {:?}: \
889
932
no argument matching {:?}",
890
- self . 0 ,
933
+ self . symbol ,
891
934
trait_ref,
892
935
s
893
936
)
894
937
}
895
938
}
896
939
}
897
940
}
898
- _ => bug ! ( "broken on_unimplemented {:?} - bad format arg" , self . 0 ) ,
941
+ _ => bug ! ( "broken on_unimplemented {:?} - bad format arg" , self . symbol ) ,
899
942
} ,
900
943
} )
901
944
. collect ( )
0 commit comments