Auto merge of #108442 - scottmcm:mir-transmute, r=oli-obk

Add `CastKind::Transmute` to MIR

~~Nothing actually produces it in this commit, so I don't know how to test it, but it also means it shouldn't be possible for it to break anything.~~

Includes lowering `transmute` calls to it, so it's used.

Zulip Conversation: <https://rust-lang.zulipchat.com/#narrow/stream/189540-t-compiler.2Fwg-mir-opt/topic/Good.20first.20isssue/near/321849610>
This commit is contained in:
bors 2023-03-23 18:43:04 +00:00
commit e216300876
55 changed files with 955 additions and 190 deletions

View File

@ -2222,6 +2222,13 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
}
}
}
CastKind::Transmute => {
span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
);
}
}
}

View File

@ -709,6 +709,10 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
let operand = codegen_operand(fx, operand);
operand.coerce_dyn_star(fx, lval);
}
Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
let operand = codegen_operand(fx, operand);
lval.write_cvalue_transmute(fx, operand);
}
Rvalue::Discriminant(place) => {
let place = codegen_place(fx, place);
let value = place.to_cvalue(fx);

View File

@ -557,16 +557,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
fx.bcx.ins().band(ptr, mask);
}
sym::transmute => {
intrinsic_args!(fx, args => (from); intrinsic);
if ret.layout().abi.is_uninhabited() {
crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
return;
}
ret.write_cvalue_transmute(fx, from);
}
sym::write_bytes | sym::volatile_set_memory => {
intrinsic_args!(fx, args => (dst, val, count); intrinsic);
let val = val.load_scalar(fx);

View File

@ -378,7 +378,7 @@ fn codegen_intrinsic_call(
}
}
_ => bug!("unknown intrinsic '{}'", name),
_ => bug!("unknown intrinsic '{}' -- should it have been lowered earlier?", name),
};
if !fn_abi.ret.is_ignore() {

View File

@ -16,7 +16,7 @@
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_session::config::OptLevel;
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
@ -769,23 +769,6 @@ fn codegen_call_terminator(
None => bx.fn_abi_of_fn_ptr(sig, extra_args),
};
if intrinsic == Some(sym::transmute) {
return if let Some(target) = target {
self.codegen_transmute(bx, &args[0], destination);
helper.funclet_br(self, bx, target, mergeable_succ)
} else {
// If we are trying to transmute to an uninhabited type,
// it is likely there is no allotted destination. In fact,
// transmuting to an uninhabited type is UB, which means
// we can do what we like. Here, we declare that transmuting
// into an uninhabited type is impossible, so anything following
// it must be unreachable.
assert_eq!(fn_abi.ret.layout.abi, abi::Abi::Uninhabited);
bx.unreachable();
MergingSucc::False
};
}
if let Some(merging_succ) = self.codegen_panic_intrinsic(
&helper,
bx,
@ -828,7 +811,6 @@ fn codegen_call_terminator(
match intrinsic {
None | Some(sym::drop_in_place) => {}
Some(sym::copy_nonoverlapping) => unreachable!(),
Some(intrinsic) => {
let dest = match ret_dest {
_ if fn_abi.ret.is_indirect() => llargs[0],
@ -1739,71 +1721,6 @@ fn make_return_dest(
}
}
fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir::Place<'tcx>) {
if let Some(index) = dst.as_local() {
match self.locals[index] {
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
LocalRef::Operand(None) => {
let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref()));
assert!(!dst_layout.ty.has_erasable_regions());
let place = PlaceRef::alloca(bx, dst_layout);
place.storage_live(bx);
self.codegen_transmute_into(bx, src, place);
let op = bx.load_operand(place);
place.storage_dead(bx);
self.locals[index] = LocalRef::Operand(Some(op));
self.debug_introduce_local(bx, index);
}
LocalRef::Operand(Some(op)) => {
assert!(op.layout.is_zst(), "assigning to initialized SSAtemp");
}
}
} else {
let dst = self.codegen_place(bx, dst.as_ref());
self.codegen_transmute_into(bx, src, dst);
}
}
fn codegen_transmute_into(
&mut self,
bx: &mut Bx,
src: &mir::Operand<'tcx>,
dst: PlaceRef<'tcx, Bx::Value>,
) {
let src = self.codegen_operand(bx, src);
// Special-case transmutes between scalars as simple bitcasts.
match (src.layout.abi, dst.layout.abi) {
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
if src_is_ptr == dst_is_ptr {
assert_eq!(src.layout.size, dst.layout.size);
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
// conversions allow handling `bool`s the same as `u8`s.
let src = bx.from_immediate(src.immediate());
// LLVM also doesn't like `bitcast`s between pointers in different address spaces.
let src_as_dst = if src_is_ptr {
bx.pointercast(src, bx.backend_type(dst.layout))
} else {
bx.bitcast(src, bx.backend_type(dst.layout))
};
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
return;
}
}
_ => {}
}
let llty = bx.backend_type(src.layout);
let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
let align = src.layout.align.abi.min(dst.align);
src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, align));
}
// Stores the return value of a function call into it's final location.
fn store_return(
&mut self,

View File

@ -13,7 +13,7 @@
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::abi::{self, VariantIdx};
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
#[instrument(level = "trace", skip(self, bx))]
@ -72,6 +72,11 @@ pub fn codegen_rvalue(
}
}
mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
let src = self.codegen_operand(bx, operand);
self.codegen_transmute(bx, src, dest);
}
mir::Rvalue::Repeat(ref elem, count) => {
let cg_elem = self.codegen_operand(bx, elem);
@ -143,6 +148,52 @@ pub fn codegen_rvalue(
}
}
fn codegen_transmute(
&mut self,
bx: &mut Bx,
src: OperandRef<'tcx, Bx::Value>,
dst: PlaceRef<'tcx, Bx::Value>,
) {
// The MIR validator enforces no unsized transmutes.
debug_assert!(src.layout.is_sized());
debug_assert!(dst.layout.is_sized());
if src.layout.size != dst.layout.size
|| src.layout.abi == abi::Abi::Uninhabited
|| dst.layout.abi == abi::Abi::Uninhabited
{
// In all of these cases it's UB to run this transmute, but that's
// known statically so might as well trap for it, rather than just
// making it unreachable.
bx.abort();
return;
}
let size_in_bytes = src.layout.size.bytes();
if size_in_bytes == 0 {
// Nothing to write
return;
}
match src.val {
OperandValue::Ref(src_llval, meta, src_align) => {
debug_assert_eq!(meta, None);
// For a place-to-place transmute, call `memcpy` directly so that
// both arguments get the best-available alignment information.
let bytes = bx.cx().const_usize(size_in_bytes);
let flags = MemFlags::empty();
bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags);
}
OperandValue::Immediate(_) | OperandValue::Pair(_, _) => {
// When we have immediate(s), the alignment of the source is irrelevant,
// so we can store them using the destination's alignment.
let llty = bx.backend_type(src.layout);
let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, dst.align));
}
}
}
pub fn codegen_rvalue_unsized(
&mut self,
bx: &mut Bx,
@ -344,6 +395,9 @@ pub fn codegen_rvalue_operand(
};
OperandValue::Immediate(newval)
}
mir::CastKind::Transmute => {
bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand);
}
};
OperandRef { val, layout: cast }
}
@ -673,6 +727,10 @@ pub fn codegen_scalar_checked_binop(
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
match *rvalue {
mir::Rvalue::Cast(mir::CastKind::Transmute, ..) =>
// FIXME: Now that transmute is an Rvalue, it would be nice if
// it could create `Immediate`s for scalars, where possible.
false,
mir::Rvalue::Ref(..) |
mir::Rvalue::CopyForDeref(..) |
mir::Rvalue::AddressOf(..) |

View File

@ -133,6 +133,22 @@ pub fn cast(
bug!()
}
}
Transmute => {
assert!(src.layout.is_sized());
assert!(dest.layout.is_sized());
if src.layout.size != dest.layout.size {
throw_ub_format!(
"transmuting from {}-byte type to {}-byte type: `{}` -> `{}`",
src.layout.size.bytes(),
dest.layout.size.bytes(),
src.layout.ty,
dest.layout.ty,
);
}
self.copy_op(src, dest, /*allow_transmute*/ true)?;
}
}
Ok(())
}

