-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix some issues around ZST handling #115277
Changes from all commits
0360b67
0da9409
bf91321
b2ebf1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,8 +157,10 @@ pub trait LayoutCalculator { | |
// for non-ZST uninhabited data (mostly partial initialization). | ||
let absent = |fields: &IndexSlice<FieldIdx, Layout<'_>>| { | ||
let uninhabited = fields.iter().any(|f| f.abi().is_uninhabited()); | ||
let is_zst = fields.iter().all(|f| f.0.is_zst()); | ||
uninhabited && is_zst | ||
// We cannot ignore alignment; that might lead us to entirely discard a variant and | ||
// produce an enum that is less aligned than it should be! | ||
let is_1zst = fields.iter().all(|f| f.0.is_1zst()); | ||
uninhabited && is_1zst | ||
}; | ||
let (present_first, present_second) = { | ||
let mut present_variants = variants | ||
|
@@ -357,10 +359,8 @@ pub trait LayoutCalculator { | |
// It'll fit, but we need to make some adjustments. | ||
match layout.fields { | ||
FieldsShape::Arbitrary { ref mut offsets, .. } => { | ||
for (j, offset) in offsets.iter_enumerated_mut() { | ||
if !variants[i][j].0.is_zst() { | ||
*offset += this_offset; | ||
} | ||
for offset in offsets.iter_mut() { | ||
*offset += this_offset; | ||
} | ||
} | ||
_ => { | ||
|
@@ -504,7 +504,7 @@ pub trait LayoutCalculator { | |
// to make room for a larger discriminant. | ||
for field_idx in st.fields.index_by_increasing_offset() { | ||
let field = &field_layouts[FieldIdx::from_usize(field_idx)]; | ||
if !field.0.is_zst() || field.align().abi.bytes() != 1 { | ||
if !field.0.is_1zst() { | ||
start_align = start_align.min(field.align().abi); | ||
break; | ||
} | ||
|
@@ -603,12 +603,15 @@ pub trait LayoutCalculator { | |
abi = Abi::Scalar(tag); | ||
} else { | ||
// Try to use a ScalarPair for all tagged enums. | ||
// That's possible only if we can find a common primitive type for all variants. | ||
let mut common_prim = None; | ||
let mut common_prim_initialized_in_all_variants = true; | ||
for (field_layouts, layout_variant) in iter::zip(variants, &layout_variants) { | ||
let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { | ||
panic!(); | ||
}; | ||
// We skip *all* ZST here and later check if we are good in terms of alignment. | ||
// This lets us handle some cases involving aligned ZST. | ||
let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.0.is_zst()); | ||
let (field, offset) = match (fields.next(), fields.next()) { | ||
(None, None) => { | ||
|
@@ -954,9 +957,6 @@ fn univariant( | |
}; | ||
|
||
( | ||
// Place ZSTs first to avoid "interesting offsets", especially with only one | ||
// or two non-ZST fields. This helps Scalar/ScalarPair layouts. | ||
!f.0.is_zst(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the other place special-casing ZST that I removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was likely obviated by #73453 |
||
// Then place largest alignments first. | ||
cmp::Reverse(alignment_group_key(f)), | ||
// Then prioritize niche placement within alignment group according to | ||
|
@@ -1073,9 +1073,10 @@ fn univariant( | |
let size = min_size.align_to(align.abi); | ||
let mut layout_of_single_non_zst_field = None; | ||
let mut abi = Abi::Aggregate { sized }; | ||
// Unpack newtype ABIs and find scalar pairs. | ||
// Try to make this a Scalar/ScalarPair. | ||
if sized && size.bytes() > 0 { | ||
// All other fields must be ZSTs. | ||
// We skip *all* ZST here and later check if we are good in terms of alignment. | ||
// This lets us handle some cases involving aligned ZST. | ||
let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst()); | ||
|
||
match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" | ||
//! Various enum layout tests. | ||
|
||
#![feature(rustc_attrs)] | ||
#![feature(never_type)] | ||
#![crate_type = "lib"] | ||
|
||
#[rustc_layout(align)] | ||
enum UninhabitedVariantAlign { //~ERROR: abi: Align(2 bytes) | ||
A([u8; 32]), | ||
B([u16; 0], !), // make sure alignment in uninhabited fields is respected | ||
} | ||
|
||
#[rustc_layout(size)] | ||
enum UninhabitedVariantSpace { //~ERROR: size: Size(16 bytes) | ||
A, | ||
B([u8; 15], !), // make sure there is space being reserved for this field. | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
error: align: AbiAndPrefAlign { abi: Align(2 bytes), pref: $PREF_ALIGN } | ||
--> $DIR/enum.rs:9:1 | ||
| | ||
LL | enum UninhabitedVariantAlign { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: size: Size(16 bytes) | ||
--> $DIR/enum.rs:15:1 | ||
| | ||
LL | enum UninhabitedVariantSpace { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to 2 previous errors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" | ||
//! Various struct layout tests. | ||
|
||
#![feature(rustc_attrs)] | ||
#![feature(never_type)] | ||
#![crate_type = "lib"] | ||
|
||
#[rustc_layout(abi)] | ||
struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: abi: Aggregate | ||
|
||
#[rustc_layout(abi)] | ||
struct AlignedZstButStillScalar(i32, [i16; 0]); //~ERROR: abi: Scalar |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
error: abi: Aggregate { sized: true } | ||
--> $DIR/struct.rs:9:1 | ||
| | ||
LL | struct AlignedZstPreventsScalar(i16, [i32; 0]); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) | ||
--> $DIR/struct.rs:12:1 | ||
| | ||
LL | struct AlignedZstButStillScalar(i32, [i16; 0]); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to 2 previous errors | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of these places special-casing ZST that I removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got added in d7a750b by @mikebenfield. But their tests still pass after removing the
if
. So... maybe it just was never needed?