@@ -1622,7 +1622,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
16221622 }
16231623
16241624 // Create the set of structs that represent each variant.
1625- let mut variants = variants. into_iter ( ) . enumerate ( ) . map ( |( i, field_layouts) | {
1625+ let mut layout_variants = variants. iter ( ) . enumerate ( ) . map ( |( i, field_layouts) | {
16261626 let mut st = univariant_uninterned ( & field_layouts,
16271627 & def. repr , StructKind :: Prefixed ( min_ity. size ( ) , prefix_align) ) ?;
16281628 st. variants = Variants :: Single { index : i } ;
@@ -1683,7 +1683,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
16831683 // Patch up the variants' first few fields.
16841684 let old_ity_size = min_ity. size ( ) ;
16851685 let new_ity_size = ity. size ( ) ;
1686- for variant in & mut variants {
1686+ for variant in & mut layout_variants {
16871687 if variant. abi == Abi :: Uninhabited {
16881688 continue ;
16891689 }
@@ -1710,15 +1710,80 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
17101710 value : Int ( ity, signed) ,
17111711 valid_range : ( min as u128 & tag_mask) ..=( max as u128 & tag_mask) ,
17121712 } ;
1713- let abi = if tag. value . size ( dl) == size {
1714- Abi :: Scalar ( tag. clone ( ) )
1715- } else {
1716- Abi :: Aggregate { sized : true }
1717- } ;
1713+ let mut abi = Abi :: Aggregate { sized : true } ;
1714+ if tag. value . size ( dl) == size {
1715+ abi = Abi :: Scalar ( tag. clone ( ) ) ;
1716+ } else if !tag. is_bool ( ) {
1717+ // HACK(nox): Blindly using ScalarPair for all tagged enums
1718+ // where applicable leads to Option<u8> being handled as {i1, i8},
1719+ // which later confuses SROA and some loop optimisations,
1720+ // ultimately leading to the repeat-trusted-len test
1721+ // failing. We make the trade-off of using ScalarPair only
1722+ // for types where the tag isn't a boolean.
1723+ let mut common_prim = None ;
1724+ for ( field_layouts, layout_variant) in variants. iter ( ) . zip ( & layout_variants) {
1725+ let offsets = match layout_variant. fields {
1726+ FieldPlacement :: Arbitrary { ref offsets, .. } => offsets,
1727+ _ => bug ! ( ) ,
1728+ } ;
1729+ let mut fields = field_layouts
1730+ . iter ( )
1731+ . zip ( offsets)
1732+ . filter ( |p| !p. 0 . is_zst ( ) ) ;
1733+ let ( field, offset) = match ( fields. next ( ) , fields. next ( ) ) {
1734+ ( None , None ) => continue ,
1735+ ( Some ( pair) , None ) => pair,
1736+ _ => {
1737+ common_prim = None ;
1738+ break ;
1739+ }
1740+ } ;
1741+ let prim = match field. details . abi {
1742+ Abi :: Scalar ( ref scalar) => scalar. value ,
1743+ _ => {
1744+ common_prim = None ;
1745+ break ;
1746+ }
1747+ } ;
1748+ if let Some ( pair) = common_prim {
1749+ // This is pretty conservative. We could go fancier
1750+ // by conflating things like i32 and u32, or even
1751+ // realising that (u8, u8) could just cohabit with
1752+ // u16 or even u32.
1753+ if pair != ( prim, offset) {
1754+ common_prim = None ;
1755+ break ;
1756+ }
1757+ } else {
1758+ common_prim = Some ( ( prim, offset) ) ;
1759+ }
1760+ }
1761+ if let Some ( ( prim, offset) ) = common_prim {
1762+ let pair = scalar_pair ( tag. clone ( ) , scalar_unit ( prim) ) ;
1763+ let pair_offsets = match pair. fields {
1764+ FieldPlacement :: Arbitrary {
1765+ ref offsets,
1766+ ref memory_index
1767+ } => {
1768+ assert_eq ! ( memory_index, & [ 0 , 1 ] ) ;
1769+ offsets
1770+ }
1771+ _ => bug ! ( )
1772+ } ;
1773+ if pair_offsets[ 0 ] == Size :: from_bytes ( 0 ) &&
1774+ pair_offsets[ 1 ] == * offset &&
1775+ align == pair. align &&
1776+ size == pair. size {
1777+ // We can use `ScalarPair` only when it matches our
1778+ // already computed layout (including `#[repr(C)]`).
1779+ abi = pair. abi ;
1780+ }
1781+ }
1782+ }
17181783 tcx. intern_layout ( LayoutDetails {
17191784 variants : Variants :: Tagged {
17201785 discr : tag,
1721- variants
1786+ variants : layout_variants ,
17221787 } ,
17231788 fields : FieldPlacement :: Arbitrary {
17241789 offsets : vec ! [ Size :: from_bytes( 0 ) ] ,
0 commit comments