View File

@ -127,7 +127,6 @@ pub fn emulate_intrinsic(
// First handle intrinsics without return place.
let ret = match ret {
None => match intrinsic_name {
sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
// Unsupported diverging intrinsic.
_ => return Ok(false),
@ -411,9 +410,6 @@ pub fn emulate_intrinsic(
self.exact_div(&val, &size, dest)?;
}
sym::transmute => {
self.copy_op(&args[0], dest, /*allow_transmute*/ true)?;
}
sym::assert_inhabited
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid => {

View File

@ -621,6 +621,33 @@ macro_rules! check_kinds {
);
}
}
CastKind::Transmute => {
if let MirPhase::Runtime(..) = self.mir_phase {
// Unlike `mem::transmute`, a MIR `Transmute` is well-formed
// for any two `Sized` types, just potentially UB to run.
if !op_ty.is_sized(self.tcx, self.param_env) {
self.fail(
location,
format!("Cannot transmute from non-`Sized` type {op_ty:?}"),
);
}
if !target_type.is_sized(self.tcx, self.param_env) {
self.fail(
location,
format!("Cannot transmute to non-`Sized` type {target_type:?}"),
);
}
} else {
self.fail(
location,
format!(
"Transmute is not supported in non-runtime phase {:?}.",
self.mir_phase
),
);
}
}
}
}
Rvalue::Repeat(_, _)

View File

@ -1967,7 +1967,8 @@ pub fn is_safe_to_remove(&self) -> bool {
| CastKind::PtrToPtr
| CastKind::Pointer(_)
| CastKind::PointerFromExposedAddress
| CastKind::DynStar,
| CastKind::DynStar
| CastKind::Transmute,
_,
_,
)

