From aa9d2d88d33266437ca770a7345cce0d23ad1011 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 12 Jun 2012 16:25:09 -0700 Subject: [PATCH] Handle class destructors correctly in metadata This allows destructors to be inlined, which is necessary since classes can have both ty params and destructors. --- src/libsyntax/ast.rs | 3 ++- src/libsyntax/ast_map.rs | 2 +- src/libsyntax/ast_util.rs | 5 ++++ src/rustc/metadata/decoder.rs | 17 +++++++------ src/rustc/metadata/encoder.rs | 38 ++++++++++++++++++----------- src/rustc/middle/astencode.rs | 16 ++++++++++++ src/rustc/middle/trans/base.rs | 16 +++++++++++- src/rustc/middle/trans/reachable.rs | 20 +++++++++++++-- 8 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 536ce3c294ef..ad1501dd8b0d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -730,7 +730,8 @@ enum inlined_item { ii_item(@item), ii_method(def_id /* impl id */, @method), ii_native(@native_item), - ii_ctor(class_ctor, ident, [ty_param], def_id /* parent id */) + ii_ctor(class_ctor, ident, [ty_param], def_id /* parent id */), + ii_dtor(class_dtor, ident, [ty_param], def_id /* parent id */) } // diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index b2e6446d7ee0..10397e795ab7 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -106,7 +106,7 @@ fn map_decoded_item(diag: span_handler, // don't decode and instantiate the impl, but just the method, we have to // add it to the table now: alt ii { - ii_item(_) | ii_ctor(_,_,_,_) { /* fallthrough */ } + ii_item(*) | ii_ctor(*) | ii_dtor(*) { /* fallthrough */ } ii_native(i) { cx.map.insert(i.id, node_native_item(i, native_abi_rust_intrinsic, @path)); diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index c81f6d9590fc..9eee9a33af8f 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -320,6 +320,7 @@ impl inlined_item_methods for inlined_item { ii_native(i) { /* FIXME: bad */ copy i.ident } ii_method(_, m) { /* FIXME: bad */ copy m.ident } ii_ctor(_, nm, _, _) { /* FIXME: bad */ copy nm } + ii_dtor(_, nm, _, _) { /* FIXME: bad */ copy nm } } } @@ -329,6 +330,7 @@ impl inlined_item_methods for inlined_item { ii_native(i) { i.id } ii_method(_, m) { m.id } ii_ctor(ctor, _, _, _) { ctor.node.id } + ii_dtor(dtor, _, _, _) { dtor.node.id } } } @@ -340,6 +342,9 @@ impl inlined_item_methods for inlined_item { ii_ctor(ctor, nm, tps, parent_id) { visit::visit_class_ctor_helper(ctor, nm, tps, parent_id, e, v); } + ii_dtor(dtor, nm, tps, parent_id) { + visit::visit_class_dtor_helper(dtor, tps, parent_id, e, v); + } } } } diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 4df45033a77c..dcb71c6718ae 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -335,15 +335,18 @@ 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 { let items = ebml::get_doc(ebml::doc(cdata.data), tag_items); + let mut found = none; 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 + none { fail (#fmt("class_dtor: class id not found \ + when looking up dtor for %d", id)); } + }; + ebml::tagged_docs(cls_items, tag_item_dtor) {|doc| + let doc1 = ebml::get_doc(doc, tag_def_id); + let did = parse_def_id(ebml::doc_data(doc1)); + found = some(translate_def_id(cdata, did)); + }; + found } fn get_symbol(data: @[u8], id: ast::node_id) -> str { diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index 113fafb73b31..215f73a6d4f4 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -9,7 +9,7 @@ import ebml::writer; import syntax::ast::*; import syntax::print::pprust; import syntax::{ast_util, visit}; -import syntax::ast_util::local_def; +import syntax::ast_util::*; import common::*; import middle::ty; import middle::ty::node_id_to_type; @@ -206,12 +206,6 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, add_to_index(ebml_w, path, index, it.ident); encode_named_def_id(ebml_w, it.ident, local_def(ctor.node.id)); - /* Encode id for dtor */ - option::iter(m_dtor) {|dtor| - ebml_w.wr_tag(tag_item_dtor) {|| - encode_def_id(ebml_w, local_def(dtor.node.id)); - } - }; encode_class_item_paths(ebml_w, items, path + [it.ident], index); } @@ -485,8 +479,8 @@ fn encode_info_for_fn(ecx: @encode_ctxt, ebml_w: ebml::writer, encode_family(ebml_w, purity_fn_family(decl.purity)); encode_type_param_bounds(ebml_w, ecx, tps); let its_ty = node_id_to_type(ecx.tcx, id); - #debug("fn name = %s ty = %s", ident, - util::ppaux::ty_to_str(ecx.tcx, its_ty)); + #debug("fn name = %s ty = %s its node id = %d", ident, + util::ppaux::ty_to_str(ecx.tcx, its_ty), id); encode_type(ecx, ebml_w, its_ty); encode_path(ebml_w, path, ast_map::path_name(ident)); alt item { @@ -623,13 +617,23 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_enum_variant_info(ecx, ebml_w, item.id, variants, path, index, tps); } - item_class(tps, ifaces, items, ctor, _dtor, rp) { + item_class(tps, ifaces, items, ctor, m_dtor, rp) { /* First, encode the fields and methods These come first because we need to write them to make the index, and the index needs to be in the item for the class itself */ let idx = encode_info_for_class(ecx, ebml_w, item.id, path, tps, items, index); + /* Encode the dtor */ + option::iter(m_dtor) {|dtor| + *index += [{val: dtor.node.id, pos: ebml_w.writer.tell()}]; + encode_info_for_fn(ecx, ebml_w, dtor.node.id, item.ident + + "_dtor", path, if tps.len() > 0u { + some(ii_dtor(dtor, item.ident, tps, + local_def(item.id))) } + else { none }, tps, ast_util::dtor_dec()); + } + /* Index the class*/ add_to_index(); /* Now, make an item for the class itself */ @@ -644,6 +648,14 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, for ifaces.each {|t| encode_iface_ref(ebml_w, ecx, t); } + /* Encode the dtor */ + /* Encode id for dtor */ + option::iter(m_dtor) {|dtor| + ebml_w.wr_tag(tag_item_dtor) {|| + encode_def_id(ebml_w, local_def(dtor.node.id)); + } + }; + /* Encode def_ids for each field and method for methods, write all the stuff get_iface_method needs to know*/ @@ -803,9 +815,7 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer, encode_info_for_item(ecx, ebml_w, i, index, *pt); /* encode ctor, then encode items */ alt i.node { - item_class(tps, _, _, ctor, _, _) { - /* this is assuming that ctors aren't inlined... - probably shouldn't assume that */ + item_class(tps, _, _, ctor, m_dtor, _) { #debug("encoding info for ctor %s %d", i.ident, ctor.node.id); *index += [{val: ctor.node.id, pos: ebml_w.writer.tell()}]; @@ -813,7 +823,7 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer, *pt, if tps.len() > 0u { some(ii_ctor(ctor, i.ident, tps, local_def(i.id))) } - else { none }, tps, ctor.node.dec) + else { none }, tps, ctor.node.dec); } _ {} } diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index d604505455cb..0d6b158a9ae5 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -427,6 +427,12 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item { with ctor.node} with ctor}, nm, tps, parent_id) } + ast::ii_dtor(dtor, nm, tps, parent_id) { + let dtor_body = fld.fold_block(dtor.node.body); + ast::ii_dtor({node: {body: dtor_body + with dtor.node} + with dtor}, nm, tps, parent_id) + } } } @@ -464,6 +470,16 @@ fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item) with ctor.node} with ctor}, nm, new_params, new_parent) } + ast::ii_dtor(dtor, nm, tps, parent_id) { + let dtor_body = fld.fold_block(dtor.node.body); + let new_params = fold::fold_ty_params(tps, fld); + let dtor_id = fld.new_id(dtor.node.id); + let new_parent = xcx.tr_def_id(parent_id); + let new_self = fld.new_id(dtor.node.self_id); + ast::ii_dtor({node: {id: dtor_id, self_id: new_self, body: dtor_body} + with dtor}, + nm, new_params, new_parent) + } } } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index fe4046c36635..2423f04d11fe 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -749,6 +749,12 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { ty::ty_opaque_closure_ptr(ck) { closure::make_opaque_cbox_free_glue(bcx, ck, v) } + ty::ty_class(did,substs) { + // Call the dtor if there is one + option::map_default(ty::ty_dtor(bcx.tcx(), did), bcx) {|dt_id| + trans_class_drop(bcx, v, dt_id, did, substs) + } + } _ { bcx } }; build_return(bcx); @@ -2287,7 +2293,7 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id) } some(none) { fn_id } // Not inlinable none { // Not seen yet - alt check csearch::maybe_get_item_ast( + alt csearch::maybe_get_item_ast( ccx.tcx, fn_id, bind astencode::decode_inlined_item(_, _, ccx.maps, _, _)) { @@ -2327,6 +2333,10 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id) trans_item(ccx, *item); local_def(my_id) } + csearch::found_parent(_, _) { + ccx.sess.bug("maybe_get_item_ast returned a found_parent \ + with a non-item parent"); + } csearch::found(ast::ii_method(impl_did, mth)) { ccx.external.insert(fn_id, some(mth.id)); let {bounds: impl_bnds, rp: _, ty: impl_ty} = @@ -2340,6 +2350,10 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id) } local_def(mth.id) } + csearch::found(ast::ii_dtor(dtor, nm, tps, parent_id)) { + ccx.external.insert(fn_id, some(dtor.node.id)); + local_def(dtor.node.id) + } } } } diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs index 25c60aa2793b..2b7084678742 100644 --- a/src/rustc/middle/trans/reachable.rs +++ b/src/rustc/middle/trans/reachable.rs @@ -9,7 +9,9 @@ import syntax::ast::*; import syntax::{visit, ast_util, ast_map}; import syntax::ast_util::def_id_of_def; import syntax::attr; +import syntax::print::pprust::expr_to_str; import std::map::hashmap; +import driver::session::*; export map, find_reachable; @@ -58,7 +60,11 @@ fn traverse_export(cx: ctx, exp_id: node_id) { fn traverse_def_id(cx: ctx, did: def_id) { if did.crate != local_crate { ret; } - alt cx.tcx.items.get(did.node) { + let n = alt cx.tcx.items.find(did.node) { + none { ret; } // This can happen for self, for example + some(n) { n } + }; + alt n { ast_map::node_item(item, _) { traverse_public_item(cx, item); } ast_map::node_method(_, impl_id, _) { traverse_def_id(cx, impl_id); } ast_map::node_native_item(item, _, _) { cx.rmap.insert(item.id, ()); } @@ -111,6 +117,10 @@ fn traverse_public_item(cx: ctx, item: @item) { cx.rmap.insert(ctor.node.id, ()); option::iter(m_dtor) {|dtor| cx.rmap.insert(dtor.node.id, ()); + // dtors don't have attrs + if tps.len() > 0u { + traverse_inline_body(cx, dtor.node.body); + } } for vec::each(items) {|item| alt item.node { @@ -134,7 +144,13 @@ fn traverse_inline_body(cx: ctx, body: blk) { fn traverse_expr(e: @expr, cx: ctx, v: visit::vt) { alt e.node { expr_path(_) { - traverse_def_id(cx, def_id_of_def(cx.tcx.def_map.get(e.id))); + alt cx.tcx.def_map.find(e.id) { + some(d) { + traverse_def_id(cx, def_id_of_def(d)); + } + none { cx.tcx.sess.span_bug(e.span, #fmt("Unbound node \ + id %? while traversing %s", e.id, expr_to_str(e))); } + } } expr_field(_, _, _) { alt cx.method_map.find(e.id) {