Skip to content

Commit 279e257

Browse files
authored
Rollup merge of #115708 - RalfJung:homogeneous, r=davidtwco
fix homogeneous_aggregate not ignoring some ZST This is an ABI-breaking change, because it fixes bugs in our ABI code. I'm not sure what that means for this PR, we don't really have a process for such changes, do we? I can only hope nobody relied on the old buggy behavior. Fixes #115664
2 parents 5a2b589 + 254e13d commit 279e257

File tree

4 files changed

+87
-12
lines changed

4 files changed

+87
-12
lines changed

compiler/rustc_target/src/abi/call/mod.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
382382
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
383383
/// special-cased in ABIs.
384384
///
385-
/// Note: We generally ignore fields of zero-sized type when computing
386-
/// this value (see #56877).
385+
/// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
387386
///
388387
/// This is public so that it can be used in unit tests, but
389388
/// should generally only be relevant to the ABI details of
@@ -441,12 +440,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
441440
let mut total = start;
442441

443442
for i in 0..layout.fields.count() {
443+
let field = layout.field(cx, i);
444+
if field.is_1zst() {
445+
// No data here and no impact on layout, can be ignored.
446+
// (We might be able to also ignore all aligned ZST but that's less clear.)
447+
continue;
448+
}
449+
444450
if !is_union && total != layout.fields.offset(i) {
451+
// This field isn't just after the previous one we considered, abort.
445452
return Err(Heterogeneous);
446453
}
447454

448-
let field = layout.field(cx, i);
449-
450455
result = result.merge(field.homogeneous_aggregate(cx)?)?;
451456

452457
// Keep track of the offset (without padding).

tests/ui/abi/compatibility.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,15 @@ test_transparent!(zst, Zst);
106106
test_transparent!(unit, ());
107107
test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment
108108
test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit
109+
test_transparent!(triple_f32, (f32, f32, f32)); // homogeneous case
110+
test_transparent!(triple_f64, (f64, f64, f64));
109111
test_transparent!(tuple, (i32, f32, i64, f64));
110112
test_transparent!(empty_array, [u32; 0]);
111113
test_transparent!(empty_1zst_array, [u8; 0]);
112114
test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit
113115
test_transparent!(large_array, [i32; 16]);
114116
test_transparent!(enum_, Option<i32>);
115117
test_transparent!(enum_niched, Option<&'static i32>);
116-
// Pure-float types that are not ScalarPair seem to be tricky.
117-
// FIXME: <https://github.com/rust-lang/rust/issues/115664>
118-
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
119-
mod tricky {
120-
use super::*;
121-
test_transparent!(triple_f32, (f32, f32, f32));
122-
test_transparent!(triple_f64, (f64, f64, f64));
123-
}
124118

125119
// RFC 3391 <https://rust-lang.github.io/rfcs/3391-result_ffi_guarantees.html>.
126120
macro_rules! test_nonnull {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![feature(rustc_attrs)]
2+
#![feature(transparent_unions)]
3+
use std::marker::PhantomData;
4+
5+
// Regression test for #115664. We want to ensure that `repr(transparent)` wrappers do not affect
6+
// the result of `homogeneous_aggregate`.
7+
8+
type Tuple = (f32, f32, f32);
9+
10+
struct Zst;
11+
12+
#[repr(transparent)]
13+
struct Wrapper1<T>(T);
14+
#[repr(transparent)]
15+
struct Wrapper2<T>((), Zst, T);
16+
#[repr(transparent)]
17+
struct Wrapper3<T>(T, [u8; 0], PhantomData<u64>);
18+
#[repr(transparent)]
19+
union WrapperUnion<T: Copy> {
20+
nothing: (),
21+
something: T,
22+
}
23+
24+
#[rustc_layout(homogeneous_aggregate)]
25+
pub type Test0 = Tuple;
26+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
27+
28+
#[rustc_layout(homogeneous_aggregate)]
29+
pub type Test1 = Wrapper1<Tuple>;
30+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
31+
32+
#[rustc_layout(homogeneous_aggregate)]
33+
pub type Test2 = Wrapper2<Tuple>;
34+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
35+
36+
#[rustc_layout(homogeneous_aggregate)]
37+
pub type Test3 = Wrapper3<Tuple>;
38+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
39+
40+
#[rustc_layout(homogeneous_aggregate)]
41+
pub type Test4 = WrapperUnion<Tuple>;
42+
//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
43+
44+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
2+
--> $DIR/homogeneous-aggr-transparent.rs:25:1
3+
|
4+
LL | pub type Test0 = Tuple;
5+
| ^^^^^^^^^^^^^^
6+
7+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
8+
--> $DIR/homogeneous-aggr-transparent.rs:29:1
9+
|
10+
LL | pub type Test1 = Wrapper1<Tuple>;
11+
| ^^^^^^^^^^^^^^
12+
13+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
14+
--> $DIR/homogeneous-aggr-transparent.rs:33:1
15+
|
16+
LL | pub type Test2 = Wrapper2<Tuple>;
17+
| ^^^^^^^^^^^^^^
18+
19+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
20+
--> $DIR/homogeneous-aggr-transparent.rs:37:1
21+
|
22+
LL | pub type Test3 = Wrapper3<Tuple>;
23+
| ^^^^^^^^^^^^^^
24+
25+
error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) }))
26+
--> $DIR/homogeneous-aggr-transparent.rs:41:1
27+
|
28+
LL | pub type Test4 = WrapperUnion<Tuple>;
29+
| ^^^^^^^^^^^^^^
30+
31+
error: aborting due to 5 previous errors
32+

0 commit comments

Comments
 (0)