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