View File

@ -1156,6 +1156,13 @@ pub enum CastKind {
IntToFloat,
PtrToPtr,
FnPtrToPtr,
/// Reinterpret the bits of the input as a different type.
///
/// MIR is well-formed if the input and output types have different sizes,
/// but running a transmute between differently-sized types is UB.
///
/// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`].
Transmute,
}
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]

View File

@ -137,6 +137,10 @@ fn parse_call(
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
parse_by_kind!(self, expr_id, expr, "rvalue",
@call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
@call("mir_cast_transmute", args) => {
let source = self.parse_operand(args[0])?;
Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
},
@call("mir_checked", args) => {
parse_by_kind!(self, args[0], _, "binary op",
ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(

View File

@ -504,6 +504,15 @@ fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<()> {
return None;
}
// Do not try creating references, nor any types with potentially-complex
// invariants. This avoids an issue where checking validity would do a
// bunch of work generating a nice message about the invariant violation,
// only to not show it to anyone (since this isn't the lint).
Rvalue::Cast(CastKind::Transmute, op, dst_ty) if !dst_ty.is_primitive() => {
trace!("skipping Transmute of {:?} to {:?}", op, dst_ty);
return None;
}
// There's no other checking to do at this time.
Rvalue::Aggregate(..)

View File

@ -221,6 +221,32 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
terminator.kind = TerminatorKind::Goto { target };
}
}
sym::transmute => {
let dst_ty = destination.ty(local_decls, tcx).ty;
let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else {
span_bug!(
terminator.source_info.span,
"Wrong number of arguments for transmute intrinsic",
);
};
// Always emit the cast, even if we transmute to an uninhabited type,
// because that lets CTFE and codegen generate better error messages
// when such a transmute actually ends up reachable.
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::Cast(CastKind::Transmute, arg, dst_ty),
))),
});
if let Some(target) = *target {
terminator.kind = TerminatorKind::Goto { target };
} else {
terminator.kind = TerminatorKind::Unreachable;
}
}
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
validate_simd_shuffle(tcx, args, terminator.source_info.span);
}

View File

@ -343,6 +343,14 @@ fn Field<F>(place: (), field: u32) -> F
/// See [`Field`] for documentation.
fn Variant<T>(place: T, index: u32) -> ()
);
define!(
"mir_cast_transmute",
/// Emits a `CastKind::Transmute` cast.
///
/// Needed to test the UB when `sizeof(T) != sizeof(U)`, which can't be
/// generated via the normal `mem::transmute`.
fn CastTransmute<T, U>(operand: T) -> U
);
define!(
"mir_make_place",
#[doc(hidden)]

View File

@ -176,6 +176,9 @@ fn check_rvalue<'tcx>(
// FIXME(dyn-star)
unimplemented!()
},
Rvalue::Cast(CastKind::Transmute, _, _) => {
Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into()))
},
// binops are fine on integers
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
check_operand(tcx, lhs, span, body)?;

View File

@ -7,6 +7,6 @@
fn main() {
let _x: ! = unsafe {
std::mem::transmute::<Human, !>(Human) //~ ERROR: transmuting to uninhabited
std::mem::transmute::<Human, !>(Human) //~ ERROR: entering unreachable code
};
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: transmuting to uninhabited type
error: Undefined Behavior: entering unreachable code
--> $DIR/never_transmute_humans.rs:LL:CC
|
LL | std::mem::transmute::<Human, !>(Human)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -10,11 +10,13 @@ enum VoidI {}
pub struct Void(VoidI);
pub fn f(v: Void) -> ! {
match v.0 {} //~ ERROR: entering unreachable code
match v.0 {}
//~^ ERROR: entering unreachable code
}
}
fn main() {
let v = unsafe { std::mem::transmute::<(), m::Void>(()) };
m::f(v); //~ NOTE: inside `main`
m::f(v);
//~^ NOTE: inside `main`
}

View File

