@@ -53,7 +53,10 @@ use middle::subst;
5353use middle:: subst:: Subst ;
5454use middle:: trans:: _match;
5555use middle:: trans:: build:: * ;
56+ use middle:: trans:: cleanup;
57+ use middle:: trans:: cleanup:: CleanupMethods ;
5658use middle:: trans:: common:: * ;
59+ use middle:: trans:: datum;
5760use middle:: trans:: machine;
5861use middle:: trans:: type_:: Type ;
5962use middle:: trans:: type_of;
@@ -83,8 +86,12 @@ pub enum Repr {
8386 /**
8487 * General-case enums: for each case there is a struct, and they
8588 * 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.
8693 */
87- General ( IntType , Vec < Struct > ) ,
94+ General ( IntType , Vec < Struct > , bool ) ,
8895 /**
8996 * Two cases distinguished by a nullable pointer: the case with discriminant
9097 * `nndiscr` must have single field which is known to be nonnull due to its type.
@@ -121,7 +128,7 @@ pub struct Struct {
121128 pub size : u64 ,
122129 pub align : u64 ,
123130 pub packed : bool ,
124- pub fields : Vec < ty:: t > ,
131+ pub fields : Vec < ty:: t >
125132}
126133
127134/**
@@ -173,14 +180,17 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
173180 let cases = get_cases ( cx. tcx ( ) , def_id, substs) ;
174181 let hint = ty:: lookup_repr_hint ( cx. tcx ( ) , def_id) ;
175182
183+ let dtor = ty:: ty_dtor ( cx. tcx ( ) , def_id) . has_drop_flag ( ) ;
184+
176185 if cases. len ( ) == 0 {
177186 // Uninhabitable; represent as unit
178187 // (Typechecking will reject discriminant-sizing attrs.)
179188 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) ;
181191 }
182192
183- if cases. iter ( ) . all ( |c| c. tys . len ( ) == 0 ) {
193+ if !dtor && cases. iter ( ) . all ( |c| c. tys . len ( ) == 0 ) {
184194 // All bodies empty -> intlike
185195 let discrs: Vec < u64 > = cases. iter ( ) . map ( |c| c. discr ) . collect ( ) ;
186196 let bounds = IntBounds {
@@ -199,20 +209,19 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
199209 cx. sess ( ) . bug ( format ! ( "non-C-like enum {} with specified \
200210 discriminants",
201211 ty:: item_path_str( cx. tcx( ) ,
202- def_id) ) . as_slice ( ) )
212+ def_id) ) . as_slice ( ) ) ;
203213 }
204214
205215 if cases. len ( ) == 1 {
206216 // Equivalent to a struct/tuple/newtype.
207217 // (Typechecking will reject discriminant-sizing attrs.)
208218 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) ;
213222 }
214223
215- if cases. len ( ) == 2 && hint == attr:: ReprAny {
224+ if !dtor && cases. len ( ) == 2 && hint == attr:: ReprAny {
216225 // Nullable pointer optimization
217226 let mut discr = 0 ;
218227 while discr < 2 {
@@ -246,10 +255,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
246255 let bounds = IntBounds { ulo : 0 , uhi : ( cases. len ( ) - 1 ) as u64 ,
247256 slo : 0 , shi : ( cases. len ( ) - 1 ) as i64 } ;
248257 let ity = range_to_inttype ( cx, hint, & bounds) ;
258+
249259 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) ;
253264 }
254265 _ => cx. sess ( ) . bug ( "adt::represent_type called on non-ADT type" )
255266 }
@@ -359,7 +370,6 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec<
359370 } ) . collect ( )
360371}
361372
362-
363373fn mk_struct ( cx : & CrateContext , tys : & [ ty:: t ] , packed : bool ) -> Struct {
364374 let lltys = tys. iter ( ) . map ( |& ty| type_of:: sizing_type_of ( cx, ty) ) . collect :: < Vec < _ > > ( ) ;
365375 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
499509 Some ( name) => { assert_eq ! ( sizing, false ) ; Type :: named_struct ( cx, name) }
500510 }
501511 }
502- General ( ity, ref sts) => {
512+ General ( ity, ref sts, _ ) => {
503513 // We need a representation that has:
504514 // * The alignment of the most-aligned field
505515 // * 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
584594 val = load_discr ( bcx, ity, scrutinee, min, max) ;
585595 signed = ity. is_signed ( ) ;
586596 }
587- General ( ity, ref cases) => {
597+ General ( ity, ref cases, _ ) => {
588598 let ptr = GEPi ( bcx, scrutinee, [ 0 , 0 ] ) ;
589599 val = load_discr ( bcx, ity, ptr, 0 , ( cases. len ( ) - 1 ) as Disr ) ;
590600 signed = ity. is_signed ( ) ;
@@ -658,7 +668,7 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
658668 _match:: single_result ( Result :: new ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) ,
659669 discr as u64 , true ) ) )
660670 }
661- General ( ity, _) => {
671+ General ( ity, _, _ ) => {
662672 _match:: single_result ( Result :: new ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) ,
663673 discr as u64 , true ) ) )
664674 }
@@ -684,17 +694,21 @@ pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
684694 Store ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) , discr as u64 , true ) ,
685695 val)
686696 }
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+ }
688703 Store ( bcx, C_integral ( ll_inttype ( bcx. ccx ( ) , ity) , discr as u64 , true ) ,
689704 GEPi ( bcx, val, [ 0 , 0 ] ) )
690705 }
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) => {
697707 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+ }
698712 }
699713 RawNullablePointer { nndiscr, nnty, ..} => {
700714 if discr != nndiscr {
@@ -737,7 +751,9 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint {
737751 assert_eq ! ( discr, 0 ) ;
738752 st. fields . len ( ) - ( if dtor { 1 } else { 0 } )
739753 }
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+ }
741757 RawNullablePointer { nndiscr, ref nullfields, .. } => {
742758 if discr == nndiscr { 1 } else { nullfields. len ( ) }
743759 }
@@ -762,7 +778,7 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
762778 assert_eq ! ( discr, 0 ) ;
763779 struct_field_ptr ( bcx, st, val, ix, false )
764780 }
765- General ( _, ref cases) => {
781+ General ( _, ref cases, _ ) => {
766782 struct_field_ptr ( bcx, cases. get ( discr as uint ) , val, ix + 1 , true )
767783 }
768784 RawNullablePointer { nndiscr, ref nullfields, .. } |
@@ -788,11 +804,10 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
788804 }
789805}
790806
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 {
795809 let val = if needs_cast {
810+ let ccx = bcx. ccx ( ) ;
796811 let fields = st. fields . iter ( ) . map ( |& ty| type_of:: type_of ( ccx, ty) ) . collect :: < Vec < _ > > ( ) ;
797812 let real_ty = Type :: struct_ ( ccx, fields. as_slice ( ) , st. packed ) ;
798813 PointerCast ( bcx, val, real_ty. ptr_to ( ) )
@@ -803,10 +818,71 @@ fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
803818 GEPi ( bcx, val, [ 0 , ix] )
804819}
805820
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+
806861/// 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 ( ) ) ;
808865 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+ }
810886 _ => bcx. ccx ( ) . sess ( ) . bug ( "tried to get drop flag of non-droppable type" )
811887 }
812888}
@@ -840,7 +916,7 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
840916 assert_discr_in_range ( ity, min, max, discr) ;
841917 C_integral ( ll_inttype ( ccx, ity) , discr as u64 , true )
842918 }
843- General ( ity, ref cases) => {
919+ General ( ity, ref cases, _ ) => {
844920 let case = cases. get ( discr as uint ) ;
845921 let max_sz = cases. iter ( ) . map ( |x| x. size ) . max ( ) . unwrap ( ) ;
846922 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)
9641040 attr:: UnsignedInt ( ..) => const_to_uint ( val) as Disr
9651041 }
9661042 }
967- General ( ity, _) => {
1043+ General ( ity, _, _ ) => {
9681044 match ity {
9691045 attr:: SignedInt ( ..) => const_to_int ( const_get_elt ( ccx, val, [ 0 ] ) ) as Disr ,
9701046 attr:: UnsignedInt ( ..) => const_to_uint ( const_get_elt ( ccx, val, [ 0 ] ) ) as Disr
0 commit comments