@@ -1622,7 +1622,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
1622
1622
}
1623
1623
1624
1624
// 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) | {
1626
1626
let mut st = univariant_uninterned ( & field_layouts,
1627
1627
& def. repr , StructKind :: Prefixed ( min_ity. size ( ) , prefix_align) ) ?;
1628
1628
st. variants = Variants :: Single { index : i } ;
@@ -1683,7 +1683,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
1683
1683
// Patch up the variants' first few fields.
1684
1684
let old_ity_size = min_ity. size ( ) ;
1685
1685
let new_ity_size = ity. size ( ) ;
1686
- for variant in & mut variants {
1686
+ for variant in & mut layout_variants {
1687
1687
if variant. abi == Abi :: Uninhabited {
1688
1688
continue ;
1689
1689
}
@@ -1710,15 +1710,80 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
1710
1710
value : Int ( ity, signed) ,
1711
1711
valid_range : ( min as u128 & tag_mask) ..=( max as u128 & tag_mask) ,
1712
1712
} ;
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
+ }
1718
1783
tcx. intern_layout ( LayoutDetails {
1719
1784
variants : Variants :: Tagged {
1720
1785
discr : tag,
1721
- variants
1786
+ variants : layout_variants ,
1722
1787
} ,
1723
1788
fields : FieldPlacement :: Arbitrary {
1724
1789
offsets : vec ! [ Size :: from_bytes( 0 ) ] ,
0 commit comments