@@ -898,56 +898,118 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
898
898
if !def. repr . inhibit_enum_layout_opt ( ) && no_explicit_discriminants {
899
899
let mut dataful_variant = None ;
900
900
let mut niche_variants = VariantIdx :: MAX ..=VariantIdx :: new ( 0 ) ;
901
+ let mut max_size = Size :: ZERO ;
902
+ let mut second_max_size = Size :: ZERO ;
903
+
904
+ // The size computations below assume that the padding is minimum.
905
+ // This is the case when fields are re-ordered.
906
+ let struct_reordering_opt = !def. repr . inhibit_struct_field_reordering_opt ( ) ;
907
+ if struct_reordering_opt {
908
+ let mut extend_niche_range = |d| {
909
+ niche_variants =
910
+ * niche_variants. start ( ) . min ( & d) ..=* niche_variants. end ( ) . max ( & d) ;
911
+ } ;
912
+ let mut align = dl. aggregate_align ;
901
913
902
- // Find one non-ZST variant.
903
- ' variants: for ( v, fields) in variants. iter_enumerated ( ) {
904
- if absent ( fields) {
905
- continue ' variants;
914
+ // Find the largest and second largest variant.
915
+ for ( v, fields) in variants. iter_enumerated ( ) {
916
+ if absent ( fields) {
917
+ continue ;
918
+ }
919
+ let mut size = Size :: ZERO ;
920
+ for & f in fields {
921
+ align = align. max ( f. align ) ;
922
+ size += f. size ;
923
+ }
924
+ if size > max_size {
925
+ second_max_size = max_size;
926
+ max_size = size;
927
+ if let Some ( d) = dataful_variant {
928
+ extend_niche_range ( d) ;
929
+ }
930
+ dataful_variant = Some ( v) ;
931
+ } else if size == max_size {
932
+ if let Some ( d) = dataful_variant {
933
+ extend_niche_range ( d) ;
934
+ }
935
+ dataful_variant = None ;
936
+ extend_niche_range ( v) ;
937
+ } else {
938
+ second_max_size = second_max_size. max ( size) ;
939
+ extend_niche_range ( v) ;
940
+ }
906
941
}
907
- for f in fields {
908
- if !f. is_zst ( ) {
909
- if dataful_variant. is_none ( ) {
910
- dataful_variant = Some ( v) ;
911
- continue ' variants;
912
- } else {
913
- dataful_variant = None ;
914
- break ' variants;
942
+ if !max_size. is_aligned ( align. abi ) {
943
+ // Don't perform niche optimisation if there is padding anyway
944
+ dataful_variant = None ;
945
+ }
946
+ } else {
947
+ // Find one non-ZST variant.
948
+ ' variants: for ( v, fields) in variants. iter_enumerated ( ) {
949
+ if absent ( fields) {
950
+ continue ' variants;
951
+ }
952
+ for f in fields {
953
+ if !f. is_zst ( ) {
954
+ if dataful_variant. is_none ( ) {
955
+ dataful_variant = Some ( v) ;
956
+ continue ' variants;
957
+ } else {
958
+ dataful_variant = None ;
959
+ break ' variants;
960
+ }
915
961
}
962
+ niche_variants = * niche_variants. start ( ) . min ( & v) ..=v
916
963
}
917
964
}
918
- niche_variants = * niche_variants. start ( ) . min ( & v) ..=v;
919
965
}
920
966
921
967
if niche_variants. start ( ) > niche_variants. end ( ) {
922
968
dataful_variant = None ;
923
969
}
924
970
925
- if let Some ( i ) = dataful_variant {
971
+ if let Some ( dataful_variant ) = dataful_variant {
926
972
let count = ( niche_variants. end ( ) . as_u32 ( )
927
973
- niche_variants. start ( ) . as_u32 ( )
928
974
+ 1 ) as u128 ;
929
975
930
976
// Find the field with the largest niche
931
- let niche_candidate = variants[ i ]
977
+ let niche_candidate = variants[ dataful_variant ]
932
978
. iter ( )
933
979
. enumerate ( )
934
980
. filter_map ( |( j, & field) | Some ( ( j, field. largest_niche . as_ref ( ) ?) ) )
935
- . max_by_key ( |( _, niche) | niche. available ( dl) ) ;
981
+ . max_by_key ( |( _, n) | ( n. available ( dl) , cmp:: Reverse ( n. offset ) ) )
982
+ . and_then ( |( field_index, niche) | {
983
+ // make sure there is enough room for the other variants
984
+ if struct_reordering_opt
985
+ && max_size - ( niche. offset + niche. scalar . value . size ( dl) )
986
+ < second_max_size
987
+ {
988
+ return None ;
989
+ }
990
+ Some ( ( field_index, niche, niche. reserve ( self , count) ?) )
991
+ } ) ;
936
992
937
993
if let Some ( ( field_index, niche, ( niche_start, niche_scalar) ) ) =
938
- niche_candidate. and_then ( |( field_index, niche) | {
939
- Some ( ( field_index, niche, niche. reserve ( self , count) ?) )
940
- } )
994
+ niche_candidate
941
995
{
942
996
let mut align = dl. aggregate_align ;
997
+ let prefix = niche. offset + niche. scalar . value . size ( dl) ;
943
998
let st = variants
944
999
. iter_enumerated ( )
945
1000
. map ( |( j, v) | {
946
1001
let mut st = self . univariant_uninterned (
947
1002
ty,
948
1003
v,
949
1004
& def. repr ,
950
- StructKind :: AlwaysSized ,
1005
+ if j == dataful_variant || second_max_size == Size :: ZERO {
1006
+ StructKind :: AlwaysSized
1007
+ } else {
1008
+ StructKind :: Prefixed (
1009
+ prefix,
1010
+ Align :: from_bytes ( 1 ) . unwrap ( ) ,
1011
+ )
1012
+ } ,
951
1013
) ?;
952
1014
st. variants = Variants :: Single { index : j } ;
953
1015
@@ -957,21 +1019,30 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
957
1019
} )
958
1020
. collect :: < Result < IndexVec < VariantIdx , _ > , _ > > ( ) ?;
959
1021
960
- let offset = st[ i] . fields . offset ( field_index) + niche. offset ;
961
- let size = st[ i] . size ;
1022
+ let niche_offset = if struct_reordering_opt {
1023
+ debug_assert_eq ! (
1024
+ st[ dataful_variant] . fields. offset( field_index) ,
1025
+ Size :: ZERO
1026
+ ) ;
1027
+ niche. offset
1028
+ } else {
1029
+ st[ dataful_variant] . fields . offset ( field_index) + niche. offset
1030
+ } ;
1031
+ let size = st[ dataful_variant] . size ;
1032
+ debug_assert ! ( st. iter( ) . all( |v| { v. size <= size } ) ) ;
962
1033
963
1034
let abi = if st. iter ( ) . all ( |v| v. abi . is_uninhabited ( ) ) {
964
1035
Abi :: Uninhabited
965
- } else {
966
- match st[ i ] . abi {
1036
+ } else if second_max_size == Size :: ZERO {
1037
+ match st[ dataful_variant ] . abi {
967
1038
Abi :: Scalar ( _) => Abi :: Scalar ( niche_scalar. clone ( ) ) ,
968
1039
Abi :: ScalarPair ( ref first, ref second) => {
969
1040
// We need to use scalar_unit to reset the
970
1041
// valid range to the maximal one for that
971
1042
// primitive, because only the niche is
972
1043
// guaranteed to be initialised, not the
973
1044
// other primitive.
974
- if offset . bytes ( ) == 0 {
1045
+ if niche_offset . bytes ( ) == 0 {
975
1046
Abi :: ScalarPair (
976
1047
niche_scalar. clone ( ) ,
977
1048
scalar_unit ( second. value ) ,
@@ -985,24 +1056,26 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
985
1056
}
986
1057
_ => Abi :: Aggregate { sized : true } ,
987
1058
}
1059
+ } else {
1060
+ Abi :: Aggregate { sized : true }
988
1061
} ;
989
1062
990
1063
let largest_niche =
991
- Niche :: from_scalar ( dl, offset , niche_scalar. clone ( ) ) ;
1064
+ Niche :: from_scalar ( dl, niche_offset , niche_scalar. clone ( ) ) ;
992
1065
993
1066
return Ok ( tcx. intern_layout ( Layout {
994
1067
variants : Variants :: Multiple {
995
1068
discr : niche_scalar,
996
1069
discr_kind : DiscriminantKind :: Niche {
997
- dataful_variant : i ,
1070
+ dataful_variant,
998
1071
niche_variants,
999
1072
niche_start,
1000
1073
} ,
1001
1074
discr_index : 0 ,
1002
1075
variants : st,
1003
1076
} ,
1004
1077
fields : FieldsShape :: Arbitrary {
1005
- offsets : vec ! [ offset ] ,
1078
+ offsets : vec ! [ niche_offset ] ,
1006
1079
memory_index : vec ! [ 0 ] ,
1007
1080
} ,
1008
1081
abi,
0 commit comments