8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use core:: libc:: c_ulonglong;
11
12
use core:: option:: { Option , Some , None } ;
12
13
use core:: vec;
13
- use lib:: llvm:: { ValueRef , TypeRef } ;
14
+ use lib:: llvm:: { ValueRef , TypeRef , True , False } ;
14
15
use middle:: trans:: _match;
15
16
use middle:: trans:: build:: * ;
16
17
use middle:: trans:: common:: * ;
@@ -23,7 +24,7 @@ use util::ppaux::ty_to_str;
23
24
24
25
// XXX: should this be done with boxed traits instead of ML-style?
25
26
pub enum Repr {
26
- CEnum ,
27
+ CEnum ( int , int ) , /* discriminant range */
27
28
Univariant ( Struct , Destructor ) ,
28
29
General ( ~[ Struct ] )
29
30
}
@@ -65,13 +66,13 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr {
65
66
} ) ) , if dt { DtorPresent } else { DtorAbsent } )
66
67
}
67
68
ty:: ty_enum( def_id, ref substs) => {
68
- struct Case { discr : i64 , tys : ~[ ty:: t ] } ;
69
+ struct Case { discr : int , tys : ~[ ty:: t ] } ;
69
70
70
71
let cases = do ty:: enum_variants ( cx. tcx , def_id) . map |vi| {
71
72
let arg_tys = do vi. args . map |& raw_ty| {
72
73
ty:: subst ( cx. tcx , substs, raw_ty)
73
74
} ;
74
- Case { discr : vi. disr_val /*bad*/ as i64 , tys : arg_tys }
75
+ Case { discr : vi. disr_val , tys : arg_tys }
75
76
} ;
76
77
if cases. len ( ) == 0 {
77
78
// Uninhabitable; represent as unit
@@ -80,9 +81,10 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> Repr {
80
81
// struct, tuple, newtype, etc.
81
82
Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NoDtor )
82
83
} else if cases. all ( |c| c. tys . len ( ) == 0 ) {
83
- CEnum
84
+ let discrs = cases. map ( |c| c. discr ) ;
85
+ CEnum ( discrs. min ( ) , discrs. max ( ) )
84
86
} else {
85
- if !cases. alli ( |i, c| c. discr == ( i as i64 ) ) {
87
+ if !cases. alli ( |i, c| c. discr == ( i as int ) ) {
86
88
cx. sess . bug ( fmt ! ( "non-C-like enum %s with specified \
87
89
discriminants",
88
90
ty:: item_path_str( cx. tcx, def_id) ) )
@@ -114,7 +116,7 @@ pub fn fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] {
114
116
fn generic_fields_of ( cx : @CrateContext , r : & Repr , sizing : bool )
115
117
-> ~[ TypeRef ] {
116
118
match * r {
117
- CEnum => ~[ T_enum_discrim ( cx) ] ,
119
+ CEnum ( * ) => ~[ T_enum_discrim ( cx) ] ,
118
120
Univariant ( ref st, dt) => {
119
121
let f = if sizing {
120
122
st. fields . map ( |& ty| type_of:: sizing_type_of ( cx, ty) )
@@ -134,25 +136,44 @@ fn generic_fields_of(cx: @CrateContext, r: &Repr, sizing: bool)
134
136
}
135
137
}
136
138
139
+ fn load_discr ( bcx : block , scrutinee : ValueRef , min : int , max : int )
140
+ -> ValueRef {
141
+ let ptr = GEPi ( bcx, scrutinee, [ 0 , 0 ] ) ;
142
+ // XXX: write tests for the edge cases here
143
+ if max + 1 == min {
144
+ // i.e., if the range is everything. The lo==hi case would be
145
+ // rejected by the LLVM verifier (it would mean either an
146
+ // empty set, which is impossible, or the entire range of the
147
+ // type, which is pointless).
148
+ Load ( bcx, ptr)
149
+ } else {
150
+ // llvm::ConstantRange can deal with ranges that wrap around,
151
+ // so an overflow on (max + 1) is fine.
152
+ LoadRangeAssert ( bcx, ptr, min as c_ulonglong ,
153
+ ( max + 1 ) as c_ulonglong ,
154
+ /* signed: */ True )
155
+ }
156
+ }
157
+
137
158
pub fn trans_switch ( bcx : block , r : & Repr , scrutinee : ValueRef ) ->
138
159
( _match:: branch_kind , Option < ValueRef > ) {
139
- // XXX: LoadRangeAssert
140
160
match * r {
141
- CEnum => {
142
- ( _match:: switch, Some ( Load ( bcx, GEPi ( bcx , scrutinee, [ 0 , 0 ] ) ) ) )
161
+ CEnum ( min , max ) => {
162
+ ( _match:: switch, Some ( load_discr ( bcx, scrutinee, min , max ) ) )
143
163
}
144
164
Univariant ( * ) => {
145
165
( _match:: single, None )
146
166
}
147
- General ( * ) => {
148
- ( _match:: switch, Some ( Load ( bcx, GEPi ( bcx, scrutinee, [ 0 , 0 ] ) ) ) )
167
+ General ( ref cases) => {
168
+ ( _match:: switch, Some ( load_discr ( bcx, scrutinee, 0 ,
169
+ ( cases. len ( ) - 1 ) as int ) ) )
149
170
}
150
171
}
151
172
}
152
173
153
174
pub fn trans_case( bcx : block , r : & Repr , discr : int ) -> _match:: opt_result {
154
175
match * r {
155
- CEnum => {
176
+ CEnum ( * ) => {
156
177
_match:: single_result ( rslt ( bcx, C_int ( bcx. ccx ( ) , discr) ) )
157
178
}
158
179
Univariant ( * ) => {
@@ -166,7 +187,8 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
166
187
167
188
pub fn trans_set_discr ( bcx : block , r : & Repr , val : ValueRef , discr : int ) {
168
189
match * r {
169
- CEnum => {
190
+ CEnum ( min, max) => {
191
+ assert min <= discr && discr <= max;
170
192
Store ( bcx, C_int ( bcx. ccx ( ) , discr) , GEPi ( bcx, val, [ 0 , 0 ] ) )
171
193
}
172
194
Univariant ( _, DtorPresent ) => {
@@ -184,7 +206,7 @@ pub fn trans_set_discr(bcx: block, r: &Repr, val: ValueRef, discr: int) {
184
206
185
207
pub fn num_args ( r : & Repr , discr : int ) -> uint {
186
208
match * r {
187
- CEnum => 0 ,
209
+ CEnum ( * ) => 0 ,
188
210
Univariant ( ref st, _dt) => { assert discr == 0 ; st. fields . len ( ) }
189
211
General ( ref cases) => cases[ discr as uint ] . fields . len ( )
190
212
}
@@ -196,7 +218,7 @@ pub fn trans_GEP(bcx: block, r: &Repr, val: ValueRef, discr: int, ix: uint)
196
218
// decide to do some kind of cdr-coding-like non-unique repr
197
219
// someday), it'll need to return a possibly-new bcx as well.
198
220
match * r {
199
- CEnum => {
221
+ CEnum ( * ) => {
200
222
bcx. ccx ( ) . sess . bug ( ~"element access in C -like enum")
201
223
}
202
224
Univariant ( ref st, dt) => {
@@ -232,8 +254,9 @@ fn struct_GEP(bcx: block, st: &Struct, val: ValueRef, ix: uint,
232
254
pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
233
255
vals : & [ ValueRef ] ) -> ValueRef {
234
256
match * r {
235
- CEnum => {
257
+ CEnum ( min , max ) => {
236
258
assert vals. len ( ) == 0 ;
259
+ assert min <= discr && discr <= max;
237
260
C_int ( ccx, discr)
238
261
}
239
262
Univariant ( ref st, _dt) => {
0 commit comments