1
+ use std:: borrow:: Cow ;
2
+
1
3
use crate :: build:: ExprCategory ;
2
4
use crate :: errors:: * ;
3
5
use rustc_middle:: thir:: visit:: { self , Visitor } ;
4
6
7
+ use rustc_errors:: DiagnosticArgValue ;
5
8
use rustc_hir as hir;
6
9
use rustc_middle:: mir:: BorrowKind ;
7
10
use rustc_middle:: thir:: * ;
@@ -392,15 +395,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
392
395
// the call requires `unsafe`. Don't check this on wasm
393
396
// targets, though. For more information on wasm see the
394
397
// is_like_wasm check in hir_analysis/src/collect.rs
398
+ let callee_features = & self . tcx . codegen_fn_attrs ( func_did) . target_features ;
395
399
if !self . tcx . sess . target . options . is_like_wasm
396
- && !self
397
- . tcx
398
- . codegen_fn_attrs ( func_did)
399
- . target_features
400
+ && !callee_features
400
401
. iter ( )
401
402
. all ( |feature| self . body_target_features . contains ( feature) )
402
403
{
403
- self . requires_unsafe ( expr. span , CallToFunctionWith ( func_did) ) ;
404
+ let missing: Vec < _ > = callee_features
405
+ . iter ( )
406
+ . copied ( )
407
+ . filter ( |feature| !self . body_target_features . contains ( feature) )
408
+ . collect ( ) ;
409
+ let build_enabled = self
410
+ . tcx
411
+ . sess
412
+ . target_features
413
+ . iter ( )
414
+ . copied ( )
415
+ . filter ( |feature| missing. contains ( feature) )
416
+ . collect ( ) ;
417
+ self . requires_unsafe (
418
+ expr. span ,
419
+ CallToFunctionWith { function : func_did, missing, build_enabled } ,
420
+ ) ;
404
421
}
405
422
}
406
423
}
@@ -526,7 +543,7 @@ struct UnusedUnsafeWarning {
526
543
enclosing_unsafe : Option < UnusedUnsafeEnclosing > ,
527
544
}
528
545
529
- #[ derive( Clone , Copy , PartialEq ) ]
546
+ #[ derive( Clone , PartialEq ) ]
530
547
enum UnsafeOpKind {
531
548
CallToUnsafeFunction ( Option < DefId > ) ,
532
549
UseOfInlineAssembly ,
@@ -537,7 +554,15 @@ enum UnsafeOpKind {
537
554
AccessToUnionField ,
538
555
MutationOfLayoutConstrainedField ,
539
556
BorrowOfLayoutConstrainedField ,
540
- CallToFunctionWith ( DefId ) ,
557
+ CallToFunctionWith {
558
+ function : DefId ,
559
+ /// Target features enabled in callee's `#[target_feature]` but missing in
560
+ /// caller's `#[target_feature]`.
561
+ missing : Vec < Symbol > ,
562
+ /// Target features in `missing` that are enabled at compile time
563
+ /// (e.g., with `-C target-feature`).
564
+ build_enabled : Vec < Symbol > ,
565
+ } ,
541
566
}
542
567
543
568
use UnsafeOpKind :: * ;
@@ -658,13 +683,22 @@ impl UnsafeOpKind {
658
683
unsafe_not_inherited_note,
659
684
} ,
660
685
) ,
661
- CallToFunctionWith ( did ) => tcx. emit_spanned_lint (
686
+ CallToFunctionWith { function , missing , build_enabled } => tcx. emit_spanned_lint (
662
687
UNSAFE_OP_IN_UNSAFE_FN ,
663
688
hir_id,
664
689
span,
665
690
UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
666
691
span,
667
- function : & with_no_trimmed_paths ! ( tcx. def_path_str( * did) ) ,
692
+ function : & with_no_trimmed_paths ! ( tcx. def_path_str( * function) ) ,
693
+ missing_target_features : DiagnosticArgValue :: StrListSepByAnd (
694
+ missing. iter ( ) . map ( |feature| Cow :: from ( feature. as_str ( ) ) ) . collect ( ) ,
695
+ ) ,
696
+ missing_target_features_count : missing. len ( ) ,
697
+ note : if build_enabled. is_empty ( ) { None } else { Some ( ( ) ) } ,
698
+ build_target_features : DiagnosticArgValue :: StrListSepByAnd (
699
+ build_enabled. iter ( ) . map ( |feature| Cow :: from ( feature. as_str ( ) ) ) . collect ( ) ,
700
+ ) ,
701
+ build_target_features_count : build_enabled. len ( ) ,
668
702
unsafe_not_inherited_note,
669
703
} ,
670
704
) ,
@@ -821,18 +855,38 @@ impl UnsafeOpKind {
821
855
unsafe_not_inherited_note,
822
856
} ) ;
823
857
}
824
- CallToFunctionWith ( did) if unsafe_op_in_unsafe_fn_allowed => {
858
+ CallToFunctionWith { function, missing, build_enabled }
859
+ if unsafe_op_in_unsafe_fn_allowed =>
860
+ {
825
861
tcx. sess . emit_err ( CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
826
862
span,
863
+ missing_target_features : DiagnosticArgValue :: StrListSepByAnd (
864
+ missing. iter ( ) . map ( |feature| Cow :: from ( feature. as_str ( ) ) ) . collect ( ) ,
865
+ ) ,
866
+ missing_target_features_count : missing. len ( ) ,
867
+ note : if build_enabled. is_empty ( ) { None } else { Some ( ( ) ) } ,
868
+ build_target_features : DiagnosticArgValue :: StrListSepByAnd (
869
+ build_enabled. iter ( ) . map ( |feature| Cow :: from ( feature. as_str ( ) ) ) . collect ( ) ,
870
+ ) ,
871
+ build_target_features_count : build_enabled. len ( ) ,
827
872
unsafe_not_inherited_note,
828
- function : & tcx. def_path_str ( * did ) ,
873
+ function : & tcx. def_path_str ( * function ) ,
829
874
} ) ;
830
875
}
831
- CallToFunctionWith ( did ) => {
876
+ CallToFunctionWith { function , missing , build_enabled } => {
832
877
tcx. sess . emit_err ( CallToFunctionWithRequiresUnsafe {
833
878
span,
879
+ missing_target_features : DiagnosticArgValue :: StrListSepByAnd (
880
+ missing. iter ( ) . map ( |feature| Cow :: from ( feature. as_str ( ) ) ) . collect ( ) ,
881
+ ) ,
882
+ missing_target_features_count : missing. len ( ) ,
883
+ note : if build_enabled. is_empty ( ) { None } else { Some ( ( ) ) } ,
884
+ build_target_features : DiagnosticArgValue :: StrListSepByAnd (
885
+ build_enabled. iter ( ) . map ( |feature| Cow :: from ( feature. as_str ( ) ) ) . collect ( ) ,
886
+ ) ,
887
+ build_target_features_count : build_enabled. len ( ) ,
834
888
unsafe_not_inherited_note,
835
- function : & tcx. def_path_str ( * did ) ,
889
+ function : & tcx. def_path_str ( * function ) ,
836
890
} ) ;
837
891
}
838
892
}
0 commit comments