@@ -82,25 +82,37 @@ pub enum Repr<'tcx> {
82
82
/// General-case enums: for each case there is a struct, and they
83
83
/// all start with a field for the discriminant.
84
84
General ( IntType , Vec < Struct < ' tcx > > ) ,
85
- /// Two cases distinguished by a nullable pointer: the case with discriminant
86
- /// `nndiscr` must have single field which is known to be nonnull due to its type.
87
- /// The other case is known to be zero sized. Hence we represent the enum
88
- /// as simply a nullable pointer: if not null it indicates the `nndiscr` variant,
89
- /// otherwise it indicates the other case.
90
- RawNullablePointer {
91
- nndiscr : Disr ,
92
- nnty : Ty < ' tcx > ,
93
- nullfields : Vec < Ty < ' tcx > >
85
+ /// Two cases distinguished by a known-to-be-forbidden value.
86
+ ///
87
+ /// Example: `Option<&T>` (a `&T` cannot be null)
88
+ /// Example: `Option<char>` (a `char` is large enough to hold 2^32 - 1,
89
+ /// but this value is forbidden by definition)
90
+ /// Example: `Result<&T, ()>` (a `&T` cannot be null)
91
+ ///
92
+ /// One of the cases (the "unit case") must be known to be
93
+ /// zero-sized (e.g. `None`). The other case (the "payload case")
94
+ /// must be known to be a single field that cannot adopt a
95
+ /// specific value (in the above examples, 0 for `&T` or 2^32 - 1
96
+ /// for `char`).
97
+ ///
98
+ /// We may safely represent the enum by its payload case and
99
+ /// differentiate between cases by checking for the forbidden
100
+ /// value.
101
+ RawForbiddenValue {
102
+ /// Unit case (e.g. `None` or `Either((), ())`)
103
+ unit_fields : Vec < Ty < ' tcx > > ,
104
+ /// Case holding a payload: the constructor
105
+ payload_discr : Disr ,
106
+ /// Case holding a payload: the type
107
+ payload_ty : Ty < ' tcx > ,
108
+ /// A value that the payload can never hold.
109
+ forbidden_value : ValueRef ,
94
110
} ,
95
111
/// Two cases distinguished by a nullable pointer: the case with discriminant
96
112
/// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
97
113
/// field is known to be nonnull due to its type; if that field is null, then
98
114
/// it represents the other case, which is inhabited by at most one value
99
115
/// (and all other fields are undefined/unused).
100
- ///
101
- /// For example, `std::option::Option` instantiated at a safe pointer type
102
- /// is represented such that `None` is a null pointer and `Some` is the
103
- /// identity function.
104
116
StructWrappedNullablePointer {
105
117
nonnull : Struct < ' tcx > ,
106
118
nndiscr : Disr ,
@@ -217,18 +229,26 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
217
229
}
218
230
219
231
if cases. len ( ) == 2 && hint == attr:: ReprAny {
220
- // Nullable pointer optimization
221
- let mut discr = 0 ;
222
- while discr < 2 {
232
+ // Two cases, so it might be possible to turn this
233
+ // into a `RawForbiddenValue` or a
234
+ // `StructWrappedNullablePointer`, if all conditions
235
+ // are met.
236
+ for discr in 0 .. 2 {
223
237
if cases[ 1 - discr] . is_zerolen ( cx, t) {
238
+ // One of the cases has zero length. We are on the right track.
224
239
let st = mk_struct ( cx, & cases[ discr] . tys ,
225
240
false , t) ;
241
+
242
+ // For the moment, we can only apply these
243
+ // optimizations to safe pointers.
226
244
match cases[ discr] . find_ptr ( cx) {
227
245
Some ( ref df) if df. len ( ) == 1 && st. fields . len ( ) == 1 => {
228
- return RawNullablePointer {
229
- nndiscr : Disr :: from ( discr) ,
230
- nnty : st. fields [ 0 ] ,
231
- nullfields : cases[ 1 - discr] . tys . clone ( )
246
+ let payload_ty = st. fields [ 0 ] ;
247
+ return RawForbiddenValue {
248
+ payload_discr : Disr :: from ( discr) ,
249
+ payload_ty : payload_ty,
250
+ forbidden_value : C_null ( type_of:: sizing_type_of ( cx, payload_ty) ) ,
251
+ unit_fields : cases[ 1 - discr] . tys . clone ( )
232
252
} ;
233
253
}
234
254
Some ( mut discrfield) => {
@@ -243,8 +263,13 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
243
263
}
244
264
None => { }
245
265
}
266
+ // No need to continue the loop. If both cases
267
+ // have zero length, we can apply neither
268
+ // `RawForbiddenValue` nor
269
+ // `StructWrappedNullablePointer`.
270
+ break ;
271
+
246
272
}
247
- discr += 1 ;
248
273
}
249
274
}
250
275
@@ -432,6 +457,8 @@ impl<'tcx> Case<'tcx> {
432
457
mk_struct ( cx, & self . tys , false , scapegoat) . size == 0
433
458
}
434
459
460
+ /// Find a safe pointer that may be used to discriminate in a
461
+ /// RawForbiddenValue or StructWrappedNullablePointer.
435
462
fn find_ptr < ' a > ( & self , cx : & CrateContext < ' a , ' tcx > ) -> Option < DiscrField > {
436
463
for ( i, & ty) in self . tys . iter ( ) . enumerate ( ) {
437
464
if let Some ( mut path) = find_discr_field_candidate ( cx. tcx ( ) , ty, vec ! [ ] ) {
@@ -643,7 +670,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
643
670
pub fn finish_type_of < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
644
671
r : & Repr < ' tcx > , llty : & mut Type ) {
645
672
match * r {
646
- CEnum ( ..) | General ( ..) | RawNullablePointer { .. } => { }
673
+ CEnum ( ..) | General ( ..) | RawForbiddenValue { .. } => { }
647
674
Univariant ( ref st) | StructWrappedNullablePointer { nonnull : ref st, .. } =>
648
675
llty. set_struct_body ( & struct_llfields ( cx, st, false , false ) ,
649
676
st. packed )
@@ -659,8 +686,8 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
659
686
r, name, sizing, dst) ;
660
687
match * r {
661
688
CEnum ( ity, _, _) => ll_inttype ( cx, ity) ,
662
- RawNullablePointer { nnty , .. } =>
663
- type_of:: sizing_type_of ( cx, nnty ) ,
689
+ RawForbiddenValue { payload_ty , .. } =>
690
+ type_of:: sizing_type_of ( cx, payload_ty ) ,
664
691
StructWrappedNullablePointer { nonnull : ref st, .. } => {
665
692
match name {
666
693
None => {
@@ -756,7 +783,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
756
783
-> ( BranchKind , Option < ValueRef > ) {
757
784
match * r {
758
785
CEnum ( ..) | General ( ..) |
759
- RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
786
+ RawForbiddenValue { .. } | StructWrappedNullablePointer { .. } => {
760
787
( BranchKind :: Switch , Some ( trans_get_discr ( bcx, r, scrutinee, None , range_assert) ) )
761
788
}
762
789
Univariant ( ..) => {
@@ -771,7 +798,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
771
798
CEnum ( ity, _, _) => ity. is_signed ( ) ,
772
799
General ( ity, _) => ity. is_signed ( ) ,
773
800
Univariant ( ..) => false ,
774
- RawNullablePointer { .. } => false ,
801
+ RawForbiddenValue { payload_ty , .. } => payload_ty . is_signed ( ) ,
775
802
StructWrappedNullablePointer { .. } => false ,
776
803
}
777
804
}
@@ -792,10 +819,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
792
819
range_assert)
793
820
}
794
821
Univariant ( ..) => C_u8 ( bcx. ccx ( ) , 0 ) ,
795
- RawNullablePointer { nndiscr, nnty, .. } => {
796
- let cmp = if nndiscr == Disr ( 0 ) { IntEQ } else { IntNE } ;
797
- let llptrty = type_of:: sizing_type_of ( bcx. ccx ( ) , nnty) ;
798
- ICmp ( bcx, cmp, Load ( bcx, scrutinee) , C_null ( llptrty) , DebugLoc :: None )
822
+ RawForbiddenValue { payload_discr, forbidden_value, .. } => {
823
+ let cmp = if payload_discr == Disr ( 0 ) { IntEQ } else { IntNE } ;
824
+ ICmp ( bcx, cmp, Load ( bcx, scrutinee) , forbidden_value, DebugLoc :: None )
799
825
}
800
826
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
801
827
struct_wrapped_nullable_bitdiscr ( bcx, nndiscr, discrfield, scrutinee)
@@ -856,7 +882,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
856
882
Univariant ( ..) => {
857
883
bug ! ( "no cases for univariants or structs" )
858
884
}
859
- RawNullablePointer { .. } |
885
+ RawForbiddenValue { .. } |
860
886
StructWrappedNullablePointer { .. } => {
861
887
assert ! ( discr == Disr ( 0 ) || discr == Disr ( 1 ) ) ;
862
888
C_bool ( bcx. ccx ( ) , discr != Disr ( 0 ) )
@@ -881,10 +907,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
881
907
Univariant ( _) => {
882
908
assert_eq ! ( discr, Disr ( 0 ) ) ;
883
909
}
884
- RawNullablePointer { nndiscr, nnty, ..} => {
885
- if discr != nndiscr {
886
- let llptrty = type_of:: sizing_type_of ( bcx. ccx ( ) , nnty) ;
887
- Store ( bcx, C_null ( llptrty) , val) ;
910
+ RawForbiddenValue { payload_discr, forbidden_value, ..} => {
911
+ if discr != payload_discr {
912
+ Store ( bcx, forbidden_value, val) ;
888
913
}
889
914
}
890
915
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
@@ -936,7 +961,7 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
936
961
General ( _, ref cases) => {
937
962
struct_field_ptr ( bcx, & cases[ discr. 0 as usize ] , val, ix + 1 , true )
938
963
}
939
- RawNullablePointer { nndiscr, ref nullfields, .. } |
964
+ RawForbiddenValue { payload_discr : nndiscr, unit_fields : ref nullfields, .. } |
940
965
StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
941
966
// The unit-like case might have a nonzero number of unit-like fields.
942
967
// (e.d., Result of Either with (), as one side.)
@@ -947,10 +972,10 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
947
972
if bcx. is_unreachable ( ) { return C_undef ( ty. ptr_to ( ) ) ; }
948
973
bcx. pointercast ( val. value , ty. ptr_to ( ) )
949
974
}
950
- RawNullablePointer { nndiscr , nnty , .. } => {
951
- assert_eq ! ( ix, 0 ) ;
952
- assert_eq ! ( discr, nndiscr ) ;
953
- let ty = type_of:: type_of ( bcx. ccx ( ) , nnty ) ;
975
+ RawForbiddenValue { payload_discr , payload_ty , .. } => {
976
+ assert_eq ! ( ix, 0 ) ; // By definition, the payload of RawForbiddenValue has a single field.
977
+ assert_eq ! ( discr, payload_discr ) ;
978
+ let ty = type_of:: type_of ( bcx. ccx ( ) , payload_ty ) ;
954
979
if bcx. is_unreachable ( ) { return C_undef ( ty. ptr_to ( ) ) ; }
955
980
bcx. pointercast ( val. value , ty. ptr_to ( ) )
956
981
}
@@ -1102,12 +1127,12 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
1102
1127
let contents = build_const_struct ( ccx, st, vals) ;
1103
1128
C_struct ( ccx, & contents[ ..] , st. packed )
1104
1129
}
1105
- RawNullablePointer { nndiscr , nnty , .. } => {
1106
- if discr == nndiscr {
1107
- assert_eq ! ( vals. len( ) , 1 ) ;
1130
+ RawForbiddenValue { payload_discr , forbidden_value , .. } => {
1131
+ if discr == payload_discr {
1132
+ assert_eq ! ( vals. len( ) , 1 ) ; // By definition, the payload has only a single field.
1108
1133
vals[ 0 ]
1109
1134
} else {
1110
- C_null ( type_of :: sizing_type_of ( ccx , nnty ) )
1135
+ forbidden_value
1111
1136
}
1112
1137
}
1113
1138
StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
@@ -1203,14 +1228,14 @@ fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
1203
1228
///
1204
1229
/// (Not to be confused with `common::const_get_elt`, which operates on
1205
1230
/// raw LLVM-level structs and arrays.)
1206
- pub fn const_get_field ( r : & Repr , val : ValueRef , _discr : Disr ,
1231
+ pub fn const_get_field ( r : & Repr , val : ValueRef , discr : Disr ,
1207
1232
ix : usize ) -> ValueRef {
1208
1233
match * r {
1209
1234
CEnum ( ..) => bug ! ( "element access in C-like enum const" ) ,
1210
1235
Univariant ( ..) => const_struct_field ( val, ix) ,
1211
1236
General ( ..) => const_struct_field ( val, ix + 1 ) ,
1212
- RawNullablePointer { .. } => {
1213
- assert_eq ! ( ix, 0 ) ;
1237
+ RawForbiddenValue { .. } => {
1238
+ assert_eq ! ( ix, 0 ) ; // By definition, the payload only has a single field.
1214
1239
val
1215
1240
} ,
1216
1241
StructWrappedNullablePointer { .. } => const_struct_field ( val, ix)
0 commit comments