Skip to content

Commit 275b55e

Browse files
authored
Unrolled build for #143718
Rollup merge of #143718 - scottmcm:ub-transmute-is-ub, r=WaffleLapkin Make UB transmutes really UB in LLVM Ralf suggested in <#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. r? codegen
2 parents 9535fee + f5fc872 commit 275b55e

File tree

3 files changed

+34
-27
lines changed

3 files changed

+34
-27
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
207207
{
208208
// These cases are all UB to actually hit, so don't emit code for them.
209209
// (The size mismatches are reachable via `transmute_unchecked`.)
210-
// We can't use unreachable because that's a terminator, and we
211-
// need something that can be in the middle of a basic block.
212-
bx.assume(bx.cx().const_bool(false))
210+
bx.unreachable_nonterminator();
213211
} else {
214212
// Since in this path we have a place anyway, we can store or copy to it,
215213
// making sure we use the destination place's alignment even if the
@@ -236,14 +234,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
236234
|| operand.layout.is_uninhabited()
237235
|| cast.is_uninhabited()
238236
{
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-
}
237+
bx.unreachable_nonterminator();
244238

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.
239+
// We still need to return a value of the appropriate type, but
240+
// it's already UB so do the easiest thing available.
247241
return OperandValue::poison(bx, cast);
248242
}
249243

compiler/rustc_codegen_ssa/src/traits/builder.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ pub trait BuilderMethods<'a, 'tcx>:
136136
) -> Self::Value;
137137
fn unreachable(&mut self);
138138

139+
/// Like [`Self::unreachable`], but for use in the middle of a basic block.
140+
fn unreachable_nonterminator(&mut self) {
141+
// This is the preferred LLVM incantation for this per
142+
// https://llvm.org/docs/Frontend/PerformanceTips.html#other-things-to-consider
143+
// Other backends may override if they have a better way.
144+
let const_true = self.cx().const_bool(true);
145+
let poison_ptr = self.const_poison(self.cx().type_ptr());
146+
self.store(const_true, poison_ptr, Align::ONE);
147+
}
148+
139149
fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
140150
fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
141151
fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;

tests/codegen/intrinsics/transmute.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,38 +29,38 @@ pub struct Aggregate8(u8);
2929
// CHECK-LABEL: @check_bigger_size(
3030
#[no_mangle]
3131
pub unsafe fn check_bigger_size(x: u16) -> u32 {
32-
// CHECK: call void @llvm.assume(i1 false)
32+
// CHECK: store i1 true, ptr poison, align 1
3333
transmute_unchecked(x)
3434
}
3535

3636
// CHECK-LABEL: @check_smaller_size(
3737
#[no_mangle]
3838
pub unsafe fn check_smaller_size(x: u32) -> u16 {
39-
// CHECK: call void @llvm.assume(i1 false)
39+
// CHECK: store i1 true, ptr poison, align 1
4040
transmute_unchecked(x)
4141
}
4242

4343
// CHECK-LABEL: @check_smaller_array(
4444
#[no_mangle]
4545
pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] {
46-
// CHECK: call void @llvm.assume(i1 false)
46+
// CHECK: store i1 true, ptr poison, align 1
4747
transmute_unchecked(x)
4848
}
4949

5050
// CHECK-LABEL: @check_bigger_array(
5151
#[no_mangle]
5252
pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] {
53-
// CHECK: call void @llvm.assume(i1 false)
53+
// CHECK: store i1 true, ptr poison, align 1
5454
transmute_unchecked(x)
5555
}
5656

5757
// CHECK-LABEL: @check_to_empty_array(
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: start
62+
// CHECK-NEXT: store i1 true, ptr poison, align 1
63+
// CHECK-NEXT: ret void
6464
mir! {
6565
{
6666
RET = CastTransmute(x);
@@ -73,9 +73,9 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] {
7373
#[no_mangle]
7474
#[custom_mir(dialect = "runtime", phase = "optimized")]
7575
pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] {
76-
// CHECK-NOT: call
77-
// CHECK: call void @llvm.assume(i1 false)
78-
// CHECK-NOT: call
76+
// CHECK: start
77+
// CHECK-NEXT: store i1 true, ptr poison, align 1
78+
// CHECK-NEXT: ret void
7979
mir! {
8080
{
8181
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: start
92+
// CHECK-NEXT: store i1 true, ptr poison, align 1
93+
// CHECK-NEXT: ret void
9494
mir! {
9595
let temp: BigNever;
9696
{
@@ -104,7 +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: ret i16 poison
107+
// CHECK: start
108+
// CHECK-NEXT: store i1 true, ptr poison, align 1
109+
// CHECK-NEXT: ret i16 poison
108110
mir! {
109111
{
110112
RET = CastTransmute(x);
@@ -401,9 +403,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] {
401403
pub unsafe fn check_unit_to_never(x: ()) {
402404
// This uses custom MIR to avoid MIR optimizations having removed ZST ops.
403405

404-
// CHECK-NOT: trap
405-
// CHECK: call void @llvm.trap
406-
// CHECK-NOT: trap
406+
// CHECK: start
407+
// CHECK-NEXT: store i1 true, ptr poison, align 1
408+
// CHECK-NEXT: ret void
407409
mir! {
408410
let temp: ZstNever;
409411
{
@@ -420,6 +422,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () {
420422
// This uses custom MIR to avoid MIR optimizations having removed ZST ops.
421423

422424
// CHECK: start
425+
// CHECK-NEXT: store i1 true, ptr poison, align 1
423426
// CHECK-NEXT: ret void
424427
mir! {
425428
{

0 commit comments

Comments
 (0)