diff options
| author | LeSeulArtichaut <leseulartichaut@gmail.com> | 2020-05-01 15:17:20 +0200 |
|---|---|---|
| committer | LeSeulArtichaut <leseulartichaut@gmail.com> | 2020-05-01 16:37:47 +0200 |
| commit | f9b9ba51d3a5d3e5ae3db4a351c2be47e36ef366 (patch) | |
| tree | 0c2df3d5a1da4e710c3983e9c2aae81ff53110c5 | |
| parent | f2c6cbd98fa8be80951385f789f49d560916c726 (diff) | |
| download | rust-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.rs | 23 | ||||
| -rw-r--r-- | src/librustc_middle/ty/structural_impls.rs | 1 | ||||
| -rw-r--r-- | src/librustc_typeck/check/coercion.rs | 12 |
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); |
