@@ -53,7 +53,10 @@ use middle::subst;
53
53
use middle:: subst:: Subst ;
54
54
use middle:: trans:: _match;
55
55
use middle:: trans:: build:: * ;
56
+ use middle:: trans:: cleanup;
57
+ use middle:: trans:: cleanup:: CleanupMethods ;
56
58
use middle:: trans:: common:: * ;
59
+ use middle:: trans:: datum;
57
60
use middle:: trans:: machine;
58
61
use middle:: trans:: type_:: Type ;
59
62
use middle:: trans:: type_of;
@@ -83,8 +86,12 @@ pub enum Repr {
83
86
/**
84
87
* General-case enums: for each case there is a struct, and they
85
88
* all start with a field for the discriminant.
89
+ *
90
+ * Types with destructors need a dynamic destroyedness flag to
91
+ * avoid running the destructor too many times; the last argument
92
+ * indicates whether such a flag is present.
86
93
*/
87
- General ( IntType , Vec < Struct > ) ,
94
+ General ( IntType , Vec < Struct > , bool ) ,
88
95
/**
89
96
* Two cases distinguished by a nullable pointer: the case with discriminant
90
97
* `nndiscr` must have single field which is known to be nonnull due to its type.
@@ -121,7 +128,7 @@ pub struct Struct {
121
128
pub size : u64 ,
122
129
pub align : u64 ,
123
130
pub packed : bool ,
124
- pub fields : Vec < ty:: t > ,
131
+ pub fields : Vec < ty:: t >
125
132
}
126
133
127
134
/**
@@ -173,14 +180,17 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
173
180
let cases = get_cases ( cx. tcx ( ) , def_id, substs) ;
174
181
let hint = ty:: lookup_repr_hint ( cx. tcx ( ) , def_id) ;
175
182
183
+ let dtor = ty:: ty_dtor ( cx. tcx ( ) , def_id) . has_drop_flag ( ) ;
184
+
176
185
if cases. len ( ) == 0 {
177
186
// Uninhabitable; represent as unit
178
187
// (Typechecking will reject discriminant-sizing attrs.)
179
188
assert_eq ! ( hint, attr:: ReprAny ) ;
180
- return Univariant ( mk_struct ( cx, [ ] , false ) , false ) ;
189
+ let ftys = if dtor { vec ! ( ty:: mk_bool( ) ) } else { vec ! ( ) } ;
190
+ return Univariant ( mk_struct ( cx, ftys. as_slice ( ) , false ) , dtor) ;
181
191
}
182
192
183
- if cases. iter ( ) . all ( |c| c. tys . len ( ) == 0 ) {
193
+ if !dtor && cases. iter ( ) . all ( |c| c. tys . len ( ) == 0 ) {
184
194
// All bodies empty -> intlike
185
195
let discrs: Vec < u64 > = cases. iter ( ) . map ( |c| c. discr ) . collect ( ) ;
186
196
let bounds = IntBounds {
@@ -199,20 +209,19 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
199
209
cx. sess ( ) . bug ( format ! ( "non-C-like enum {} with specified \
200
210
discriminants",
201
211
ty:: item_path_str( cx. tcx( ) ,
202
- def_id) ) . as_slice ( ) )
212
+ def_id) ) . as_slice ( ) ) ;
203
213
}
204
214
205
215
if cases. len ( ) == 1 {
206
216
// Equivalent to a struct/tuple/newtype.
207
217
// (Typechecking will reject discriminant-sizing attrs.)
208
218
assert_eq ! ( hint, attr:: ReprAny ) ;
209
- return Univariant ( mk_struct ( cx,
210
- cases. get ( 0 ) . tys . as_slice ( ) ,
211
- false ) ,
212
- false )
219
+ let mut ftys = cases. get ( 0 ) . tys . clone ( ) ;
220
+ if dtor { ftys. push ( ty:: mk_bool ( ) ) ; }
221
+ return Univariant ( mk_struct ( cx, ftys. as_slice ( ) , false ) , dtor) ;
213
222
}
214
223
215
- if cases. len ( ) == 2 && hint == attr:: ReprAny {
224
+ if !dtor && cases. len ( ) == 2 && hint == attr:: ReprAny {
216
225
// Nullable pointer optimization
217
226
let mut discr = 0 ;
218
227
while discr < 2 {
@@ -246,10 +255,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
246
255
let bounds = IntBounds { ulo : 0 , uhi : ( cases. len ( ) - 1 ) as u64 ,
247
256
slo : 0 , shi : ( cases. len ( ) - 1 ) as i64 } ;
248
257
let ity = range_to_inttype ( cx, hint, & bounds) ;
258
+
249
259
return General ( ity, cases. iter ( ) . map ( |c| {
250
- let discr = vec ! ( ty_of_inttype( ity) ) ;
251
- mk_struct ( cx, discr. append ( c. tys . as_slice ( ) ) . as_slice ( ) , false )
252
- } ) . collect ( ) )
260
+ let mut ftys = vec ! ( ty_of_inttype( ity) ) . append ( c. tys . as_slice ( ) ) ;
261
+ if dtor { ftys. push ( ty:: mk_bool ( ) ) ; }
262
+ mk_struct ( cx, ftys. as_slice ( ) , false )
263
+ } ) . collect ( ) , dtor) ;
253
264
}
254
265
_ => cx. sess ( ) . bug ( "adt::represent_type called on non-ADT type" )
255
266
}
@@ -359,7 +370,6 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec<
359
370
} ) . collect ( )
360
371
}
361
372
362
-
363
373
fn mk_struct ( cx : & CrateContext , tys : & [ ty:: t ] , packed : bool ) -> Struct {
364
374
let lltys = tys. iter ( ) . map ( |& ty| type_of:: sizing_type_of ( cx, ty) ) . collect :: < Vec < _ > > ( ) ;
365
375
let llty_rec = Type :: struct_ ( cx, lltys. as_slice ( ) , packed) ;
@@ -499,7 +509,7 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool
499
509
Some ( name) => { assert_eq ! ( sizing, false ) ; Type :: named_struct ( cx, name) }
500
510
}
501
511
}
502
- General ( ity, ref sts) => {
512
+ General ( ity, ref sts, _ ) => {
503
513
// We need a representation that has:
504
514
// * The alignment of the most-aligned field
505
515
// * The size of the largest variant (rounded up to that alignment)
@@ -584,7 +594,7 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti
584
594
val = load_discr ( bcx, ity, scrutinee, min, max) ;
585
595
signed = ity. is_signed ( ) ;
586
596
}
587
- General ( ity, ref cases) => {
597
+ General ( ity, ref cases, _ ) => {
588
598
let ptr = GEPi ( bcx, scrutinee, [ 0 , 0 ] ) ;
589
599
val = load_discr ( bcx, ity, ptr, 0 , ( cases. len ( ) - 1 ) as Disr ) ;
590
600
signed = ity. is_signed ( ) ;
@@ -658,7 +668,7 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
658
668
_match:: single_result ( Result :: new ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) ,
659
669
discr as u64 , true ) ) )
660
670
}
661
- General ( ity, _) => {
671
+ General ( ity, _, _ ) => {
662
672
_match:: single_result ( Result :: new ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) ,
663
673
discr as u64 , true ) ) )
664
674
}
@@ -684,17 +694,21 @@ pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
684
694
Store ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) , discr as u64 , true ) ,
685
695
val)
686
696
}
687
- General ( ity, _) => {
697
+ General ( ity, ref cases, dtor) => {
698
+ if dtor {
699
+ let ptr = trans_field_ptr ( bcx, r, val, discr,
700
+ cases. get ( discr as uint ) . fields . len ( ) - 2 ) ;
701
+ Store ( bcx, C_u8 ( bcx. ccx ( ) , 1 ) , ptr) ;
702
+ }
688
703
Store ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) , discr as u64 , true ) ,
689
704
GEPi ( bcx, val, [ 0 , 0 ] ) )
690
705
}
691
- Univariant ( ref st, true ) => {
692
- assert_eq ! ( discr, 0 ) ;
693
- Store ( bcx, C_u8 ( bcx. ccx ( ) , 1 ) ,
694
- GEPi ( bcx, val, [ 0 , st. fields . len ( ) - 1 ] ) )
695
- }
696
- Univariant ( ..) => {
706
+ Univariant ( ref st, dtor) => {
697
707
assert_eq ! ( discr, 0 ) ;
708
+ if dtor {
709
+ Store ( bcx, C_u8 ( bcx. ccx ( ) , 1 ) ,
710
+ GEPi ( bcx, val, [ 0 , st. fields . len ( ) - 1 ] ) ) ;
711
+ }
698
712
}
699
713
RawNullablePointer { nndiscr, nnty, ..} => {
700
714
if discr != nndiscr {
@@ -737,7 +751,9 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint {
737
751
assert_eq ! ( discr, 0 ) ;
738
752
st. fields . len ( ) - ( if dtor { 1 } else { 0 } )
739
753
}
740
- General ( _, ref cases) => cases. get ( discr as uint ) . fields . len ( ) - 1 ,
754
+ General ( _, ref cases, dtor) => {
755
+ cases. get ( discr as uint ) . fields . len ( ) - 1 - ( if dtor { 1 } else { 0 } )
756
+ }
741
757
RawNullablePointer { nndiscr, ref nullfields, .. } => {
742
758
if discr == nndiscr { 1 } else { nullfields. len ( ) }
743
759
}
@@ -762,7 +778,7 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
762
778
assert_eq ! ( discr, 0 ) ;
763
779
struct_field_ptr ( bcx, st, val, ix, false )
764
780
}
765
- General ( _, ref cases) => {
781
+ General ( _, ref cases, _ ) => {
766
782
struct_field_ptr ( bcx, cases. get ( discr as uint ) , val, ix + 1 , true )
767
783
}
768
784
RawNullablePointer { nndiscr, ref nullfields, .. } |
@@ -788,11 +804,10 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
788
804
}
789
805
}
790
806
791
- fn struct_field_ptr ( bcx : & Block , st : & Struct , val : ValueRef , ix : uint ,
792
- needs_cast : bool ) -> ValueRef {
793
- let ccx = bcx. ccx ( ) ;
794
-
807
+ pub fn struct_field_ptr ( bcx : & Block , st : & Struct , val : ValueRef ,
808
+ ix : uint , needs_cast : bool ) -> ValueRef {
795
809
let val = if needs_cast {
810
+ let ccx = bcx. ccx ( ) ;
796
811
let fields = st. fields . iter ( ) . map ( |& ty| type_of:: type_of ( ccx, ty) ) . collect :: < Vec < _ > > ( ) ;
797
812
let real_ty = Type :: struct_ ( ccx, fields. as_slice ( ) , st. packed ) ;
798
813
PointerCast ( bcx, val, real_ty. ptr_to ( ) )
@@ -803,10 +818,71 @@ fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
803
818
GEPi ( bcx, val, [ 0 , ix] )
804
819
}
805
820
821
+ pub fn fold_variants < ' r , ' b > (
822
+ bcx : & ' b Block < ' b > , r : & Repr , value : ValueRef ,
823
+ f : |& ' b Block < ' b > , & Struct , ValueRef |: ' r -> & ' b Block <' b>
824
+ ) -> & ' b Block <' b > {
825
+ let fcx = bcx. fcx ;
826
+ match * r {
827
+ Univariant ( ref st, _) => {
828
+ f ( bcx, st, value)
829
+ }
830
+ General ( ity, ref cases, _) => {
831
+ let ccx = bcx. ccx ( ) ;
832
+ let unr_cx = fcx. new_temp_block ( "enum-variant-iter-unr" ) ;
833
+ Unreachable ( unr_cx) ;
834
+
835
+ let discr_val = trans_get_discr ( bcx, r, value, None ) ;
836
+ let llswitch = Switch ( bcx, discr_val, unr_cx. llbb , cases. len ( ) ) ;
837
+ let bcx_next = fcx. new_temp_block ( "enum-variant-iter-next" ) ;
838
+
839
+ for ( discr, case) in cases. iter ( ) . enumerate ( ) {
840
+ let mut variant_cx = fcx. new_temp_block (
841
+ format ! ( "enum-variant-iter-{}" , discr. to_string( ) ) . as_slice ( )
842
+ ) ;
843
+ let rhs_val = C_integral ( ll_inttype ( ccx, ity) , discr as u64 , true ) ;
844
+ AddCase ( llswitch, rhs_val, variant_cx. llbb ) ;
845
+
846
+ let fields = case. fields . iter ( ) . map ( |& ty|
847
+ type_of:: type_of ( bcx. ccx ( ) , ty) ) . collect :: < Vec < _ > > ( ) ;
848
+ let real_ty = Type :: struct_ ( ccx, fields. as_slice ( ) , case. packed ) ;
849
+ let variant_value = PointerCast ( variant_cx, value, real_ty. ptr_to ( ) ) ;
850
+
851
+ variant_cx = f ( variant_cx, case, variant_value) ;
852
+ Br ( variant_cx, bcx_next. llbb ) ;
853
+ }
854
+
855
+ bcx_next
856
+ }
857
+ _ => unreachable ! ( )
858
+ }
859
+ }
860
+
806
861
/// Access the struct drop flag, if present.
807
- pub fn trans_drop_flag_ptr ( bcx : & Block , r : & Repr , val : ValueRef ) -> ValueRef {
862
+ pub fn trans_drop_flag_ptr < ' b > ( mut bcx : & ' b Block < ' b > , r : & Repr ,
863
+ val : ValueRef ) -> datum:: DatumBlock < ' b , datum:: Expr > {
864
+ let ptr_ty = ty:: mk_imm_ptr ( bcx. tcx ( ) , ty:: mk_bool ( ) ) ;
808
865
match * r {
809
- Univariant ( ref st, true ) => GEPi ( bcx, val, [ 0 , st. fields . len ( ) - 1 ] ) ,
866
+ Univariant ( ref st, true ) => {
867
+ let flag_ptr = GEPi ( bcx, val, [ 0 , st. fields . len ( ) - 1 ] ) ;
868
+ datum:: immediate_rvalue_bcx ( bcx, flag_ptr, ptr_ty) . to_expr_datumblock ( )
869
+ }
870
+ General ( _, _, true ) => {
871
+ let fcx = bcx. fcx ;
872
+ let custom_cleanup_scope = fcx. push_custom_cleanup_scope ( ) ;
873
+ let scratch = unpack_datum ! ( bcx, datum:: lvalue_scratch_datum(
874
+ bcx, ty:: mk_bool( ) , "drop_flag" , false ,
875
+ cleanup:: CustomScope ( custom_cleanup_scope) , ( ) , |_, bcx, _| bcx
876
+ ) ) ;
877
+ bcx = fold_variants ( bcx, r, val, |variant_cx, st, value| {
878
+ let ptr = struct_field_ptr ( variant_cx, st, value, ( st. fields . len ( ) - 1 ) , false ) ;
879
+ datum:: Datum :: new ( ptr, ptr_ty, datum:: Rvalue :: new ( datum:: ByRef ) )
880
+ . store_to ( variant_cx, scratch. val )
881
+ } ) ;
882
+ let expr_datum = scratch. to_expr_datum ( ) ;
883
+ fcx. pop_custom_cleanup_scope ( custom_cleanup_scope) ;
884
+ datum:: DatumBlock :: new ( bcx, expr_datum)
885
+ }
810
886
_ => bcx. ccx ( ) . sess ( ) . bug ( "tried to get drop flag of non-droppable type" )
811
887
}
812
888
}
@@ -840,7 +916,7 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
840
916
assert_discr_in_range ( ity, min, max, discr) ;
841
917
C_integral ( ll_inttype ( ccx, ity) , discr as u64 , true )
842
918
}
843
- General ( ity, ref cases) => {
919
+ General ( ity, ref cases, _ ) => {
844
920
let case = cases. get ( discr as uint ) ;
845
921
let max_sz = cases. iter ( ) . map ( |x| x. size ) . max ( ) . unwrap ( ) ;
846
922
let lldiscr = C_integral ( ll_inttype ( ccx, ity) , discr as u64 , true ) ;
@@ -964,7 +1040,7 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
964
1040
attr:: UnsignedInt ( ..) => const_to_uint ( val) as Disr
965
1041
}
966
1042
}
967
- General ( ity, _) => {
1043
+ General ( ity, _, _ ) => {
968
1044
match ity {
969
1045
attr:: SignedInt ( ..) => const_to_int ( const_get_elt ( ccx, val, [ 0 ] ) ) as Disr ,
970
1046
attr:: UnsignedInt ( ..) => const_to_uint ( const_get_elt ( ccx, val, [ 0 ] ) ) as Disr
0 commit comments