@@ -790,17 +790,18 @@ pub enum Variants {
790
790
variants : Vec < CachedLayout > ,
791
791
} ,
792
792
793
- /// Two cases distinguished by a niche: the case with discriminant
794
- /// `nndiscr` is represented by the struct `nonnull`, where field `0`
795
- /// is known to be nonnull due to its type; if that field is null, then
796
- /// it represents the other case, which is known to be zero sized .
793
+ /// Two cases distinguished by a niche (a value invalid for a type):
794
+ /// the variant `dataful_variant` contains a niche at an arbitrary
795
+ /// offset (field 0 of the enum), which is set to `niche_value`
796
+ /// for the other variant .
797
797
///
798
- /// For example, `std::option:: Option` instantiated at a safe pointer type
799
- /// is represented such that `None` is a null pointer and `Some` is the
800
- /// identity function.
798
+ /// For example, `Option<(usize, &T)>` is represented such that
799
+ /// `None` has a null pointer for the second tuple field, and
800
+ /// `Some` is the identity function (with a non-null reference) .
801
801
NicheFilling {
802
- nndiscr : u64 ,
803
- discr : Primitive ,
802
+ dataful_variant : usize ,
803
+ niche : Primitive ,
804
+ niche_value : u128 ,
804
805
variants : Vec < CachedLayout > ,
805
806
}
806
807
}
@@ -1323,7 +1324,7 @@ impl<'a, 'tcx> CachedLayout {
1323
1324
}
1324
1325
1325
1326
for ( field_index, field) in variants[ i] . iter ( ) . enumerate ( ) {
1326
- if let Some ( ( offset, discr ) ) = field. non_zero_field ( cx) ? {
1327
+ if let Some ( ( offset, niche , niche_value ) ) = field. find_niche ( cx) ? {
1327
1328
let mut st = vec ! [
1328
1329
univariant_uninterned( & variants[ 0 ] ,
1329
1330
& def. repr, StructKind :: AlwaysSized ) ?,
@@ -1342,23 +1343,23 @@ impl<'a, 'tcx> CachedLayout {
1342
1343
..
1343
1344
} = st[ i] ;
1344
1345
1345
- let mut discr_align = discr . align ( dl) ;
1346
- if offset. bytes ( ) == 0 && discr . size ( dl) == size {
1347
- abi = Abi :: Scalar ( discr ) ;
1346
+ let mut niche_align = niche . align ( dl) ;
1347
+ if offset. bytes ( ) == 0 && niche . size ( dl) == size {
1348
+ abi = Abi :: Scalar ( niche ) ;
1348
1349
} else if let Abi :: Aggregate { ref mut packed, .. } = abi {
1349
- if offset. abi_align ( discr_align ) != offset {
1350
+ if offset. abi_align ( niche_align ) != offset {
1350
1351
* packed = true ;
1351
- discr_align = dl. i8_align ;
1352
+ niche_align = dl. i8_align ;
1352
1353
}
1353
1354
}
1354
- align = align. max ( discr_align ) ;
1355
- primitive_align = primitive_align. max ( discr_align ) ;
1355
+ align = align. max ( niche_align ) ;
1356
+ primitive_align = primitive_align. max ( niche_align ) ;
1356
1357
1357
1358
return Ok ( tcx. intern_layout ( CachedLayout {
1358
1359
variants : Variants :: NicheFilling {
1359
- nndiscr : i as u64 ,
1360
-
1361
- discr ,
1360
+ dataful_variant : i,
1361
+ niche ,
1362
+ niche_value ,
1362
1363
variants : st,
1363
1364
} ,
1364
1365
fields : FieldPlacement :: Arbitrary {
@@ -2048,7 +2049,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2048
2049
2049
2050
// Discriminant field for enums (where applicable).
2050
2051
Variants :: Tagged { discr, .. } |
2051
- Variants :: NicheFilling { discr, .. } => {
2052
+ Variants :: NicheFilling { niche : discr, .. } => {
2052
2053
return cx. layout_of ( [ discr. to_ty ( tcx) ] [ i] ) ;
2053
2054
}
2054
2055
}
@@ -2084,30 +2085,48 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2084
2085
( self . size , self . align )
2085
2086
}
2086
2087
2087
- /// Find the offset of a non-zero leaf field, starting from
2088
+ /// Find the offset of a niche leaf field, starting from
2088
2089
/// the given type and recursing through aggregates.
2089
- /// The tuple is `(offset, primitive, source_path )`.
2090
+ /// The tuple is `(offset, primitive, niche_value )`.
2090
2091
// FIXME(eddyb) track value ranges and traverse already optimized enums.
2091
- fn non_zero_field < C > ( & self , cx : C )
2092
- -> Result < Option < ( Size , Primitive ) > , LayoutError < ' tcx > >
2092
+ fn find_niche < C > ( & self , cx : C )
2093
+ -> Result < Option < ( Size , Primitive , u128 ) > , LayoutError < ' tcx > >
2093
2094
where C : LayoutOf < Ty < ' tcx > , TyLayout = Result < Self , LayoutError < ' tcx > > > +
2094
2095
HasTyCtxt < ' tcx >
2095
2096
{
2096
2097
let tcx = cx. tcx ( ) ;
2097
2098
match ( & self . variants , self . abi , & self . ty . sty ) {
2098
2099
// FIXME(eddyb) check this via value ranges on scalars.
2100
+ ( _, Abi :: Scalar ( Int ( I1 , _) ) , _) => {
2101
+ Ok ( Some ( ( Size :: from_bytes ( 0 ) , Int ( I8 , false ) , 2 ) ) )
2102
+ }
2103
+ ( _, Abi :: Scalar ( Int ( I32 , _) ) , & ty:: TyChar ) => {
2104
+ Ok ( Some ( ( Size :: from_bytes ( 0 ) , Int ( I32 , false ) , 0x10FFFF +1 ) ) )
2105
+ }
2099
2106
( _, Abi :: Scalar ( Pointer ) , & ty:: TyRef ( ..) ) |
2100
2107
( _, Abi :: Scalar ( Pointer ) , & ty:: TyFnPtr ( ..) ) => {
2101
- Ok ( Some ( ( Size :: from_bytes ( 0 ) , Pointer ) ) )
2108
+ Ok ( Some ( ( Size :: from_bytes ( 0 ) , Pointer , 0 ) ) )
2102
2109
}
2103
2110
( _, Abi :: Scalar ( Pointer ) , & ty:: TyAdt ( def, _) ) if def. is_box ( ) => {
2104
- Ok ( Some ( ( Size :: from_bytes ( 0 ) , Pointer ) ) )
2111
+ Ok ( Some ( ( Size :: from_bytes ( 0 ) , Pointer , 0 ) ) )
2105
2112
}
2106
2113
2107
2114
// FIXME(eddyb) check this via value ranges on scalars.
2108
- ( & Variants :: Tagged { discr, .. } , _, & ty:: TyAdt ( def, _) ) => {
2109
- if def. discriminants ( tcx) . all ( |d| d. to_u128_unchecked ( ) != 0 ) {
2110
- Ok ( Some ( ( self . fields . offset ( 0 ) , discr) ) )
2115
+ ( & Variants :: Tagged { discr, ref discr_range, .. } , _, _) => {
2116
+ // FIXME(eddyb) support negative/wrap-around discriminant ranges.
2117
+ if discr_range. start < discr_range. end {
2118
+ if discr_range. start > 0 {
2119
+ Ok ( Some ( ( self . fields . offset ( 0 ) , discr, 0 ) ) )
2120
+ } else {
2121
+ let bits = discr. size ( tcx) . bits ( ) ;
2122
+ assert ! ( bits <= 128 ) ;
2123
+ let max_value = !0u128 >> ( 128 - bits) ;
2124
+ if discr_range. end < max_value {
2125
+ Ok ( Some ( ( self . fields . offset ( 0 ) , discr, discr_range. end + 1 ) ) )
2126
+ } else {
2127
+ Ok ( None )
2128
+ }
2129
+ }
2111
2130
} else {
2112
2131
Ok ( None )
2113
2132
}
@@ -2118,7 +2137,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2118
2137
let field = self . field ( cx, 0 ) ?;
2119
2138
let offset = self . fields . offset ( 0 ) ;
2120
2139
if let Abi :: Scalar ( value) = field. abi {
2121
- Ok ( Some ( ( offset, value) ) )
2140
+ Ok ( Some ( ( offset, value, 0 ) ) )
2122
2141
} else {
2123
2142
Ok ( None )
2124
2143
}
@@ -2128,13 +2147,14 @@ impl<'a, 'tcx> TyLayout<'tcx> {
2128
2147
_ => {
2129
2148
if let FieldPlacement :: Array { count, .. } = self . fields {
2130
2149
if count > 0 {
2131
- return self . field ( cx, 0 ) ?. non_zero_field ( cx) ;
2150
+ return self . field ( cx, 0 ) ?. find_niche ( cx) ;
2132
2151
}
2133
2152
}
2134
2153
for i in 0 ..self . fields . count ( ) {
2135
- let r = self . field ( cx, i) ?. non_zero_field ( cx) ?;
2136
- if let Some ( ( offset, primitive) ) = r {
2137
- return Ok ( Some ( ( self . fields . offset ( i) + offset, primitive) ) ) ;
2154
+ let r = self . field ( cx, i) ?. find_niche ( cx) ?;
2155
+ if let Some ( ( offset, primitive, niche_value) ) = r {
2156
+ let offset = self . fields . offset ( i) + offset;
2157
+ return Ok ( Some ( ( offset, primitive, niche_value) ) ) ;
2138
2158
}
2139
2159
}
2140
2160
Ok ( None )
@@ -2165,13 +2185,15 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Variants {
2165
2185
variants. hash_stable ( hcx, hasher) ;
2166
2186
}
2167
2187
NicheFilling {
2168
- nndiscr,
2188
+ dataful_variant,
2189
+ ref niche,
2190
+ niche_value,
2169
2191
ref variants,
2170
- ref discr,
2171
2192
} => {
2172
- nndiscr. hash_stable ( hcx, hasher) ;
2193
+ dataful_variant. hash_stable ( hcx, hasher) ;
2194
+ niche. hash_stable ( hcx, hasher) ;
2195
+ niche_value. hash_stable ( hcx, hasher) ;
2173
2196
variants. hash_stable ( hcx, hasher) ;
2174
- discr. hash_stable ( hcx, hasher) ;
2175
2197
}
2176
2198
}
2177
2199
}
0 commit comments