@@ -920,7 +920,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
920920
921921 match b. kind ( ) {
922922 ty:: FnPtr ( _, b_hdr) => {
923- let a_sig = a. fn_sig ( self . tcx ) ;
923+ let mut a_sig = a. fn_sig ( self . tcx ) ;
924924 if let ty:: FnDef ( def_id, _) = * a. kind ( ) {
925925 // Intrinsics are not coercible to function pointers
926926 if self . tcx . intrinsic ( def_id) . is_some ( ) {
@@ -932,19 +932,26 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
932932 return Err ( TypeError :: ForceInlineCast ) ;
933933 }
934934
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..
944935 if b_hdr. safety . is_safe ( )
945936 && self . tcx . codegen_fn_attrs ( def_id) . safe_target_features
946937 {
947- return Err ( TypeError :: TargetFeatureCast ( def_id) ) ;
938+ // Allow the coercion if the current function has all the features that would be
939+ // needed to call the coercee safely.
940+ let coercee_features = & self . tcx . codegen_fn_attrs ( def_id) . target_features ;
941+ let body_features =
942+ & self . tcx . codegen_fn_attrs ( self . fcx . body_id ) . target_features ;
943+ if !self . tcx . sess . target . options . is_like_wasm
944+ && !coercee_features
945+ . iter ( )
946+ . all ( |feature| body_features. iter ( ) . any ( |f| f. name == feature. name ) )
947+ {
948+ return Err ( TypeError :: TargetFeatureCast ( def_id) ) ;
949+ } else {
950+ // The coercee behaves like a safe function, since it is a target_feature
951+ // function that would be callable safely in this context.
952+ a_sig = a_sig
953+ . map_bound ( |sig| ty:: FnSig { safety : hir:: Safety :: Safe , ..sig } )
954+ }
948955 }
949956 }
950957
0 commit comments