@@ -755,6 +755,7 @@ impl FieldPlacement {
755
755
/// in terms of categories of C types there are ABI rules for.
756
756
#[ derive( Clone , PartialEq , Eq , Hash , Debug ) ]
757
757
pub enum Abi {
758
+ Uninhabited ,
758
759
Scalar ( Scalar ) ,
759
760
Vector ,
760
761
Aggregate {
@@ -768,15 +769,15 @@ impl Abi {
768
769
/// Returns true if the layout corresponds to an unsized type.
769
770
pub fn is_unsized ( & self ) -> bool {
770
771
match * self {
771
- Abi :: Scalar ( _) | Abi :: Vector => false ,
772
+ Abi :: Uninhabited | Abi :: Scalar ( _) | Abi :: Vector => false ,
772
773
Abi :: Aggregate { sized, .. } => !sized
773
774
}
774
775
}
775
776
776
777
/// Returns true if the fields of the layout are packed.
777
778
pub fn is_packed ( & self ) -> bool {
778
779
match * self {
779
- Abi :: Scalar ( _) | Abi :: Vector => false ,
780
+ Abi :: Uninhabited | Abi :: Scalar ( _) | Abi :: Vector => false ,
780
781
Abi :: Aggregate { packed, .. } => packed
781
782
}
782
783
}
@@ -807,6 +808,7 @@ pub enum Variants {
807
808
/// `Some` is the identity function (with a non-null reference).
808
809
NicheFilling {
809
810
dataful_variant : usize ,
811
+ niche_variant : usize ,
810
812
niche : Scalar ,
811
813
niche_value : u128 ,
812
814
variants : Vec < CachedLayout > ,
@@ -855,6 +857,18 @@ impl CachedLayout {
855
857
primitive_align : align
856
858
}
857
859
}
860
+
861
+ fn uninhabited ( field_count : usize ) -> Self {
862
+ let align = Align :: from_bytes ( 1 , 1 ) . unwrap ( ) ;
863
+ CachedLayout {
864
+ variants : Variants :: Single { index : 0 } ,
865
+ fields : FieldPlacement :: Union ( field_count) ,
866
+ abi : Abi :: Uninhabited ,
867
+ align,
868
+ primitive_align : align,
869
+ size : Size :: from_bytes ( 0 )
870
+ }
871
+ }
858
872
}
859
873
860
874
fn layout_raw < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
@@ -915,13 +929,14 @@ impl<'a, 'tcx> CachedLayout {
915
929
bug ! ( "struct cannot be packed and aligned" ) ;
916
930
}
917
931
918
- let mut align = if packed {
932
+ let base_align = if packed {
919
933
dl. i8_align
920
934
} else {
921
935
dl. aggregate_align
922
936
} ;
923
937
924
- let mut primitive_align = align;
938
+ let mut align = base_align;
939
+ let mut primitive_align = base_align;
925
940
let mut sized = true ;
926
941
927
942
// Anything with repr(C) or repr(packed) doesn't optimize.
@@ -978,13 +993,17 @@ impl<'a, 'tcx> CachedLayout {
978
993
}
979
994
}
980
995
981
- for i in inverse_memory_index. iter ( ) {
982
- let field = fields[ * i as usize ] ;
996
+ for & i in & inverse_memory_index {
997
+ let field = fields[ i as usize ] ;
983
998
if !sized {
984
999
bug ! ( "univariant: field #{} of `{}` comes after unsized field" ,
985
1000
offsets. len( ) , ty) ;
986
1001
}
987
1002
1003
+ if field. abi == Abi :: Uninhabited {
1004
+ return Ok ( CachedLayout :: uninhabited ( fields. len ( ) ) ) ;
1005
+ }
1006
+
988
1007
if field. is_unsized ( ) {
989
1008
sized = false ;
990
1009
}
@@ -997,7 +1016,7 @@ impl<'a, 'tcx> CachedLayout {
997
1016
}
998
1017
999
1018
debug ! ( "univariant offset: {:?} field: {:#?}" , offset, field) ;
1000
- offsets[ * i as usize ] = offset;
1019
+ offsets[ i as usize ] = offset;
1001
1020
1002
1021
offset = offset. checked_add ( field. size , dl)
1003
1022
. ok_or ( LayoutError :: SizeOverflow ( ty) ) ?;
@@ -1124,7 +1143,7 @@ impl<'a, 'tcx> CachedLayout {
1124
1143
1125
1144
// The never type.
1126
1145
ty:: TyNever => {
1127
- univariant ( & [ ] , & ReprOptions :: default ( ) , StructKind :: AlwaysSized ) ?
1146
+ tcx . intern_layout ( CachedLayout :: uninhabited ( 0 ) )
1128
1147
}
1129
1148
1130
1149
// Potentially-fat pointers.
@@ -1278,11 +1297,15 @@ impl<'a, 'tcx> CachedLayout {
1278
1297
} ) . collect :: < Result < Vec < _ > , _ > > ( )
1279
1298
} ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1280
1299
1281
- if variants. is_empty ( ) {
1282
- // Uninhabitable; represent as unit
1283
- // (Typechecking will reject discriminant-sizing attrs.)
1284
-
1285
- return univariant ( & [ ] , & def. repr , StructKind :: AlwaysSized ) ;
1300
+ let ( inh_first, inh_second, inh_third) = {
1301
+ let mut inh_variants = ( 0 ..variants. len ( ) ) . filter ( |& v| {
1302
+ variants[ v] . iter ( ) . all ( |f| f. abi != Abi :: Uninhabited )
1303
+ } ) ;
1304
+ ( inh_variants. next ( ) , inh_variants. next ( ) , inh_variants. next ( ) )
1305
+ } ;
1306
+ if inh_first. is_none ( ) {
1307
+ // Uninhabited because it has no variants, or only uninhabited ones.
1308
+ return Ok ( tcx. intern_layout ( CachedLayout :: uninhabited ( 0 ) ) ) ;
1286
1309
}
1287
1310
1288
1311
if def. is_union ( ) {
@@ -1329,49 +1352,58 @@ impl<'a, 'tcx> CachedLayout {
1329
1352
} ) ) ;
1330
1353
}
1331
1354
1332
- if !def. is_enum ( ) || ( variants. len ( ) == 1 &&
1333
- !def. repr . inhibit_enum_layout_opt ( ) &&
1334
- !variants[ 0 ] . is_empty ( ) ) {
1335
- // Struct, or union, or univariant enum equivalent to a struct.
1355
+ let is_struct = !def. is_enum ( ) ||
1356
+ // Only one variant is inhabited.
1357
+ ( inh_second. is_none ( ) &&
1358
+ // Representation optimizations are allowed.
1359
+ !def. repr . inhibit_enum_layout_opt ( ) &&
1360
+ // Inhabited variant either has data ...
1361
+ ( !variants[ inh_first. unwrap ( ) ] . is_empty ( ) ||
1362
+ // ... or there other, uninhabited, variants.
1363
+ variants. len ( ) > 1 ) ) ;
1364
+ if is_struct {
1365
+ // Struct, or univariant enum equivalent to a struct.
1336
1366
// (Typechecking will reject discriminant-sizing attrs.)
1337
1367
1338
- let kind = if def. is_enum ( ) || variants[ 0 ] . len ( ) == 0 {
1368
+ let v = inh_first. unwrap ( ) ;
1369
+ let kind = if def. is_enum ( ) || variants[ v] . len ( ) == 0 {
1339
1370
StructKind :: AlwaysSized
1340
1371
} else {
1341
1372
let param_env = tcx. param_env ( def. did ) ;
1342
- let last_field = def. variants [ 0 ] . fields . last ( ) . unwrap ( ) ;
1373
+ let last_field = def. variants [ v ] . fields . last ( ) . unwrap ( ) ;
1343
1374
let always_sized = tcx. type_of ( last_field. did )
1344
1375
. is_sized ( tcx, param_env, DUMMY_SP ) ;
1345
1376
if !always_sized { StructKind :: MaybeUnsized }
1346
1377
else { StructKind :: AlwaysSized }
1347
1378
} ;
1348
1379
1349
- return univariant ( & variants[ 0 ] , & def. repr , kind) ;
1380
+ let mut st = univariant_uninterned ( & variants[ v] , & def. repr , kind) ?;
1381
+ st. variants = Variants :: Single { index : v } ;
1382
+ return Ok ( tcx. intern_layout ( st) ) ;
1350
1383
}
1351
1384
1352
1385
let no_explicit_discriminants = def. variants . iter ( ) . enumerate ( )
1353
1386
. all ( |( i, v) | v. discr == ty:: VariantDiscr :: Relative ( i) ) ;
1354
1387
1355
- if variants . len ( ) == 2 &&
1388
+ if inh_second . is_some ( ) && inh_third . is_none ( ) &&
1356
1389
!def. repr . inhibit_enum_layout_opt ( ) &&
1357
1390
no_explicit_discriminants {
1358
1391
// Nullable pointer optimization
1359
- for i in 0 ..2 {
1360
- if !variants[ 1 - i] . iter ( ) . all ( |f| f. is_zst ( ) ) {
1392
+ let ( a, b) = ( inh_first. unwrap ( ) , inh_second. unwrap ( ) ) ;
1393
+ for & ( i, other) in & [ ( a, b) , ( b, a) ] {
1394
+ if !variants[ other] . iter ( ) . all ( |f| f. is_zst ( ) ) {
1361
1395
continue ;
1362
1396
}
1363
1397
1364
1398
for ( field_index, field) in variants[ i] . iter ( ) . enumerate ( ) {
1365
1399
if let Some ( ( offset, niche, niche_value) ) = field. find_niche ( cx) ? {
1366
- let mut st = vec ! [
1367
- univariant_uninterned( & variants[ 0 ] ,
1368
- & def. repr, StructKind :: AlwaysSized ) ?,
1369
- univariant_uninterned( & variants[ 1 ] ,
1370
- & def. repr, StructKind :: AlwaysSized ) ?
1371
- ] ;
1372
- for ( i, v) in st. iter_mut ( ) . enumerate ( ) {
1373
- v. variants = Variants :: Single { index : i } ;
1374
- }
1400
+ let st = variants. iter ( ) . enumerate ( ) . map ( |( j, v) | {
1401
+ let mut st = univariant_uninterned ( v,
1402
+ & def. repr , StructKind :: AlwaysSized ) ?;
1403
+ st. variants = Variants :: Single { index : j } ;
1404
+ Ok ( st)
1405
+ } ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1406
+
1375
1407
let offset = st[ i] . fields . offset ( field_index) + offset;
1376
1408
let CachedLayout {
1377
1409
size,
@@ -1400,6 +1432,7 @@ impl<'a, 'tcx> CachedLayout {
1400
1432
return Ok ( tcx. intern_layout ( CachedLayout {
1401
1433
variants : Variants :: NicheFilling {
1402
1434
dataful_variant : i,
1435
+ niche_variant : other,
1403
1436
niche,
1404
1437
niche_value,
1405
1438
variants : st,
@@ -1419,11 +1452,15 @@ impl<'a, 'tcx> CachedLayout {
1419
1452
}
1420
1453
1421
1454
let ( mut min, mut max) = ( i128:: max_value ( ) , i128:: min_value ( ) ) ;
1422
- for discr in def. discriminants ( tcx) {
1455
+ for ( i, discr) in def. discriminants ( tcx) . enumerate ( ) {
1456
+ if variants[ i] . iter ( ) . any ( |f| f. abi == Abi :: Uninhabited ) {
1457
+ continue ;
1458
+ }
1423
1459
let x = discr. to_u128_unchecked ( ) as i128 ;
1424
1460
if x < min { min = x; }
1425
1461
if x > max { max = x; }
1426
1462
}
1463
+ assert ! ( min <= max, "discriminant range is {}...{}" , min, max) ;
1427
1464
let ( min_ity, signed) = Integer :: repr_discr ( tcx, ty, & def. repr , min, max) ;
1428
1465
1429
1466
let mut align = dl. aggregate_align ;
@@ -1498,6 +1535,9 @@ impl<'a, 'tcx> CachedLayout {
1498
1535
let old_ity_size = min_ity. size ( ) ;
1499
1536
let new_ity_size = ity. size ( ) ;
1500
1537
for variant in & mut variants {
1538
+ if variant. abi == Abi :: Uninhabited {
1539
+ continue ;
1540
+ }
1501
1541
match variant. fields {
1502
1542
FieldPlacement :: Arbitrary { ref mut offsets, .. } => {
1503
1543
for i in offsets {
@@ -1663,16 +1703,11 @@ impl<'a, 'tcx> CachedLayout {
1663
1703
} ;
1664
1704
1665
1705
match layout. variants {
1666
- Variants :: Single { .. } => {
1667
- let variant_names = || {
1668
- adt_def. variants . iter ( ) . map ( |v|format ! ( "{}" , v. name) ) . collect :: < Vec < _ > > ( )
1669
- } ;
1670
- debug ! ( "print-type-size `{:#?}` variants: {:?}" ,
1671
- layout, variant_names( ) ) ;
1672
- assert ! ( adt_def. variants. len( ) <= 1 ,
1673
- "univariant with variants {:?}" , variant_names( ) ) ;
1674
- if adt_def. variants . len ( ) == 1 {
1675
- let variant_def = & adt_def. variants [ 0 ] ;
1706
+ Variants :: Single { index } => {
1707
+ debug ! ( "print-type-size `{:#?}` variant {}" ,
1708
+ layout, adt_def. variants[ index] . name) ;
1709
+ if !adt_def. variants . is_empty ( ) {
1710
+ let variant_def = & adt_def. variants [ index] ;
1676
1711
let fields: Vec < _ > =
1677
1712
variant_def. fields . iter ( ) . map ( |f| f. name ) . collect ( ) ;
1678
1713
record ( adt_kind. into ( ) ,
@@ -1697,7 +1732,7 @@ impl<'a, 'tcx> CachedLayout {
1697
1732
variant_def. fields . iter ( ) . map ( |f| f. name ) . collect ( ) ;
1698
1733
build_variant_info ( Some ( variant_def. name ) ,
1699
1734
& fields,
1700
- layout. for_variant ( i) )
1735
+ layout. for_variant ( cx , i) )
1701
1736
} )
1702
1737
. collect ( ) ;
1703
1738
record ( adt_kind. into ( ) , match layout. variants {
@@ -1989,15 +2024,35 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
1989
2024
}
1990
2025
1991
2026
impl < ' a , ' tcx > TyLayout < ' tcx > {
1992
- pub fn for_variant ( & self , variant_index : usize ) -> Self {
2027
+ pub fn for_variant < C > ( & self , cx : C , variant_index : usize ) -> Self
2028
+ where C : LayoutOf < Ty < ' tcx > > + HasTyCtxt < ' tcx > ,
2029
+ C :: TyLayout : MaybeResult < TyLayout < ' tcx > >
2030
+ {
1993
2031
let cached = match self . variants {
1994
- Variants :: Single { .. } => self . cached ,
2032
+ Variants :: Single { index } if index == variant_index => self . cached ,
2033
+
2034
+ Variants :: Single { index } => {
2035
+ // Deny calling for_variant more than once for non-Single enums.
2036
+ cx. layout_of ( self . ty ) . map_same ( |layout| {
2037
+ assert_eq ! ( layout. variants, Variants :: Single { index } ) ;
2038
+ layout
2039
+ } ) ;
2040
+
2041
+ let fields = match self . ty . sty {
2042
+ ty:: TyAdt ( def, _) => def. variants [ variant_index] . fields . len ( ) ,
2043
+ _ => bug ! ( )
2044
+ } ;
2045
+ let mut cached = CachedLayout :: uninhabited ( fields) ;
2046
+ cached. variants = Variants :: Single { index : variant_index } ;
2047
+ cx. tcx ( ) . intern_layout ( cached)
2048
+ }
1995
2049
1996
2050
Variants :: NicheFilling { ref variants, .. } |
1997
2051
Variants :: Tagged { ref variants, .. } => {
1998
2052
& variants[ variant_index]
1999
2053
}
2000
2054
} ;
2055
+
2001
2056
assert_eq ! ( cached. variants, Variants :: Single { index: variant_index } ) ;
2002
2057
2003
2058
TyLayout {
@@ -2138,6 +2193,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2138
2193
/// Returns true if the type is a ZST and not unsized.
2139
2194
pub fn is_zst ( & self ) -> bool {
2140
2195
match self . abi {
2196
+ Abi :: Uninhabited => true ,
2141
2197
Abi :: Scalar ( _) => false ,
2142
2198
Abi :: Vector => self . size . bytes ( ) == 0 ,
2143
2199
Abi :: Aggregate { sized, .. } => sized && self . size . bytes ( ) == 0
@@ -2241,11 +2297,13 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
2241
2297
}
2242
2298
NicheFilling {
2243
2299
dataful_variant,
2300
+ niche_variant,
2244
2301
ref niche,
2245
2302
niche_value,
2246
2303
ref variants,
2247
2304
} => {
2248
2305
dataful_variant. hash_stable ( hcx, hasher) ;
2306
+ niche_variant. hash_stable ( hcx, hasher) ;
2249
2307
niche. hash_stable ( hcx, hasher) ;
2250
2308
niche_value. hash_stable ( hcx, hasher) ;
2251
2309
variants. hash_stable ( hcx, hasher) ;
@@ -2285,6 +2343,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
2285
2343
mem:: discriminant ( self ) . hash_stable ( hcx, hasher) ;
2286
2344
2287
2345
match * self {
2346
+ Uninhabited => { }
2288
2347
Scalar ( ref value) => {
2289
2348
value. hash_stable ( hcx, hasher) ;
2290
2349
}
0 commit comments