@@ -51,6 +51,7 @@ use rustc_infer::traits::{
5151 PredicateObligations ,
5252} ;
5353use rustc_middle:: lint:: in_external_macro;
54+ use rustc_middle:: middle:: codegen_fn_attrs:: is_target_feature_call_safe;
5455use rustc_middle:: span_bug;
5556use rustc_middle:: traits:: BuiltinImplSource ;
5657use rustc_middle:: ty:: adjustment:: {
@@ -920,7 +921,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
920921
921922 match b. kind ( ) {
922923 ty:: FnPtr ( _, b_hdr) => {
923- let a_sig = a. fn_sig ( self . tcx ) ;
924+ let mut a_sig = a. fn_sig ( self . tcx ) ;
924925 if let ty:: FnDef ( def_id, _) = * a. kind ( ) {
925926 // Intrinsics are not coercible to function pointers
926927 if self . tcx . intrinsic ( def_id) . is_some ( ) {
@@ -932,19 +933,23 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
932933 return Err ( TypeError :: ForceInlineCast ) ;
933934 }
934935
935- let fn_attrs = self . tcx . codegen_fn_attrs ( def_id) ;
936- if matches ! ( fn_attrs. inline, InlineAttr :: Force { .. } ) {
937- return Err ( TypeError :: ForceInlineCast ) ;
938- }
939-
940- // FIXME(target_feature): Safe `#[target_feature]` functions could be cast to safe fn pointers (RFC 2396),
941- // as you can already write that "cast" in user code by wrapping a target_feature fn call in a closure,
942- // which is safe. This is sound because you already need to be executing code that is satisfying the target
943- // feature constraints..
944936 if b_hdr. safety . is_safe ( )
945937 && self . tcx . codegen_fn_attrs ( def_id) . safe_target_features
946938 {
947- return Err ( TypeError :: TargetFeatureCast ( def_id) ) ;
939+ // Allow the coercion if the current function has all the features that would be
940+ // needed to call the coercee safely.
941+ let coercee_features = & self . tcx . codegen_fn_attrs ( def_id) . target_features ;
942+ let body_features =
943+ & self . tcx . codegen_fn_attrs ( self . fcx . body_id ) . target_features ;
944+ if !is_target_feature_call_safe ( self . tcx , & coercee_features, & body_features)
945+ {
946+ return Err ( TypeError :: TargetFeatureCast ( def_id) ) ;
947+ } else {
948+ // The coercee behaves like a safe function, since it is a target_feature
949+ // function that would be callable safely in this context.
950+ a_sig = a_sig
951+ . map_bound ( |sig| ty:: FnSig { safety : hir:: Safety :: Safe , ..sig } )
952+ }
948953 }
949954 }
950955
0 commit comments