@ -0,0 +1,196 @@
// compile-flags: -O -C no-prepopulate-passes
// only-64bit (so I don't need to worry about usize)
// min-llvm-version: 15.0 # this test assumes `ptr`s
#![crate_type = "lib"]
#![feature(core_intrinsics)]
#![feature(custom_mir)]
#![feature(inline_const)]
use std::mem::transmute;
// Some of the cases here are statically rejected by `mem::transmute`, so
// we need to generate custom MIR for those cases to get to codegen.
use std::intrinsics::mir::*;
enum Never {}
#[repr(align(2))]
pub struct BigNever(Never, u16, Never);
#[repr(align(8))]
pub struct Scalar64(i64);
#[repr(C, align(4))]
pub struct Aggregate64(u16, u8, i8, f32);
// CHECK-LABEL: @check_bigger_size(
#[no_mangle]
#[custom_mir(dialect = "runtime", phase = "initial")]
pub unsafe fn check_bigger_size(x: u16) -> u32 {
// CHECK: call void @llvm.trap
mir!{
{
RET = CastTransmute(x);
Return()
}
}
}
// CHECK-LABEL: @check_smaller_size(
#[no_mangle]
#[custom_mir(dialect = "runtime", phase = "initial")]
pub unsafe fn check_smaller_size(x: u32) -> u16 {
// CHECK: call void @llvm.trap
mir!{
{
RET = CastTransmute(x);
Return()
}
}
}
// CHECK-LABEL: @check_to_uninhabited(
#[no_mangle]
#[custom_mir(dialect = "runtime", phase = "initial")]
pub unsafe fn check_to_uninhabited(x: u16) -> BigNever {
// CHECK: call void @llvm.trap
mir!{
{
RET = CastTransmute(x);
Return()
}
}
}
// CHECK-LABEL: @check_from_uninhabited(
#[no_mangle]
#[custom_mir(dialect = "runtime", phase = "initial")]
pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
// CHECK: call void @llvm.trap
mir!{
{
RET = CastTransmute(x);
Return()
}
}
}
// CHECK-LABEL: @check_to_newtype(
#[no_mangle]
pub unsafe fn check_to_newtype(x: u64) -> Scalar64 {
// CHECK: %0 = alloca i64
// CHECK: store i64 %x, ptr %0
// CHECK: %1 = load i64, ptr %0
// CHECK: ret i64 %1
transmute(x)
}
// CHECK-LABEL: @check_from_newtype(
#[no_mangle]
pub unsafe fn check_from_newtype(x: Scalar64) -> u64 {
// CHECK: %0 = alloca i64
// CHECK: store i64 %x, ptr %0
// CHECK: %1 = load i64, ptr %0
// CHECK: ret i64 %1
transmute(x)
}
// CHECK-LABEL: @check_to_pair(
#[no_mangle]
pub unsafe fn check_to_pair(x: u64) -> Option<i32> {
// CHECK: %0 = alloca { i32, i32 }, align 4
// CHECK: store i64 %x, ptr %0, align 4
transmute(x)
}
// CHECK-LABEL: @check_from_pair(
#[no_mangle]
pub unsafe fn check_from_pair(x: Option<i32>) -> u64 {
// The two arguments are of types that are only 4-aligned, but they're
// immediates so we can write using the destination alloca's alignment.
const { assert!(std::mem::align_of::<Option<i32>>() == 4) };
// CHECK: %0 = alloca i64, align 8
// CHECK: store i32 %x.0, ptr %1, align 8
// CHECK: store i32 %x.1, ptr %2, align 4
// CHECK: %3 = load i64, ptr %0, align 8
// CHECK: ret i64 %3
transmute(x)
}
// CHECK-LABEL: @check_to_float(
#[no_mangle]
pub unsafe fn check_to_float(x: u32) -> f32 {
// CHECK: %0 = alloca float
// CHECK: store i32 %x, ptr %0
// CHECK: %1 = load float, ptr %0
// CHECK: ret float %1
transmute(x)
}
// CHECK-LABEL: @check_from_float(
#[no_mangle]
pub unsafe fn check_from_float(x: f32) -> u32 {
// CHECK: %0 = alloca i32
// CHECK: store float %x, ptr %0
// CHECK: %1 = load i32, ptr %0
// CHECK: ret i32 %1
transmute(x)
}
// CHECK-LABEL: @check_to_bytes(
#[no_mangle]
pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] {
// CHECK: %0 = alloca [4 x i8], align 1
// CHECK: store i32 %x, ptr %0, align 1
// CHECK: %1 = load i32, ptr %0, align 1
// CHECK: ret i32 %1
transmute(x)
}
// CHECK-LABEL: @check_from_bytes(
#[no_mangle]
pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 {
// CHECK: %1 = alloca i32, align 4
// CHECK: %x = alloca [4 x i8], align 1
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false)
// CHECK: %3 = load i32, ptr %1, align 4
// CHECK: ret i32 %3
transmute(x)
}
// CHECK-LABEL: @check_to_aggregate(
#[no_mangle]
pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 {
// CHECK: %0 = alloca %Aggregate64, align 4
// CHECK: store i64 %x, ptr %0, align 4
// CHECK: %1 = load i64, ptr %0, align 4
// CHECK: ret i64 %1
transmute(x)
}
// CHECK-LABEL: @check_from_aggregate(
#[no_mangle]
pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 {
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false)
transmute(x)
}
// CHECK-LABEL: @check_long_array_less_aligned(
#[no_mangle]
pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] {
// CHECK-NEXT: start
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false)
// CHECK-NEXT: ret void
transmute(x)
}
// CHECK-LABEL: @check_long_array_more_aligned(
#[no_mangle]
pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] {
// CHECK-NEXT: start
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false)
// CHECK-NEXT: ret void
transmute(x)
}

View File

