diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 26a5d438edb98..26f42a0ea3247 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use std::{fmt, iter, mem}; -use rustc_abi::FieldIdx; +use rustc_abi::{ExternAbi, FieldIdx}; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; @@ -39,7 +39,8 @@ use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::symbol::sym; +use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument, trace}; @@ -1743,6 +1744,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }; } + // NOTE(eddyb) see comment on `prepare_fn_sig_for_reify` + // in `rustc_typeck::check::coercion`. + let src_sig = src_sig.map_bound(|mut sig| -> _ { + if matches!(sig.abi, ExternAbi::RustIntrinsic) { + sig.abi = ExternAbi::Rust; + } + + sig + }); + let src_ty = Ty::new_fn_ptr(tcx, src_sig); // HACK: We want to assert that the signature of the source fn is // well-formed, because we don't enforce that via the WF of FnDef diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index d8015bcc91424..86c162806db80 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -38,7 +38,6 @@ use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -748,9 +747,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { AllowTwoPhase::No, None, ); - if let Err(TypeError::IntrinsicCast) = res { - return Err(CastError::IllegalCast); - } if res.is_err() { return Err(CastError::NonScalar); } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 14dd0f32d8206..830bfda6403d9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -98,6 +98,23 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; +/// Make any adjustments necessary for a function signature to be compatible +/// with reification to a `fn` pointer. In particular, intrinsics are imported +/// using pseudo-ABIs (`extern "rust-intrinsic" {...}`) currently, but that's +/// an implementation detail and any `fn` pointers that may be taken to them +/// should be indistinguishable from those to regular Rust functions, in order +/// to allow e.g. libcore public APIs to be replaced with intrinsics, without +/// breaking code that was, explicitly or implicitly, creating `fn` pointers. +// FIXME(eddyb) intrinsics shouldn't use pseudo-ABIs, but rather the Rust ABI +// and some other way to indicate that they are intrinsics (e.g. new attributes). +fn prepare_fn_sig_for_reify<'tcx>(mut sig: ty::FnSig<'tcx>) -> ty::FnSig<'tcx> { + if matches!(sig.abi, ExternAbi::RustIntrinsic) { + sig.abi = ExternAbi::Rust; + } + + sig +} + /// Coercing a mutable reference to an immutable works, while /// coercing `&T` to `&mut T` should be forbidden. fn coerce_mutbls<'tcx>( @@ -911,12 +928,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.kind() { ty::FnPtr(_, b_hdr) => { let mut a_sig = a.fn_sig(self.tcx); - if let ty::FnDef(def_id, _) = *a.kind() { - // Intrinsics are not coercible to function pointers - if self.tcx.intrinsic(def_id).is_some() { - return Err(TypeError::IntrinsicCast); - } + // NOTE(eddyb) see comment on `prepare_fn_sig_for_reify`. + a_sig = a_sig.map_bound(prepare_fn_sig_for_reify); + if let ty::FnDef(def_id, _) = *a.kind() { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); if matches!(fn_attrs.inline, InlineAttr::Force { .. }) { return Err(TypeError::ForceInlineCast); @@ -1266,10 +1281,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { - // Intrinsics are not coercible to function pointers. - if a_sig.abi() == ExternAbi::RustIntrinsic || b_sig.abi() == ExternAbi::RustIntrinsic { - return Err(TypeError::IntrinsicCast); - } // The signature must match. let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let sig = self diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 8c1991ddb36ee..eef27c57e4d84 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -112,7 +112,6 @@ impl<'tcx> TypeError<'tcx> { TypeError::ForceInlineCast => { "cannot coerce functions which must be inlined to function pointers".into() } - TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), TypeError::TargetFeatureCast(_) => { "cannot coerce functions with `#[target_feature]` to safe function pointers".into() } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b7a648aae3f19..085a4d03ed10e 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -656,6 +656,10 @@ impl<'tcx> Instance<'tcx> { // unresolved instance. resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } } + InstanceKind::Intrinsic(def_id) => { + debug!(" => fn pointer created for intrinsic call"); + resolved.def = InstanceKind::ReifyShim(def_id, reason); + } _ => {} } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f7ec0f740d300..b2bb6c7f9e18c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -21,7 +21,8 @@ use tracing::{debug, instrument}; use crate::{ abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, inline, - instsimplify, mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify, + instsimplify, lower_intrinsics, mentioned_items, pass_manager as pm, remove_noop_landing_pads, + simplify, }; mod async_destructor_ctor; @@ -154,6 +155,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< &add_moves_for_packed_drops::AddMovesForPackedDrops, &deref_separator::Derefer, &remove_noop_landing_pads::RemoveNoopLandingPads, + &lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::MakeShim, &instsimplify::InstSimplify::BeforeInline, // Perform inlining of `#[rustc_force_inline]`-annotated callees. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 091773009e98d..af30825e80bff 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2321,7 +2321,7 @@ impl<'tcx> ObligationCause<'tcx> { { FailureCode::Error0644 } - TypeError::IntrinsicCast | TypeError::ForceInlineCast => FailureCode::Error0308, + TypeError::ForceInlineCast => FailureCode::Error0308, _ => FailureCode::Error0308, }, } @@ -2387,9 +2387,6 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::ForceInlineCast => { ObligationCauseFailureCode::CantCoerceForceInline { span, subdiags } } - TypeError::IntrinsicCast => { - ObligationCauseFailureCode::CantCoerceIntrinsic { span, subdiags } - } _ => ObligationCauseFailureCode::Generic { span, subdiags }, }, } diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 68b11489ae7c1..5d73e00dbf26b 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -50,7 +50,6 @@ pub enum TypeError { ExistentialMismatch(ExpectedFound), ConstMismatch(ExpectedFound), - IntrinsicCast, /// `#[rustc_force_inline]` functions must be inlined and must not be codegened independently, /// so casting to a function pointer must be prohibited. ForceInlineCast, @@ -86,8 +85,7 @@ impl TypeError { | ProjectionMismatched(_) | ExistentialMismatch(_) | ConstMismatch(_) - | ForceInlineCast - | IntrinsicCast => true, + | ForceInlineCast => true, } } } diff --git a/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-discriminant_value.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-discriminant_value.LowerIntrinsics.diff new file mode 100644 index 0000000000000..ef3bcf4be0362 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-discriminant_value.LowerIntrinsics.diff @@ -0,0 +1,23 @@ +- // MIR for `discriminant_value` before LowerIntrinsics ++ // MIR for `discriminant_value` after LowerIntrinsics + + fn discriminant_value(_1: &T) -> ::Discriminant { + let mut _0: ::Discriminant; // return place in scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + + bb0: { +- _0 = discriminant_value::(move _1) -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // mir::Constant +- // + span: $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> ::Discriminant {std::intrinsics::discriminant_value::}, val: Value(Scalar()) } ++ _0 = discriminant((*_1)); // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL ++ goto -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb1: { + return; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb2 (cleanup): { + resume; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } \ No newline at end of file diff --git a/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-forget.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-forget.LowerIntrinsics.diff new file mode 100644 index 0000000000000..23d0092e0e957 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-forget.LowerIntrinsics.diff @@ -0,0 +1,23 @@ +- // MIR for `std::intrinsics::forget` before LowerIntrinsics ++ // MIR for `std::intrinsics::forget` after LowerIntrinsics + + fn std::intrinsics::forget(_1: T) -> () { + let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + + bb0: { +- _0 = std::intrinsics::forget::(move _1) -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // mir::Constant +- // + span: $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::}, val: Value(Scalar()) } ++ _0 = const (); // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL ++ goto -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb1: { + return; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb2 (cleanup): { + resume; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } \ No newline at end of file diff --git a/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-size_of.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-size_of.LowerIntrinsics.diff new file mode 100644 index 0000000000000..461689a2d1a23 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-size_of.LowerIntrinsics.diff @@ -0,0 +1,23 @@ +- // MIR for `std::intrinsics::size_of` before LowerIntrinsics ++ // MIR for `std::intrinsics::size_of` after LowerIntrinsics + + fn std::intrinsics::size_of() -> usize { + let mut _0: usize; // return place in scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + + bb0: { +- _0 = std::intrinsics::size_of::() -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // mir::Constant +- // + span: $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value(Scalar()) } ++ _0 = SizeOf(T); // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL ++ goto -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb1: { + return; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb2 (cleanup): { + resume; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } \ No newline at end of file diff --git a/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-unreachable.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-unreachable.LowerIntrinsics.diff new file mode 100644 index 0000000000000..01bfbc158c553 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-unreachable.LowerIntrinsics.diff @@ -0,0 +1,22 @@ +- // MIR for `std::intrinsics::unreachable` before LowerIntrinsics ++ // MIR for `std::intrinsics::unreachable` after LowerIntrinsics + + fn std::intrinsics::unreachable() -> ! { + let mut _0: !; // return place in scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + + bb0: { +- _0 = std::intrinsics::unreachable() -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // mir::Constant +- // + span: $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(Scalar()) } ++ unreachable; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb1: { + return; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb2 (cleanup): { + resume; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } \ No newline at end of file diff --git a/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-wrapping_add.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-wrapping_add.LowerIntrinsics.diff new file mode 100644 index 0000000000000..1965aca03a889 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.core.intrinsics-#1-wrapping_add.LowerIntrinsics.diff @@ -0,0 +1,23 @@ +- // MIR for `wrapping_add` before LowerIntrinsics ++ // MIR for `wrapping_add` after LowerIntrinsics + + fn wrapping_add(_1: T, _2: T) -> T { + let mut _0: T; // return place in scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + + bb0: { +- _0 = wrapping_add::(move _1, move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // mir::Constant +- // + span: $SRC_DIR/core/src/intrinsics.rs:LL:COL +- // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {std::intrinsics::wrapping_add::}, val: Value(Scalar()) } ++ _0 = Add(move _1, move _2); // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL ++ goto -> bb1; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb1: { + return; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + + bb2 (cleanup): { + resume; // scope 0 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } \ No newline at end of file diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 4859d93546196..8e8d7d9191aab 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -267,3 +267,15 @@ pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug let _usize = ptr_metadata(b); let _vtable = ptr_metadata(c); } + +// Check that the MIR shims used for reifying intrinsics to `fn` pointers, +// also go through the lowering pass. +pub fn reify_intrinsics() -> impl Copy { + ( + core::intrinsics::wrapping_add:: as unsafe fn(_, _) -> _, + core::intrinsics::size_of:: as unsafe fn() -> _, + core::intrinsics::unreachable as unsafe fn() -> !, + core::intrinsics::forget:: as unsafe fn(_), + core::intrinsics::discriminant_value:: as unsafe fn(_) -> _, + ) +} diff --git a/tests/ui/intrinsics/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs index 5b2324235c1a9..384812471a4a1 100644 --- a/tests/ui/intrinsics/reify-intrinsic.rs +++ b/tests/ui/intrinsics/reify-intrinsic.rs @@ -1,22 +1,46 @@ -//@ check-fail +//@ run-pass #![feature(core_intrinsics, intrinsics)] -fn a() { - let _: unsafe fn(isize) -> usize = std::mem::transmute; - //~^ ERROR cannot coerce +// NOTE(eddyb) `#[inline(never)]` and returning `fn` pointers from functions is +// done to force codegen (of the reification-to-`fn`-ptr shims around intrinsics). + +#[inline(never)] +fn a() -> unsafe fn(isize) -> usize { + let f: unsafe fn(isize) -> usize = std::mem::transmute; + f } -fn b() { - let _ = std::mem::transmute as unsafe fn(isize) -> usize; - //~^ ERROR casting +#[inline(never)] +fn b() -> unsafe fn(isize) -> usize { + let f = std::mem::transmute as unsafe fn(isize) -> usize; + f } -fn c() { - let _: [unsafe fn(f32) -> f32; 2] = [ - std::intrinsics::floorf32, //~ ERROR cannot coerce +#[inline(never)] +fn c() -> [unsafe fn(f32) -> f32; 2] { + let fs = [ + std::intrinsics::floorf32, std::intrinsics::log2f32, ]; + fs +} + +fn call_by_ptr() { + let ptr: fn(u8, u8) -> u8 = std::intrinsics::wrapping_add::; + let res = ptr(u8::MAX, 1); + assert_eq!(res, 0); } -fn main() {} +fn main() { + unsafe { + assert_eq!(a()(-1), !0); + assert_eq!(b()(-1), !0); + + let [floorf32_ptr, log2f32_ptr] = c(); + assert_eq!(floorf32_ptr(1.5), 1.0); + assert_eq!(log2f32_ptr(2.0), 1.0); + } + + call_by_ptr(); +} diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr deleted file mode 100644 index aea6f838e0d44..0000000000000 --- a/tests/ui/intrinsics/reify-intrinsic.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0308]: cannot coerce intrinsics to function pointers - --> $DIR/reify-intrinsic.rs:6:40 - | -LL | let _: unsafe fn(isize) -> usize = std::mem::transmute; - | ------------------------- ^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers - | | - | expected due to this - | - = note: expected fn pointer `unsafe fn(isize) -> usize` - found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` - -error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe fn(isize) -> usize` is invalid - --> $DIR/reify-intrinsic.rs:11:13 - | -LL | let _ = std::mem::transmute as unsafe fn(isize) -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0308]: cannot coerce intrinsics to function pointers - --> $DIR/reify-intrinsic.rs:17:9 - | -LL | std::intrinsics::floorf32, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers - | - = note: expected fn pointer `unsafe fn(_) -> _` - found fn item `unsafe fn(_) -> _ {floorf32}` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0308, E0606. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/transmute/transmute-different-sizes-reified.rs b/tests/ui/transmute/transmute-different-sizes-reified.rs new file mode 100644 index 0000000000000..f355a6b78b4de --- /dev/null +++ b/tests/ui/transmute/transmute-different-sizes-reified.rs @@ -0,0 +1,31 @@ +//@ normalize-stderr: "\d+ bits" -> "N bits" + +// Tests that `transmute` cannot be indirectly called on types of different size. + +#![allow(warnings)] +#![feature(specialization)] + +use std::mem::transmute; + +unsafe fn f() { + let _: i8 = (transmute as unsafe fn(_) -> _)(16i16); + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types +} + +unsafe fn g(x: &T) { + let _: i8 = (transmute as unsafe fn(_) -> _)(x); + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types +} + +trait Specializable { type Output; } + +impl Specializable for T { + default type Output = u16; +} + +unsafe fn specializable(x: u16) -> ::Output { + (transmute as unsafe fn(_) -> _)(x) + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types +} + +fn main() {} diff --git a/tests/ui/transmute/transmute-different-sizes-reified.stderr b/tests/ui/transmute/transmute-different-sizes-reified.stderr new file mode 100644 index 0000000000000..bde5da74ee7db --- /dev/null +++ b/tests/ui/transmute/transmute-different-sizes-reified.stderr @@ -0,0 +1,30 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-different-sizes-reified.rs:11:18 + | +LL | let _: i8 = (transmute as unsafe fn(_) -> _)(16i16); + | ^^^^^^^^^ + | + = note: source type: `i16` (N bits) + = note: target type: `i8` (N bits) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-different-sizes-reified.rs:16:18 + | +LL | let _: i8 = (transmute as unsafe fn(_) -> _)(x); + | ^^^^^^^^^ + | + = note: source type: `&T` (N bits) + = note: target type: `i8` (N bits) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-different-sizes-reified.rs:27:6 + | +LL | (transmute as unsafe fn(_) -> _)(x) + | ^^^^^^^^^ + | + = note: source type: `u16` (N bits) + = note: target type: `::Output` (this type does not have a fixed size) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0512`.