mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-20 02:43:45 +00:00
Rollup merge of #46809 - eddyb:issue-46769-optimal, r=arielb1
rustc: do not raise the alignment of optimized enums to the niche's alignment. This is the improved fix for #46769 that does not increase the size of any types (see also #46808).
This commit is contained in:
commit
d4981e9742
@ -1484,27 +1484,25 @@ impl<'a, 'tcx> LayoutDetails {
|
|||||||
Some(niche) => niche,
|
Some(niche) => niche,
|
||||||
None => continue
|
None => continue
|
||||||
};
|
};
|
||||||
|
let mut align = dl.aggregate_align;
|
||||||
let st = variants.iter().enumerate().map(|(j, v)| {
|
let st = variants.iter().enumerate().map(|(j, v)| {
|
||||||
let mut st = univariant_uninterned(v,
|
let mut st = univariant_uninterned(v,
|
||||||
&def.repr, StructKind::AlwaysSized)?;
|
&def.repr, StructKind::AlwaysSized)?;
|
||||||
st.variants = Variants::Single { index: j };
|
st.variants = Variants::Single { index: j };
|
||||||
|
|
||||||
|
align = align.max(st.align);
|
||||||
|
|
||||||
Ok(st)
|
Ok(st)
|
||||||
}).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 { mut size, mut align, .. } = st[i];
|
let size = st[i].size;
|
||||||
|
|
||||||
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 {
|
||||||
Abi::Scalar(niche.clone())
|
Abi::Scalar(niche.clone())
|
||||||
} else {
|
} else {
|
||||||
if offset.abi_align(niche_align) != offset {
|
|
||||||
niche_align = dl.i8_align;
|
|
||||||
}
|
|
||||||
Abi::Aggregate { sized: true }
|
Abi::Aggregate { sized: true }
|
||||||
};
|
};
|
||||||
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 {
|
||||||
|
@ -19,7 +19,9 @@ impl<T: Copy> Clone for Packed<T> {
|
|||||||
fn sanity_check_size<T: Copy>(one: T) {
|
fn sanity_check_size<T: Copy>(one: T) {
|
||||||
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));
|
let (size, align) = (std::mem::size_of::<T>(), std::mem::align_of::<T>());
|
||||||
|
assert_eq!(stride, size);
|
||||||
|
assert_eq!(size % align, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -32,5 +34,12 @@ fn main() {
|
|||||||
// In #46769, `Option<(Packed<&()>, bool)>` was found to have
|
// In #46769, `Option<(Packed<&()>, bool)>` was found to have
|
||||||
// pointer alignment, without actually being aligned in size.
|
// pointer alignment, without actually being aligned in size.
|
||||||
// E.g. on 64-bit platforms, it had alignment `8` but size `9`.
|
// E.g. on 64-bit platforms, it had alignment `8` but size `9`.
|
||||||
sanity_check_size(Some((Packed(&()), true)));
|
type PackedRefAndBool<'a> = (Packed<&'a ()>, bool);
|
||||||
|
sanity_check_size::<Option<PackedRefAndBool>>(Some((Packed(&()), true)));
|
||||||
|
|
||||||
|
// Make sure we don't pay for the enum optimization in size,
|
||||||
|
// e.g. we shouldn't need extra padding after the packed data.
|
||||||
|
assert_eq!(std::mem::align_of::<Option<PackedRefAndBool>>(), 1);
|
||||||
|
assert_eq!(std::mem::size_of::<Option<PackedRefAndBool>>(),
|
||||||
|
std::mem::size_of::<PackedRefAndBool>());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user