Auto merge of #46808 - eddyb:issue-46769-quick, r=arielb1
rustc: ensure optimized enums have a properly aligned size. Fixes #46769 by padding the optimized enums wrapping packed data as necessary. Note that this is not the only way to solve this - on nightly, #46436 makes it easier to fix without adding new padding because of the replacement of `packed` flags with a non-redundant scheme. But because it can't be backported, the optimal fix will be in a separate nightly-only PR (#46809).
This commit is contained in:
commit
e7db42fb5b
|
@ -1492,7 +1492,7 @@ impl<'a, 'tcx> LayoutDetails {
|
||||||
}).collect::<Result<Vec<_>, _>>()?;
|
}).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let offset = st[i].fields.offset(field_index) + offset;
|
let offset = st[i].fields.offset(field_index) + offset;
|
||||||
let LayoutDetails { size, mut align, .. } = st[i];
|
let LayoutDetails { mut size, mut align, .. } = st[i];
|
||||||
|
|
||||||
let mut niche_align = niche.value.align(dl);
|
let mut niche_align = niche.value.align(dl);
|
||||||
let abi = if offset.bytes() == 0 && niche.value.size(dl) == size {
|
let abi = if offset.bytes() == 0 && niche.value.size(dl) == size {
|
||||||
|
@ -1504,6 +1504,7 @@ impl<'a, 'tcx> LayoutDetails {
|
||||||
Abi::Aggregate { sized: true }
|
Abi::Aggregate { sized: true }
|
||||||
};
|
};
|
||||||
align = align.max(niche_align);
|
align = align.max(niche_align);
|
||||||
|
size = size.abi_align(align);
|
||||||
|
|
||||||
return Ok(tcx.intern_layout(LayoutDetails {
|
return Ok(tcx.intern_layout(LayoutDetails {
|
||||||
variants: Variants::NicheFilling {
|
variants: Variants::NicheFilling {
|
||||||
|
|
|
@ -16,14 +16,21 @@ impl<T: Copy> Clone for Packed<T> {
|
||||||
fn clone(&self) -> Self { *self }
|
fn clone(&self) -> Self { *self }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn sanity_check_size<T: Copy>(one: T) {
|
||||||
let one = (Some(Packed((&(), 0))), true);
|
|
||||||
let two = [one, one];
|
let two = [one, one];
|
||||||
let stride = (&two[1] as *const _ as usize) - (&two[0] as *const _ as usize);
|
let stride = (&two[1] as *const _ as usize) - (&two[0] as *const _ as usize);
|
||||||
|
assert_eq!(stride, std::mem::size_of_val(&one));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
// This can fail if rustc and LLVM disagree on the size of a type.
|
// This can fail if rustc and LLVM disagree on the size of a type.
|
||||||
// In this case, `Option<Packed<(&(), u32)>>` was erronously not
|
// In this case, `Option<Packed<(&(), u32)>>` was erronously not
|
||||||
// marked as packed despite needing alignment `1` and containing
|
// marked as packed despite needing alignment `1` and containing
|
||||||
// its `&()` discriminant, which has alignment larger than `1`.
|
// its `&()` discriminant, which has alignment larger than `1`.
|
||||||
assert_eq!(stride, std::mem::size_of_val(&one));
|
sanity_check_size((Some(Packed((&(), 0))), true));
|
||||||
|
|
||||||
|
// In #46769, `Option<(Packed<&()>, bool)>` was found to have
|
||||||
|
// pointer alignment, without actually being aligned in size.
|
||||||
|
// E.g. on 64-bit platforms, it had alignment `8` but size `9`.
|
||||||
|
sanity_check_size(Some((Packed(&()), true)));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue