about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeSeulArtichaut <leseulartichaut@gmail.com>2020-05-01 15:17:20 +0200
committerLeSeulArtichaut <leseulartichaut@gmail.com>2020-05-01 16:37:47 +0200
commitf9b9ba51d3a5d3e5ae3db4a351c2be47e36ef366 (patch)
tree0c2df3d5a1da4e710c3983e9c2aae81ff53110c5
parentf2c6cbd98fa8be80951385f789f49d560916c726 (diff)
downloadrust-f9b9ba51d3a5d3e5ae3db4a351c2be47e36ef366.tar.gz
rust-f9b9ba51d3a5d3e5ae3db4a351c2be47e36ef366.zip
Prevent functions with `#[target_feature]` to be coerced to safe function pointers
-rw-r--r--src/librustc_middle/ty/error.rs23
-rw-r--r--src/librustc_middle/ty/structural_impls.rs1
-rw-r--r--src/librustc_typeck/check/coercion.rs12
3 files changed, 34 insertions, 2 deletions
diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs
index d0bc0d5fabf..78a94b62d47 100644
--- a/src/librustc_middle/ty/error.rs
+++ b/src/librustc_middle/ty/error.rs
@@ -3,11 +3,13 @@ use rustc_ast::ast;
 use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi;
 
 use std::borrow::Cow;
 use std::fmt;
+use std::ops::Deref;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
 pub struct ExpectedFound<T> {
@@ -58,6 +60,8 @@ pub enum TypeError<'tcx> {
     ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
 
     IntrinsicCast,
+    /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
+    TargetFeatureCast(DefId),
 }
 
 pub enum UnconstrainedNumeric {
@@ -183,6 +187,10 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                 write!(f, "expected `{}`, found `{}`", values.expected, values.found)
             }
             IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"),
+            TargetFeatureCast(_) => write!(
+                f,
+                "cannot coerce functions with `#[target_feature]` to safe function pointers"
+            ),
             ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
         }
     }
@@ -193,7 +201,8 @@ impl<'tcx> TypeError<'tcx> {
         use self::TypeError::*;
         match self {
             CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
-            | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) => false,
+            | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_)
+            | TargetFeatureCast(_) => false,
 
             Mutability
             | TupleSize(_)
@@ -489,6 +498,18 @@ impl Trait for X {
                     );
                 }
             }
+            TargetFeatureCast(def_id) => {
+                let attrs = self.get_attrs(*def_id);
+                let target_spans = attrs
+                    .deref()
+                    .iter()
+                    .filter(|attr| attr.has_name(sym::target_feature))
+                    .map(|attr| attr.span);
+                db.note(
+                    "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
+                );
+                db.span_labels(target_spans, "`#[target_feature]` added here");
+            }
             _ => {}
         }
     }
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index 1c0ffe12314..c8406a024ec 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -645,6 +645,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
             ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
             IntrinsicCast => IntrinsicCast,
+            TargetFeatureCast(ref x) => TargetFeatureCast(*x),
             ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
         })
     }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 5d1a1a16485..9a3bb7ee88a 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -688,12 +688,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
 
         match b.kind {
-            ty::FnPtr(_) => {
+            ty::FnPtr(b_sig) => {
                 let a_sig = a.fn_sig(self.tcx);
                 // Intrinsics are not coercible to function pointers
                 if a_sig.abi() == Abi::RustIntrinsic || a_sig.abi() == Abi::PlatformIntrinsic {
                     return Err(TypeError::IntrinsicCast);
                 }
+
+                // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
+                if let ty::FnDef(def_id, _) = a.kind {
+                    if b_sig.unsafety() == hir::Unsafety::Normal
+                        && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+                    {
+                        return Err(TypeError::TargetFeatureCast(def_id));
+                    }
+                }
+
                 let InferOk { value: a_sig, mut obligations } =
                     self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);