diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 9be73cf3c6d16..e684ccfeeb7ed 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1636,6 +1636,9 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { Error0644("closure/generator type that references itself") } + TypeError::IntrinsicCast => { + Error0308("cannot coerce intrinsics to function pointers") + } _ => Error0308("mismatched types"), }, } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index c70006b68d69a..fe8f94ab1d314 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -46,6 +46,8 @@ pub enum TypeError<'tcx> { ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), + + IntrinsicCast, } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -179,6 +181,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ConstMismatch(ref values) => { write!(f, "expected `{}`, found `{}`", values.expected, values.found) } + IntrinsicCast => { + write!(f, "cannot coerce intrinsics to function pointers") + } } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 649a5244728ba..ec7cf1a13c596 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -748,6 +748,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), + IntrinsicCast => IntrinsicCast, }) } } @@ -1338,6 +1339,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::Sorts)(x), (ty::error::TypeError::ExistentialMismatch)(x), (ty::error::TypeError::ConstMismatch)(x), + (ty::error::TypeError::IntrinsicCast), } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 55e7a10f1aaa4..c216cc92b1e58 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -40,6 +40,7 @@ use rustc::ty::{self, Ty, TypeFoldable, TypeAndMut}; use rustc::ty::subst::SubstsRef; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::cast::{CastKind, CastTy}; +use rustc::ty::error::TypeError; use rustc::middle::lang_items; use syntax::ast; use syntax_pos::Span; @@ -461,6 +462,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, fcx.tcx.mk_fn_ptr(f), AllowTwoPhase::No); + if let Err(TypeError::IntrinsicCast) = res { + return Err(CastError::IllegalCast); + } if res.is_err() { return Err(CastError::NonScalar); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 61b9c2a15ba16..f2e1a6e29d6fc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -70,6 +70,7 @@ use std::ops::Deref; use syntax::feature_gate; use syntax::symbol::sym; use syntax_pos; +use rustc_target::spec::abi::Abi; struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -689,6 +690,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.sty { ty::FnPtr(_) => { 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); + } let InferOk { value: a_sig, mut obligations } = self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); diff --git a/src/test/ui/reify-intrinsic.rs b/src/test/ui/reify-intrinsic.rs new file mode 100644 index 0000000000000..09baa059e5567 --- /dev/null +++ b/src/test/ui/reify-intrinsic.rs @@ -0,0 +1,15 @@ +// check-fail + +#![feature(intrinsics)] + +fn a() { + let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + //~^ ERROR cannot coerce +} + +fn b() { + let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + //~^ ERROR casting +} + +fn main() {} diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr new file mode 100644 index 0000000000000..4a1bd77cf7ee9 --- /dev/null +++ b/src/test/ui/reify-intrinsic.stderr @@ -0,0 +1,22 @@ +error[E0308]: cannot coerce intrinsics to function pointers + --> $DIR/reify-intrinsic.rs:6:64 + | +LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + | ^^^^^^^^^^^^^^^^^^^ + | | + | cannot coerce intrinsics to function pointers + | help: use parentheses to call this function: `std::mem::transmute(...)` + | + = note: expected type `unsafe extern "rust-intrinsic" fn(isize) -> usize` + found type `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + +error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid + --> $DIR/reify-intrinsic.rs:11:13 + | +LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0606. +For more information about an error, try `rustc --explain E0308`.