@@ -921,6 +921,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
921
921
match b. kind ( ) {
922
922
ty:: FnPtr ( _, b_hdr) => {
923
923
let a_sig = a. fn_sig ( self . tcx ) ;
924
+ let mut allow_unsafe_to_safe_coercion = false ;
924
925
if let ty:: FnDef ( def_id, _) = * a. kind ( ) {
925
926
// Intrinsics are not coercible to function pointers
926
927
if self . tcx . intrinsic ( def_id) . is_some ( ) {
@@ -932,26 +933,38 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
932
933
return Err ( TypeError :: ForceInlineCast ) ;
933
934
}
934
935
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..
944
936
if b_hdr. safety . is_safe ( )
945
937
&& self . tcx . codegen_fn_attrs ( def_id) . safe_target_features
946
938
{
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
+ }
948
953
}
949
954
}
950
955
951
956
let InferOk { value : a_sig, obligations : o1 } =
952
957
self . at ( & self . cause , self . param_env ) . normalize ( a_sig) ;
953
958
obligations. extend ( o1) ;
954
959
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
+
955
968
let a_fn_pointer = Ty :: new_fn_ptr ( self . tcx , a_sig) ;
956
969
let InferOk { value, obligations : o2 } = self . coerce_from_safe_fn (
957
970
a_fn_pointer,
0 commit comments