@@ -71,16 +71,18 @@ use util::ppaux::ty_to_str;
71
71
72
72
/// Representations.
73
73
pub enum Repr {
74
- /// C-like enums; basically an int.
75
- CEnum ( int , int ) , // discriminant range
76
74
/**
77
- * Single-case variants, and structs/tuples/records.
78
- *
79
- * Structs with destructors need a dynamic destroyedness flag to
80
- * avoid running the destructor too many times; this is included
81
- * in the `Struct` if present .
75
+ * `Unit` exists only so that an enum with a single C-like variant
76
+ * can occupy no space, for ABI compatibility with rustc from
77
+ * before (and during) the creation of this module. It may not be
78
+ * worth keeping around; `CEnum` and `Univariant` cover it
79
+ * overwise .
82
80
*/
83
- Univariant ( Struct , bool ) ,
81
+ Unit ( int ) ,
82
+ /// C-like enums; basically an int.
83
+ CEnum ( int , int ) , // discriminant range
84
+ /// Single-case variants, and structs/tuples/records.
85
+ Univariant ( Struct , Destructor ) ,
84
86
/**
85
87
* General-case enums: discriminant as int, followed by fields.
86
88
* The fields start immediately after the discriminant, meaning
@@ -90,6 +92,18 @@ pub enum Repr {
90
92
General ( ~[ Struct ] )
91
93
}
92
94
95
+ /**
96
+ * Structs without destructors have historically had an extra layer of
97
+ * LLVM-struct to make accessing them work the same as structs with
98
+ * destructors. This could probably be flattened to a boolean now
99
+ * that this module exists.
100
+ */
101
+ enum Destructor {
102
+ StructWithDtor ,
103
+ StructWithoutDtor ,
104
+ NonStruct
105
+ }
106
+
93
107
/// For structs, and struct-like parts of anything fancier.
94
108
struct Struct {
95
109
size : u64 ,
@@ -115,17 +129,14 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
115
129
}
116
130
let repr = @match ty:: get ( t) . sty {
117
131
ty:: ty_tup( ref elems) => {
118
- Univariant ( mk_struct ( cx, * elems) , false )
132
+ Univariant ( mk_struct ( cx, * elems) , NonStruct )
119
133
}
120
134
ty:: ty_struct( def_id, ref substs) => {
121
135
let fields = ty:: lookup_struct_fields ( cx. tcx , def_id) ;
122
- let ftys = do fields. map |field| {
136
+ let dt = ty:: ty_dtor ( cx. tcx , def_id) . is_present ( ) ;
137
+ Univariant ( mk_struct ( cx, fields. map ( |field| {
123
138
ty:: lookup_field_type ( cx. tcx , def_id, field. id , substs)
124
- } ;
125
- let dtor = ty:: ty_dtor ( cx. tcx , def_id) . is_present ( ) ;
126
- let ftys =
127
- if dtor { ftys + [ ty:: mk_bool ( cx. tcx ) ] } else { ftys } ;
128
- Univariant ( mk_struct ( cx, ftys) , dtor)
139
+ } ) ) , if dt { StructWithDtor } else { StructWithoutDtor } )
129
140
}
130
141
ty:: ty_enum( def_id, ref substs) => {
131
142
struct Case { discr : int , tys : ~[ ty:: t ] } ;
@@ -138,15 +149,18 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr {
138
149
} ;
139
150
if cases. len ( ) == 0 {
140
151
// Uninhabitable; represent as unit
141
- Univariant ( mk_struct ( cx, ~[ ] ) , false )
152
+ Unit ( 0 )
153
+ } else if cases. len ( ) == 1 && cases[ 0 ] . tys . len ( ) == 0 {
154
+ // `()`-like; see comment on definition of `Unit`.
155
+ Unit ( cases[ 0 ] . discr )
156
+ } else if cases. len ( ) == 1 {
157
+ // Equivalent to a struct/tuple/newtype.
158
+ fail_unless ! ( cases[ 0 ] . discr == 0 ) ;
159
+ Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , NonStruct )
142
160
} else if cases. all ( |c| c. tys . len ( ) == 0 ) {
143
161
// All bodies empty -> intlike
144
162
let discrs = cases. map ( |c| c. discr ) ;
145
163
CEnum ( discrs. min ( ) , discrs. max ( ) )
146
- } else if cases. len ( ) == 1 {
147
- // Equivalent to a struct/tuple/newtype.
148
- fail_unless ! ( cases[ 0 ] . discr == 0 ) ;
149
- Univariant ( mk_struct ( cx, cases[ 0 ] . tys ) , false )
150
164
} else {
151
165
// The general case. Since there's at least one
152
166
// non-empty body, explicit discriminants should have
@@ -190,12 +204,18 @@ pub fn sizing_fields_of(cx: @CrateContext, r: &Repr) -> ~[TypeRef] {
190
204
fn generic_fields_of ( cx : @CrateContext , r : & Repr , sizing : bool )
191
205
-> ~[ TypeRef ] {
192
206
match * r {
207
+ Unit ( * ) => ~[ ] ,
193
208
CEnum ( * ) => ~[ T_enum_discrim ( cx) ] ,
194
- Univariant ( ref st, _dtor ) => {
195
- if sizing {
209
+ Univariant ( ref st, dt ) => {
210
+ let f = if sizing {
196
211
st. fields . map ( |& ty| type_of:: sizing_type_of ( cx, ty) )
197
212
} else {
198
213
st. fields . map ( |& ty| type_of:: type_of ( cx, ty) )
214
+ } ;
215
+ match dt {
216
+ NonStruct => f,
217
+ StructWithoutDtor => ~[ T_struct ( f) ] ,
218
+ StructWithDtor => ~[ T_struct ( f) , T_i8 ( ) ]
199
219
}
200
220
}
201
221
General ( ref sts) => {
@@ -217,7 +237,7 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
217
237
CEnum ( * ) | General ( * ) => {
218
238
( _match:: switch, Some ( trans_get_discr ( bcx, r, scrutinee) ) )
219
239
}
220
- Univariant ( * ) => {
240
+ Unit ( * ) | Univariant ( * ) => {
221
241
( _match:: single, None )
222
242
}
223
243
}
@@ -227,6 +247,7 @@ pub fn trans_switch(bcx: block, r: &Repr, scrutinee: ValueRef)
227
247
pub fn trans_get_discr ( bcx : block , r : & Repr , scrutinee : ValueRef )
228
248
-> ValueRef {
229
249
match * r {
250
+ Unit ( the_disc) => C_int ( bcx. ccx ( ) , the_disc) ,
230
251
CEnum ( min, max) => load_discr ( bcx, scrutinee, min, max) ,
231
252
Univariant ( * ) => C_int ( bcx. ccx ( ) , 0 ) ,
232
253
General ( ref cases) => load_discr ( bcx, scrutinee, 0 ,
@@ -264,7 +285,7 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
264
285
CEnum ( * ) => {
265
286
_match:: single_result ( rslt ( bcx, C_int ( bcx. ccx ( ) , discr) ) )
266
287
}
267
- Univariant ( * ) => {
288
+ Unit ( * ) | Univariant ( * ) => {
268
289
bcx. ccx ( ) . sess . bug ( ~"no cases for univariants or structs")
269
290
}
270
291
General ( * ) => {
@@ -280,14 +301,16 @@ pub fn trans_case(bcx: block, r: &Repr, discr: int) -> _match::opt_result {
280
301
*/
281
302
pub fn trans_start_init ( bcx : block , r : & Repr , val : ValueRef , discr : int ) {
282
303
match * r {
304
+ Unit ( the_discr) => {
305
+ fail_unless ! ( discr == the_discr) ;
306
+ }
283
307
CEnum ( min, max) => {
284
308
fail_unless ! ( min <= discr && discr <= max) ;
285
309
Store ( bcx, C_int ( bcx. ccx ( ) , discr) , GEPi ( bcx, val, [ 0 , 0 ] ) )
286
310
}
287
- Univariant ( ref st , true ) => {
311
+ Univariant ( _ , StructWithDtor ) => {
288
312
fail_unless ! ( discr == 0 ) ;
289
- Store ( bcx, C_bool ( true ) ,
290
- GEPi ( bcx, val, [ 0 , st. fields . len ( ) - 1 ] ) )
313
+ Store ( bcx, C_u8 ( 1 ) , GEPi ( bcx, val, [ 0 , 1 ] ) )
291
314
}
292
315
Univariant ( * ) => {
293
316
fail_unless ! ( discr == 0 ) ;
@@ -304,11 +327,8 @@ pub fn trans_start_init(bcx: block, r: &Repr, val: ValueRef, discr: int) {
304
327
*/
305
328
pub fn num_args ( r : & Repr , discr : int ) -> uint {
306
329
match * r {
307
- CEnum ( * ) => 0 ,
308
- Univariant ( ref st, dtor) => {
309
- fail_unless ! ( discr == 0 ) ;
310
- st. fields . len ( ) - ( if dtor { 1 } else { 0 } )
311
- }
330
+ Unit ( * ) | CEnum ( * ) => 0 ,
331
+ Univariant ( ref st, _) => { fail_unless ! ( discr == 0 ) ; st. fields . len ( ) }
312
332
General ( ref cases) => cases[ discr as uint ] . fields . len ( )
313
333
}
314
334
}
@@ -320,11 +340,15 @@ pub fn trans_field_ptr(bcx: block, r: &Repr, val: ValueRef, discr: int,
320
340
// decide to do some kind of cdr-coding-like non-unique repr
321
341
// someday), it will need to return a possibly-new bcx as well.
322
342
match * r {
323
- CEnum ( * ) => {
343
+ Unit ( * ) | CEnum ( * ) => {
324
344
bcx. ccx ( ) . sess . bug ( ~"element access in C -like enum")
325
345
}
326
- Univariant ( ref st, _dtor ) => {
346
+ Univariant ( ref st, dt ) => {
327
347
fail_unless ! ( discr == 0 ) ;
348
+ let val = match dt {
349
+ NonStruct => val,
350
+ StructWithDtor | StructWithoutDtor => GEPi ( bcx, val, [ 0 , 0 ] )
351
+ } ;
328
352
struct_field_ptr ( bcx, st, val, ix, false )
329
353
}
330
354
General ( ref cases) => {
@@ -352,7 +376,7 @@ fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint,
352
376
/// Access the struct drop flag, if present.
353
377
pub fn trans_drop_flag_ptr ( bcx : block , r : & Repr , val : ValueRef ) -> ValueRef {
354
378
match * r {
355
- Univariant ( ref st , true ) => GEPi ( bcx, val, [ 0 , st . fields . len ( ) - 1 ] ) ,
379
+ Univariant ( _ , StructWithDtor ) => GEPi ( bcx, val, [ 0 , 1 ] ) ,
356
380
_ => bcx. ccx ( ) . sess . bug ( ~"tried to get drop flag of non-droppable \
357
381
type ")
358
382
}
@@ -383,14 +407,23 @@ pub fn trans_drop_flag_ptr(bcx: block, r: &Repr, val: ValueRef) -> ValueRef {
383
407
pub fn trans_const ( ccx : @CrateContext , r : & Repr , discr : int ,
384
408
vals : & [ ValueRef ] ) -> ValueRef {
385
409
match * r {
410
+ Unit ( * ) => {
411
+ C_struct ( ~[ ] )
412
+ }
386
413
CEnum ( min, max) => {
387
414
fail_unless ! ( vals. len( ) == 0 ) ;
388
415
fail_unless ! ( min <= discr && discr <= max) ;
389
416
C_int ( ccx, discr)
390
417
}
391
- Univariant ( ref st, _dro ) => {
418
+ Univariant ( ref st, dt ) => {
392
419
fail_unless ! ( discr == 0 ) ;
393
- C_struct ( build_const_struct ( ccx, st, vals) )
420
+ let s = C_struct ( build_const_struct ( ccx, st, vals) ) ;
421
+ match dt {
422
+ NonStruct => s,
423
+ // The actual destructor flag doesn't need to be present.
424
+ // But add an extra struct layer for compatibility.
425
+ StructWithDtor | StructWithoutDtor => C_struct ( ~[ s] )
426
+ }
394
427
}
395
428
General ( ref cases) => {
396
429
let case = & cases[ discr as uint ] ;
@@ -456,6 +489,7 @@ fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
456
489
pub fn const_get_discrim ( ccx : @CrateContext , r : & Repr , val : ValueRef )
457
490
-> int {
458
491
match * r {
492
+ Unit ( discr) => discr,
459
493
CEnum ( * ) => const_to_int ( val) as int ,
460
494
Univariant ( * ) => 0 ,
461
495
General ( * ) => const_to_int ( const_get_elt ( ccx, val, [ 0 ] ) ) as int ,
@@ -472,9 +506,11 @@ pub fn const_get_discrim(ccx: @CrateContext, r: &Repr, val: ValueRef)
472
506
pub fn const_get_field ( ccx : @CrateContext , r : & Repr , val : ValueRef ,
473
507
_discr : int , ix : uint ) -> ValueRef {
474
508
match * r {
475
- CEnum ( * ) => ccx. sess . bug ( ~"element access in C -like enum \
509
+ Unit ( * ) | CEnum ( * ) => ccx. sess . bug ( ~"element access in C -like enum \
476
510
const ") ,
477
- Univariant ( * ) => const_struct_field ( ccx, val, ix) ,
511
+ Univariant ( _, NonStruct ) => const_struct_field ( ccx, val, ix) ,
512
+ Univariant ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
513
+ [ 0 ] ) , ix) ,
478
514
General ( * ) => const_struct_field ( ccx, const_get_elt ( ccx, val,
479
515
[ 1 , 0 ] ) , ix)
480
516
}
@@ -506,7 +542,8 @@ fn const_struct_field(ccx: @CrateContext, val: ValueRef, ix: uint)
506
542
/// Is it safe to bitcast a value to the one field of its one variant?
507
543
pub fn is_newtypeish ( r : & Repr ) -> bool {
508
544
match * r {
509
- Univariant ( ref st, false ) => st. fields . len ( ) == 1 ,
545
+ Univariant ( ref st, StructWithoutDtor )
546
+ | Univariant ( ref st, NonStruct ) => st. fields . len ( ) == 1 ,
510
547
_ => false
511
548
}
512
549
}
0 commit comments