1+ use std:: borrow:: Cow ;
2+
13use crate :: build:: ExprCategory ;
24use crate :: errors:: * ;
35use rustc_middle:: thir:: visit:: { self , Visitor } ;
46
7+ use rustc_errors:: DiagnosticArgValue ;
58use rustc_hir as hir;
69use rustc_middle:: mir:: BorrowKind ;
710use rustc_middle:: thir:: * ;
@@ -392,15 +395,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
392395 // the call requires `unsafe`. Don't check this on wasm
393396 // targets, though. For more information on wasm see the
394397 // is_like_wasm check in hir_analysis/src/collect.rs
398+ let callee_features = & self . tcx . codegen_fn_attrs ( func_did) . target_features ;
395399 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
400401 . iter ( )
401402 . all ( |feature| self . body_target_features . contains ( feature) )
402403 {
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+ ) ;
404421 }
405422 }
406423 }
@@ -526,7 +543,7 @@ struct UnusedUnsafeWarning {
526543 enclosing_unsafe : Option < UnusedUnsafeEnclosing > ,
527544}
528545
529- #[ derive( Clone , Copy , PartialEq ) ]
546+ #[ derive( Clone , PartialEq ) ]
530547enum UnsafeOpKind {
531548 CallToUnsafeFunction ( Option < DefId > ) ,
532549 UseOfInlineAssembly ,
@@ -537,7 +554,15 @@ enum UnsafeOpKind {
537554 AccessToUnionField ,
538555 MutationOfLayoutConstrainedField ,
539556 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+ } ,
541566}
542567
543568use UnsafeOpKind :: * ;
@@ -658,13 +683,22 @@ impl UnsafeOpKind {
658683 unsafe_not_inherited_note,
659684 } ,
660685 ) ,
661- CallToFunctionWith ( did ) => tcx. emit_spanned_lint (
686+ CallToFunctionWith { function , missing , build_enabled } => tcx. emit_spanned_lint (
662687 UNSAFE_OP_IN_UNSAFE_FN ,
663688 hir_id,
664689 span,
665690 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
666691 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 ( ) ,
668702 unsafe_not_inherited_note,
669703 } ,
670704 ) ,
@@ -821,18 +855,38 @@ impl UnsafeOpKind {
821855 unsafe_not_inherited_note,
822856 } ) ;
823857 }
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+ {
825861 tcx. sess . emit_err ( CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
826862 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 ( ) ,
827872 unsafe_not_inherited_note,
828- function : & tcx. def_path_str ( * did ) ,
873+ function : & tcx. def_path_str ( * function ) ,
829874 } ) ;
830875 }
831- CallToFunctionWith ( did ) => {
876+ CallToFunctionWith { function , missing , build_enabled } => {
832877 tcx. sess . emit_err ( CallToFunctionWithRequiresUnsafe {
833878 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 ( ) ,
834888 unsafe_not_inherited_note,
835- function : & tcx. def_path_str ( * did ) ,
889+ function : & tcx. def_path_str ( * function ) ,
836890 } ) ;
837891 }
838892 }
0 commit comments