diff options
| author | Scott McMurray <scottmcm@users.noreply.github.com> | 2025-07-09 22:30:15 -0700 |
|---|---|---|
| committer | Scott McMurray <scottmcm@users.noreply.github.com> | 2025-07-09 22:30:15 -0700 |
| commit | 58d7c2d5a760c1adfa4c3984eeb12787f5ad5b1d (patch) | |
| tree | 74e9de114d2d128b5a693c29e6985c10b47a3c2c | |
| parent | 32cd9114712a24010b0583624dc52ac302194128 (diff) | |
Make UB transmutes really UB in LLVM
Ralf suggested in <https://github.com/rust-lang/rust/pull/143410#discussion_r2184928123> that UB transmutes shouldn't be trapping, which happened for the one path that PR was changing, but there's another path as well, so this PR changes that other path to match.
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 12 | ||||
| -rw-r--r-- | tests/codegen/intrinsics/transmute.rs | 22 |
2 files changed, 18 insertions, 16 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index cbbb0196890..1e3b76e5f93 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -236,14 +236,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { || operand.layout.is_uninhabited() || cast.is_uninhabited() { - if !operand.layout.is_uninhabited() { - // Since this is known statically and the input could have existed - // without already having hit UB, might as well trap for it. - bx.abort(); - } + // We can't use unreachable because that's a terminator, and we + // need something that can be in the middle of a basic block. + bx.assume(bx.cx().const_bool(false)); - // Because this transmute is UB, return something easy to generate, - // since it's fine that later uses of the value are probably UB. + // We still need to return a value of the appropriate type, but + // it's already UB so do the easiest thing available. return OperandValue::poison(bx, cast); } diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index e375724bc1b..36d6a2f722f 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -58,9 +58,9 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { { RET = CastTransmute(x); @@ -88,9 +88,9 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_uninhabited(x: u16) { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { let temp: BigNever; { @@ -104,6 +104,9 @@ pub unsafe fn check_to_uninhabited(x: u16) { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call // CHECK: ret i16 poison mir! { { @@ -401,9 +404,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { pub unsafe fn check_unit_to_never(x: ()) { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK-NOT: call + // CHECK: call void @llvm.assume(i1 false) + // CHECK-NOT: call mir! { let temp: ZstNever; { @@ -420,6 +423,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. // CHECK: start + // CHECK-NEXT: call void @llvm.assume(i1 false) // CHECK-NEXT: ret void mir! { { |
