@@ -19,6 +19,7 @@ use crate::util;
19
19
20
20
pub struct UnsafetyChecker < ' a , ' tcx > {
21
21
body : & ' a Body < ' tcx > ,
22
+ body_did : LocalDefId ,
22
23
const_context : bool ,
23
24
min_const_fn : bool ,
24
25
violations : Vec < UnsafetyViolation > ,
@@ -35,6 +36,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
35
36
const_context : bool ,
36
37
min_const_fn : bool ,
37
38
body : & ' a Body < ' tcx > ,
39
+ body_did : LocalDefId ,
38
40
tcx : TyCtxt < ' tcx > ,
39
41
param_env : ty:: ParamEnv < ' tcx > ,
40
42
) -> Self {
@@ -44,6 +46,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
44
46
}
45
47
Self {
46
48
body,
49
+ body_did,
47
50
const_context,
48
51
min_const_fn,
49
52
violations : vec ! [ ] ,
@@ -87,6 +90,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
87
90
UnsafetyViolationKind :: GeneralAndConstFn ,
88
91
)
89
92
}
93
+
94
+ if let ty:: FnDef ( func_id, _) = func_ty. kind {
95
+ self . check_target_features ( func_id) ;
96
+ }
90
97
}
91
98
}
92
99
self . super_terminator ( terminator, location) ;
@@ -436,6 +443,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
436
443
}
437
444
}
438
445
}
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
+ }
439
462
}
440
463
441
464
pub ( crate ) fn provide ( providers : & mut Providers < ' _ > ) {
@@ -502,7 +525,8 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckRe
502
525
}
503
526
hir:: BodyOwnerKind :: Const | hir:: BodyOwnerKind :: Static ( _) => ( true , false ) ,
504
527
} ;
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) ;
506
530
checker. visit_body ( & body) ;
507
531
508
532
check_unused_unsafe ( tcx, def_id, & checker. used_unsafe , & mut checker. inherited_blocks ) ;
0 commit comments