about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorLeSeulArtichaut <leseulartichaut@gmail.com>2021-05-14 23:52:34 +0200
committerLeSeulArtichaut <leseulartichaut@gmail.com>2021-05-20 00:06:32 +0200
commitd7787bbaeffefc4c89910b1aac2cd370c2c27955 (patch)
treef3f3bf937c507a32efc839e423606fa5a6b15d3e /compiler
parent27fe959c2c99207828cedfe19dbf96debd3be591 (diff)
downloadrust-d7787bbaeffefc4c89910b1aac2cd370c2c27955.tar.gz
rust-d7787bbaeffefc4c89910b1aac2cd370c2c27955.zip
Check for calls to functions with `#[target_feature]` in THIR unsafeck
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs31
1 files changed, 27 insertions, 4 deletions
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index c1866b9a437..3c2d770390d 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -7,6 +7,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
 use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 struct UnsafetyVisitor<'a, 'tcx> {
@@ -19,6 +20,9 @@ struct UnsafetyVisitor<'a, 'tcx> {
     /// `unsafe` block, and whether it has been used.
     safety_context: SafetyContext,
     body_unsafety: BodyUnsafety,
+    /// The `#[target_feature]` attributes of the body. Used for checking
+    /// calls to functions with `#[target_feature]` (RFC 2396).
+    body_target_features: &'tcx Vec<Symbol>,
 }
 
 impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
@@ -148,6 +152,18 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
                 if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
                     self.requires_unsafe(expr.span, CallToUnsafeFunction);
+                } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
+                    // If the called function has target features the calling function hasn't,
+                    // the call requires `unsafe`.
+                    if !self
+                        .tcx
+                        .codegen_fn_attrs(func_did)
+                        .target_features
+                        .iter()
+                        .all(|feature| self.body_target_features.contains(feature))
+                    {
+                        self.requires_unsafe(expr.span, CallToFunctionWith);
+                    }
                 }
             }
             ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
@@ -217,7 +233,6 @@ enum UnsafeOpKind {
     MutationOfLayoutConstrainedField,
     #[allow(dead_code)] // FIXME
     BorrowOfLayoutConstrainedField,
-    #[allow(dead_code)] // FIXME
     CallToFunctionWith,
 }
 
@@ -291,6 +306,7 @@ pub fn check_unsafety<'tcx>(
     tcx: TyCtxt<'tcx>,
     thir: &Thir<'tcx>,
     expr: ExprId,
+    def_id: LocalDefId,
     hir_id: hir::HirId,
 ) {
     let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
@@ -300,10 +316,17 @@ pub fn check_unsafety<'tcx>(
             BodyUnsafety::Safe
         }
     });
+    let body_target_features = &tcx.codegen_fn_attrs(def_id).target_features;
     let safety_context =
         if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
-    let mut visitor =
-        UnsafetyVisitor { tcx, thir, safety_context, hir_context: hir_id, body_unsafety };
+    let mut visitor = UnsafetyVisitor {
+        tcx,
+        thir,
+        safety_context,
+        hir_context: hir_id,
+        body_unsafety,
+        body_target_features,
+    };
     visitor.visit_expr(&thir[expr]);
 }
 
@@ -315,7 +338,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
     let body_id = tcx.hir().body_owned_by(hir_id);
     let body = tcx.hir().body(body_id);
     let (thir, expr) = cx::build_thir(tcx, def, &body.value);
-    check_unsafety(tcx, &thir, expr, hir_id);
+    check_unsafety(tcx, &thir, expr, def.did, hir_id);
 }
 
 crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {