1
Fork 0

Don't re-assume in transmutes that don't change niches

This commit is contained in:
Scott McMurray 2025-02-23 23:18:04 -08:00
parent a18bd8acfc
commit 23c6b93de8
2 changed files with 32 additions and 0 deletions

View file

@ -386,6 +386,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> Bx::Value {
assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
// While optimizations will remove no-op transmutes, they might still be
// there in debug or things that aren't no-op in MIR because they change
// the Rust type but not the underlying layout/niche.
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
return imm;
}
use abi::Primitive::*;
imm = bx.from_immediate(imm);

View file

@ -10,6 +10,7 @@
use std::intrinsics::mir::*;
use std::intrinsics::{transmute, transmute_unchecked};
use std::mem::MaybeUninit;
use std::num::NonZero;
// FIXME(LLVM18REMOVED): `trunc nuw` doesn't exist in LLVM 18, so once we no
// longer support it the optional flag checks can be changed to required.
@ -470,3 +471,27 @@ pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 {
// CHECK: ret i64 %[[VAL]]
transmute(x)
}
#[repr(transparent)]
struct Level1(std::num::NonZero<u32>);
#[repr(transparent)]
struct Level2(Level1);
#[repr(transparent)]
struct Level3(Level2);
// CHECK-LABEL: @repeatedly_transparent_transmute
// CHECK-SAME: (i32{{.+}}%[[ARG:[^)]+]])
#[no_mangle]
#[custom_mir(dialect = "runtime", phase = "optimized")]
pub unsafe fn repeatedly_transparent_transmute(x: NonZero<u32>) -> Level3 {
// CHECK: start
// CHECK-NEXT: ret i32 %[[ARG]]
mir! {
{
let A = CastTransmute::<NonZero<u32>, Level1>(x);
let B = CastTransmute::<Level1, Level2>(A);
RET = CastTransmute::<Level2, Level3>(B);
Return()
}
}
}