Skip to content

Commit e1aa348

Browse files
committed
Correctly handle recursive #[repr(transparent)] layouts
1 parent f31e07f commit e1aa348

File tree

2 files changed

+46
-25
lines changed

2 files changed

+46
-25
lines changed

compiler/rustc_ty_utils/src/abi.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -787,18 +787,10 @@ fn fn_abi_adjust_for_abi<'tcx>(
787787

788788
// Let's see if we can add a `noundef`. This is only legal for arrays, definitely
789789
// not for unions. This is also legal for `#[repr(transparent)] struct` or
790-
// `#[repr(transparent)] enum` containing array.
791-
let is_transparent_array =
792-
if arg.layout.is_transparent::<LayoutCx<'tcx, TyCtxt<'tcx>>>()
793-
&& let Some((_, layout)) = arg.layout.non_1zst_field(cx)
794-
&& layout.ty.is_array()
795-
{
796-
true
797-
} else {
798-
false
799-
};
800-
801-
if arg.layout.ty.is_array() || is_transparent_array {
790+
// `#[repr(transparent)] enum` containing array. Note that `#[repr(transparent)]`
791+
// can contain other `#[repr(transparent)]` structs or enums, which can eventually
792+
// contain an array!
793+
if arg.layout.ty.is_array() || is_transparent_array(cx, arg.layout) {
802794
// Fixup arg attribute with `noundef`.
803795
let PassMode::Cast { ref mut cast, .. } = &mut arg.mode else {
804796
bug!("this cannot fail because of the previous cast_to `Reg`");
@@ -842,6 +834,20 @@ fn fn_abi_adjust_for_abi<'tcx>(
842834
Ok(())
843835
}
844836

837+
fn is_transparent_array<'tcx>(
838+
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
839+
outermost_layout: TyAndLayout<'tcx>,
840+
) -> bool {
841+
let mut adt_layout = outermost_layout;
842+
// Recursively walk a layout, seeing through all `#[repr(transparent)]` layers.
843+
while adt_layout.is_transparent::<LayoutCx<'tcx, TyCtxt<'tcx>>>() {
844+
if let Some((_, layout)) = adt_layout.non_1zst_field(cx) {
845+
adt_layout = layout;
846+
}
847+
}
848+
adt_layout.ty.is_array()
849+
}
850+
845851
#[tracing::instrument(level = "debug", skip(cx))]
846852
fn make_thin_self_ptr<'tcx>(
847853
cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),

tests/codegen/array-immediate-param-noundef.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,67 @@
88
//@ compile-flags: -C no-prepopulate-passes -O
99
#![crate_type = "lib"]
1010

11-
// CHECK: define noundef i64 @replace_short_array_u64x1(ptr noalias noundef align 8 dereferenceable(8) %r, i64 noundef %0)
11+
// CHECK: define noundef i64 @replace_short_array_u64x1(ptr {{.*}}, i64 noundef %{{.*}})
1212
#[no_mangle]
1313
pub fn replace_short_array_u64x1(r: &mut [u64; 1], v: [u64; 1]) -> [u64; 1] {
1414
std::mem::replace(r, v)
1515
}
1616

17-
// CHECK: define noundef i32 @replace_short_array_u32x1(ptr noalias noundef align 4 dereferenceable(4) %r, i32 noundef %0)
17+
// CHECK: define noundef i32 @replace_short_array_u32x1(ptr {{.*}}, i32 noundef %{{.*}})
1818
#[no_mangle]
1919
pub fn replace_short_array_u32x1(r: &mut [u32; 1], v: [u32; 1]) -> [u32; 1] {
2020
std::mem::replace(r, v)
2121
}
2222

23-
// CHECK: define noundef i64 @replace_short_array_u32x2(ptr noalias noundef align 4 dereferenceable(8) %r, i64 noundef %0)
23+
// CHECK: define noundef i64 @replace_short_array_u32x2(ptr {{.*}}, i64 noundef %{{.*}})
2424
#[no_mangle]
2525
pub fn replace_short_array_u32x2(r: &mut [u32; 2], v: [u32; 2]) -> [u32; 2] {
2626
std::mem::replace(r, v)
2727
}
2828

29-
// CHECK: define noundef i16 @replace_short_array_u16x1(ptr noalias noundef align 2 dereferenceable(2) %r, i16 noundef %0)
29+
// CHECK: define noundef i16 @replace_short_array_u16x1(ptr {{.*}}, i16 noundef %{{.*}})
3030
#[no_mangle]
3131
pub fn replace_short_array_u16x1(r: &mut [u16; 1], v: [u16; 1]) -> [u16; 1] {
3232
std::mem::replace(r, v)
3333
}
3434

35-
// CHECK: define noundef i32 @replace_short_array_u16x2(ptr noalias noundef align 2 dereferenceable(4) %r, i32 noundef %0)
35+
// CHECK: define noundef i32 @replace_short_array_u16x2(ptr {{.*}}, i32 noundef %{{.*}})
3636
#[no_mangle]
3737
pub fn replace_short_array_u16x2(r: &mut [u16; 2], v: [u16; 2]) -> [u16; 2] {
3838
std::mem::replace(r, v)
3939
}
4040

