Skip to content

Commit f9b9ba5

Browse files
Prevent functions with #[target_feature] to be coerced to safe function pointers
1 parent f2c6cbd commit f9b9ba5

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

src/librustc_middle/ty/error.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ use rustc_ast::ast;
33
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
44
use rustc_hir as hir;
55
use rustc_hir::def_id::DefId;
6+
use rustc_span::symbol::sym;
67
use rustc_span::Span;
78
use rustc_target::spec::abi;
89

910
use std::borrow::Cow;
1011
use std::fmt;
12+
use std::ops::Deref;
1113

1214
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
1315
pub struct ExpectedFound<T> {
@@ -58,6 +60,8 @@ pub enum TypeError<'tcx> {
5860
ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
5961

6062
IntrinsicCast,
63+
/// Safe `#[target_feature]` functions are not assignable to safe function pointers.
64+
TargetFeatureCast(DefId),
6165
}
6266

6367
pub enum UnconstrainedNumeric {
@@ -183,6 +187,10 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
183187
write!(f, "expected `{}`, found `{}`", values.expected, values.found)
184188
}
185189
IntrinsicCast => write!(f, "cannot coerce intrinsics to function pointers"),
190+
TargetFeatureCast(_) => write!(
191+
f,
192+
"cannot coerce functions with `#[target_feature]` to safe function pointers"
193+
),
186194
ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
187195
}
188196
}
@@ -193,7 +201,8 @@ impl<'tcx> TypeError<'tcx> {
193201
use self::TypeError::*;
194202
match self {
195203
CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
196-
| Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) => false,
204+
| Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_)
205+
| TargetFeatureCast(_) => false,
197206

198207
Mutability
199208
| TupleSize(_)
@@ -489,6 +498,18 @@ impl Trait for X {
489498
);
490499
}
491500
}
501+
TargetFeatureCast(def_id) => {
502+
let attrs = self.get_attrs(*def_id);
503+
let target_spans = attrs
504+
.deref()
505+
.iter()
506+
.filter(|attr| attr.has_name(sym::target_feature))
507+
.map(|attr| attr.span);
508+
db.note(
509+
"functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
510+
);
511+
db.span_labels(target_spans, "`#[target_feature]` added here");
512+
}
492513
_ => {}
493514
}
494515
}

src/librustc_middle/ty/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
645645
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
646646
ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
647647
IntrinsicCast => IntrinsicCast,
648+
TargetFeatureCast(ref x) => TargetFeatureCast(*x),
648649
ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
649650
})
650651
}

src/librustc_typeck/check/coercion.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -688,12 +688,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
688688
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
689689

690690
match b.kind {
691-
ty::FnPtr(_) => {
691+
ty::FnPtr(b_sig) => {
692692
let a_sig = a.fn_sig(self.tcx);
693693
// Intrinsics are not coercible to function pointers
694694
if a_sig.abi() == Abi::RustIntrinsic || a_sig.abi() == Abi::PlatformIntrinsic {
695695
return Err(TypeError::IntrinsicCast);
696696
}
697+
698+
// Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
699+
if let ty::FnDef(def_id, _) = a.kind {
700+
if b_sig.unsafety() == hir::Unsafety::Normal
701+
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
702+
{
703+
return Err(TypeError::TargetFeatureCast(def_id));
704+
}
705+
}
706+
697707
let InferOk { value: a_sig, mut obligations } =
698708
self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);
699709

0 commit comments

Comments
 (0)