Skip to content

Commit 23d09ae

Browse files
oli-obkluqmana
authored andcommitted
Do not use scalar layout if there are ZSTs with alignment > 1
1 parent 4b94c23 commit 23d09ae

File tree

3 files changed

+157
-21
lines changed

3 files changed

+157
-21
lines changed

compiler/rustc_abi/src/layout.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -731,36 +731,58 @@ pub trait LayoutCalculator {
731731

732732
let optimize = !repr.inhibit_union_abi_opt();
733733
let mut size = Size::ZERO;
734-
let mut abi = Abi::Aggregate { sized: true };
734+
let mut abi = None;
735+
let mut biggest_zst_align = align;
736+
let mut biggest_non_zst_align = align;
735737
let only_variant = &variants[FIRST_VARIANT];
736738
for field in only_variant {
737-
assert!(field.0.is_sized());
738-
align = align.max(field.align());
739+
assert!(!field.0.is_unsized());
739740

740-
// If all non-ZST fields have the same ABI, forward this ABI
741-
if optimize && !field.0.is_zst() {
742-
// Discard valid range information and allow undef
743-
let field_abi = match field.abi() {
744-
Abi::Scalar(x) => Abi::Scalar(x.to_union()),
745-
Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
746-
Abi::Vector { element: x, count } => {
747-
Abi::Vector { element: x.to_union(), count }
748-
}
749-
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
750-
};
741+
if optimize {
742+
// If all non-ZST fields have the same ABI, forward this ABI
743+
if field.0.is_zst() {
744+
biggest_zst_align = biggest_zst_align.max(field.align());
745+
} else {
746+
biggest_non_zst_align = biggest_non_zst_align.max(field.align());
747+
// Discard valid range information and allow undef
748+
let field_abi = match field.abi() {
749+
Abi::Scalar(x) => Abi::Scalar(x.to_union()),
750+
Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
751+
Abi::Vector { element: x, count } => {
752+
Abi::Vector { element: x.to_union(), count }
753+
}
754+
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
755+
};
751756

752-
if size == Size::ZERO {
753-
// first non ZST: initialize 'abi'
754-
abi = field_abi;
755-
} else if abi != field_abi {
756-
// different fields have different ABI: reset to Aggregate
757-
abi = Abi::Aggregate { sized: true };
757+
if let Some(abi) = &mut abi {
758+
if *abi != field_abi {
759+
// different fields have different ABI: reset to Aggregate
760+
*abi = Abi::Aggregate { sized: true };
761+
}
762+
} else {
763+
abi = Some(field_abi);
764+
}
758765
}
759766
}
760767

768+
align = align.max(field.align());
761769
size = cmp::max(size, field.size());
762770
}
763771

772+
let abi = match abi {
773+
None => Abi::Aggregate { sized: true },
774+
Some(non_zst_abi) => {
775+
if biggest_zst_align.abi > biggest_non_zst_align.abi {
776+
// If a zst has a bigger alignment than the non-zst fields,
777+
// we cannot use scalar layout, because scalar(pair)s can't be
778+
// more aligned than their primitive.
779+
Abi::Aggregate { sized: true }
780+
} else {
781+
non_zst_abi
782+
}
783+
}
784+
};
785+
764786
if let Some(pack) = repr.pack {
765787
align = align.min(AbiAndPrefAlign::new(pack));
766788
}

tests/ui/layout/debug.rs

Lines changed: 21 additions & 0 deletions
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
}

tests/ui/layout/debug.stderr

Lines changed: 94 additions & 1 deletion
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)