Generate drop glue correctly for classes with destructors
This commit is contained in:
@@ -95,6 +95,7 @@ const tag_mod_impl_iface: uint = 0x47u;
|
||||
different tags.
|
||||
*/
|
||||
const tag_item_impl_method: uint = 0x48u;
|
||||
const tag_item_dtor: uint = 0x49u;
|
||||
|
||||
// used to encode crate_ctxt side tables
|
||||
enum astencode_tag { // Reserves 0x50 -- 0x6f
|
||||
|
||||
@@ -10,6 +10,7 @@ import driver::session::expect;
|
||||
import common::*;
|
||||
import std::map::hashmap;
|
||||
|
||||
export class_dtor;
|
||||
export get_symbol;
|
||||
export get_class_fields;
|
||||
export get_class_method;
|
||||
@@ -185,6 +186,12 @@ fn get_class_method(cstore: cstore::cstore, def: ast::def_id, mname: str)
|
||||
decoder::get_class_method(cdata, def.node, mname)
|
||||
}
|
||||
|
||||
/* If def names a class with a dtor, return it. Otherwise, return none. */
|
||||
fn class_dtor(cstore: cstore::cstore, def: ast::def_id)
|
||||
-> option<ast::def_id> {
|
||||
let cdata = cstore::get_crate_data(cstore, def.crate);
|
||||
decoder::class_dtor(cdata, def.node)
|
||||
}
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
||||
@@ -16,6 +16,7 @@ import util::ppaux::ty_to_str;
|
||||
import ebml::deserializer;
|
||||
import syntax::diagnostic::span_handler;
|
||||
|
||||
export class_dtor;
|
||||
export get_class_fields;
|
||||
export get_symbol;
|
||||
export get_enum_variants;
|
||||
@@ -331,6 +332,19 @@ fn get_class_method(cdata: cmd, id: ast::node_id, name: str) -> ast::def_id {
|
||||
}
|
||||
}
|
||||
|
||||
fn class_dtor(cdata: cmd, id: ast::node_id) -> option<ast::def_id> {
|
||||
let items = ebml::get_doc(ebml::doc(cdata.data), tag_items);
|
||||
let cls_items = alt maybe_find_item(id, items) {
|
||||
some(it) { it }
|
||||
none { ret none; }};
|
||||
let mut rslt = none;
|
||||
ebml::tagged_docs(cls_items, tag_item_dtor) {|f|
|
||||
let did = parse_def_id(ebml::doc_data(f));
|
||||
rslt = some(translate_def_id(cdata, did));
|
||||
}
|
||||
rslt
|
||||
}
|
||||
|
||||
fn get_symbol(data: @[u8], id: ast::node_id) -> str {
|
||||
ret item_symbol(lookup_item(id, data));
|
||||
}
|
||||
|
||||
@@ -201,8 +201,7 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
|
||||
encode_def_id(ebml_w, local_def(it.id));
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
// FIXME: I don't *think* dtor needs to be serialized?
|
||||
item_class(_, _, items, ctor, _dtor, _) {
|
||||
item_class(_, _, items, ctor, m_dtor, _) {
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
ebml_w.start_tag(tag_paths_data_item);
|
||||
encode_name(ebml_w, it.ident);
|
||||
@@ -212,6 +211,12 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt,
|
||||
add_to_index(ebml_w, path, index, it.ident);
|
||||
#debug("ctor id: %d", ctor.node.id);
|
||||
encode_named_def_id(ebml_w, it.ident, local_def(ctor.node.id));
|
||||
/* Encode id for dtor */
|
||||
option::iter(m_dtor) {|dtor|
|
||||
ebml_w.start_tag(tag_item_dtor);
|
||||
encode_def_id(ebml_w, local_def(dtor.node.id));
|
||||
ebml_w.end_tag();
|
||||
};
|
||||
encode_class_item_paths(ebml_w, items, path + [it.ident],
|
||||
index);
|
||||
ebml_w.end_tag();
|
||||
|
||||
@@ -302,7 +302,6 @@ fn node_id_to_str(map: map, id: node_id) -> str {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
||||
@@ -717,6 +717,48 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
|
||||
ty::ty_res(did, inner, substs) {
|
||||
trans_res_drop(bcx, v0, did, inner, substs.tps)
|
||||
}
|
||||
ty::ty_class(did, substs) {
|
||||
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
|
||||
}
|
||||
}
|
||||
none {
|
||||
// No dtor? Just the default case
|
||||
iter_structural_ty(bcx, v0, t, drop_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_fn(_) {
|
||||
closure::make_fn_glue(bcx, v0, t, drop_ty)
|
||||
}
|
||||
@@ -1015,11 +1057,12 @@ fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
|
||||
ret next_cx;
|
||||
}
|
||||
ty::ty_class(did, substs) {
|
||||
// a class is like a record type
|
||||
for vec::eachi(ty::class_items_as_fields(cx.tcx(), did, substs))
|
||||
assert(ty::ty_dtor(cx.tcx(), did) == none);
|
||||
// a class w/ no dtor is like a record type
|
||||
for vec::eachi(ty::class_items_as_fields(cx.tcx(), did, substs))
|
||||
{|i, fld|
|
||||
let llfld_a = GEPi(cx, av, [0u, i]);
|
||||
cx = f(cx, llfld_a, fld.mt.ty);
|
||||
let llfld_a = GEPi(cx, av, [0u, i]);
|
||||
cx = f(cx, llfld_a, fld.mt.ty);
|
||||
}
|
||||
}
|
||||
_ { cx.sess().unimpl("type in iter_structural_ty"); }
|
||||
@@ -2340,16 +2383,24 @@ 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) {
|
||||
ty::class_items_as_fields(bcx.tcx(), did, substs) }
|
||||
// Constraint?
|
||||
_ { bcx.tcx().sess.span_bug(sp, "trans_rec_field:\
|
||||
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?
|
||||
_ { bcx.tcx().sess.span_bug(sp, "trans_rec_field:\
|
||||
base expr has non-record type"); }
|
||||
};
|
||||
};
|
||||
let ix = field_idx_strict(bcx.tcx(), sp, field, fields);
|
||||
let val = GEPi(bcx, val, [0u, ix]);
|
||||
let val = GEPi(bcx, if is_class_with_dtor {
|
||||
GEPi(bcx, val, [0u, 1u])
|
||||
}
|
||||
else { val }, [0u, ix]);
|
||||
ret {bcx: bcx, val: val, kind: owned};
|
||||
}
|
||||
|
||||
@@ -4596,6 +4647,19 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
|
||||
// So we initialize it here
|
||||
|
||||
let selfptr = alloc_ty(bcx_top, rslt_ty);
|
||||
// If we have a dtor, we have a two-word representation with a drop
|
||||
// flag, then a pointer to the class itself
|
||||
let valptr = if option::is_some(ty::ty_dtor(bcx_top.tcx(),
|
||||
parent_id)) {
|
||||
// Initialize the drop flag
|
||||
let one = C_u8(1u);
|
||||
let flag = GEPi(bcx_top, selfptr, [0u, 0u]);
|
||||
Store(bcx_top, one, flag);
|
||||
// Select the pointer to the class itself
|
||||
GEPi(bcx_top, selfptr, [0u, 1u])
|
||||
}
|
||||
else { selfptr };
|
||||
|
||||
// initialize fields to zero
|
||||
let fields = ty::class_items_as_fields(bcx_top.tcx(), parent_id,
|
||||
dummy_substs(psubsts.tys));
|
||||
@@ -4604,7 +4668,7 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
|
||||
// drop their LHS
|
||||
for fields.each {|field|
|
||||
let ix = field_idx_strict(bcx.tcx(), sp, field.ident, fields);
|
||||
bcx = zero_alloca(bcx, GEPi(bcx, selfptr, [0u, ix]),
|
||||
bcx = zero_alloca(bcx, GEPi(bcx, valptr, [0u, ix]),
|
||||
field.mt.ty);
|
||||
}
|
||||
|
||||
@@ -4626,7 +4690,7 @@ 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;
|
||||
let class_ty = ty::lookup_item_type(ccx.tcx, parent_id).ty;
|
||||
trans_fn(ccx, path, ast_util::dtor_dec(),
|
||||
body, lldtor_decl, impl_self(class_ty), none, dtor_id);
|
||||
}
|
||||
|
||||
@@ -414,10 +414,25 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
||||
s
|
||||
}
|
||||
ty::ty_iface(_, _) { [shape_box_fn] }
|
||||
ty::ty_class(did, ts) {
|
||||
// same as records
|
||||
let mut s = [shape_struct], sub = [];
|
||||
for ty::class_items_as_fields(ccx.tcx, did, ts).each {|f|
|
||||
ty::ty_class(did, substs) {
|
||||
// same as records, unless there's a dtor
|
||||
let tps = substs.tps;
|
||||
let m_dtor_did = ty::ty_dtor(ccx.tcx, did);
|
||||
let mut s = if option::is_some(m_dtor_did) {
|
||||
[shape_res]
|
||||
}
|
||||
else { [shape_struct] };
|
||||
let mut sub = [];
|
||||
option::iter(m_dtor_did) {|dtor_did|
|
||||
let ri = {did: dtor_did, tps: tps};
|
||||
let id = interner::intern(ccx.shape_cx.resources, ri);
|
||||
add_u16(s, id as u16);
|
||||
add_u16(s, vec::len(tps) as u16);
|
||||
for vec::each(tps) {|tp|
|
||||
add_substr(s, shape_of(ccx, tp, ty_param_map));
|
||||
}
|
||||
};
|
||||
for ty::class_items_as_fields(ccx.tcx, did, substs).each {|f|
|
||||
sub += shape_of(ccx, f.mt.ty, ty_param_map);
|
||||
}
|
||||
add_substr(s, sub);
|
||||
@@ -571,14 +586,11 @@ fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
|
||||
|
||||
fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
|
||||
let mut dtors = [];
|
||||
let mut i = 0u;
|
||||
let len = interner::len(ccx.shape_cx.resources);
|
||||
while i < len {
|
||||
let ri = interner::get(ccx.shape_cx.resources, i);
|
||||
dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.tps)];
|
||||
i += 1u;
|
||||
uint::range(0u, len) {|i|
|
||||
let ri = interner::get(ccx.shape_cx.resources, i);
|
||||
dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.tps)];
|
||||
}
|
||||
|
||||
ret mk_global(ccx, "resource_shapes", C_struct(dtors), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,13 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
|
||||
let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
|
||||
type_of(cx, t)
|
||||
};
|
||||
T_struct(tys)
|
||||
if ty::ty_dtor(cx.tcx, did) == none {
|
||||
T_struct(tys)
|
||||
}
|
||||
else {
|
||||
// resource type
|
||||
T_struct([T_i8(), T_struct(tys)])
|
||||
}
|
||||
}
|
||||
ty::ty_self { cx.tcx.sess.unimpl("type_of: ty_self"); }
|
||||
ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
|
||||
|
||||
@@ -6,7 +6,7 @@ import session::session;
|
||||
import syntax::ast;
|
||||
import syntax::ast::*;
|
||||
import syntax::ast_util;
|
||||
import syntax::ast_util::{is_local, split_class_items};
|
||||
import syntax::ast_util::{is_local, local_def, split_class_items};
|
||||
import syntax::codemap::span;
|
||||
import metadata::csearch;
|
||||
import util::common::*;
|
||||
@@ -69,6 +69,7 @@ export new_ty_hash;
|
||||
export enum_variants, substd_enum_variants;
|
||||
export iface_methods, store_iface_methods, impl_iface;
|
||||
export enum_variant_with_id;
|
||||
export ty_dtor;
|
||||
export ty_param_bounds_and_ty;
|
||||
export ty_bool, mk_bool, type_is_bool;
|
||||
export ty_bot, mk_bot, type_is_bot;
|
||||
@@ -2377,6 +2378,22 @@ fn item_path_str(cx: ctxt, id: ast::def_id) -> str {
|
||||
ast_map::path_to_str(item_path(cx, id))
|
||||
}
|
||||
|
||||
/* If class_id names a class with a dtor, return some(the dtor's id).
|
||||
Otherwise return none. */
|
||||
fn ty_dtor(cx: ctxt, class_id: def_id) -> option<def_id> {
|
||||
if is_local(class_id) {
|
||||
alt cx.items.find(class_id.node) {
|
||||
some(ast_map::node_item(@{node: ast::item_class(_, _, _, _,
|
||||
some(dtor), _), _}, _))
|
||||
{ some(local_def(dtor.node.id)) }
|
||||
_ { none }
|
||||
}
|
||||
}
|
||||
else {
|
||||
csearch::class_dtor(cx.sess.cstore, class_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
|
||||
if id.crate != ast::local_crate {
|
||||
csearch::get_item_path(cx, id)
|
||||
|
||||
Reference in New Issue
Block a user