@ -1,13 +1,19 @@
// compile-flags: -O -C no-prepopulate-passes
// min-llvm-version: 15.0 # this test assumes `ptr`s and thus no `pointercast`s
#![crate_type = "lib"]
// FIXME(eddyb) all of these tests show memory stores and loads, even after a
// scalar `bitcast`, more special-casing is required to remove `alloca` usage.
// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
// without needing to pointercast, and SRoA will turn that into a `bitcast`.
// As such, there's no longer special-casing in `transmute` to attempt to
// generate `bitcast` ourselves, as that just made the IR longer.
// FIXME: That said, `bitcast`s could still be a valuable addition if they could
// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely.
// CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x)
// CHECK: store i32 %{{.*}}, {{.*}} %0
// CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0
// CHECK: store float %{{.*}}, ptr %0
// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0
// CHECK: ret i32 %[[RES]]
#[no_mangle]
pub fn f32_to_bits(x: f32) -> u32 {
@ -25,12 +31,10 @@ pub fn bool_to_byte(b: bool) -> u8 {
}
// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte)
// CHECK: %1 = trunc i8 %byte to i1
// CHECK-NEXT: %2 = zext i1 %1 to i8
// CHECK-NEXT: store i8 %2, {{.*}} %0
// CHECK-NEXT: %3 = load i8, {{.*}} %0
// CHECK-NEXT: %4 = trunc i8 %3 to i1
// CHECK: ret i1 %4
// CHECK: store i8 %byte, ptr %0
// CHECK-NEXT: %1 = load i8, {{.*}} %0
// CHECK-NEXT: %2 = trunc i8 %1 to i1
// CHECK: ret i1 %2
#[no_mangle]
pub unsafe fn byte_to_bool(byte: u8) -> bool {
std::mem::transmute(byte)
@ -45,20 +49,8 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
unsafe { std::mem::transmute(p) }
}
// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are
// currently not special-cased like other scalar `transmute`s, because
// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`.
//
// Tests below show the non-special-cased behavior (with the possible
// future special-cased instructions in the "NOTE(eddyb)" comments).
// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p)
// NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
// %2 = ptrtoint i16* %p to [[USIZE]]
// store [[USIZE]] %2, [[USIZE]]* %0
// CHECK: store {{i16\*|ptr}} %p, {{.*}}
// CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0
// CHECK: ret [[USIZE]] %[[RES]]
#[no_mangle]
@ -67,12 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
}
// CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i)
// NOTE(eddyb) see above, the following two CHECK lines should ideally be this:
// %2 = inttoptr [[USIZE]] %i to i16*
// store i16* %2, i16** %0
// CHECK: store [[USIZE]] %i, {{.*}}
// CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0
// CHECK: ret {{i16\*|ptr}} %[[RES]]
#[no_mangle]

View File

