Skip to content

Commit

Permalink
Prevent functions with #[target_feature] to be coerced to safe func…
Browse files Browse the repository at this point in the history
…tion pointers
  • Loading branch information
LeSeulArtichaut committed May 1, 2020
1 parent f2c6cbd commit f9b9ba5
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 2 deletions.
23 changes: 22 additions & 1 deletion src/librustc_middle/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"),
}
}
Expand All @@ -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(_)
Expand Down Expand Up @@ -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");
}
_ => {}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_middle/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
})
}
Expand Down
12 changes: 11 additions & 1 deletion src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit f9b9ba5

Please sign in to comment.