41-
// CHECK: define noundef i48 @replace_short_array_u16x3(ptr noalias noundef align 2 dereferenceable(6) %r, i48 noundef %0)
41+
// CHECK: define noundef i48 @replace_short_array_u16x3(ptr {{.*}}, i48 noundef %{{.*}})
4242
#[no_mangle]
4343
pub fn replace_short_array_u16x3(r: &mut [u16; 3], v: [u16; 3]) -> [u16; 3] {
4444
std::mem::replace(r, v)
4545
}
4646

47-
// CHECK: define noundef i64 @replace_short_array_u16x4(ptr noalias noundef align 2 dereferenceable(8) %r, i64 noundef %0)
47+
// CHECK: define noundef i64 @replace_short_array_u16x4(ptr {{.*}}, i64 noundef %{{.*}})
4848
#[no_mangle]
4949
pub fn replace_short_array_u16x4(r: &mut [u16; 4], v: [u16; 4]) -> [u16; 4] {
5050
std::mem::replace(r, v)
5151
}
5252

53-
// CHECK: define noundef i8 @replace_short_array_u8x1(ptr noalias noundef align 1 dereferenceable(1) %r, i8 noundef %0)
53+
// CHECK: define noundef i8 @replace_short_array_u8x1(ptr {{.*}}, i8 noundef %{{.*}})
5454
#[no_mangle]
5555
pub fn replace_short_array_u8x1(r: &mut [u8; 1], v: [u8; 1]) -> [u8; 1] {
5656
std::mem::replace(r, v)
5757
}
5858

59-
// CHECK: define noundef i16 @replace_short_array_u8x2(ptr noalias noundef align 1 dereferenceable(2) %r, i16 noundef %0)
59+
// CHECK: define noundef i16 @replace_short_array_u8x2(ptr {{.*}}, i16 noundef %{{.*}})
6060
#[no_mangle]
6161
pub fn replace_short_array_u8x2(r: &mut [u8; 2], v: [u8; 2]) -> [u8; 2] {
6262
std::mem::replace(r, v)
6363
}
6464

65-
// CHECK: define noundef i24 @replace_short_array_u8x3(ptr noalias noundef align 1 dereferenceable(3) %r, i24 noundef %0)
65+
// CHECK: define noundef i24 @replace_short_array_u8x3(ptr {{.*}}, i24 noundef %{{.*}})
6666
#[no_mangle]
6767
pub fn replace_short_array_u8x3(r: &mut [u8; 3], v: [u8; 3]) -> [u8; 3] {
6868
std::mem::replace(r, v)
6969
}
7070

71-
// CHECK: define noundef i64 @replace_short_array_u8x8(ptr noalias noundef align 1 dereferenceable(8) %r, i64 noundef %0)
71+
// CHECK: define noundef i64 @replace_short_array_u8x8(ptr {{.*}}, i64 noundef %{{.*}})
7272
#[no_mangle]
7373
pub fn replace_short_array_u8x8(r: &mut [u8; 8], v: [u8; 8]) -> [u8; 8] {
7474
std::mem::replace(r, v)
@@ -77,7 +77,7 @@ pub fn replace_short_array_u8x8(r: &mut [u8; 8], v: [u8; 8]) -> [u8; 8] {
7777
#[repr(transparent)]
7878
pub struct Foo([u8; 4]);
7979

80-
// CHECK: define noundef i32 @replace_repr_transparent_struct_short_array(ptr noalias noundef align 1 dereferenceable(4) %r, i32 noundef %0)
80+
// CHECK: define noundef i32 @replace_repr_transparent_struct_short_array(ptr {{.*}}, i32 noundef %{{.*}})
8181
#[no_mangle]
8282
pub fn replace_repr_transparent_struct_short_array(r: &mut Foo, v: Foo) -> Foo {
8383
std::mem::replace(r, v)
@@ -88,8 +88,23 @@ pub enum Bar {
8888
Default([u8; 4])
8989
}
9090

91-
// CHECK: define noundef i32 @replace_repr_transparent_enum_short_array(ptr noalias noundef align 1 dereferenceable(4) %r, i32 noundef %0)
91+
// CHECK: define noundef i32 @replace_repr_transparent_enum_short_array(ptr {{.*}}, i32 noundef %{{.*}})
9292
#[no_mangle]
9393
pub fn replace_repr_transparent_enum_short_array(r: &mut Bar, v: Bar) -> Bar {
9494
std::mem::replace(r, v)
9595
}
96+
97+
#[repr(transparent)]
98+
pub struct Owo([u8; 4]);
99+
100+
#[repr(transparent)]
101+
pub struct Uwu(Owo);
102+
103+
#[repr(transparent)]
104+
pub struct Oowoo(Uwu);
105+
106+
// CHECK: define noundef i32 @replace_repr_transparent_nested_struct_short_array(ptr {{.*}}, i32 noundef %{{.*}})
107+
#[no_mangle]
108+
pub fn replace_repr_transparent_nested_struct_short_array(r: &mut Oowoo, v: Oowoo) -> Oowoo {
109+
std::mem::replace(r, v)
110+
}

0 commit comments

Comments
 (0)