@@ -942,8 +942,8 @@ impl<'a, 'tcx> LayoutDetails {
942
942
AlwaysSized ,
943
943
/// A univariant, the last field of which may be coerced to unsized.
944
944
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 ) ,
947
947
}
948
948
let univariant_uninterned = |fields : & [ TyLayout ] , repr : & ReprOptions , kind| {
949
949
let packed = repr. packed ( ) ;
@@ -962,14 +962,11 @@ impl<'a, 'tcx> LayoutDetails {
962
962
let mut inverse_memory_index: Vec < u32 > = ( 0 ..fields. len ( ) as u32 ) . collect ( ) ;
963
963
964
964
// 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
+
973
970
if optimize {
974
971
let end = if let StructKind :: MaybeUnsized = kind {
975
972
fields. len ( ) - 1
@@ -987,7 +984,7 @@ impl<'a, 'tcx> LayoutDetails {
987
984
( !f. is_zst ( ) , cmp:: Reverse ( f. align . abi ( ) ) )
988
985
} )
989
986
}
990
- StructKind :: EnumVariant ( _ ) => {
987
+ StructKind :: Prefixed ( .. ) => {
991
988
optimizing. sort_by_key ( |& x| fields[ x as usize ] . align . abi ( ) ) ;
992
989
}
993
990
}
@@ -1001,12 +998,11 @@ impl<'a, 'tcx> LayoutDetails {
1001
998
1002
999
let mut offset = Size :: from_bytes ( 0 ) ;
1003
1000
1004
- if let StructKind :: EnumVariant ( discr) = kind {
1005
- offset = discr. size ( ) ;
1001
+ if let StructKind :: Prefixed ( prefix_size, prefix_align) = kind {
1006
1002
if !packed {
1007
- let discr_align = discr. align ( dl) ;
1008
- align = align. max ( discr_align) ;
1003
+ align = align. max ( prefix_align) ;
1009
1004
}
1005
+ offset = prefix_size. abi_align ( prefix_align) ;
1010
1006
}
1011
1007
1012
1008
for & i in & inverse_memory_index {
@@ -1558,10 +1554,24 @@ impl<'a, 'tcx> LayoutDetails {
1558
1554
let mut start_align = Align :: from_bytes ( 256 , 256 ) . unwrap ( ) ;
1559
1555
assert_eq ! ( Integer :: for_abi_align( dl, start_align) , None ) ;
1560
1556
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
+
1561
1571
// Create the set of structs that represent each variant.
1562
1572
let mut variants = variants. into_iter ( ) . enumerate ( ) . map ( |( i, field_layouts) | {
1563
1573
let mut st = univariant_uninterned ( & field_layouts,
1564
- & def. repr , StructKind :: EnumVariant ( min_ity) ) ?;
1574
+ & def. repr , StructKind :: Prefixed ( min_ity. size ( ) , prefix_align ) ) ?;
1565
1575
st. variants = Variants :: Single { index : i } ;
1566
1576
// Find the first field we can't move later
1567
1577
// to make room for a larger discriminant.
0 commit comments