From 0cca08a21a33b60f9a27a4bab119b5ec8261be56 Mon Sep 17 00:00:00 2001 From: James Miller Date: Sun, 23 Jun 2013 14:41:45 +1200 Subject: [PATCH] Add support for #[no_drop_flag] attribute --- src/librustc/middle/trans/adt.rs | 2 +- src/librustc/middle/trans/glue.rs | 57 ++++++++++++++++++++++++++----- src/librustc/middle/ty.rs | 15 ++++++-- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 624c6607859..9b7c7037f42 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -135,7 +135,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr { ty::lookup_field_type(cx.tcx, def_id, field.id, substs) }; let packed = ty::lookup_packed(cx.tcx, def_id); - let dtor = ty::ty_dtor(cx.tcx, def_id).is_present(); + let dtor = ty::ty_dtor(cx.tcx, def_id).has_drop_flag(); let ftys = if dtor { ftys + [ty::mk_bool()] } else { ftys }; return Univariant(mk_struct(cx, ftys, packed), dtor) diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index d8ba524b2bd..056e5b8cdf7 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -406,13 +406,8 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { build_return(bcx); } -pub fn trans_struct_drop(bcx: block, - t: ty::t, - v0: ValueRef, - dtor_did: ast::def_id, - class_did: ast::def_id, - substs: &ty::substs) - -> block { +pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id, + class_did: ast::def_id, substs: &ty::substs) -> block { let repr = adt::represent_type(bcx.ccx(), t); let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0); do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| { @@ -454,6 +449,49 @@ pub fn trans_struct_drop(bcx: block, } } +pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id, + class_did: ast::def_id, substs: &ty::substs) -> block { + let repr = adt::represent_type(bcx.ccx(), t); + + // Find and call the actual destructor + let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, + class_did, /*bad*/copy substs.tps); + + // The second argument is the "self" argument for drop + let params = unsafe { + let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr)); + ty.element_type().func_params() + }; + + // Class dtors have no explicit args, so the params should + // just consist of the environment (self) + assert_eq!(params.len(), 1); + + // Take a reference to the class (because it's using the Drop trait), + // do so now. + let llval = alloca(bcx, val_ty(v0)); + Store(bcx, v0, llval); + + let self_arg = PointerCast(bcx, llval, params[0]); + let args = ~[self_arg]; + + Call(bcx, dtor_addr, args); + + // Drop the fields + let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs); + for field_tys.iter().enumerate().advance |(i, fld)| { + let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i); + bcx = drop_ty(bcx, llfld_a, fld.mt.ty); + } + + // Zero out the struct + unsafe { + let ty = Type::from_ref(llvm::LLVMTypeOf(v0)); + memzero(bcx, v0, ty); + } + + bcx +} pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { // NB: v0 is an *alias* of type t here, not a direct value. @@ -474,7 +512,10 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { ty::ty_struct(did, ref substs) => { let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { - ty::TraitDtor(dtor) => { + ty::TraitDtor(dtor, true) => { + trans_struct_drop_flag(bcx, t, v0, dtor, did, substs) + } + ty::TraitDtor(dtor, false) => { trans_struct_drop(bcx, t, v0, dtor, did, substs) } ty::NoDtor => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 90cd8a8665e..424307502f2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3855,7 +3855,7 @@ pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { pub enum DtorKind { NoDtor, - TraitDtor(def_id) + TraitDtor(def_id, bool) } impl DtorKind { @@ -3869,13 +3869,24 @@ impl DtorKind { pub fn is_present(&const self) -> bool { !self.is_not_present() } + + pub fn has_drop_flag(&self) -> bool { + match self { + &NoDtor => false, + &TraitDtor(_, flag) => flag + } + } } /* If struct_id names a struct with a dtor, return Some(the dtor's id). Otherwise return none. */ pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind { match cx.destructor_for_type.find(&struct_id) { - Some(&method_def_id) => TraitDtor(method_def_id), + Some(&method_def_id) => { + let flag = has_attr(cx, struct_id, "no_drop_flag"); + + TraitDtor(method_def_id, flag) + } None => NoDtor, } }