Auto merge of #130508 - adwinwhite:niche-not-depend-on-order, r=the8472
Get rid of niche selection's dependence on fields's order Fixes #125630. Use the optimal niche selection decided in `univariant()` rather than picking niche field manually. r? `@the8472`
This commit is contained in:
commit
2b11f265b6
4 changed files with 29 additions and 13 deletions
|
@ -527,15 +527,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
let count =
|
let count =
|
||||||
(niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1;
|
(niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1;
|
||||||
|
|
||||||
// Find the field with the largest niche
|
// Use the largest niche in the largest variant.
|
||||||
let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index]
|
let niche = variant_layouts[largest_variant_index].largest_niche?;
|
||||||
.iter()
|
let (niche_start, niche_scalar) = niche.reserve(dl, count)?;
|
||||||
.enumerate()
|
let niche_offset = niche.offset;
|
||||||
.filter_map(|(j, field)| Some((j, field.largest_niche?)))
|
|
||||||
.max_by_key(|(_, niche)| niche.available(dl))
|
|
||||||
.and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?;
|
|
||||||
let niche_offset =
|
|
||||||
niche.offset + variant_layouts[largest_variant_index].fields.offset(field_index);
|
|
||||||
let niche_size = niche.value.size(dl);
|
let niche_size = niche.value.size(dl);
|
||||||
let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
|
let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,11 @@ fn main() {
|
||||||
assert!(matches!(*p.as_ptr(), E::None));
|
assert!(matches!(*p.as_ptr(), E::None));
|
||||||
|
|
||||||
// Turns out the discriminant is (currently) stored
|
// Turns out the discriminant is (currently) stored
|
||||||
// in the 2nd pointer, so the first half is padding.
|
// in the 1st pointer, so the second half is padding.
|
||||||
let c = &p as *const _ as *const u8;
|
let c = &p as *const _ as *const u8;
|
||||||
|
let padding_offset = mem::size_of::<&'static ()>();
|
||||||
// Read a padding byte.
|
// Read a padding byte.
|
||||||
let _val = *c.add(0);
|
let _val = *c.add(padding_offset);
|
||||||
//~^ERROR: uninitialized
|
//~^ERROR: uninitialized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
|
||||||
--> tests/fail/uninit/padding-enum.rs:LL:CC
|
--> tests/fail/uninit/padding-enum.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | let _val = *c.add(0);
|
LL | let _val = *c.add(padding_offset);
|
||||||
| ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
| ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
||||||
|
|
|
|
||||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
|
|
@ -209,6 +209,23 @@ struct ReorderEndNiche {
|
||||||
b: MiddleNiche4,
|
b: MiddleNiche4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want that the niche selection doesn't depend on order of the fields. See issue #125630.
|
||||||
|
pub enum NicheFieldOrder1 {
|
||||||
|
A {
|
||||||
|
x: NonZero<u64>,
|
||||||
|
y: [NonZero<u64>; 2],
|
||||||
|
},
|
||||||
|
B([u64; 2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NicheFieldOrder2 {
|
||||||
|
A {
|
||||||
|
y: [NonZero<u64>; 2],
|
||||||
|
x: NonZero<u64>,
|
||||||
|
},
|
||||||
|
B([u64; 2]),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// standins for std types which we want to be laid out in a reasonable way
|
// standins for std types which we want to be laid out in a reasonable way
|
||||||
struct RawVecDummy {
|
struct RawVecDummy {
|
||||||
|
@ -260,6 +277,9 @@ pub fn main() {
|
||||||
size_of::<EnumWithMaybeUninhabitedVariant<()>>());
|
size_of::<EnumWithMaybeUninhabitedVariant<()>>());
|
||||||
assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
|
assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
|
||||||
|
|
||||||
|
assert_eq!(size_of::<NicheFieldOrder1>(), 24);
|
||||||
|
assert_eq!(size_of::<NicheFieldOrder2>(), 24);
|
||||||
|
|
||||||
assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
|
assert_eq!(size_of::<Option<Option<(bool, &())>>>(), size_of::<(bool, &())>());
|
||||||
assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
|
assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
|
||||||
assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
|
assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue