@@ -921,6 +921,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
921921 match b. kind ( ) {
922922 ty:: FnPtr ( _, b_hdr) => {
923923 let a_sig = a. fn_sig ( self . tcx ) ;
924+ let mut allow_unsafe_to_safe_coercion = false ;
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,26 +933,38 @@ 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 !self . tcx . sess . target . options . is_like_wasm
945+ && !coercee_features
946+ . iter ( )
947+ . all ( |feature| body_features. iter ( ) . any ( |f| f. name == feature. name ) )
948+ {
949+ return Err ( TypeError :: TargetFeatureCast ( def_id) ) ;
950+ } else {
951+ allow_unsafe_to_safe_coercion = true ;
952+ }
948953 }
949954 }
950955
951956 let InferOk { value : a_sig, obligations : o1 } =
952957 self . at ( & self . cause , self . param_env ) . normalize ( a_sig) ;
953958 obligations. extend ( o1) ;
954959
960+ let a_sig = if allow_unsafe_to_safe_coercion {
961+ // The coercee behaves like a safe function, since it is a target_feature
962+ // function that would be callable safely in this context.
963+ a_sig. map_bound ( |sig| ty:: FnSig { safety : hir:: Safety :: Safe , ..sig } )
964+ } else {
965+ a_sig
966+ } ;
967+
955968 let a_fn_pointer = Ty :: new_fn_ptr ( self . tcx , a_sig) ;
956969 let InferOk { value, obligations : o2 } = self . coerce_from_safe_fn (
957970 a_fn_pointer,
0 commit comments