diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 038354da683..a4970268efd 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -698,6 +698,38 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { build_return(bcx); } +fn trans_class_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id, + class_did: ast::def_id, + substs: ty::substs) -> block { + let drop_flag = GEPi(bcx, v0, [0u, 0u]); + with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|cx| + let mut bcx = cx; + // We have to cast v0 + let classptr = GEPi(bcx, v0, [0u, 1u]); + // Find and call the actual destructor + let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, substs.tps); + // The second argument is the "self" argument for drop + let params = lib::llvm::fn_ty_param_tys + (llvm::LLVMGetElementType + (llvm::LLVMTypeOf(dtor_addr))); + // Class dtors have no explicit args, so the params should just consist + // of the output pointer and the environment (self) + assert(params.len() == 2u); + let self_arg = PointerCast(bcx, v0, params[1u]); + let args = [bcx.fcx.llretptr, self_arg]; + Call(bcx, dtor_addr, args); + // Drop the fields + for vec::eachi(ty::class_items_as_fields(bcx.tcx(), class_did, substs)) + {|i, fld| + let llfld_a = GEPi(bcx, classptr, [0u, i]); + bcx = drop_ty(bcx, llfld_a, fld.mt.ty); + } + Store(bcx, C_u8(0u), drop_flag); + bcx + } +} + + fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { // NB: v0 is an *alias* of type t here, not a direct value. let _icx = bcx.insn_ctxt("make_drop_glue"); @@ -718,37 +750,7 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { let tcx = bcx.tcx(); alt ty::ty_dtor(tcx, did) { some(dtor) { - let drop_flag = GEPi(bcx, v0, [0u, 0u]); - with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|cx| - let mut bcx = cx; - // we have to cast v0 - let classptr = GEPi(bcx, v0, [0u, 1u]); - // Find and call the actual destructor - let dtor_addr = get_res_dtor(bcx.ccx(), dtor, substs.tps); - // The second argument is the "self" argument for drop - let params = lib::llvm::fn_ty_param_tys - (llvm::LLVMGetElementType - (llvm::LLVMTypeOf(dtor_addr))); - let self_arg = PointerCast(bcx, v0, params[1u]); - let args = [bcx.fcx.llretptr, self_arg]; - let val_llty = lib::llvm::fn_ty_param_tys - (llvm::LLVMGetElementType - (llvm::LLVMTypeOf(dtor_addr)))[args.len()]; - let val_cast = BitCast(bcx, classptr, val_llty); - #debug("fn_ty: %s", ty_str(bcx.ccx().tn, - (llvm::LLVMGetElementType - (llvm::LLVMTypeOf(dtor_addr))))); - #debug("self's ty: %s", val_str(bcx.ccx().tn, v0)); - Call(bcx, dtor_addr, args + [val_cast]); - // Drop the fields - for vec::eachi(ty::class_items_as_fields(tcx, did, substs)) - {|i, fld| - let llfld_a = GEPi(bcx, classptr, [0u, i]); - bcx = drop_ty(bcx, llfld_a, fld.mt.ty); - } - Store(bcx, C_u8(0u), drop_flag); - bcx - } + trans_class_drop(bcx, v0, dtor, did, substs) } none { // No dtor? Just the default case @@ -2063,8 +2065,21 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t], ret {val: get_item_val(ccx, fn_id.node), must_cast: true}; } - ast_map::node_ctor(nm, _, _, pt) { (pt, nm, ast_util::dummy_sp()) } - _ { fail "unexpected node type"; } + ast_map::node_ctor(nm, _, ct, pt) { (pt, nm, alt ct { + ast_map::res_ctor(_, _, sp) { sp } + ast_map::class_ctor(ct_, _) { ct_.span }}) } + ast_map::node_dtor(_, dtor, _, pt) {(pt, "drop", dtor.span)} + ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") } + ast_map::node_export(*) { + ccx.tcx.sess.bug("Can't monomorphize an export") + } + ast_map::node_arg(*) { ccx.tcx.sess.bug("Can't monomorphize an arg") } + ast_map::node_block(*) { + ccx.tcx.sess.bug("Can't monomorphize a block") + } + ast_map::node_local(*) { + ccx.tcx.sess.bug("Can't monomorphize a local") + } }; let mono_ty = ty::subst_tps(ccx.tcx, substs, item_ty); let llfty = type_of_fn_from_ty(ccx, mono_ty); @@ -2081,55 +2096,97 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t], let pt = *pt + [path_name(ccx.names(name))]; let s = mangle_exported_name(ccx, pt, mono_ty); - let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty); - ccx.monomorphized.insert(hash_id, lldecl); + + let mk_lldecl = {|| + let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty); + ccx.monomorphized.insert(hash_id, lldecl); + lldecl + }; let psubsts = some({tys: substs, vtables: vtables, bounds: tpt.bounds}); - alt check map_node { + let lldecl = alt map_node { ast_map::node_item(i@@{node: ast::item_fn(decl, _, body), _}, _) { - set_inline_hint_if_appr(i.attrs, lldecl); - trans_fn(ccx, pt, decl, body, lldecl, no_self, psubsts, fn_id.node); + let d = mk_lldecl(); + set_inline_hint_if_appr(i.attrs, d); + trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node); + d } ast_map::node_item( - @{node: ast::item_res(d, _, body, d_id, _, _), _}, _) { - trans_fn(ccx, pt, d, body, lldecl, no_self, psubsts, d_id); + @{node: ast::item_res(dt, _, body, d_id, _, _), _}, _) { + let d = mk_lldecl(); + trans_fn(ccx, pt, dt, body, d, no_self, psubsts, d_id); + d + } + ast_map::node_item(*) { + ccx.tcx.sess.bug("Can't monomorphize this kind of item") } ast_map::node_native_item(i, _, _) { - native::trans_intrinsic(ccx, lldecl, i, pt, option::get(psubsts), + let d = mk_lldecl(); + native::trans_intrinsic(ccx, d, i, pt, option::get(psubsts), ref_id); + d } ast_map::node_variant(v, enum_item, _) { let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id)); let this_tv = option::get(vec::find(*tvs, {|tv| tv.id.node == fn_id.node})); - set_inline_hint(lldecl); + let d = mk_lldecl(); + set_inline_hint(d); trans_enum_variant(ccx, enum_item.id, v, this_tv.disr_val, - (*tvs).len() == 1u, psubsts, lldecl); + (*tvs).len() == 1u, psubsts, d); + d } ast_map::node_method(mth, impl_def_id, _) { - set_inline_hint_if_appr(mth.attrs, lldecl); + let d = mk_lldecl(); + set_inline_hint_if_appr(mth.attrs, d); let selfty = ty::node_id_to_type(ccx.tcx, mth.self_id); let selfty = ty::subst_tps(ccx.tcx, substs, selfty); - trans_fn(ccx, pt, mth.decl, mth.body, lldecl, + trans_fn(ccx, pt, mth.decl, mth.body, d, impl_self(selfty), psubsts, fn_id.node); + d } ast_map::node_ctor(nm, tps, ct, _) { + let d = mk_lldecl(); alt ct { ast_map::res_ctor(decl,_, _) { - set_inline_hint(lldecl); - trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, lldecl); + set_inline_hint(d); + trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, d); + d } ast_map::class_ctor(ctor, parent_id) { // ctors don't have attrs, at least not right now let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps); - trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, lldecl, + trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, d, option::get_default(psubsts, {tys:tp_tys, vtables: none, bounds: @[]}), fn_id.node, parent_id, ctor.span); + d } } } - } + ast_map::node_dtor(_, dtor, _, pt) { + let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx, + dtor.node.self_id)) { + some(did) { did } + none { ccx.sess.span_bug(dtor.span, "Bad self ty in \ + dtor"); } + }; + trans_class_dtor(ccx, *pt, dtor.node.body, + dtor.node.id, psubsts, some(hash_id), parent_id, s) + } + // Ugh -- but this ensures any new variants won't be forgotten + ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") } + ast_map::node_export(*) { + ccx.tcx.sess.bug("Can't monomorphize an export") + } + ast_map::node_arg(*) { ccx.tcx.sess.bug("Can't monomorphize an arg") } + ast_map::node_block(*) { + ccx.tcx.sess.bug("Can't monomorphize a block") + } + ast_map::node_local(*) { + ccx.tcx.sess.bug("Can't monomorphize a local") + } + }; ccx.monomorphizing.insert(fn_id, depth); {val: lldecl, must_cast: must_cast} } @@ -2283,8 +2340,7 @@ fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef { } fn cast_self(cx: block, slf: val_self_pair) -> ValueRef { - let rslt = PointerCast(cx, slf.v, T_ptr(type_of(cx.ccx(), slf.t))); - rslt + PointerCast(cx, slf.v, T_ptr(type_of(cx.ccx(), slf.t))) } fn trans_local_var(cx: block, def: ast::def) -> local_var_result { @@ -2310,14 +2366,25 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result { assert (cx.fcx.lllocals.contains_key(nid)); ret take_local(cx.fcx.lllocals, nid); } - ast::def_self(_) { + ast::def_self(sid) { let slf = alt copy cx.fcx.llself { - some(s) { s } - none { cx.sess().bug("trans_local_var: reference to self \ + some(s) { + alt option::map(ty::ty_to_def_id(s.t)) {|did| + ty::ty_dtor(cx.tcx(), did)} { + some(some(_)) { + /* self is a class with a dtor, which means we + have to select out the object itself + (If any other code does the same thing, that's + a bug */ + GEPi(cx, cast_self(cx, s), [0u, 1u]) + } + _ { cast_self(cx, s) } + } + } + none { cx.sess().bug("trans_local_var: reference to self \ out of context"); } }; - let ptr = cast_self(cx, slf); - ret {val: ptr, kind: owned}; + ret {val: slf, kind: owned}; } _ { cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?", @@ -2388,13 +2455,9 @@ fn trans_rec_field(bcx: block, base: @ast::expr, fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t, field: ast::ident, sp: span) -> lval_result { - let mut is_class_with_dtor = false; let fields = alt ty::get(ty).struct { ty::ty_rec(fs) { fs } ty::ty_class(did, substs) { - if option::is_some(ty::ty_dtor(bcx.tcx(), did)) { - is_class_with_dtor = true; - } ty::class_items_as_fields(bcx.tcx(), did, substs) } // Constraint? @@ -2402,10 +2465,8 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t, base expr has non-record type"); } }; let ix = field_idx_strict(bcx.tcx(), sp, field, fields); - let val = GEPi(bcx, if is_class_with_dtor { - GEPi(bcx, val, [0u, 1u]) - } - else { val }, [0u, ix]); + let val = GEPi(bcx, val, [0u, ix]); + ret {bcx: bcx, val: val, kind: owned}; } @@ -4726,12 +4787,39 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl, } fn trans_class_dtor(ccx: @crate_ctxt, path: path, - body: ast::blk, lldtor_decl: ValueRef, - dtor_id: ast::node_id, - parent_id: ast::def_id) { - let class_ty = ty::lookup_item_type(ccx.tcx, parent_id).ty; + body: ast::blk, + dtor_id: ast::node_id, substs: option, + hash_id: option, parent_id: ast::def_id, + // mangled exported name for dtor + s: str) -> ValueRef { + let tcx = ccx.tcx; + /* Look up the parent class's def_id */ + let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty; + /* Substitute in the class type if necessary */ + option::iter(substs) {|ss| + class_ty = ty::subst_tps(tcx, ss.tys, class_ty); + } + + /* The dtor takes a (null) output pointer, and a self argument, + and returns () */ + let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))), + T_ptr(type_of(ccx, class_ty))], + llvm::LLVMVoidType()); + /* Register the dtor as a function. It has external linkage */ + let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty); + lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage); + + /* If we're monomorphizing, register the monomorphized decl + for the dtor */ + option::iter(hash_id) {|h_id| + ccx.monomorphized.insert(h_id, lldecl); + } + /* Register the symbol for the dtor, and generate the code for its + body */ + ccx.item_symbols.insert(dtor_id, s); trans_fn(ccx, path, ast_util::dtor_dec(), - body, lldtor_decl, impl_self(class_ty), none, dtor_id); + body, lldecl, impl_self(class_ty), substs, dtor_id); + lldecl } fn trans_item(ccx: @crate_ctxt, item: ast::item) { @@ -4811,9 +4899,11 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { get_item_val(ccx, ctor.node.id), psubsts, ctor.node.id, local_def(item.id), ctor.span); option::iter(m_dtor) {|dtor| - trans_class_dtor(ccx, *path, dtor.node.body, - get_item_val(ccx, dtor.node.id), - dtor.node.id, local_def(item.id)); + let s = mangle_exported_name(ccx, *path + + [path_name(ccx.names("dtor"))], + ty::node_id_to_type(ccx.tcx, dtor.node.id)); + trans_class_dtor(ccx, *path, dtor.node.body, + dtor.node.id, none, none, local_def(item.id), s); }; } // If there are ty params, the ctor will get monomorphized @@ -4976,6 +5066,7 @@ fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path { fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef { #debug("get_item_val: %d", id); + let tcx = ccx.tcx; alt ccx.item_vals.find(id) { some(v) { v } none { @@ -5041,9 +5132,27 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef { } } ast_map::node_dtor(tps, dt, parent_id, pt) { - let my_path = *pt + [path_name("dtor")]; - let t = ty::node_id_to_type(ccx.tcx, dt.node.id); - register_fn_full(ccx, dt.span, my_path, dt.node.id, t) + /* + Don't just call register_fn, since we don't want to add + the implicit self argument automatically (we want to make sure + it has the right type) + */ + // Want parent_id and not id, because id is the dtor's type + let class_ty = ty::lookup_item_type(tcx, parent_id).ty; + // This code shouldn't be reached if the class is generic + assert !ty::type_has_params(class_ty); + let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))), + T_ptr(type_of(ccx, class_ty))], + llvm::LLVMVoidType()); + /* The symbol for the dtor should have already been registered */ + let s: str = alt ccx.item_symbols.find(id) { + some(s) { s } + none { ccx.sess.bug("in get_item_val, dtor is unbound"); } + }; + /* Make the declaration for the dtor */ + let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty); + lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage); + llfn } ast_map::node_variant(v, enm, pth) { diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index d69e7101aba..6ffd80cdceb 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -423,6 +423,12 @@ impl bcx_cxs for block { fn tcx() -> ty::ctxt { self.fcx.ccx.tcx } fn sess() -> session { self.fcx.ccx.sess } + fn val_str(val: ValueRef) -> str { + val_str(self.ccx().tn, val) + } + fn ty_to_str(t: ty::t) -> str { + ty_to_str(self.tcx(), t) + } fn to_str() -> str { alt self.node_info { some(node_info) { diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index 7d40a9535b2..25aee106a8b 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -6,6 +6,7 @@ import build::*; import driver::session::session; import syntax::{ast, ast_map}; import ast_map::{path, path_mod, path_name, node_id_to_str}; +import driver::session::expect; import syntax::ast_util::{local_def, split_class_items}; import metadata::csearch; import back::{link, abi}; @@ -247,7 +248,10 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: [ty::t], vtables: typeck::vtable_res) -> ValueRef { let _icx = ccx.insn_ctxt("impl::make_impl_vtable"); let tcx = ccx.tcx; - let ifce_id = ty::ty_to_def_id(option::get(ty::impl_iface(tcx, impl_id))); + let ifce_id = expect(ccx.sess, + ty::ty_to_def_id(option::get(ty::impl_iface(tcx, + impl_id))), + {|| "make_impl_vtable: non-iface-type implemented"}); let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u; make_vtable(ccx, vec::map(*ty::iface_methods(tcx, ifce_id)) {|im| let fty = ty::subst_tps(tcx, substs, ty::mk_fn(tcx, im.fty)); diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index b91cdff15b7..1ba04547604 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -90,6 +90,10 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint) ast_map::node_ctor(_, _, ast_map::class_ctor(ctor, _), _){ handle_body(cx, ctor.node.body); } + ast_map::node_dtor(_, dtor, _, _){ + handle_body(cx, dtor.node.body); + } + } let uses = vec::from_mut(cx.uses); ccx.type_use_cache.insert(fn_id, uses); diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 6410cfe5b6a..7ad4bb0103b 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2375,11 +2375,12 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option { } } -fn ty_to_def_id(ty: t) -> ast::def_id { - alt check get(ty).struct { +fn ty_to_def_id(ty: t) -> option { + alt get(ty).struct { ty_iface(id, _) | ty_class(id, _) | ty_res(id, _, _) | ty_enum(id, _) { - id + some(id) } + _ { none } } } @@ -2413,7 +2414,7 @@ fn ty_dtor(cx: ctxt, class_id: def_id) -> option { some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, some(dtor), _), _}, _)) { some(local_def(dtor.node.id)) } - _ { none } + _ { none } } } else { diff --git a/src/test/run-pass/resource-destruct-with-class.rs b/src/test/run-pass/resource-destruct-with-class.rs deleted file mode 100644 index 0ae85a5af0b..00000000000 --- a/src/test/run-pass/resource-destruct-with-class.rs +++ /dev/null @@ -1,13 +0,0 @@ -class shrinky_pointer { - let i: @@mut int; - fn look_at() -> int { ret **(self.i); } - new(i: @@mut int) { self.i = i; } - drop { log(error, "Hello!"); **(self.i) -= 1; } -} - -fn main() { - let my_total = @@mut 10; - { let pt <- shrinky_pointer(my_total); assert (pt.look_at() == 10); } - log(error, #fmt("my_total = %d", **my_total)); - assert (**my_total == 9); -} diff --git a/src/test/run-pass/resource-destruct.rs b/src/test/run-pass/resource-destruct.rs index a575d17d2f6..0ae85a5af0b 100644 --- a/src/test/run-pass/resource-destruct.rs +++ b/src/test/run-pass/resource-destruct.rs @@ -1,9 +1,13 @@ -resource shrinky_pointer(i: @mut int) { *i -= 1; } - -fn look_at(pt: shrinky_pointer) -> int { ret **pt; } +class shrinky_pointer { + let i: @@mut int; + fn look_at() -> int { ret **(self.i); } + new(i: @@mut int) { self.i = i; } + drop { log(error, "Hello!"); **(self.i) -= 1; } +} fn main() { - let my_total = @mut 10; - { let pt <- shrinky_pointer(my_total); assert (look_at(pt) == 10); } - assert (*my_total == 9); + let my_total = @@mut 10; + { let pt <- shrinky_pointer(my_total); assert (pt.look_at() == 10); } + log(error, #fmt("my_total = %d", **my_total)); + assert (**my_total == 9); } diff --git a/src/test/run-pass/resource-generic.rs b/src/test/run-pass/resource-generic.rs index 08e546749dc..2cc23c1daad 100644 --- a/src/test/run-pass/resource-generic.rs +++ b/src/test/run-pass/resource-generic.rs @@ -1,11 +1,15 @@ -resource finish(arg: {val: T, fin: native fn(T)}) { - arg.fin(arg.val); +class finish { + let arg: {val: T, fin: native fn(T)}; + new(arg: {val: T, fin: native fn(T)}) { + self.arg = arg; + } + drop { self.arg.fin(self.arg.val); } } fn main() { let box = @mut 10; fn dec_box(&&i: @mut int) { *i -= 1; } - { let i <- finish({val: box, fin: dec_box}); } + { let _i <- finish({val: box, fin: dec_box}); } assert (*box == 9); }