Skip to content

Commit 8293fe9

Browse files
committed
Implement the special repr(C)-non-clike-enum layout
1 parent f50fd07 commit 8293fe9

File tree

1 file changed

+26
-16
lines changed

1 file changed

+26
-16
lines changed

src/librustc/ty/layout.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -942,8 +942,8 @@ impl<'a, 'tcx> LayoutDetails {
942942
AlwaysSized,
943943
/// A univariant, the last field of which may be coerced to unsized.
944944
MaybeUnsized,
945-
/// A univariant, but part of an enum.
946-
EnumVariant(Integer),
945+
/// A univariant, but with a prefix of an arbitrary size & alignment (e.g. enum tag).
946+
Prefixed(Size, Align),
947947
}
948948
let univariant_uninterned = |fields: &[TyLayout], repr: &ReprOptions, kind| {
949949
let packed = repr.packed();
@@ -962,14 +962,11 @@ impl<'a, 'tcx> LayoutDetails {
962962
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
963963

964964
// Anything with repr(C) or repr(packed) doesn't optimize.
965-
let optimize = match kind {
966-
StructKind::AlwaysSized |
967-
StructKind::MaybeUnsized |
968-
StructKind::EnumVariant(I8) => {
969-
(repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty()
970-
}
971-
StructKind::EnumVariant(_) => false
972-
};
965+
let mut optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
966+
if let StructKind::Prefixed(_, align) = kind {
967+
optimize &= align.abi() == 1;
968+
}
969+
973970
if optimize {
974971
let end = if let StructKind::MaybeUnsized = kind {
975972
fields.len() - 1
@@ -987,7 +984,7 @@ impl<'a, 'tcx> LayoutDetails {
987984
(!f.is_zst(), cmp::Reverse(f.align.abi()))
988985
})
989986
}
990-
StructKind::EnumVariant(_) => {
987+
StructKind::Prefixed(..) => {
991988
optimizing.sort_by_key(|&x| fields[x as usize].align.abi());
992989
}
993990
}
@@ -1001,12 +998,11 @@ impl<'a, 'tcx> LayoutDetails {
1001998

1002999
let mut offset = Size::from_bytes(0);
10031000

1004-
if let StructKind::EnumVariant(discr) = kind {
1005-
offset = discr.size();
1001+
if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
10061002
if !packed {
1007-
let discr_align = discr.align(dl);
1008-
align = align.max(discr_align);
1003+
align = align.max(prefix_align);
10091004
}
1005+
offset = prefix_size.abi_align(prefix_align);
10101006
}
10111007

10121008
for &i in &inverse_memory_index {
@@ -1558,10 +1554,24 @@ impl<'a, 'tcx> LayoutDetails {
15581554
let mut start_align = Align::from_bytes(256, 256).unwrap();
15591555
assert_eq!(Integer::for_abi_align(dl, start_align), None);
15601556

1557+
// repr(C) on an enum tells us to make a (tag, union) layout,
1558+
// so we need to grow the prefix alignment to be at least
1559+
// the alignment of the union. (This value is used both for
1560+
// determining the alignment of the overall enum, and the
1561+
// determining the alignment of the payload after the tag.)
1562+
let mut prefix_align = min_ity.align(dl);
1563+
if def.repr.c() {
1564+
for fields in &variants {
1565+
for field in fields {
1566+
prefix_align = prefix_align.max(field.align);
1567+
}
1568+
}
1569+
}
1570+
15611571
// Create the set of structs that represent each variant.
15621572
let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| {
15631573
let mut st = univariant_uninterned(&field_layouts,
1564-
&def.repr, StructKind::EnumVariant(min_ity))?;
1574+
&def.repr, StructKind::Prefixed(min_ity.size(), prefix_align))?;
15651575
st.variants = Variants::Single { index: i };
15661576
// Find the first field we can't move later
15671577
// to make room for a larger discriminant.

0 commit comments

Comments
 (0)