about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-05-15 17:59:55 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-05-15 18:00:41 -0700
commitfa5cc5bcd0e370a677de141d46455d4ee518dcfc (patch)
treeb918a6d1643f41eb4f17b65eca80b283c6cefbd7 /src/rustc
parent5d625af9f944c7b6567c443a6f796e30dbb01bf2 (diff)
downloadrust-fa5cc5bcd0e370a677de141d46455d4ee518dcfc.tar.gz
rust-fa5cc5bcd0e370a677de141d46455d4ee518dcfc.zip
Generate drop glue correctly for classes with destructors
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/metadata/common.rs1
-rw-r--r--src/rustc/metadata/csearch.rs7
-rw-r--r--src/rustc/metadata/decoder.rs14
-rw-r--r--src/rustc/metadata/encoder.rs9
-rw-r--r--src/rustc/middle/ast_map.rs1
-rw-r--r--src/rustc/middle/trans/base.rs90
-rw-r--r--src/rustc/middle/trans/shape.rs32
-rw-r--r--src/rustc/middle/trans/type_of.rs8
-rw-r--r--src/rustc/middle/ty.rs19
9 files changed, 153 insertions, 28 deletions
diff --git a/src/rustc/metadata/common.rs b/src/rustc/metadata/common.rs
index 42331973baa..35373bffd84 100644
--- a/src/rustc/metadata/common.rs
+++ b/src/rustc/metadata/common.rs
@@ -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
diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs
index 333ad2806c4..5ebdc144ae7 100644
--- a/src/rustc/metadata/csearch.rs
+++ b/src/rustc/metadata/csearch.rs
@@ -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;
diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs
index 1c8caa0f4aa..832dda817e3 100644
--- a/src/rustc/metadata/decoder.rs
+++ b/src/rustc/metadata/decoder.rs
@@ -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));
 }
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index c4f3225ebfc..4638d8ea4e5 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -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();
diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs
index ef5851c3faf..71ce361c626 100644
--- a/src/rustc/middle/ast_map.rs
+++ b/src/rustc/middle/ast_map.rs
@@ -302,7 +302,6 @@ fn node_id_to_str(map: map, id: node_id) -> str {
       }
     }
 }
-
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 43dfda53484..dcecd3f2251 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -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);
 }
diff --git a/src/rustc/middle/trans/shape.rs b/src/rustc/middle/trans/shape.rs
index 14215efb199..73897fd3175 100644
--- a/src/rustc/middle/trans/shape.rs
+++ b/src/rustc/middle/trans/shape.rs
@@ -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);
 }
 
diff --git a/src/rustc/middle/trans/type_of.rs b/src/rustc/middle/trans/type_of.rs
index 16646472de8..b094a576cb1 100644
--- a/src/rustc/middle/trans/type_of.rs
+++ b/src/rustc/middle/trans/type_of.rs
@@ -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"); }
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 09a1ef7c4c3..2d12870d25b 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -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)