Remove support for obj dtors

This commit is contained in:
Marijn Haverbeke 2011-07-29 13:36:57 +02:00
parent 30d2e358be
commit b1d2a00b4a
15 changed files with 19 additions and 323 deletions

View File

@ -1327,11 +1327,10 @@ fn make_free_glue(cx: &@block_ctxt, v0: ValueRef, t: &ty::t) {
cx.build.GEP(body,
~[C_int(0), C_int(abi::obj_body_elt_tydesc)]);
let tydesc = cx.build.Load(tydescptr);
let cx_ = maybe_call_dtor(cx, v0);
let ti = none[@tydesc_info];
call_tydesc_glue_full(cx_, body, tydesc,
call_tydesc_glue_full(cx, body, tydesc,
abi::tydesc_field_drop_glue, ti);
trans_non_gc_free(cx_, b)
trans_non_gc_free(cx, b)
}
ty::ty_fn(_, _, _, _, _) {
let box_cell =
@ -2318,28 +2317,6 @@ fn call_tydesc_glue(cx: &@block_ctxt, v: ValueRef, t: &ty::t, field: int) ->
ret rslt(td.bcx, C_nil());
}
fn maybe_call_dtor(cx: &@block_ctxt, v: ValueRef) -> @block_ctxt {
let vtbl = cx.build.GEP(v, ~[C_int(0), C_int(abi::obj_field_vtbl)]);
vtbl = cx.build.Load(vtbl);
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), 1u));
vtbl = cx.build.PointerCast(vtbl, vtbl_type);
let dtor_ptr = cx.build.GEP(vtbl, ~[C_int(0), C_int(0)]);
dtor_ptr = cx.build.Load(dtor_ptr);
dtor_ptr = cx.build.BitCast(dtor_ptr, T_ptr(T_dtor(bcx_ccx(cx), cx.sp)));
let dtor_cx = new_sub_block_ctxt(cx, "dtor");
let after_cx = new_sub_block_ctxt(cx, "after_dtor");
let test =
cx.build.ICmp(lib::llvm::LLVMIntNE, dtor_ptr,
C_null(val_ty(dtor_ptr)));
cx.build.CondBr(test, dtor_cx.llbb, after_cx.llbb);
let me = dtor_cx.build.Load(v);
dtor_cx.build.FastCall(dtor_ptr,
~[C_null(T_ptr(T_nil())), cx.fcx.lltaskptr, me]);
dtor_cx.build.Br(after_cx.llbb);
ret after_cx;
}
fn call_cmp_glue(cx: &@block_ctxt, lhs: ValueRef, rhs: ValueRef, t: &ty::t,
llop: ValueRef) -> result {
// We can't use call_tydesc_glue_full() and friends here because compare
@ -3943,8 +3920,7 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
ast::expr_call(f, args) {
let pair =
create_real_fn_pair(cx, iter_body_llty, lliterbody, llenv.ptr);
r =
trans_call(cx, f, some[ValueRef](cx.build.Load(pair)), args,
r = trans_call(cx, f, some[ValueRef](cx.build.Load(pair)), args,
seq.id);
ret rslt(r.bcx, C_nil());
}
@ -4177,11 +4153,10 @@ fn trans_field(cx: &@block_ctxt, sp: &span, v: ValueRef, t0: &ty::t,
r.bcx.build.GEP(r.val, ~[C_int(0), C_int(abi::obj_field_vtbl)]);
vtbl = r.bcx.build.Load(vtbl);
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 2u));
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
vtbl = cx.build.PointerCast(vtbl, vtbl_type);
// +1 because slot #0 contains the destructor
let v = r.bcx.build.GEP(vtbl, ~[C_int(0), C_int(ix + 1u as int)]);
let v = r.bcx.build.GEP(vtbl, ~[C_int(0), C_int(ix as int)]);
let fn_ty: ty::t = ty::method_ty_to_fn_ty(bcx_tcx(cx), methods.(ix));
let tcx = bcx_tcx(cx);
let ll_fn_ty =
@ -5701,8 +5676,7 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
{fields:
std::ivec::map(ast::obj_field_from_anon_obj_field,
additional_fields),
methods: anon_obj.methods,
dtor: none[@ast::method]};
methods: anon_obj.methods};
let inner_obj_ty: ty::t;
let vtbl;
@ -6666,13 +6640,12 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
}
}
// Pick out the original method from the vtable. The +1 is because slot
// #0 contains the destructor.
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 2u));
// Pick out the original method from the vtable.
let vtbl_type = T_ptr(T_array(T_ptr(T_nil()), ix + 1u));
llinner_obj_vtbl = bcx.build.PointerCast(llinner_obj_vtbl, vtbl_type);
let llorig_mthd =
bcx.build.GEP(llinner_obj_vtbl, ~[C_int(0), C_int(ix + 1u as int)]);
bcx.build.GEP(llinner_obj_vtbl, ~[C_int(0), C_int(ix as int)]);
// Set up the original method to be called.
let orig_mthd_ty = ty::method_ty_to_fn_ty(cx.ccx.tcx, *m);
@ -6756,16 +6729,7 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
inner_obj_ty: option::t[ty::t],
additional_field_tys: &ty::t[]) -> ValueRef {
let dtor = C_null(T_ptr(T_i8()));
alt ob.dtor {
some(d) {
let dtor_1 = trans_dtor(cx, outer_obj_ty, ty_params, d);
dtor = llvm::LLVMConstBitCast(dtor_1, val_ty(dtor));
}
none. { }
}
let llmethods: ValueRef[] = ~[dtor];
let llmethods: ValueRef[] = ~[];
let meths: vtbl_mthd[] = ~[];
let backwarding_vtbl: option::t[ValueRef] = none;
@ -6911,19 +6875,6 @@ fn create_vtbl(cx: @local_ctxt, sp: &span, outer_obj_ty: ty::t,
ret gvar;
}
fn trans_dtor(cx: @local_ctxt, outer_obj_ty: ty::t,
ty_params: &ast::ty_param[],
dtor: &@ast::method) -> ValueRef {
let llfnty = T_dtor(cx.ccx, dtor.span);
let s: str = mangle_internal_name_by_path(cx.ccx, cx.path + ~["drop"]);
let llfn: ValueRef = decl_internal_fastcall_fn(cx.ccx.llmod, s, llfnty);
cx.ccx.item_ids.insert(dtor.node.id, llfn);
cx.ccx.item_symbols.insert(dtor.node.id, s);
trans_fn(cx, dtor.span, dtor.node.meth, llfn, some(outer_obj_ty),
ty_params, dtor.node.id);
ret llfn;
}
fn create_backwarding_vtbl(cx: @local_ctxt, sp: &span, inner_obj_ty: ty::t,
outer_obj_ty: ty::t) -> ValueRef {
@ -6931,8 +6882,7 @@ fn create_backwarding_vtbl(cx: @local_ctxt, sp: &span, inner_obj_ty: ty::t,
// object, and it needs to forward them to the corresponding slots on the
// outer object. All we know about either one are their types.
let dtor = C_null(T_ptr(T_i8()));
let llmethods: ValueRef[] = ~[dtor];
let llmethods: ValueRef[] = ~[];
let meths: vtbl_mthd[]= ~[];
// Gather up methods on the inner object.

View File

@ -542,11 +542,6 @@ fn T_glue_fn(cx: &crate_ctxt) -> TypeRef {
ret t;
}
fn T_dtor(ccx: &@crate_ctxt, sp: &span) -> TypeRef {
ret type_of_fn_full(ccx, sp, ast::proto_fn, true, ~[],
ty::mk_nil(ccx.tcx), 0u);
}
fn T_cmp_glue_fn(cx: &crate_ctxt) -> TypeRef {
let s = "cmp_glue_fn";
if cx.tn.name_has_type(s) { ret cx.tn.get_type(s); }

View File

@ -67,7 +67,6 @@ fn find_pre_post_obj(ccx: &crate_ctxt, o: _obj) {
find_pre_post_fn(fcx, m.node.meth);
}
for m: @method in o.methods { do_a_method(ccx, m); }
option::map[@method, ()](bind do_a_method(ccx, _), o.dtor);
}
fn find_pre_post_item(ccx: &crate_ctxt, i: &item) {

View File

@ -805,18 +805,6 @@ mod collect {
write::ty_only(cx.tcx, fld.id, args.(i).ty);
i += 1u;
}
// Finally, write in the type of the destructor.
alt object.dtor {
none. {/* nothing to do */ }
some(m) {
let t =
ty::mk_fn(cx.tcx, ast::proto_fn, ~[], ty::mk_nil(cx.tcx),
ast::return, ~[]);
write::ty_only(cx.tcx, m.node.id, t);
}
}
}
ast::item_res(f, dtor_id, tps, ctor_id) {
let t_arg = ty_of_arg(cx, f.decl.inputs.(0));
@ -2624,7 +2612,6 @@ fn check_item(ccx: @crate_ctxt, it: &@ast::item) {
// Typecheck the methods.
for method: @ast::method in ob.methods { check_method(ccx, method); }
option::may[@ast::method](bind check_method(ccx, _), ob.dtor);
// Now remove the info from the stack.
ivec::pop[obj_info](ccx.obj_infos);

View File

@ -524,8 +524,7 @@ type obj_field = {mut: mutability, ty: @ty, ident: ident, id: node_id};
type anon_obj_field =
{mut: mutability, ty: @ty, expr: @expr, ident: ident, id: node_id};
type _obj =
{fields: obj_field[], methods: (@method)[], dtor: option::t[@method]};
type _obj = {fields: obj_field[], methods: (@method)[]};
type anon_obj =
// New fields and methods, if they exist.
@ -590,16 +589,10 @@ tag item_ {
item_ty(@ty, ty_param[]);
item_tag(variant[], ty_param[]);
item_obj(_obj, ty_param[], /* constructor id */node_id);
item_res(
/* dtor */
_fn,
/* dtor id */
node_id,
item_res(_fn, /* dtor */
node_id, /* dtor id */
ty_param[],
/* ctor id */
node_id);
node_id /* ctor id */);
}
type native_item =

View File

@ -232,8 +232,8 @@ fn noop_fold_item_underscore(i: &item_, fld: ast_fold) -> item_ {
}
item_obj(o, typms, d) {
item_obj({fields: ivec::map(fold_obj_field, o.fields),
methods: ivec::map(fld.fold_method, o.methods),
dtor: option::map(fld.fold_method, o.dtor)}, typms, d)
methods: ivec::map(fld.fold_method, o.methods)},
typms, d)
}
item_res(dtor, did, typms, cid) {
item_res(fld.fold_fn(dtor), did, typms, cid)

View File

@ -1816,24 +1816,6 @@ fn parse_method(p: &parser) -> @ast::method {
ret @spanned(lo, f.body.span.hi, meth);
}
fn parse_dtor(p: &parser) -> @ast::method {
let lo = p.get_last_lo_pos();
let b: ast::blk = parse_block(p);
let inputs: ast::arg[] = ~[];
let output: @ast::ty = @spanned(lo, lo, ast::ty_nil);
// I guess dtors can't have constraints?
let d: ast::fn_decl = {
inputs: inputs,
output: output,
purity: ast::impure_fn,
cf: ast::return,
constraints: ~[]
};
let f: ast::_fn = {decl: d, proto: ast::proto_fn, body: b};
let m: ast::method_ = {ident: "drop", meth: f, id: p.get_id()};
ret @spanned(lo, f.body.span.hi, m);
}
fn parse_item_obj(p: &parser, attrs: &ast::attribute[]) ->
@ast::item {
let lo = p.get_last_lo_pos();
@ -1843,16 +1825,13 @@ fn parse_item_obj(p: &parser, attrs: &ast::attribute[]) ->
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_obj_field, p);
let meths: (@ast::method)[] = ~[];
let dtor: option::t[@ast::method] = none;
expect(p, token::LBRACE);
while p.peek() != token::RBRACE {
if eat_word(p, "drop") {
dtor = some(parse_dtor(p));
} else { meths += ~[parse_method(p)]; }
meths += ~[parse_method(p)];
}
let hi = p.get_hi_pos();
expect(p, token::RBRACE);
let ob: ast::_obj = {fields: fields.node, methods: meths, dtor: dtor};
let ob: ast::_obj = {fields: fields.node, methods: meths};
ret mk_item(p, lo, hi, ident, ast::item_obj(ob, ty_params, p.get_id()),
attrs);
}

View File

@ -510,14 +510,6 @@ fn print_item(s: &ps, item: &@ast::item) {
word(s.s, " ");
print_block(s, meth.node.meth.body);
}
alt _obj.dtor {
some(dtor) {
space(s.s);
head(s, "drop");
print_block(s, dtor.node.meth.body);
}
_ { }
}
bclose(s, item.span);
}
ast::item_res(dt, dt_id, tps, ct_id) {

View File

@ -106,13 +106,6 @@ fn visit_item[E](i: &@item, e: &E, v: &vt[E]) {
v.visit_fn(m.node.meth, ~[], m.span, some(m.node.ident),
m.node.id, e, v);
}
alt ob.dtor {
none. { }
some(m) {
v.visit_fn(m.node.meth, ~[], m.span, some(m.node.ident),
m.node.id, e, v);
}
}
}
}
}