@ -0,0 +1,15 @@
- // MIR for `from_char` before ConstProp
+ // MIR for `from_char` after ConstProp
fn from_char() -> i32 {
let mut _0: i32; // return place in scope 0 at $DIR/transmute.rs:+0:23: +0:26
scope 1 {
}
bb0: {
- _0 = const 'R' as i32 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:28
+ _0 = const 82_i32; // scope 1 at $DIR/transmute.rs:+1:14: +1:28
return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,14 @@
- // MIR for `invalid_bool` before ConstProp
+ // MIR for `invalid_bool` after ConstProp
fn invalid_bool() -> bool {
let mut _0: bool; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37
scope 1 {
}
bb0: {
_0 = const -1_i8 as bool (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:30
return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,14 @@
- // MIR for `invalid_char` before ConstProp
+ // MIR for `invalid_char` after ConstProp
fn invalid_char() -> char {
let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37
scope 1 {
}
bb0: {
_0 = const _ as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33
return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,23 @@
- // MIR for `less_as_i8` before ConstProp
+ // MIR for `less_as_i8` after ConstProp
fn less_as_i8() -> i8 {
let mut _0: i8; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:26
let mut _1: std::cmp::Ordering; // in scope 0 at $DIR/transmute.rs:+1:24: +1:48
scope 1 {
}
bb0: {
StorageLive(_1); // scope 1 at $DIR/transmute.rs:+1:24: +1:48
- _1 = Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48
- _0 = move _1 as i8 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:49
+ _1 = const Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48
+ // mir::Constant
+ // + span: no-location
+ // + literal: Const { ty: std::cmp::Ordering, val: Value(Scalar(0xff)) }
+ _0 = const -1_i8; // scope 1 at $DIR/transmute.rs:+1:14: +1:49
StorageDead(_1); // scope 1 at $DIR/transmute.rs:+1:48: +1:49
return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,61 @@
// unit-test: ConstProp
// compile-flags: -O --crate-type=lib
use std::mem::transmute;
// EMIT_MIR transmute.less_as_i8.ConstProp.diff
pub fn less_as_i8() -> i8 {
unsafe { transmute(std::cmp::Ordering::Less) }
}
// EMIT_MIR transmute.from_char.ConstProp.diff
pub fn from_char() -> i32 {
unsafe { transmute('R') }
}
// EMIT_MIR transmute.valid_char.ConstProp.diff
pub fn valid_char() -> char {
unsafe { transmute(0x52_u32) }
}
// EMIT_MIR transmute.invalid_char.ConstProp.diff
pub unsafe fn invalid_char() -> char {
unsafe { transmute(i32::MAX) }
}
// EMIT_MIR transmute.invalid_bool.ConstProp.diff
pub unsafe fn invalid_bool() -> bool {
unsafe { transmute(-1_i8) }
}
// EMIT_MIR transmute.undef_union_as_integer.ConstProp.diff
pub unsafe fn undef_union_as_integer() -> u32 {
union Union32 { value: u32, unit: () }
unsafe { transmute(Union32 { unit: () }) }
}
// EMIT_MIR transmute.unreachable_direct.ConstProp.diff
pub unsafe fn unreachable_direct() -> ! {
let x: Never = unsafe { transmute(()) };
match x {}
}
// EMIT_MIR transmute.unreachable_ref.ConstProp.diff
pub unsafe fn unreachable_ref() -> ! {
let x: &Never = unsafe { transmute(1_usize) };
match *x {}
}
// EMIT_MIR transmute.unreachable_mut.ConstProp.diff
pub unsafe fn unreachable_mut() -> ! {
let x: &mut Never = unsafe { transmute(1_usize) };
match *x {}
}
// EMIT_MIR transmute.unreachable_box.ConstProp.diff
pub unsafe fn unreachable_box() -> ! {
let x: Box<Never> = unsafe { transmute(1_usize) };
match *x {}
}
enum Never {}

View File

@ -0,0 +1,22 @@
- // MIR for `undef_union_as_integer` before ConstProp
+ // MIR for `undef_union_as_integer` after ConstProp
fn undef_union_as_integer() -> u32 {
let mut _0: u32; // return place in scope 0 at $DIR/transmute.rs:+0:43: +0:46
let mut _1: undef_union_as_integer::Union32; // in scope 0 at $DIR/transmute.rs:+2:24: +2:44
let mut _2: (); // in scope 0 at $DIR/transmute.rs:+2:40: +2:42
scope 1 {
}
bb0: {
StorageLive(_1); // scope 1 at $DIR/transmute.rs:+2:24: +2:44
StorageLive(_2); // scope 1 at $DIR/transmute.rs:+2:40: +2:42
_2 = (); // scope 1 at $DIR/transmute.rs:+2:40: +2:42
_1 = Union32 { value: move _2 }; // scope 1 at $DIR/transmute.rs:+2:24: +2:44
StorageDead(_2); // scope 1 at $DIR/transmute.rs:+2:43: +2:44
_0 = move _1 as u32 (Transmute); // scope 1 at $DIR/transmute.rs:+2:14: +2:45
StorageDead(_1); // scope 1 at $DIR/transmute.rs:+2:44: +2:45
return; // scope 0 at $DIR/transmute.rs:+3:2: +3:2
}
}

View File

@ -0,0 +1,23 @@
- // MIR for `unreachable_box` before ConstProp
+ // MIR for `unreachable_box` after ConstProp
fn unreachable_box() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37
let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2
let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16
scope 1 {
debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
}
scope 2 {
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2
StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10
_2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52
StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16
unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13
}
}

View File

@ -0,0 +1,25 @@
- // MIR for `unreachable_direct` before ConstProp
+ // MIR for `unreachable_direct` after ConstProp
fn unreachable_direct() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40
let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2
let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41
let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15
scope 1 {
debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
}
scope 2 {
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2
StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10
StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41
_3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41
_2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42
unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42
}
}

View File

@ -0,0 +1,27 @@
- // MIR for `unreachable_mut` before ConstProp
+ // MIR for `unreachable_mut` after ConstProp
fn unreachable_mut() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37
let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2
let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52
let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16
scope 1 {
debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
}
scope 2 {
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2
StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10
StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52
_3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52
_2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52
StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55
StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16
unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13
}
}

View File

@ -0,0 +1,23 @@
- // MIR for `unreachable_ref` before ConstProp
+ // MIR for `unreachable_ref` after ConstProp
fn unreachable_ref() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37
let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2
let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10
let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16
scope 1 {
debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10
}
scope 2 {
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2
StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10
_2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48
StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16
unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13
}
}

View File

@ -0,0 +1,15 @@
- // MIR for `valid_char` before ConstProp
+ // MIR for `valid_char` after ConstProp
fn valid_char() -> char {
let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:28
scope 1 {
}
bb0: {
- _0 = const 82_u32 as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33
+ _0 = const 'R'; // scope 1 at $DIR/transmute.rs:+1:14: +1:33
return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2
}
}

View File

@ -24,61 +24,49 @@
StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15
StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
_3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
_2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
// mir::Constant
// + span: $DIR/issue_75439.rs:8:37: 8:46
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
_2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb1: {
StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb2: {
switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb3: {
switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb4: {
StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38
StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
_6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
_5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
// mir::Constant
// + span: $DIR/issue_75439.rs:11:23: 11:32
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
_5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
_0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}
bb4: {
StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
_4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb5: {
StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
_4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb6: {
StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
_4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
_0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}
bb7: {
StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
_0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}
bb8: {
_0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}
bb9: {
StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2
return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2
}

View File

@ -11,7 +11,7 @@
StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
- _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
- // + span: $DIR/lower_intrinsics.rs:105:9: 105:32
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
+ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38

View File

@ -31,7 +31,7 @@
_3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
- _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41
- // + span: $DIR/lower_intrinsics.rs:82:5: 82:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
@ -46,13 +46,13 @@
StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:50:42: 50:44
// + span: $DIR/lower_intrinsics.rs:83:42: 83:44
// + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41
- // + span: $DIR/lower_intrinsics.rs:83:5: 83:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
@ -67,13 +67,13 @@
StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:51:42: 51:45
// + span: $DIR/lower_intrinsics.rs:84:42: 84:45
// + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41
- // + span: $DIR/lower_intrinsics.rs:84:5: 84:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
@ -88,13 +88,13 @@
StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:52:42: 52:47
// + span: $DIR/lower_intrinsics.rs:85:42: 85:47
// + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41
- // + span: $DIR/lower_intrinsics.rs:85:5: 85:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48

View File

@ -49,7 +49,7 @@
StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
- _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:65:9: 65:28
- // + span: $DIR/lower_intrinsics.rs:98:9: 98:28
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
+ copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+ goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95

View File

@ -24,7 +24,7 @@
_4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
- _3 = option_payload_ptr::<usize>(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:99:18: 99:54
- // + span: $DIR/lower_intrinsics.rs:132:18: 132:54
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) }
+ _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
@ -37,7 +37,7 @@
_6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
- _5 = option_payload_ptr::<String>(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:100:18: 100:54
- // + span: $DIR/lower_intrinsics.rs:133:18: 133:54
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) }
+ _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
+ goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57

View File

@ -13,7 +13,7 @@
_2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
- _0 = read_via_copy::<i32>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:85:14: 85:45
- // + span: $DIR/lower_intrinsics.rs:118:14: 118:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) }
+ _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48

View File

@ -13,7 +13,7 @@
_2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
- _0 = read_via_copy::<Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:90:14: 90:45
- // + span: $DIR/lower_intrinsics.rs:123:14: 123:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) }
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
}

View File

@ -38,6 +38,39 @@ pub fn non_const<T>() -> usize {
size_of_t()
}
// EMIT_MIR lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff
pub fn transmute_inhabited(c: std::cmp::Ordering) -> i8 {
unsafe { std::mem::transmute(c) }
}
// EMIT_MIR lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff
pub unsafe fn transmute_uninhabited(u: ()) -> Never {
unsafe { std::mem::transmute::<(), Never>(u) }
}
// EMIT_MIR lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff
pub unsafe fn transmute_ref_dst<T: ?Sized>(u: &T) -> *const T {
unsafe { std::mem::transmute(u) }
}
// EMIT_MIR lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff
pub unsafe fn transmute_to_ref_uninhabited() -> ! {
let x: &Never = std::mem::transmute(1usize);
match *x {}
}
// EMIT_MIR lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff
pub unsafe fn transmute_to_mut_uninhabited() -> ! {
let x: &mut Never = std::mem::transmute(1usize);
match *x {}
}
// EMIT_MIR lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff
pub unsafe fn transmute_to_box_uninhabited() -> ! {
let x: Box<Never> = std::mem::transmute(1usize);
match *x {}
}
pub enum E {
A,
B,

View File

@ -0,0 +1,27 @@
- // MIR for `transmute_inhabited` before LowerIntrinsics
+ // MIR for `transmute_inhabited` after LowerIntrinsics
fn transmute_inhabited(_1: std::cmp::Ordering) -> i8 {
debug c => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:28: +0:29
let mut _0: i8; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:56
let mut _2: std::cmp::Ordering; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35
scope 1 {
}
bb0: {
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
- _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:43:14: 43:33
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::<std::cmp::Ordering, i8>}, val: Value(<ZST>) }
+ _0 = move _2 as i8 (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
}
bb1: {
StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,27 @@
- // MIR for `transmute_ref_dst` before LowerIntrinsics
+ // MIR for `transmute_ref_dst` after LowerIntrinsics
fn transmute_ref_dst(_1: &T) -> *const T {
debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:45
let mut _0: *const T; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:62
let mut _2: &T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35
scope 1 {
}
bb0: {
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
- _0 = transmute::<&T, *const T>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:53:14: 53:33
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value(<ZST>) }
+ _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
}
bb1: {
StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,29 @@
- // MIR for `transmute_to_box_uninhabited` before LowerIntrinsics
+ // MIR for `transmute_to_box_uninhabited` after LowerIntrinsics
fn transmute_to_box_uninhabited() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50
let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16
scope 1 {
debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
- _2 = transmute::<usize, Box<Never>>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) }
+ _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
}
bb1: {
StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16
unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13
}
}

View File

@ -0,0 +1,29 @@
- // MIR for `transmute_to_mut_uninhabited` before LowerIntrinsics
+ // MIR for `transmute_to_mut_uninhabited` after LowerIntrinsics
fn transmute_to_mut_uninhabited() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50
let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
let _2: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16
scope 1 {
debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
- _2 = transmute::<usize, &mut Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:64:25: 64:44
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) }
+ _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
}
bb1: {
StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16
unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13
}
}

View File

@ -0,0 +1,29 @@
- // MIR for `transmute_to_ref_uninhabited` before LowerIntrinsics
+ // MIR for `transmute_to_ref_uninhabited` after LowerIntrinsics
fn transmute_to_ref_uninhabited() -> ! {
let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50
let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
let _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16
scope 1 {
debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2
StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
- _2 = transmute::<usize, &Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:58:21: 58:40
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) }
+ _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
}
bb1: {
StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16
unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13
}
}

View File

@ -0,0 +1,22 @@
- // MIR for `transmute_uninhabited` before LowerIntrinsics
+ // MIR for `transmute_uninhabited` after LowerIntrinsics
fn transmute_uninhabited(_1: ()) -> Never {
debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:37: +0:38
let mut _0: Never; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:47: +0:52
let mut _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:47: +1:48
scope 1 {
}
bb0: {
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
- _0 = transmute::<(), Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:48:14: 48:46
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value(<ZST>) }
+ _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
}
}

View File

@ -32,7 +32,7 @@
_5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54
- _3 = add_with_overflow::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:78:14: 78:49
- // + span: $DIR/lower_intrinsics.rs:111:14: 111:49
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::<i32>}, val: Value(<ZST>) }
+ _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
@ -48,7 +48,7 @@
_8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54
- _6 = sub_with_overflow::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:79:14: 79:49
- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::<i32>}, val: Value(<ZST>) }
+ _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
+ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
@ -64,7 +64,7 @@
_11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54
- _9 = mul_with_overflow::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:80:14: 80:49
- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::<i32>}, val: Value(<ZST>) }
+ _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
+ goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55

