Skip to content

Commit

Permalink
Auto merge of #46808 - eddyb:issue-46769-quick, r=arielb1
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
bors committed Dec 18, 2017
2 parents b058dc0 + 087f1c2 commit e7db42f
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 4 deletions.
3 changes: 2 additions & 1 deletion src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ impl<'a, 'tcx> LayoutDetails {
}).collect::<Result<Vec<_>, _>>()?;

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 abi = if offset.bytes() == 0 && niche.value.size(dl) == size {
Expand All @@ -1504,6 +1504,7 @@ impl<'a, 'tcx> LayoutDetails {
Abi::Aggregate { sized: true }
};
align = align.max(niche_align);
size = size.abi_align(align);

return Ok(tcx.intern_layout(LayoutDetails {
variants: Variants::NicheFilling {
Expand Down
13 changes: 10 additions & 3 deletions src/test/run-pass/packed-struct-optimized-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,21 @@ impl<T: Copy> Clone for Packed<T> {
fn clone(&self) -> Self { *self }
}

fn main() {
let one = (Some(Packed((&(), 0))), true);
fn sanity_check_size<T: Copy>(one: T) {
let two = [one, one];
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.
// In this case, `Option<Packed<(&(), u32)>>` was erronously not
// marked as packed despite needing alignment `1` and containing
// 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)));
}

0 comments on commit e7db42f

Please sign in to comment.