Skip to content

Commit 9f69049

Browse files
committed
Do not use scalar layout if there are ZSTs with alignment > 1
1 parent 41e0363 commit 9f69049

File tree

3 files changed

+157
-21
lines changed

3 files changed

+157
-21
lines changed

compiler/rustc_abi/src/layout.rs

+42-20
Original file line numberDiff line numberDiff line change
@@ -901,36 +901,58 @@ pub trait LayoutCalculator {
901901

902902
let optimize = !repr.inhibit_union_abi_opt();
903903
let mut size = Size::ZERO;
904-
let mut abi = Abi::Aggregate { sized: true };
904+
let mut abi = None;
905+
let mut biggest_zst_align = align;
906+
let mut biggest_non_zst_align = align;
905907
let index = V::new(0);
906908
for field in &variants[index] {
907-
assert!(field.is_sized());
908-
align = align.max(field.align);
909+
assert!(!field.is_unsized());
909910

910-
// If all non-ZST fields have the same ABI, forward this ABI
911-
if optimize && !field.is_zst() {
912-
// Discard valid range information and allow undef
913-
let field_abi = match field.abi {
914-
Abi::Scalar(x) => Abi::Scalar(x.to_union()),
915-
Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
916-
Abi::Vector { element: x, count } => {
917-
Abi::Vector { element: x.to_union(), count }
918-
}
919-
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
920-
};
911+
if optimize {
912+
// If all non-ZST fields have the same ABI, forward this ABI
913+
if field.is_zst() {
914+
biggest_zst_align = biggest_zst_align.max(field.align);
915+
} else {
916+
biggest_non_zst_align = biggest_non_zst_align.max(field.align);
917+
// Discard valid range information and allow undef
918+
let field_abi = match field.abi {
919+
Abi::Scalar(x) => Abi::Scalar(x.to_union()),
920+
Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
921+
Abi::Vector { element: x, count } => {
922+
Abi::Vector { element: x.to_union(), count }
923+
}
924+
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
925+
};
921926

922-
if size == Size::ZERO {
923-
// first non ZST: initialize 'abi'
924-
abi = field_abi;
925-
} else if abi != field_abi {
926-
// different fields have different ABI: reset to Aggregate
927-
abi = Abi::Aggregate { sized: true };
927+
if let Some(abi) = &mut abi {
928+
if *abi != field_abi {
929+
// different fields have different ABI: reset to Aggregate
930+
*abi = Abi::Aggregate { sized: true };
931+
}
932+
} else {
933+
abi = Some(field_abi);
934+
}
928935
}
929936
}
930937

938+
align = align.max(field.align);
931939
size = cmp::max(size, field.size);
932940
}
933941

942+
let abi = match abi {
943+
None => Abi::Aggregate { sized: true },
944+
Some(non_zst_abi) => {
945+
if biggest_zst_align.abi > biggest_non_zst_align.abi {
946+
// If a zst has a bigger alignment than the non-zst fields,
947+
// we cannot use scalar layout, because scalar(pair)s can't be
948+
// more aligned than their primitive.
949+
Abi::Aggregate { sized: true }
950+
} else {
951+
non_zst_abi
952+
}
953+
}
954+
};
955+
934956
if let Some(pack) = repr.pack {
935957
align = align.min(AbiAndPrefAlign::new(pack));
936958
}

src/test/ui/layout/debug.rs

+21
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,27 @@ type Test = Result<i32, i32>; //~ ERROR: layout_of
1717
#[rustc_layout(debug)]
1818
type T = impl std::fmt::Debug; //~ ERROR: layout_of
1919

20+
#[rustc_layout(debug)]
21+
pub union V { //~ ERROR: layout_of
22+
a: [u16; 0],
23+
b: u8,
24+
}
25+
26+
#[rustc_layout(debug)]
27+
pub union W { //~ ERROR: layout_of
28+
b: u8,
29+
a: [u16; 0],
30+
}
31+
32+
#[rustc_layout(debug)]
33+
pub union Y { //~ ERROR: layout_of
34+
b: [u8; 0],
35+
a: [u16; 0],
36+
}
37+
38+
#[rustc_layout(debug)]
39+
type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
40+
2041
fn f() -> T {
2142
0i32
2243
}

src/test/ui/layout/debug.stderr

+94-1
Original file line numberDiff line numberDiff line change
@@ -307,5 +307,98 @@ error: layout_of(i32) = Layout {
307307
LL | type T = impl std::fmt::Debug;
308308
| ^^^^^^
309309

310-
error: aborting due to 5 previous errors
310+
error: layout_of(V) = Layout {
311+
size: Size(2 bytes),
312+
align: AbiAndPrefAlign {
313+
abi: Align(2 bytes),
314+
pref: $PREF_ALIGN,
315+
},
316+
abi: Aggregate {
317+
sized: true,
318+
},
319+
fields: Union(
320+
2,
321+
),
322+
largest_niche: None,
323+
variants: Single {
324+
index: 0,
325+
},
326+
}
327+
--> $DIR/debug.rs:21:1
328+
|
329+
LL | pub union V {
330+
| ^^^^^^^^^^^
331+
332+
error: layout_of(W) = Layout {
333+
size: Size(2 bytes),
334+
align: AbiAndPrefAlign {
335+
abi: Align(2 bytes),
336+
pref: $PREF_ALIGN,
337+
},
338+
abi: Aggregate {
339+
sized: true,
340+
},
341+
fields: Union(
342+
2,
343+
),
344+
largest_niche: None,
345+
variants: Single {
346+
index: 0,
347+
},
348+
}
349+
--> $DIR/debug.rs:27:1
350+
|
351+
LL | pub union W {
352+
| ^^^^^^^^^^^
353+
354+
error: layout_of(Y) = Layout {
355+
size: Size(0 bytes),
356+
align: AbiAndPrefAlign {
357+
abi: Align(2 bytes),
358+
pref: $PREF_ALIGN,
359+
},
360+
abi: Aggregate {
361+
sized: true,
362+
},
363+
fields: Union(
364+
2,
365+
),
366+
largest_niche: None,
367+
variants: Single {
368+
index: 0,
369+
},
370+
}
371+
--> $DIR/debug.rs:33:1
372+
|
373+
LL | pub union Y {
374+
| ^^^^^^^^^^^
375+
376+
error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
377+
size: Size(1 bytes),
378+
align: AbiAndPrefAlign {
379+
abi: Align(1 bytes),
380+
pref: $PREF_ALIGN,
381+
},
382+
abi: Scalar(
383+
Union {
384+
value: Int(
385+
I8,
386+
false,
387+
),
388+
},
389+
),
390+
fields: Union(
391+
2,
392+
),
393+
largest_niche: None,
394+
variants: Single {
395+
index: 0,
396+
},
397+
}
398+
--> $DIR/debug.rs:39:1
399+
|
400+
LL | type X = std::mem::MaybeUninit<u8>;
401+
| ^^^^^^
402+
403+
error: aborting due to 9 previous errors
311404

0 commit comments

Comments
 (0)