Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 59edfdd

Browse files
author
Jakub Wieczorek
committedJul 22, 2014
Add Drop support for enums
Fixes #13041.
1 parent 31c908b commit 59edfdd

File tree

11 files changed

+312
-84
lines changed

11 files changed

+312
-84
lines changed
 

‎src/librustc/middle/kind.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ use middle::freevars::freevar_entry;
1313
use middle::freevars;
1414
use middle::subst;
1515
use middle::ty;
16-
use middle::typeck::{MethodCall, NoAdjustment};
16+
use middle::ty_fold;
17+
use middle::ty_fold::TypeFoldable;
1718
use middle::typeck;
19+
use middle::typeck::{MethodCall, NoAdjustment};
1820
use util::ppaux::{Repr, ty_to_string};
1921
use util::ppaux::UserString;
2022

@@ -83,18 +85,29 @@ pub fn check_crate(tcx: &ty::ctxt,
8385
tcx.sess.abort_if_errors();
8486
}
8587

88+
struct EmptySubstsFolder<'a> {
89+
tcx: &'a ty::ctxt
90+
}
91+
impl<'a> ty_fold::TypeFolder for EmptySubstsFolder<'a> {
92+
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
93+
self.tcx
94+
}
95+
fn fold_substs(&mut self, _: &subst::Substs) -> subst::Substs {
96+
subst::Substs::empty()
97+
}
98+
}
99+
86100
fn check_struct_safe_for_destructor(cx: &mut Context,
87101
span: Span,
88102
struct_did: DefId) {
89103
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
90104
if !struct_tpt.generics.has_type_params(subst::TypeSpace)
91105
&& !struct_tpt.generics.has_region_params(subst::TypeSpace) {
92-
let struct_ty = ty::mk_struct(cx.tcx, struct_did,
93-
subst::Substs::empty());
94-
if !ty::type_is_sendable(cx.tcx, struct_ty) {
106+
let mut folder = EmptySubstsFolder { tcx: cx.tcx };
107+
if !ty::type_is_sendable(cx.tcx, struct_tpt.ty.fold_with(&mut folder)) {
95108
span_err!(cx.tcx.sess, span, E0125,
96109
"cannot implement a destructor on a \
97-
structure that does not satisfy Send");
110+
structure or enumeration that does not satisfy Send");
98111
span_note!(cx.tcx.sess, span,
99112
"use \"#[unsafe_destructor]\" on the implementation \
100113
to force the compiler to allow this");

‎src/librustc/middle/trans/adt.rs

Lines changed: 110 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ use middle::subst;
5353
use middle::subst::Subst;
5454
use middle::trans::_match;
5555
use middle::trans::build::*;
56+
use middle::trans::cleanup;
57+
use middle::trans::cleanup::CleanupMethods;
5658
use middle::trans::common::*;
59+
use middle::trans::datum;
5760
use middle::trans::machine;
5861
use middle::trans::type_::Type;
5962
use 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-
363373
fn 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

‎src/librustc/middle/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1856,7 +1856,7 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span,
18561856

18571857
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
18581858
match *avar {
1859-
adt::General(_, ref variants) => {
1859+
adt::General(_, ref variants, _) => {
18601860
for var in variants.iter() {
18611861
let mut size = 0;
18621862
for field in var.fields.iter().skip(1) {

‎src/librustc/middle/trans/debuginfo.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,7 @@ struct EnumMemberDescriptionFactory {
19931993
impl EnumMemberDescriptionFactory {
19941994
fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription> {
19951995
match *self.type_rep {
1996-
adt::General(_, ref struct_defs) => {
1996+
adt::General(_, ref struct_defs, _) => {
19971997
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
19981998
.expect(""));
19991999

@@ -2362,7 +2362,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
23622362
adt::RawNullablePointer { .. } |
23632363
adt::StructWrappedNullablePointer { .. } |
23642364
adt::Univariant(..) => None,
2365-
adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
2365+
adt::General(inttype, _, _) => Some(discriminant_type_metadata(inttype)),
23662366
};
23672367

23682368
let enum_llvm_type = type_of::type_of(cx, enum_type);

‎src/librustc/middle/trans/glue.rs

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -204,16 +204,16 @@ fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
204204
bcx
205205
}
206206

207-
fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
207+
fn trans_struct_drop_flag<'a>(mut bcx: &'a Block<'a>,
208208
t: ty::t,
209209
v0: ValueRef,
210210
dtor_did: ast::DefId,
211211
class_did: ast::DefId,
212212
substs: &subst::Substs)
213213
-> &'a Block<'a> {
214214
let repr = adt::represent_type(bcx.ccx(), t);
215-
let drop_flag = adt::trans_drop_flag_ptr(bcx, &*repr, v0);
216-
with_cond(bcx, load_ty(bcx, drop_flag, ty::mk_bool()), |cx| {
215+
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, v0));
216+
with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| {
217217
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
218218
})
219219
}
@@ -237,33 +237,33 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
237237
ty.element_type().func_params()
238238
};
239239

240-
// Class dtors have no explicit args, so the params should
241-
// just consist of the environment (self)
242-
assert_eq!(params.len(), 1);
243-
244-
// Be sure to put all of the fields into a scope so we can use an invoke
245-
// instruction to call the user destructor but still call the field
246-
// destructors if the user destructor fails.
247-
let field_scope = bcx.fcx.push_custom_cleanup_scope();
248-
249-
let self_arg = PointerCast(bcx, v0, *params.get(0));
250-
let args = vec!(self_arg);
251-
252-
// Add all the fields as a value which needs to be cleaned at the end of
253-
// this scope.
254-
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
255-
for (i, fld) in field_tys.iter().enumerate() {
256-
let llfld_a = adt::trans_field_ptr(bcx, &*repr, v0, 0, i);
257-
bcx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
258-
llfld_a,
259-
fld.mt.ty);
260-
}
240+
adt::fold_variants(bcx, &*repr, v0, |variant_cx, st, value| {
241+
// Be sure to put all of the fields into a scope so we can use an invoke
242+
// instruction to call the user destructor but still call the field
243+
// destructors if the user destructor fails.
244+
let field_scope = variant_cx.fcx.push_custom_cleanup_scope();
245+
246+
// Class dtors have no explicit args, so the params should
247+
// just consist of the environment (self).
248+
assert_eq!(params.len(), 1);
249+
let self_arg = PointerCast(variant_cx, value, *params.get(0));
250+
let args = vec!(self_arg);
251+
252+
// Add all the fields as a value which needs to be cleaned at the end of
253+
// this scope.
254+
for (i, ty) in st.fields.iter().enumerate() {
255+
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
256+
variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
257+
llfld_a, *ty);
258+
}
261259

262-
let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), ast::DUMMY_NODE_ID,
263-
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
264-
let (_, bcx) = invoke(bcx, dtor_addr, args, dtor_ty, None);
260+
let dtor_ty = ty::mk_ctor_fn(variant_cx.tcx(), ast::DUMMY_NODE_ID,
261+
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
262+
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None);
265263

266-
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
264+
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
265+
variant_cx
266+
})
267267
}
268268

269269
fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
@@ -317,7 +317,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
317317
}
318318
}
319319
}
320-
ty::ty_struct(did, ref substs) => {
320+
ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) => {
321321
let tcx = bcx.tcx();
322322
match ty::ty_dtor(tcx, did) {
323323
ty::TraitDtor(dtor, true) => {

‎src/librustc/middle/ty.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,13 +2106,16 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
21062106

21072107
ty_enum(did, ref substs) => {
21082108
let variants = substd_enum_variants(cx, did, substs);
2109-
let res =
2109+
let mut res =
21102110
TypeContents::union(variants.as_slice(), |variant| {
21112111
TypeContents::union(variant.args.as_slice(),
21122112
|arg_ty| {
21132113
tc_ty(cx, *arg_ty, cache)
21142114
})
21152115
});
2116+
if ty::has_dtor(cx, did) {
2117+
res = res | TC::OwnsDtor;
2118+
}
21162119
apply_lang_items(cx, did, res)
21172120
}
21182121

@@ -3778,17 +3781,13 @@ pub enum DtorKind {
37783781
}
37793782

37803783
impl DtorKind {
3781-
pub fn is_not_present(&self) -> bool {
3784+
pub fn is_present(&self) -> bool {
37823785
match *self {
3783-
NoDtor => true,
3786+
TraitDtor(..) => true,
37843787
_ => false
37853788
}
37863789
}
37873790

3788-
pub fn is_present(&self) -> bool {
3789-
!self.is_not_present()
3790-
}
3791-
37923791
pub fn has_drop_flag(&self) -> bool {
37933792
match self {
37943793
&NoDtor => false,

‎src/test/compile-fail/kindck-destructor-owned.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct Foo {
1717
}
1818

1919
impl Drop for Foo {
20-
//~^ ERROR cannot implement a destructor on a structure that does not satisfy Send
20+
//~^ ERROR cannot implement a destructor on a structure or enumeration that does not satisfy Send
2121
fn drop(&mut self) {
2222
}
2323
}

‎src/test/run-pass/drop-trait-enum.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(struct_variant)]
12+
13+
use std::task;
14+
15+
#[deriving(PartialEq, Show)]
16+
enum Message {
17+
Dropped,
18+
DestructorRan
19+
}
20+
21+
struct SendOnDrop {
22+
sender: Sender<Message>
23+
}
24+
25+
impl Drop for SendOnDrop {
26+
fn drop(&mut self) {
27+
self.sender.send(Dropped);
28+
}
29+
}
30+
31+
enum Foo {
32+
SimpleVariant(Sender<Message>),
33+
NestedVariant(Box<uint>, SendOnDrop, Sender<Message>),
34+
FailingVariant { on_drop: SendOnDrop }
35+
}
36+
37+
impl Drop for Foo {
38+
fn drop(&mut self) {
39+
match self {
40+
&SimpleVariant(ref mut sender) => {
41+
sender.send(DestructorRan);
42+
}
43+
&NestedVariant(_, _, ref mut sender) => {
44+
sender.send(DestructorRan);
45+
}
46+
&FailingVariant { .. } => {
47+
fail!("Failed");
48+
}
49+
}
50+
}
51+
}
52+
53+
pub fn main() {
54+
let (sender, receiver) = channel();
55+
{
56+
let v = SimpleVariant(sender);
57+
}
58+
assert_eq!(receiver.recv(), DestructorRan);
59+
assert_eq!(receiver.recv_opt().ok(), None);
60+
61+
let (sender, receiver) = channel();
62+
{
63+
let v = NestedVariant(box 42u, SendOnDrop { sender: sender.clone() }, sender);
64+
}
65+
assert_eq!(receiver.recv(), DestructorRan);
66+
assert_eq!(receiver.recv(), Dropped);
67+
assert_eq!(receiver.recv_opt().ok(), None);
68+
69+
let (sender, receiver) = channel();
70+
task::spawn(proc() {
71+
let v = FailingVariant { on_drop: SendOnDrop { sender: sender } };
72+
});
73+
assert_eq!(receiver.recv(), Dropped);
74+
assert_eq!(receiver.recv_opt().ok(), None);
75+
76+
let (sender, receiver) = channel();
77+
{
78+
task::spawn(proc() {
79+
let mut v = NestedVariant(box 42u, SendOnDrop {
80+
sender: sender.clone()
81+
}, sender.clone());
82+
v = NestedVariant(box 42u, SendOnDrop { sender: sender.clone() }, sender.clone());
83+
v = SimpleVariant(sender.clone());
84+
v = FailingVariant { on_drop: SendOnDrop { sender: sender } };
85+
});
86+
}
87+
assert_eq!(receiver.recv(), DestructorRan);
88+
assert_eq!(receiver.recv(), Dropped);
89+
assert_eq!(receiver.recv(), DestructorRan);
90+
assert_eq!(receiver.recv(), Dropped);
91+
assert_eq!(receiver.recv(), DestructorRan);
92+
assert_eq!(receiver.recv(), Dropped);
93+
assert_eq!(receiver.recv_opt().ok(), None);
94+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
enum Foo { }
12+
13+
impl Drop for Foo {
14+
fn drop(&mut self) { }
15+
}
16+
17+
fn foo(x: Foo) { }
18+
19+
fn main() { }

‎src/test/run-pass/issue-10802.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
1211
struct DroppableStruct;
12+
enum DroppableEnum {
13+
DroppableVariant1, DroppableVariant2
14+
}
1315

1416
static mut DROPPED: bool = false;
1517

@@ -18,9 +20,15 @@ impl Drop for DroppableStruct {
1820
unsafe { DROPPED = true; }
1921
}
2022
}
23+
impl Drop for DroppableEnum {
24+
fn drop(&mut self) {
25+
unsafe { DROPPED = true; }
26+
}
27+
}
2128

2229
trait MyTrait { }
2330
impl MyTrait for Box<DroppableStruct> {}
31+
impl MyTrait for Box<DroppableEnum> {}
2432

2533
struct Whatever { w: Box<MyTrait> }
2634
impl Whatever {
@@ -35,4 +43,10 @@ fn main() {
3543
let _a = Whatever::new(box f as Box<MyTrait>);
3644
}
3745
assert!(unsafe { DROPPED });
46+
unsafe { DROPPED = false; }
47+
{
48+
let f = box DroppableVariant1;
49+
let _a = Whatever::new(box f as Box<MyTrait>);
50+
}
51+
assert!(unsafe { DROPPED });
3852
}

‎src/test/run-pass/issue-6892.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
struct Foo;
1515
struct Bar { x: int }
1616
struct Baz(int);
17+
enum FooBar { _Foo(Foo), _Bar(uint) }
1718

1819
static mut NUM_DROPS: uint = 0;
1920

@@ -32,6 +33,11 @@ impl Drop for Baz {
3233
unsafe { NUM_DROPS += 1; }
3334
}
3435
}
36+
impl Drop for FooBar {
37+
fn drop(&mut self) {
38+
unsafe { NUM_DROPS += 1; }
39+
}
40+
}
3541

3642
fn main() {
3743
assert_eq!(unsafe { NUM_DROPS }, 0);
@@ -41,12 +47,19 @@ fn main() {
4147
assert_eq!(unsafe { NUM_DROPS }, 2);
4248
{ let _x = Baz(21); }
4349
assert_eq!(unsafe { NUM_DROPS }, 3);
50+
{ let _x = _Foo(Foo); }
51+
assert_eq!(unsafe { NUM_DROPS }, 5);
52+
{ let _x = _Bar(42u); }
53+
assert_eq!(unsafe { NUM_DROPS }, 6);
4454

45-
assert_eq!(unsafe { NUM_DROPS }, 3);
4655
{ let _ = Foo; }
47-
assert_eq!(unsafe { NUM_DROPS }, 4);
56+
assert_eq!(unsafe { NUM_DROPS }, 7);
4857
{ let _ = Bar { x: 21 }; }
49-
assert_eq!(unsafe { NUM_DROPS }, 5);
58+
assert_eq!(unsafe { NUM_DROPS }, 8);
5059
{ let _ = Baz(21); }
51-
assert_eq!(unsafe { NUM_DROPS }, 6);
60+
assert_eq!(unsafe { NUM_DROPS }, 9);
61+
{ let _ = _Foo(Foo); }
62+
assert_eq!(unsafe { NUM_DROPS }, 11);
63+
{ let _ = _Bar(42u); }
64+
assert_eq!(unsafe { NUM_DROPS }, 12);
5265
}

5 commit comments

Comments
 (5)

bors commented on Jul 22, 2014

@bors
Collaborator

bors commented on Jul 22, 2014

@bors
Collaborator

jakub-/rust/issue-13041 = 59edfdd merged ok, testing candidate = 217f1fb

bors commented on Jul 22, 2014

@bors
Collaborator

merging jakub-/rust/issue-13041 = 59edfdd into auto

bors commented on Jul 23, 2014

@bors
Collaborator

fast-forwarding master to auto = 217f1fb

Please sign in to comment.