View File

@ -11,5 +11,5 @@ impl PrintName {
}
fn main() {
let _ = PrintName::VOID; //~ constant
let _ = PrintName::VOID; //~ erroneous constant used
}

View File

@ -0,0 +1,24 @@
#![feature(core_intrinsics)]
#![feature(custom_mir)]
// These cases are statically rejected by `mem::transmute`, so we need custom
// MIR to be able to get to constant evaluation.
use std::intrinsics::mir::*;
#[custom_mir(dialect = "runtime", phase = "initial")]
const unsafe fn mir_transmute<T, U>(x: T) -> U {
mir!{
{
RET = CastTransmute(x);
//~^ ERROR evaluation of constant value failed
//~| ERROR evaluation of constant value failed
Return()
}
}
}
const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) };
const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) };
fn main() {}

View File

@ -0,0 +1,37 @@
error[E0080]: evaluation of constant value failed
--> $DIR/transmute-size-mismatch.rs:12:13
|
LL | RET = CastTransmute(x);
| ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 4-byte type to 2-byte type: `i32` -> `u16`
|
note: inside `mir_transmute::<i32, u16>`
--> $DIR/transmute-size-mismatch.rs:12:13
|
LL | RET = CastTransmute(x);
| ^^^^^^^^^^^^^^^^^^^^^^
note: inside `FROM_BIGGER`
--> $DIR/transmute-size-mismatch.rs:20:35
|
LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) };
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
--> $DIR/transmute-size-mismatch.rs:12:13
|
LL | RET = CastTransmute(x);
| ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 2-byte type to 4-byte type: `i16` -> `u32`
|
note: inside `mir_transmute::<i16, u32>`
--> $DIR/transmute-size-mismatch.rs:12:13
|
LL | RET = CastTransmute(x);
| ^^^^^^^^^^^^^^^^^^^^^^
note: inside `FROM_SMALLER`
--> $DIR/transmute-size-mismatch.rs:22:36
|
LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) };
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.

View File

@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:96:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:98:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
error: aborting due to 13 previous errors

View File

@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:96:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:98:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
error: aborting due to 13 previous errors

View File

@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/validate_uninhabited_zsts.rs:4:14
|
LL | unsafe { std::mem::transmute(()) }
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!`
|
note: inside `foo`
--> $DIR/validate_uninhabited_zsts.rs:4:14

View File

@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/validate_uninhabited_zsts.rs:4:14
|
LL | unsafe { std::mem::transmute(()) }
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!`
|
note: inside `foo`
--> $DIR/validate_uninhabited_zsts.rs:4:14

View File

@ -47,7 +47,7 @@ error[E0080]: could not evaluate static initializer
--> $DIR/uninhabited-static.rs:12:31
|
LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void
warning: the type `Void` does not permit zero-initialization
--> $DIR/uninhabited-static.rs:12:31
@ -66,7 +66,7 @@ error[E0080]: could not evaluate static initializer
--> $DIR/uninhabited-static.rs:16:32
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void
warning: the type `Void` does not permit zero-initialization
--> $DIR/uninhabited-static.rs:16:32