diff options
| author | LeSeulArtichaut <leseulartichaut@gmail.com> | 2020-05-01 15:16:17 +0200 |
|---|---|---|
| committer | LeSeulArtichaut <leseulartichaut@gmail.com> | 2020-05-01 16:24:59 +0200 |
| commit | f2c6cbd98fa8be80951385f789f49d560916c726 (patch) | |
| tree | af19c86afa886f276ea26cd35cd58d869e9ea850 | |
| parent | 2474f0ed88bc1a06e02230619b18e7bc8bb673fc (diff) | |
| download | rust-f2c6cbd98fa8be80951385f789f49d560916c726.tar.gz rust-f2c6cbd98fa8be80951385f789f49d560916c726.zip | |
Prevent calls to functions with `#[target_feature]` in safe contexts
| -rw-r--r-- | src/librustc_mir/transform/check_unsafety.rs | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 1c1560cbf9d..a015dc60352 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -19,6 +19,7 @@ use crate::util; pub struct UnsafetyChecker<'a, 'tcx> { body: &'a Body<'tcx>, + body_did: LocalDefId, const_context: bool, min_const_fn: bool, violations: Vec<UnsafetyViolation>, @@ -35,6 +36,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { const_context: bool, min_const_fn: bool, body: &'a Body<'tcx>, + body_did: LocalDefId, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -44,6 +46,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } Self { body, + body_did, const_context, min_const_fn, violations: vec![], @@ -87,6 +90,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { UnsafetyViolationKind::GeneralAndConstFn, ) } + + if let ty::FnDef(func_id, _) = func_ty.kind { + self.check_target_features(func_id); + } } } self.super_terminator(terminator, location); @@ -436,6 +443,22 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } } } + + /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether + /// the called function has target features the calling function hasn't. + fn check_target_features(&mut self, func_did: DefId) { + let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; + let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features; + + // Is `callee_features` a subset of `calling_features`? + if !callee_features.iter().all(|feature| self_features.contains(feature)) { + self.require_unsafe( + "call to function with `#[target_feature]`", + "can only be called if the required target features are available", + UnsafetyViolationKind::GeneralAndConstFn, + ) + } + } } pub(crate) fn provide(providers: &mut Providers<'_>) { @@ -502,7 +525,8 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckRe } hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false), }; - let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env); + let mut checker = + UnsafetyChecker::new(const_context, min_const_fn, body, def_id, tcx, param_env); checker.visit_body(&body); check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks); |