View File

@ -118,13 +118,6 @@ fn walk_item(v: &ast_visitor, i: @ast::item) {
m.node.id);
v.visit_method_post(m);
}
alt ob.dtor {
none. { }
some(m) {
walk_fn(v, m.node.meth, ~[], m.span, some(m.node.ident),
m.node.id);
}
}
}
}
v.visit_item_post(i);

View File

@ -1,14 +0,0 @@
// -*- rust -*-
// error-pattern: attempted dynamic environment-capture
fn f(x: bool) { }
obj foobar(x: bool)
{drop {
let y = x;
fn test() { f(y); }
}
}
fn main() { }

View File

@ -1,6 +0,0 @@
// error-pattern:Unsatisfied precondition
fn main() {
obj foo(x: int) {drop { let baz: int; log baz; } }
fail;
}

View File

@ -1,123 +0,0 @@
// xfail-stage0
// xfail-stage1
// xfail-stage2
// xfail-stage3
// This test checks that destructors run in the right order. Because
// stateful objects can't have destructors, we have the destructors
// record their expected order into a channel when they execute (so
// the object becomes 'io' rather than 'state'). Then each test case
// asserts that the channel produces values in ascending order.
//
// FIXME: Write an int->str function and concatenate the whole failure
// message into a single log statement (or, even better, a print).
//
// FIXME: check_order should take only 1 line in a test, not 2+a block
// block. Since destructor-having objects can't refer to mutable state
// (like the port), we'd need a with-like construct to do the same for
// stateful objects within a scope.
//
// FIXME #21: Each test should execute in its own task, so it can fail
// independently, writing its error message to a channel that the
// parent task aggregates.
type order_info = rec(int order, str msg);
io fn check_order(port[order_info] expected_p) {
chan(expected_p) <| rec(order=-1, msg="");
let mutable int actual = 0;
// FIXME #121: Workaround for while(true) bug.
auto expected; expected_p |> expected;
auto done = -1; // FIXME: Workaround for typechecking bug.
while(expected.order != done) {
if (expected.order != actual) {
log expected.order;
log " != ";
log actual;
log expected.msg;
fail;
}
actual += 1;
expected_p |> expected;
}
}
obj dorder(chan[order_info] expected, int order, str message) {
drop {
expected <| rec(order=order, msg=message);
}
}
io fn test_simple() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
dorder(tracker, 1, "Reverse decl order");
dorder(tracker, 0, "Reverse decl order");
check_order(tracker_p);
}
io fn test_block() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
dorder(tracker, 2, "Before block");
{
dorder(tracker, 0, "Inside block");
}
dorder(tracker, 1, "After block");
}
check_order(tracker_p);
}
io fn test_decl_v_init() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
auto var1;
auto var2;
var2 = dorder(tracker, 0, "decl, not init");
var1 = dorder(tracker, 1, "decl, not init");
}
check_order(tracker_p);
}
io fn test_overwritten_obj() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
auto var1 = dorder(tracker, 0, "overwritten object destroyed first");
auto var2 = dorder(tracker, 2, "destroyed at end of scope");
var1 = dorder(tracker, 3, "overwriter deleted in rev decl order");
{
dorder(tracker, 1, "overwritten object destroyed before end of scope");
}
}
check_order(tracker_p);
}
// Used to embed dorder objects into an expression. Note that the
// parameters don't get destroyed.
fn combine_dorders(dorder d1, dorder d2) -> int {
ret 1;
}
io fn test_expression_destroyed_right_to_left() {
let port[order_info] tracker_p = port();
auto tracker = chan(tracker_p);
{
combine_dorders(dorder(tracker, 4, ""), dorder(tracker, 3, ""))
/ combine_dorders(dorder(tracker, 2, ""), dorder(tracker, 1, ""));
{
dorder(tracker, 0,
"expression objects live to end of block, not statement");
}
}
check_order(tracker_p);
}
io fn main() {
test_simple();
test_block();
test_decl_v_init();
test_overwritten_obj();
test_expression_destroyed_right_to_left();
}

View File

@ -1,9 +0,0 @@
obj foo(x: @mutable int) {drop { log "running dtor"; *x = *x + 1; } }
fn main() {
let mbox = @mutable 10;
{ let x = foo(mbox); }
assert (*mbox == 11);
}

View File

@ -1,33 +0,0 @@
// xfail-stage0
// xfail-stage1
// xfail-stage2
// xfail-stage3
obj worker(c: chan[int]) {drop { log "in dtor"; c <| 10; } }
fn do_work(c: chan[int]) {
log "in child task";
{ let w: worker = worker(c); log "constructed worker"; }
log "destructed worker";
while true {
// Deadlock-condition not handled properly yet, need to avoid
// exiting the child early.
c <| 11;
yield;
}
}
fn main() {
let p: port[int] = port();
log "spawning worker";
let w = spawn do_work(chan(p));
let i: int;
log "parent waiting for shutdown";
p |> i;
log "received int";
assert (i == 10);
log "int is OK, child-dtor ran as expected";
}