@@ -19,6 +19,7 @@ use crate::util;
1919
2020pub struct UnsafetyChecker < ' a , ' tcx > {
2121 body : & ' a Body < ' tcx > ,
22+ body_did : LocalDefId ,
2223 const_context : bool ,
2324 min_const_fn : bool ,
2425 violations : Vec < UnsafetyViolation > ,
@@ -35,6 +36,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
3536 const_context : bool ,
3637 min_const_fn : bool ,
3738 body : & ' a Body < ' tcx > ,
39+ body_did : LocalDefId ,
3840 tcx : TyCtxt < ' tcx > ,
3941 param_env : ty:: ParamEnv < ' tcx > ,
4042 ) -> Self {
@@ -44,6 +46,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
4446 }
4547 Self {
4648 body,
49+ body_did,
4750 const_context,
4851 min_const_fn,
4952 violations : vec ! [ ] ,
@@ -87,6 +90,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
8790 UnsafetyViolationKind :: GeneralAndConstFn ,
8891 )
8992 }
93+
94+ if let ty:: FnDef ( func_id, _) = func_ty. kind {
95+ self . check_target_features ( func_id) ;
96+ }
9097 }
9198 }
9299 self . super_terminator ( terminator, location) ;
@@ -436,6 +443,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
436443 }
437444 }
438445 }
446+
447+ /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
448+ /// the called function has target features the calling function hasn't.
449+ fn check_target_features ( & mut self , func_did : DefId ) {
450+ let callee_features = & self . tcx . codegen_fn_attrs ( func_did) . target_features ;
451+ let self_features = & self . tcx . codegen_fn_attrs ( self . body_did ) . target_features ;
452+
453+ // Is `callee_features` a subset of `calling_features`?
454+ if !callee_features. iter ( ) . all ( |feature| self_features. contains ( feature) ) {
455+ self . require_unsafe (
456+ "call to function with `#[target_feature]`" ,
457+ "can only be called if the required target features are available" ,
458+ UnsafetyViolationKind :: GeneralAndConstFn ,
459+ )
460+ }
461+ }
439462}
440463
441464pub ( crate ) fn provide ( providers : & mut Providers < ' _ > ) {
@@ -502,7 +525,8 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckRe
502525 }
503526 hir:: BodyOwnerKind :: Const | hir:: BodyOwnerKind :: Static ( _) => ( true , false ) ,
504527 } ;
505- let mut checker = UnsafetyChecker :: new ( const_context, min_const_fn, body, tcx, param_env) ;
528+ let mut checker =
529+ UnsafetyChecker :: new ( const_context, min_const_fn, body, def_id, tcx, param_env) ;
506530 checker. visit_body ( & body) ;
507531
508532 check_unused_unsafe ( tcx, def_id, & checker. used_unsafe , & mut checker. inherited_blocks ) ;
0 commit comments