Skip to content

Commit 58d7c2d

Browse files
committed
Make UB transmutes really UB in LLVM
Ralf suggested in <rust-lang#143410 (comment)> 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.
1 parent 32cd911 commit 58d7c2d

File tree

2 files changed

+18
-16
lines changed

2 files changed

+18
-16
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
236236
|| operand.layout.is_uninhabited()
237237
|| cast.is_uninhabited()
238238
{
239-
if !operand.layout.is_uninhabited() {
240-
// Since this is known statically and the input could have existed
241-
// without already having hit UB, might as well trap for it.
242-
bx.abort();
243-
}
239+
// We can't use unreachable because that's a terminator, and we
240+
// need something that can be in the middle of a basic block.
241+
bx.assume(bx.cx().const_bool(false));
244242

245-
// Because this transmute is UB, return something easy to generate,
246-
// since it's fine that later uses of the value are probably UB.
243+
// We still need to return a value of the appropriate type, but
244+
// it's already UB so do the easiest thing available.
247245
return OperandValue::poison(bx, cast);
248246
}
249247

tests/codegen/intrinsics/transmute.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] {
5858
#[no_mangle]
5959
#[custom_mir(dialect = "runtime", phase = "optimized")]
6060
pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] {
61-
// CHECK-NOT: trap
62-
// CHECK: call void @llvm.trap
63-
// CHECK-NOT: trap
61+
// CHECK-NOT: call
62+
// CHECK: call void @llvm.assume(i1 false)
63+
// CHECK-NOT: call
6464
mir! {
6565
{
6666
RET = CastTransmute(x);
@@ -88,9 +88,9 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] {
8888
#[no_mangle]
8989
#[custom_mir(dialect = "runtime", phase = "optimized")]
9090
pub unsafe fn check_to_uninhabited(x: u16) {
91-
// CHECK-NOT: trap
92-
// CHECK: call void @llvm.trap
93-
// CHECK-NOT: trap
91+
// CHECK-NOT: call
92+
// CHECK: call void @llvm.assume(i1 false)
93+
// CHECK-NOT: call
9494
mir! {
9595
let temp: BigNever;
9696
{
@@ -104,6 +104,9 @@ pub unsafe fn check_to_uninhabited(x: u16) {
104104
#[no_mangle]
105105
#[custom_mir(dialect = "runtime", phase = "optimized")]
106106
pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 {
107+
// CHECK-NOT: call
108+
// CHECK: call void @llvm.assume(i1 false)
109+
// CHECK-NOT: call
107110
// CHECK: ret i16 poison
108111
mir! {
109112
{
@@ -401,9 +404,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] {
401404
pub unsafe fn check_unit_to_never(x: ()) {
402405
// This uses custom MIR to avoid MIR optimizations having removed ZST ops.
403406

404-
// CHECK-NOT: trap
405-
// CHECK: call void @llvm.trap
406-
// CHECK-NOT: trap
407+
// CHECK-NOT: call
408+
// CHECK: call void @llvm.assume(i1 false)
409+
// CHECK-NOT: call
407410
mir! {
408411
let temp: ZstNever;
409412
{
@@ -420,6 +423,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () {
420423
// This uses custom MIR to avoid MIR optimizations having removed ZST ops.
421424

422425
// CHECK: start
426+
// CHECK-NEXT: call void @llvm.assume(i1 false)
423427
// CHECK-NEXT: ret void
424428
mir! {
425429
{

0 commit comments

Comments
 (0)