@@ -117,25 +117,40 @@ pub enum Repr<'tcx> {
117
117
/// (The flag, if nonzero, represents the initialization value to use;
118
118
/// if zero, then use no flag at all.)
119
119
General ( IntType , Vec < Struct < ' tcx > > , u8 ) ,
120
- /// Two cases distinguished by a nullable pointer: the case with discriminant
121
- /// `nndiscr` must have single field which is known to be nonnull due to its type.
122
- /// The other case is known to be zero sized. Hence we represent the enum
123
- /// as simply a nullable pointer: if not null it indicates the `nndiscr` variant,
124
- /// otherwise it indicates the other case.
125
- RawNullablePointer {
126
- nndiscr : Disr ,
127
- nnty : Ty < ' tcx > ,
128
- nullfields : Vec < Ty < ' tcx > >
120
+ /// Two cases distinguised by a known-to-be-forbidden value.
121
+ ///
122
+ /// Example: `Option<&T>` (a `&T` cannot be null)
123
+ /// Example: `Option<char>` (a `char` is large enough to hold 2^32 - 1,
124
+ /// but this value is forbidden by definition)
125
+ /// Example: `Result<&T, ()>` (a `&T` cannot be null)
126
+ ///
127
+ /// One of the cases (the "unit case") must be known to be
128
+ /// zero-sized (e.g. `None`). The other case (the "payload case")
129
+ /// must be known to be a single field that cannot adopt a
130
+ /// specific value (in the above examples, 0 for `&T` or 2^32 - 1
131
+ /// for `char`).
132
+ ///
133
+ /// We may safely represent the enum by its payload case and
134
+ /// differentiate between cases by checking for the forbidden
135
+ /// value.
136
+ RawForbiddenValue {
137
+ /// Unit case (e.g. `None` or `Either((), ())`)
138
+ unit_fields : Vec < Ty < ' tcx > > ,
139
+
140
+ /// Case holding a payload: the constructor
141
+ payload_discr : Disr ,
142
+
143
+ /// Case holding a payload: the type
144
+ payload_ty : Ty < ' tcx > ,
145
+
146
+ /// A value that the payload can never hold.
147
+ forbidden_value : ValueRef ,
129
148
} ,
130
149
/// Two cases distinguished by a nullable pointer: the case with discriminant
131
150
/// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
132
151
/// field is known to be nonnull due to its type; if that field is null, then
133
152
/// it represents the other case, which is inhabited by at most one value
134
153
/// (and all other fields are undefined/unused).
135
- ///
136
- /// For example, `std::option::Option` instantiated at a safe pointer type
137
- /// is represented such that `None` is a null pointer and `Some` is the
138
- /// identity function.
139
154
StructWrappedNullablePointer {
140
155
nonnull : Struct < ' tcx > ,
141
156
nndiscr : Disr ,
@@ -322,18 +337,26 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
322
337
}
323
338
324
339
if !dtor && cases. len ( ) == 2 && hint == attr:: ReprAny {
325
- // Nullable pointer optimization
326
- let mut discr = 0 ;
327
- while discr < 2 {
340
+ // Two cases, so it might be possible to turn this
341
+ // into a `RawForbiddenValue` or a
342
+ // `StructWrappedNullablePointer`, if all conditions
343
+ // are met.
344
+ for discr in 0 .. 2 {
328
345
if cases[ 1 - discr] . is_zerolen ( cx, t) {
346
+ // One of the cases has zero length. We are on the right track.
329
347
let st = mk_struct ( cx, & cases[ discr] . tys ,
330
348
false , t) ;
349
+
350
+ // For the moment, we can only apply these
351
+ // optimizations to safe pointers.
331
352
match cases[ discr] . find_ptr ( cx) {
332
353
Some ( ref df) if df. len ( ) == 1 && st. fields . len ( ) == 1 => {
333
- return RawNullablePointer {
334
- nndiscr : Disr :: from ( discr) ,
335
- nnty : st. fields [ 0 ] ,
336
- nullfields : cases[ 1 - discr] . tys . clone ( )
354
+ let payload_ty = st. fields [ 0 ] ;
355
+ return RawForbiddenValue {
356
+ payload_discr : Disr :: from ( discr) ,
357
+ payload_ty : payload_ty,
358
+ forbidden_value : C_null ( type_of:: sizing_type_of ( cx, payload_ty) ) ,
359
+ unit_fields : cases[ 1 - discr] . tys . clone ( )
337
360
} ;
338
361
}
339
362
Some ( mut discrfield) => {
@@ -348,8 +371,13 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
348
371
}
349
372
None => { }
350
373
}
374
+ // No need to continue the loop. If both cases
375
+ // have zero length, we can apply neither
376
+ // `RawForbiddenValue` nor
377
+ // `StructWrappedNullablePointer`.
378
+ break ;
379
+
351
380
}
352
- discr += 1 ;
353
381
}
354
382
}
355
383
@@ -529,6 +557,8 @@ impl<'tcx> Case<'tcx> {
529
557
mk_struct ( cx, & self . tys , false , scapegoat) . size == 0
530
558
}
531
559
560
+ /// Find a safe pointer that may be used to discriminate in a
561
+ /// RawForbiddenValue or StructWrappedNullablePointer.
532
562
fn find_ptr < ' a > ( & self , cx : & CrateContext < ' a , ' tcx > ) -> Option < DiscrField > {
533
563
for ( i, & ty) in self . tys . iter ( ) . enumerate ( ) {
534
564
if let Some ( mut path) = find_discr_field_candidate ( cx. tcx ( ) , ty, vec ! [ ] ) {
@@ -748,7 +778,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
748
778
pub fn finish_type_of < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
749
779
r : & Repr < ' tcx > , llty : & mut Type ) {
750
780
match * r {
751
- CEnum ( ..) | General ( ..) | RawNullablePointer { .. } => { }
781
+ CEnum ( ..) | General ( ..) | RawForbiddenValue { .. } => { }
752
782
Univariant ( ref st, _) | StructWrappedNullablePointer { nonnull : ref st, .. } =>
753
783
llty. set_struct_body ( & struct_llfields ( cx, st, false , false ) ,
754
784
st. packed )
@@ -765,8 +795,8 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
765
795
r, name, sizing, dst, delay_drop_flag) ;
766
796
match * r {
767
797
CEnum ( ity, _, _) => TypeContext :: direct ( ll_inttype ( cx, ity) ) ,
768
- RawNullablePointer { nnty , .. } =>
769
- TypeContext :: direct ( type_of:: sizing_type_of ( cx, nnty ) ) ,
798
+ RawForbiddenValue { payload_ty , .. } =>
799
+ TypeContext :: direct ( type_of:: sizing_type_of ( cx, payload_ty ) ) ,
770
800
StructWrappedNullablePointer { nonnull : ref st, .. } => {
771
801
match name {
772
802
None => {
@@ -880,9 +910,8 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
880
910
-> ( _match:: BranchKind , Option < ValueRef > ) {
881
911
match * r {
882
912
CEnum ( ..) | General ( ..) |
883
- RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
884
- ( _match:: Switch , Some ( trans_get_discr ( bcx, r, scrutinee, None ,
885
- range_assert) ) )
913
+ RawForbiddenValue { .. } | StructWrappedNullablePointer { .. } => {
914
+ ( _match:: Switch , Some ( trans_get_discr ( bcx, r, scrutinee, None , range_assert) ) )
886
915
}
887
916
Univariant ( ..) => {
888
917
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
@@ -896,7 +925,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
896
925
CEnum ( ity, _, _) => ity. is_signed ( ) ,
897
926
General ( ity, _, _) => ity. is_signed ( ) ,
898
927
Univariant ( ..) => false ,
899
- RawNullablePointer { .. } => false ,
928
+ RawForbiddenValue { payload_ty , .. } => payload_ty . is_signed ( ) ,
900
929
StructWrappedNullablePointer { .. } => false ,
901
930
}
902
931
}
@@ -917,10 +946,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
917
946
range_assert)
918
947
}
919
948
Univariant ( ..) => C_u8 ( bcx. ccx ( ) , 0 ) ,
920
- RawNullablePointer { nndiscr, nnty, .. } => {
921
- let cmp = if nndiscr == Disr ( 0 ) { IntEQ } else { IntNE } ;
922
- let llptrty = type_of:: sizing_type_of ( bcx. ccx ( ) , nnty) ;
923
- ICmp ( bcx, cmp, Load ( bcx, scrutinee) , C_null ( llptrty) , DebugLoc :: None )
949
+ RawForbiddenValue { payload_discr, forbidden_value, .. } => {
950
+ let cmp = if payload_discr == Disr ( 0 ) { IntEQ } else { IntNE } ;
951
+ ICmp ( bcx, cmp, Load ( bcx, scrutinee) , forbidden_value, DebugLoc :: None )
924
952
}
925
953
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
926
954
struct_wrapped_nullable_bitdiscr ( bcx, nndiscr, discrfield, scrutinee)
@@ -981,7 +1009,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
981
1009
Univariant ( ..) => {
982
1010
bcx. ccx ( ) . sess ( ) . bug ( "no cases for univariants or structs" )
983
1011
}
984
- RawNullablePointer { .. } |
1012
+ RawForbiddenValue { .. } |
985
1013
StructWrappedNullablePointer { .. } => {
986
1014
assert ! ( discr == Disr ( 0 ) || discr == Disr ( 1 ) ) ;
987
1015
C_bool ( bcx. ccx ( ) , discr != Disr ( 0 ) )
@@ -1015,10 +1043,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1015
1043
StructGEP ( bcx, val, st. fields . len ( ) - 1 ) ) ;
1016
1044
}
1017
1045
}
1018
- RawNullablePointer { nndiscr, nnty, ..} => {
1019
- if discr != nndiscr {
1020
- let llptrty = type_of:: sizing_type_of ( bcx. ccx ( ) , nnty) ;
1021
- Store ( bcx, C_null ( llptrty) , val) ;
1046
+ RawForbiddenValue { payload_discr, forbidden_value, ..} => {
1047
+ if discr != payload_discr {
1048
+ Store ( bcx, forbidden_value, val) ;
1022
1049
}
1023
1050
}
1024
1051
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
@@ -1056,8 +1083,16 @@ pub fn num_args(r: &Repr, discr: Disr) -> usize {
1056
1083
General ( _, ref cases, dtor) => {
1057
1084
cases[ discr. 0 as usize ] . fields . len ( ) - 1 - ( if dtor_active ( dtor) { 1 } else { 0 } )
1058
1085
}
1059
- RawNullablePointer { nndiscr, ref nullfields, .. } => {
1060
- if discr == nndiscr { 1 } else { nullfields. len ( ) }
1086
+ RawForbiddenValue { payload_discr, ref unit_fields, .. } => {
1087
+ if discr == payload_discr {
1088
+ // By definition of `RawForbiddenValue`, the payload case
1089
+ // has exactly one field.
1090
+ 1
1091
+ } else {
1092
+ // In the unit case, we may have any number of fields,
1093
+ // including 0.
1094
+ unit_fields. len ( )
1095
+ }
1061
1096
}
1062
1097
StructWrappedNullablePointer { ref nonnull, nndiscr,
1063
1098
ref nullfields, .. } => {
@@ -1083,7 +1118,7 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1083
1118
General ( _, ref cases, _) => {
1084
1119
struct_field_ptr ( bcx, & cases[ discr. 0 as usize ] , val, ix + 1 , true )
1085
1120
}
1086
- RawNullablePointer { nndiscr, ref nullfields, .. } |
1121
+ RawForbiddenValue { payload_discr : nndiscr, unit_fields : ref nullfields, .. } |
1087
1122
StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
1088
1123
// The unit-like case might have a nonzero number of unit-like fields.
1089
1124
// (e.d., Result of Either with (), as one side.)
@@ -1093,10 +1128,10 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1093
1128
// the value that's "reasonable" in case of pointer comparison.
1094
1129
PointerCast ( bcx, val. value , ty. ptr_to ( ) )
1095
1130
}
1096
- RawNullablePointer { nndiscr , nnty , .. } => {
1097
- assert_eq ! ( ix, 0 ) ;
1098
- assert_eq ! ( discr, nndiscr ) ;
1099
- let ty = type_of:: type_of ( bcx. ccx ( ) , nnty ) ;
1131
+ RawForbiddenValue { payload_discr , payload_ty , .. } => {
1132
+ assert_eq ! ( ix, 0 ) ; // By definition, the payload of RawForbiddenValue has a single field.
1133
+ assert_eq ! ( discr, payload_discr ) ;
1134
+ let ty = type_of:: type_of ( bcx. ccx ( ) , payload_ty ) ;
1100
1135
PointerCast ( bcx, val. value , ty. ptr_to ( ) )
1101
1136
}
1102
1137
StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
@@ -1345,12 +1380,12 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
1345
1380
let contents = build_const_struct ( ccx, st, vals) ;
1346
1381
C_struct ( ccx, & contents[ ..] , st. packed )
1347
1382
}
1348
- RawNullablePointer { nndiscr , nnty , .. } => {
1349
- if discr == nndiscr {
1350
- assert_eq ! ( vals. len( ) , 1 ) ;
1383
+ RawForbiddenValue { payload_discr , forbidden_value , .. } => {
1384
+ if discr == payload_discr {
1385
+ assert_eq ! ( vals. len( ) , 1 ) ; // By definition, the payload has only a single field.
1351
1386
vals[ 0 ]
1352
1387
} else {
1353
- C_null ( type_of :: sizing_type_of ( ccx , nnty ) )
1388
+ forbidden_value
1354
1389
}
1355
1390
}
1356
1391
StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
@@ -1457,7 +1492,7 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr {
1457
1492
}
1458
1493
}
1459
1494
Univariant ( ..) => Disr ( 0 ) ,
1460
- RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1495
+ RawForbiddenValue { .. } | StructWrappedNullablePointer { .. } => {
1461
1496
ccx. sess ( ) . bug ( "const discrim access of non c-like enum" )
1462
1497
}
1463
1498
}
@@ -1469,14 +1504,19 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr {
1469
1504
/// (Not to be confused with `common::const_get_elt`, which operates on
1470
1505
/// raw LLVM-level structs and arrays.)
1471
1506
pub fn const_get_field ( ccx : & CrateContext , r : & Repr , val : ValueRef ,
1472
- _discr : Disr , ix : usize ) -> ValueRef {
1507
+ discr : Disr , ix : usize ) -> ValueRef {
1473
1508
match * r {
1474
1509
CEnum ( ..) => ccx. sess ( ) . bug ( "element access in C-like enum const" ) ,
1475
1510
Univariant ( ..) => const_struct_field ( ccx, val, ix) ,
1476
1511
General ( ..) => const_struct_field ( ccx, val, ix + 1 ) ,
1477
- RawNullablePointer { .. } => {
1478
- assert_eq ! ( ix, 0 ) ;
1479
- val
1512
+ RawForbiddenValue { payload_discr, .. } => {
1513
+ if discr == payload_discr {
1514
+ assert_eq ! ( ix, 0 ) ; // By definition, the payload only has a single field.
1515
+ val
1516
+ } else {
1517
+ // All values are unit.
1518
+ C_null ( Type :: nil ( ccx) )
1519
+ }
1480
1520
} ,
1481
1521
StructWrappedNullablePointer { .. } => const_struct_field ( ccx, val, ix)
1482
1522
}
0 commit comments