about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-05-14 14:13:32 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-05-14 14:26:10 -0700
commit5428a22b95ccd8c84a402e2f5cb4aa53ddc6f4d4 (patch)
tree5d5b8f41d0011249fd613c23d6033d05f36101c3 /src
parent89cd2f6bd01e66f41b8dc49dd09930aa86cd2bd9 (diff)
downloadrust-5428a22b95ccd8c84a402e2f5cb4aa53ddc6f4d4.tar.gz
rust-5428a22b95ccd8c84a402e2f5cb4aa53ddc6f4d4.zip
First cut at dtors for classes
Classes with dtors should compile now. Haven't yet tested
whether they actually run correctly.

Beginnings of support for #2295, though that won't be done until
there's more test cases and resources are removed.
Diffstat (limited to 'src')
-rw-r--r--src/librustsyntax/ast.rs12
-rw-r--r--src/librustsyntax/ast_util.rs6
-rw-r--r--src/librustsyntax/fold.rs11
-rw-r--r--src/librustsyntax/parse/parser.rs61
-rw-r--r--src/librustsyntax/parse/token.rs2
-rw-r--r--src/librustsyntax/print/pprust.rs7
-rw-r--r--src/librustsyntax/visit.rs23
-rw-r--r--src/rustc/metadata/astencode.rs7
-rw-r--r--src/rustc/metadata/encoder.rs9
-rw-r--r--src/rustc/middle/ast_map.rs15
-rw-r--r--src/rustc/middle/kind.rs2
-rw-r--r--src/rustc/middle/region.rs2
-rw-r--r--src/rustc/middle/resolve.rs28
-rw-r--r--src/rustc/middle/trans/base.rs22
-rw-r--r--src/rustc/middle/trans/impl.rs2
-rw-r--r--src/rustc/middle/trans/reachable.rs5
-rw-r--r--src/rustc/middle/tstate/pre_post_conditions.rs2
-rw-r--r--src/rustc/middle/ty.rs10
-rw-r--r--src/rustc/middle/typeck.rs34
-rw-r--r--src/test/run-pass/class-dtor.rs11
20 files changed, 216 insertions, 55 deletions
diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs
index fb97751fd51..8c27b8ba989 100644
--- a/src/librustsyntax/ast.rs
+++ b/src/librustsyntax/ast.rs
@@ -669,8 +669,10 @@ enum item_ {
     item_class([ty_param], /* ty params for class */
                [@iface_ref],   /* ifaces this class implements */
                [@class_member], /* methods, etc. */
-                               /* (not including ctor) */
+                               /* (not including ctor or dtor) */
                class_ctor,
+               /* dtor is optional */
+               option<class_dtor>,
                region_param
                ),
     item_iface([ty_param], region_param, [ty_method]),
@@ -700,6 +702,14 @@ type class_ctor_ = {id: node_id,
                     body: blk};
 
 #[auto_serialize]
+type class_dtor = spanned<class_dtor_>;
+
+#[auto_serialize]
+type class_dtor_ = {id: node_id,
+                    self_id: node_id,
+                    body: blk};
+
+#[auto_serialize]
 type native_item =
     {ident: ident,
      attrs: [attribute],
diff --git a/src/librustsyntax/ast_util.rs b/src/librustsyntax/ast_util.rs
index f2cb613f54b..eb442e1ec48 100644
--- a/src/librustsyntax/ast_util.rs
+++ b/src/librustsyntax/ast_util.rs
@@ -361,6 +361,12 @@ fn operator_prec(op: ast::binop) -> uint {
       or                {  1u }
   }
 }
+
+fn dtor_dec() -> fn_decl {
+    {inputs: [], output: @{id: 0, node: ty_nil, span: dummy_sp()},
+     purity: impure_fn, cf: return_val, constraints: []}
+}
+
 // Local Variables:
 // mode: rust
 // fill-column: 78;
diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs
index 7e5a315a1e1..bc1cec9021e 100644
--- a/src/librustsyntax/fold.rs
+++ b/src/librustsyntax/fold.rs
@@ -274,10 +274,16 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
                       fold_ty_params(typms, fld),
                       r)
           }
-          item_class(typms, ifaces, items, ctor, rp) {
+          item_class(typms, ifaces, items, ctor, m_dtor, rp) {
               let ctor_body = fld.fold_block(ctor.node.body);
               let ctor_decl = fold_fn_decl(ctor.node.dec, fld);
               let ctor_id   = fld.new_id(ctor.node.id);
+              let dtor = option::map(m_dtor) {|dtor|
+                let dtor_body = fld.fold_block(dtor.node.body);
+                let dtor_id   = fld.new_id(dtor.node.id);
+                {node: {body: dtor_body,
+                        id: dtor_id with dtor.node}
+                    with dtor}};
               item_class(
                   typms,
                   vec::map(ifaces, {|p| fold_iface_ref(p, fld) }),
@@ -285,8 +291,7 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
                   {node: {body: ctor_body,
                           dec: ctor_decl,
                           id: ctor_id with ctor.node}
-                   with ctor},
-                  rp)
+                      with ctor}, dtor, rp)
           }
           item_impl(tps, rp, ifce, ty, methods) {
               item_impl(fold_ty_params(tps, fld),
diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs
index 125dbb927f4..7c1e3a85a29 100644
--- a/src/librustsyntax/parse/parser.rs
+++ b/src/librustsyntax/parse/parser.rs
@@ -1940,14 +1940,24 @@ fn parse_item_class(p: parser) -> item_info {
     let mut ms: [@class_member] = [];
     let ctor_id = p.get_id();
     let mut the_ctor : option<(fn_decl, blk, codemap::span)> = none;
+    let mut the_dtor : option<(blk, codemap::span)> = none;
     while p.token != token::RBRACE {
         alt parse_class_item(p, class_path) {
-            ctor_decl(a_fn_decl, blk, s) {
-               the_ctor = some((a_fn_decl, blk, s));
-            }
-            members(mms) { ms += mms; }
+          ctor_decl(a_fn_decl, blk, s) {
+            the_ctor = some((a_fn_decl, blk, s));
+          }
+          dtor_decl(blk, s) {
+            the_dtor = some((blk, s));
+          }
+          members(mms) { ms += mms; }
        }
     }
+    let actual_dtor = option::map(the_dtor) {|dtor|
+       let (d_body, d_s) = dtor;
+       {node: {id: p.get_id(),
+               self_id: p.get_id(),
+               body: d_body},
+               span: d_s}};
     p.bump();
     alt the_ctor {
       some((ct_d, ct_b, ct_s)) {
@@ -1957,7 +1967,7 @@ fn parse_item_class(p: parser) -> item_info {
                     self_id: p.get_id(),
                     dec: ct_d,
                     body: ct_b},
-             span: ct_s}, rp),
+                     span: ct_s}, actual_dtor, rp),
         none)
       }
        /*
@@ -1982,24 +1992,41 @@ fn parse_single_class_item(p: parser, vis: visibility)
    }
 }
 
-// lets us identify the constructor declaration at
-// parse time
+/*
+  So that we can distinguish a class ctor or dtor
+  from other class members
+ */
 enum class_contents { ctor_decl(fn_decl, blk, codemap::span),
+                      dtor_decl(blk, codemap::span),
                       members([@class_member]) }
 
+fn parse_ctor(p: parser, result_ty: ast::ty_) -> class_contents {
+  // Can ctors/dtors have attrs? FIXME
+  let lo = p.last_span.lo;
+  let (decl_, _) = parse_fn_decl(p, impure_fn, parse_arg);
+  let decl = {output: @{id: p.get_id(),
+                        node: result_ty, span: decl_.output.span}
+              with decl_};
+  let body = parse_block(p);
+  ctor_decl(decl, body, mk_sp(lo, p.last_span.hi))
+}
+
+fn parse_dtor(p: parser) -> class_contents {
+  // Can ctors/dtors have attrs? FIXME
+  let lo = p.last_span.lo;
+  let body = parse_block(p);
+  dtor_decl(body, mk_sp(lo, p.last_span.hi))
+}
+
 fn parse_class_item(p:parser, class_name_with_tps: @path)
     -> class_contents {
     if eat_keyword(p, "new") {
-        let lo = p.last_span.lo;
-        // Can ctors have attrs?
-            // result type is always the type of the class
-        let (decl_, _) = parse_fn_decl(p, impure_fn, parse_arg);
-        let decl = {output: @{id: p.get_id(),
-                      node: ty_path(class_name_with_tps, p.get_id()),
-                      span: decl_.output.span}
-                    with decl_};
-        let body = parse_block(p);
-        ret ctor_decl(decl, body, mk_sp(lo, p.last_span.hi));
+       // result type is always the type of the class
+       ret parse_ctor(p, ty_path(class_name_with_tps,
+                              p.get_id()));
+    }
+    else if eat_keyword(p, "drop") {
+      ret parse_dtor(p);
     }
     else if eat_keyword(p, "priv") {
             expect(p, token::LBRACE);
diff --git a/src/librustsyntax/parse/token.rs b/src/librustsyntax/parse/token.rs
index 8ee9af1ac4d..07e2d6fa249 100644
--- a/src/librustsyntax/parse/token.rs
+++ b/src/librustsyntax/parse/token.rs
@@ -261,7 +261,7 @@ fn restricted_keyword_table() -> hashmap<str, ()> {
         "assert",
         "be", "break",
         "check", "claim", "class", "const", "cont", "copy", "crust",
-        "do",
+        "do", "drop",
         "else", "enum", "export",
         "fail", "false", "fn", "for",
         "if", "iface", "impl", "import",
diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs
index 46745b7e28c..5f1f2323b60 100644
--- a/src/librustsyntax/print/pprust.rs
+++ b/src/librustsyntax/print/pprust.rs
@@ -507,7 +507,7 @@ fn print_item(s: ps, &&item: @ast::item) {
             bclose(s, item.span);
         }
       }
-      ast::item_class(tps,ifaces,items,ctor, rp) {
+      ast::item_class(tps, ifaces, items, ctor, m_dtor, rp) {
           head(s, "class");
           word_nbsp(s, item.ident);
           print_region_param(s, rp);
@@ -522,6 +522,11 @@ fn print_item(s: ps, &&item: @ast::item) {
           print_fn_args_and_ret(s, ctor.node.dec, []);
           space(s.s);
           print_block(s, ctor.node.body);
+          option::iter(m_dtor) {|dtor|
+            hardbreak_if_not_bol(s);
+            head(s, "drop");
+            print_block(s, dtor.node.body);
+          }
           for items.each {|ci|
                   /*
                      FIXME: collect all private items and print them
diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs
index c9c751900c8..980f9244c35 100644
--- a/src/librustsyntax/visit.rs
+++ b/src/librustsyntax/visit.rs
@@ -19,7 +19,10 @@ enum fn_kind {
     fk_anon(proto, capture_clause),  //< an anonymous function like fn@(...)
     fk_fn_block(capture_clause),     //< a block {||...}
     fk_ctor(ident, [ty_param], node_id /* self id */,
-            def_id /* parent class id */) // class constructor
+            def_id /* parent class id */), // class constructor
+    fk_dtor([ty_param], node_id /* self id */,
+            def_id /* parent class id */) // class destructor
+
 }
 
 fn name_of_fn(fk: fn_kind) -> ident {
@@ -27,13 +30,14 @@ fn name_of_fn(fk: fn_kind) -> ident {
       fk_item_fn(name, _) | fk_method(name, _, _) | fk_res(name, _, _)
           | fk_ctor(name, _, _, _) { name }
       fk_anon(*) | fk_fn_block(*) { "anon" }
+      fk_dtor(*)                  { "drop" }
     }
 }
 
 fn tps_of_fn(fk: fn_kind) -> [ty_param] {
     alt fk {
       fk_item_fn(_, tps) | fk_method(_, tps, _) | fk_res(_, tps, _)
-          | fk_ctor(_, tps, _, _) { tps }
+          | fk_ctor(_, tps, _, _) | fk_dtor(tps, _, _) { tps }
       fk_anon(*) | fk_fn_block(*) { [] }
     }
 }
@@ -140,7 +144,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
             visit_method_helper(m, e, v)
         }
       }
-      item_class(tps, ifaces, members, ctor, _) {
+      item_class(tps, ifaces, members, ctor, m_dtor, _) {
           v.visit_ty_params(tps, e, v);
           for members.each {|m|
              v.visit_class_item(m, e, v);
@@ -148,6 +152,9 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
           for ifaces.each {|p| visit_path(p.path, e, v); }
           visit_class_ctor_helper(ctor, i.ident, tps,
                                   ast_util::local_def(i.id), e, v);
+          option::iter(m_dtor) {|dtor|
+                  visit_class_dtor_helper(dtor, tps,
+                     ast_util::local_def(i.id), e, v)};
       }
       item_iface(tps, _rp, methods) {
         v.visit_ty_params(tps, e, v);
@@ -280,12 +287,20 @@ fn visit_method_helper<E>(m: @method, e: E, v: vt<E>) {
 // Similar logic to the comment on visit_method_helper - Tim
 fn visit_class_ctor_helper<E>(ctor: class_ctor, nm: ident, tps: [ty_param],
                               parent_id: def_id, e: E, v: vt<E>) {
-    v.visit_fn(visit::fk_ctor(nm, tps, ctor.node.self_id,
+    v.visit_fn(fk_ctor(nm, tps, ctor.node.self_id,
                               parent_id), ctor.node.dec,
                ctor.node.body, ctor.span, ctor.node.id, e, v)
 
 }
 
+fn visit_class_dtor_helper<E>(dtor: class_dtor, tps: [ty_param],
+                              parent_id: def_id, e: E, v: vt<E>) {
+    v.visit_fn(fk_dtor(tps, dtor.node.self_id,
+                       parent_id), ast_util::dtor_dec(),
+               dtor.node.body, dtor.span, dtor.node.id, e, v)
+
+}
+
 fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span,
                _id: node_id, e: E, v: vt<E>) {
     visit_fn_decl(decl, e, v);
diff --git a/src/rustc/metadata/astencode.rs b/src/rustc/metadata/astencode.rs
index 080a5431faa..315836fc0c3 100644
--- a/src/rustc/metadata/astencode.rs
+++ b/src/rustc/metadata/astencode.rs
@@ -214,6 +214,13 @@ fn visit_ids(item: ast::inlined_item, vfn: fn@(ast::node_id)) {
                 vfn(self_id);
                 vfn(parent_id.node);
               }
+              // not sure if this should be here? FIXME
+              visit::fk_dtor(tps, self_id, parent_id) {
+                vec::iter(tps) {|tp| vfn(tp.id)}
+                vfn(id);
+                vfn(self_id);
+                vfn(parent_id.node);
+              }
               visit::fk_item_fn(_, tps) |
               visit::fk_res(_, tps, _) {
                 vec::iter(tps) {|tp| vfn(tp.id)}
diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs
index 7c261829084..3afa3776cca 100644
--- a/src/rustc/metadata/encoder.rs
+++ b/src/rustc/metadata/encoder.rs
@@ -187,7 +187,8 @@ 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();
           }
-          item_class(_, _, items, ctor, _) {
+          // FIXME: I don't *think* dtor needs to be serialized?
+          item_class(_, _, items, ctor, _dtor, _) {
             add_to_index(ebml_w, path, index, it.ident);
             ebml_w.start_tag(tag_paths_data_item);
             encode_name(ebml_w, it.ident);
@@ -621,7 +622,8 @@ 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, rp) {
+      // FIXME: not sure if the dtor should be serialized
+      item_class(tps, ifaces, items, ctor, _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
@@ -801,7 +803,8 @@ 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, _) {
+                   // FIXME: not doing anything with dtor
+                   item_class(tps, _, _, ctor, _, _) {
                    /* this is assuming that ctors aren't inlined...
                       probably shouldn't assume that */
                    #debug("encoding info for ctor %s %d", i.ident,
diff --git a/src/rustc/middle/ast_map.rs b/src/rustc/middle/ast_map.rs
index f2300f9695a..ef5851c3faf 100644
--- a/src/rustc/middle/ast_map.rs
+++ b/src/rustc/middle/ast_map.rs
@@ -47,6 +47,8 @@ enum ast_node {
     node_local(uint),
     // Constructor for either a resource or a class
     node_ctor(ident, [ty_param], a_ctor, @path),
+    // Destructor for a class
+    node_dtor([ty_param], @class_dtor, def_id, @path),
     node_block(blk),
 }
 
@@ -134,6 +136,12 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
           cx.map.insert(id, node_ctor(nm, tps, class_ctor(ct, parent_id),
                                       @cx.path));
        }
+      visit::fk_dtor(tps, self_id, parent_id) {
+          let dt = @{node: {id: id, self_id: self_id, body: body},
+                    span: sp};
+          cx.map.insert(id, node_dtor(tps, dt, parent_id, @cx.path));
+       }
+
        _ {}
     }
     visit::visit_fn(fk, decl, body, sp, id, cx, v);
@@ -204,7 +212,7 @@ fn map_item(i: @item, cx: ctx, v: vt) {
             cx.map.insert(nitem.id, node_native_item(nitem, abi, @cx.path));
         }
       }
-      item_class(tps, ifces, items, ctor, _) {
+      item_class(tps, ifces, items, ctor, dtor, _) {
           let (_, ms) = ast_util::split_class_items(items);
           // Map iface refs to their parent classes. This is
           // so we can find the self_ty
@@ -283,9 +291,12 @@ fn node_id_to_str(map: map, id: node_id) -> str {
       some(node_local(_)) { // FIXME: add more info here
         #fmt["local (id=%?)", id]
       }
-      some(node_ctor(_, _, _, _)) { // FIXME: add more info here
+      some(node_ctor(*)) { // FIXME: add more info here
         #fmt["node_ctor (id=%?)", id]
       }
+      some(node_dtor(*)) { // FIXME: add more info here
+        #fmt["node_dtor (id=%?)", id]
+      }
       some(node_block(_)) {
         #fmt["block"]
       }
diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs
index 0b86f62eeb9..999c4390487 100644
--- a/src/rustc/middle/kind.rs
+++ b/src/rustc/middle/kind.rs
@@ -133,7 +133,7 @@ fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
         let cap_clause = alt fk {
           visit::fk_anon(_, cc) | visit::fk_fn_block(cc) { cc }
           visit::fk_item_fn(*) | visit::fk_method(*) |
-          visit::fk_res(*) | visit::fk_ctor(*) { @[] }
+          visit::fk_res(*) | visit::fk_ctor(*) | visit::fk_dtor(*) { @[] }
         };
         let captured_vars = (*cap_clause).map { |cap_item|
             let cap_def = cx.tcx.def_map.get(cap_item.id);
diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs
index 2635476dfb7..6cdc2724e0c 100644
--- a/src/rustc/middle/region.rs
+++ b/src/rustc/middle/region.rs
@@ -375,7 +375,7 @@ fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
 
     let fn_cx = alt fk {
       visit::fk_item_fn(*) | visit::fk_method(*) | visit::fk_res(*) |
-      visit::fk_ctor(*) {
+      visit::fk_ctor(*) | visit::fk_dtor(*) {
         // Top-level functions are a root scope.
         {parent: some(id), closure_parent: some(id) with cx}
       }
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs
index 4461da16a1b..8e9eccf5a0b 100644
--- a/src/rustc/middle/resolve.rs
+++ b/src/rustc/middle/resolve.rs
@@ -437,7 +437,7 @@ fn resolve_names(e: @env, c: @ast::crate) {
           ast::item_impl(_, _, ifce, _, _) {
             ifce.iter {|p| resolve_iface_ref(p, sc, e);}
           }
-          ast::item_class(_, ifaces, _, _, _) {
+          ast::item_class(_, ifaces, _, _, _, _) {
             for ifaces.each {|p|
                resolve_iface_ref(p, sc, e);
             }
@@ -564,22 +564,31 @@ fn visit_item_with_scope(e: @env, i: @ast::item, sc: scopes, v: vt<scopes>) {
             v.visit_ty(m.decl.output, msc, v);
         }
       }
-      ast::item_class(tps, ifaces, members, ctor, _) {
+      ast::item_class(tps, ifaces, members, ctor, m_dtor, _) {
         visit::visit_ty_params(tps, sc, v);
         // Can maybe skip this now that we require self on class fields
         let class_scope = cons(scope_item(i), @sc);
         /* visit the constructor... */
         let ctor_scope = cons(scope_method(ctor.node.self_id, tps),
                               @class_scope);
-        /*
-          but, I should visit the ifaces refs in the class scope, no?
-         */
+        /* visit the iface refs in the class scope */
         for ifaces.each {|p|
             visit::visit_path(p.path, class_scope, v);
         }
+        // FIXME: should be fk_ctor?
         visit_fn_with_scope(e, visit::fk_item_fn(i.ident, tps), ctor.node.dec,
                             ctor.node.body, ctor.span, ctor.node.id,
                             ctor_scope, v);
+        option::iter(m_dtor) {|dtor|
+          let dtor_scope = cons(scope_method(dtor.node.self_id, tps),
+                              @class_scope);
+
+          visit_fn_with_scope(e, visit::fk_dtor(tps, dtor.node.self_id,
+                                                local_def(i.id)),
+                            ast_util::dtor_dec(),
+                            dtor.node.body, dtor.span, dtor.node.id,
+                            dtor_scope, v);
+        };
         /* visit the items */
         for members.each {|cm|
             alt cm.node {
@@ -625,7 +634,8 @@ fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
     for decl.constraints.each {|c| resolve_constr(e, c, sc, v); }
     let scope = alt fk {
       visit::fk_item_fn(_, tps) | visit::fk_res(_, tps, _) |
-      visit::fk_method(_, tps, _) | visit::fk_ctor(_, tps, _, _) {
+      visit::fk_method(_, tps, _) | visit::fk_ctor(_, tps, _, _)  |
+      visit::fk_dtor(tps, _, _) {
         scope_bare_fn(decl, id, tps) }
       visit::fk_anon(ast::proto_bare, _) {
         scope_bare_fn(decl, id, []) }
@@ -1041,7 +1051,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace,
               ast::item_native_mod(m) {
                 ret lookup_in_local_native_mod(e, it.id, sp, name, ns);
               }
-              ast::item_class(tps, _, members, ctor, _) {
+              ast::item_class(tps, _, members, ctor, _, _) {
                   if ns == ns_type {
                     ret lookup_in_ty_params(e, name, tps);
                   }
@@ -1633,7 +1643,7 @@ fn index_mod(md: ast::_mod) -> mod_index {
                 variant_idx += 1u;
             }
           }
-          ast::item_class(tps, _, items, ctor, _) {
+          ast::item_class(tps, _, items, ctor, _, _) {
               // add the class name itself
               add_to_index(index, it.ident, mie_item(it));
               // add the constructor decl
@@ -2236,7 +2246,7 @@ fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
                         })}];
         }
       }
-      ast::item_class(tps, ifces, items, _, _) {
+      ast::item_class(tps, ifces, items, _, _, _) {
           let (_, mthds) = ast_util::split_class_items(items);
           let n_tps = tps.len();
           vec::iter(ifces) {|p|
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index 6bad2249cac..0136570a68a 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -4443,6 +4443,15 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
   finish_fn(fcx, lltop);
 }
 
+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;
+  trans_fn(ccx, path, ast_util::dtor_dec(),
+           body, lldtor_decl, impl_self(class_ty), none, dtor_id);
+}
+
 fn trans_item(ccx: @crate_ctxt, item: ast::item) {
     let _icx = ccx.insn_ctxt("trans_item");
     let path = alt check ccx.tcx.items.get(item.id) {
@@ -4509,7 +4518,7 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
         };
         native::trans_native_mod(ccx, native_mod, abi);
       }
-      ast::item_class(tps, _ifaces, items, ctor, _) {
+      ast::item_class(tps, _ifaces, items, ctor, m_dtor, _) {
         if tps.len() == 0u {
           let psubsts = {tys: ty::ty_params_to_tys(ccx.tcx, tps),
                          // FIXME: vtables have to get filled in depending
@@ -4519,6 +4528,11 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
           trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
                            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));
+          };
         }
         // If there are ty params, the ctor will get monomorphized
 
@@ -4744,6 +4758,12 @@ 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)
+          }
+
           ast_map::node_variant(v, enm, pth) {
             assert v.node.args.len() != 0u;
             let pth = *pth + [path_name(enm.ident), path_name(v.node.name)];
diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs
index ec49a0ec7cb..7578b0d1351 100644
--- a/src/rustc/middle/trans/impl.rs
+++ b/src/rustc/middle/trans/impl.rs
@@ -94,7 +94,7 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id,
             method_from_methods(ms, name)
           }
           ast_map::node_item(@{node:
-               ast::item_class(_, _, items, _, _), _}, _) {
+              ast::item_class(_, _, items, _, _, _), _}, _) {
             let (_,ms) = split_class_items(items);
             method_from_methods(ms, name)
           }
diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs
index bd4800c970a..cfae74b8eb1 100644
--- a/src/rustc/middle/trans/reachable.rs
+++ b/src/rustc/middle/trans/reachable.rs
@@ -102,8 +102,11 @@ fn traverse_public_item(cx: ctx, item: @item) {
             }
         }
       }
-      item_class(tps, _ifaces, items, ctor, _) {
+      item_class(tps, _ifaces, items, ctor, m_dtor, _) {
         cx.rmap.insert(ctor.node.id, ());
+        option::iter(m_dtor) {|dtor|
+            cx.rmap.insert(dtor.node.id, ());
+        }
         for vec::each(items) {|item|
             alt item.node {
               class_method(m) {
diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs
index 559e8587cef..e5bcec7a46c 100644
--- a/src/rustc/middle/tstate/pre_post_conditions.rs
+++ b/src/rustc/middle/tstate/pre_post_conditions.rs
@@ -57,7 +57,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) {
              ccx: ccx};
         find_pre_post_fn(fcx, body);
       }
-      item_class(_,_,_,_,_) {
+      item_class(*) {
           fail "find_pre_post_item: shouldn't be called on item_class";
       }
       item_impl(_, _, _, _, ms) {
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index 70f32771e00..c4f5c0663d3 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -2326,7 +2326,7 @@ fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
               _, _, some(@{id: id, _}), _, _), _}, _)) {
               some(node_id_to_type(cx, id))
            }
-           some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, _),
+           some(ast_map::node_item(@{node: ast::item_class(_, _, _, _, _, _),
                            _},_)) {
              alt cx.def_map.find(id.node) {
                some(def_ty(iface_id)) {
@@ -2408,6 +2408,10 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
           ast_map::node_ctor(nm, _, _, path) {
               *path + [ast_map::path_name(nm)]
           }
+          ast_map::node_dtor(_, _, _, path) {
+              *path + [ast_map::path_name("dtor")]
+          }
+
 
           ast_map::node_expr(_) | ast_map::node_arg(_, _) |
           ast_map::node_local(_) | ast_map::node_export(_, _) |
@@ -2527,7 +2531,7 @@ fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] {
     alt cx.items.find(did.node) {
        some(ast_map::node_item(i,_)) {
          alt i.node {
-           ast::item_class(_, _, items, _, _) {
+                 ast::item_class(_, _, items, _, _, _) {
                class_field_tys(items)
            }
            _ { cx.sess.bug("class ID bound to non-class"); }
@@ -2569,7 +2573,7 @@ pure fn is_public(f: field_ty) -> bool {
 fn lookup_class_method_ids(cx: ctxt, did: ast::def_id)
     : is_local(did) -> [{name: ident, id: node_id, vis: visibility}] {
     alt cx.items.find(did.node) {
-       some(ast_map::node_item(@{node: item_class(_,_,items,_,_), _}, _)) {
+       some(ast_map::node_item(@{node: item_class(_,_,items,_,_,_), _}, _)) {
          let (_,ms) = split_class_items(items);
          vec::map(ms, {|m| {name: m.ident, id: m.id,
                             vis: m.vis}})
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index 6f77fc957b2..8d897161678 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -926,7 +926,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
         tcx.tcache.insert(local_def(it.id), tpt);
         ret tpt;
       }
-      ast::item_class(tps, _, _, _, rp) {
+      ast::item_class(tps, _, _, _, _, rp) {
           let {bounds,substs} = mk_substs(ccx, tps, rp);
           let t = ty::mk_class(tcx, local_def(it.id), substs);
           let tpt = {bounds: bounds, rp: rp, ty: t};
@@ -1487,7 +1487,7 @@ mod collect {
                   ty_of_ty_method(ccx, m, rp)
               };
           }
-          ast_map::node_item(@{node: ast::item_class(_,_,its,_,rp), _}, _) {
+          ast_map::node_item(@{node: ast::item_class(_,_,its,_,_,rp), _}, _) {
               let (_,ms) = split_class_items(its);
               // All methods need to be stored, since lookup_method
               // relies on the same method cache for self-calls
@@ -1654,7 +1654,7 @@ mod collect {
             write_ty_to_tcx(tcx, it.id, tpt.ty);
             ensure_iface_methods(ccx, it.id);
           }
-          ast::item_class(tps, ifaces, members, ctor, rp) {
+          ast::item_class(tps, ifaces, members, ctor, m_dtor, rp) {
             // Write the class type
             let tpt = ty_of_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, tpt.ty);
@@ -1671,6 +1671,22 @@ mod collect {
                               {bounds: tpt.bounds,
                                rp: ast::rp_none,
                                ty: t_ctor});
+            option::iter(m_dtor) {|dtor|
+              // Write the dtor type
+              let t_dtor = ty::mk_fn(tcx,
+                                   // not sure about empty_rscope
+                                   // FIXME
+                                   ty_of_fn_decl(ccx,
+                                                 empty_rscope,
+                                                 ast::proto_any,
+                                                 ast_util::dtor_dec(),
+                                                 none));
+              write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
+              tcx.tcache.insert(local_def(dtor.node.id),
+                                {bounds: tpt.bounds,
+                                 rp: ast::rp_none,
+                                 ty: t_dtor});
+            };
             ensure_iface_methods(ccx, it.id);
             /* FIXME: check for proper public/privateness */
             // Write the type of each of the members
@@ -2441,7 +2457,7 @@ fn impl_self_ty(fcx: @fn_ctxt, did: ast::def_id) -> ty_param_substs_and_ty {
              raw_ty: fcx.ccx.to_ty(type_rscope(rp), st)}
           }
           some(ast_map::node_item(@{node: ast::item_class(ts,
-                                    _,_,_,rp), id: class_id, _},_)) {
+                                 _,_,_,_,rp), id: class_id, _},_)) {
               /* If the impl is a class, the self ty is just the class ty
                  (doing a no-op subst for the ty params; in the next step,
                  we substitute in fresh vars for them)
@@ -4443,7 +4459,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
         let self_ty = ccx.to_ty(type_rscope(rp), ty);
         for ms.each {|m| check_method(ccx, m, self_ty);}
       }
-      ast::item_class(tps, ifaces, members, ctor, rp) {
+      ast::item_class(tps, ifaces, members, ctor, m_dtor, rp) {
           let cid = some(it.id), tcx = ccx.tcx;
           let class_t = ty::node_id_to_type(tcx, it.id);
           let members_info = class_types(ccx, members, rp);
@@ -4458,6 +4474,14 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
           // Write the ctor's self's type
           write_ty_to_tcx(tcx, ctor.node.self_id, class_t);
 
+          option::iter(m_dtor) {|dtor|
+            // typecheck the dtor
+           check_bare_fn(class_ccx, ast_util::dtor_dec(),
+                           dtor.node.body, dtor.node.id,
+                           some(class_t));
+           // Write the dtor's self's type
+           write_ty_to_tcx(tcx, dtor.node.self_id, class_t);
+          };
           // typecheck the members
           for members.each {|m| check_class_member(class_ccx, class_t, m); }
       }
diff --git a/src/test/run-pass/class-dtor.rs b/src/test/run-pass/class-dtor.rs
new file mode 100644
index 00000000000..8c539cd8328
--- /dev/null
+++ b/src/test/run-pass/class-dtor.rs
@@ -0,0 +1,11 @@
+class cat {
+  let done : native fn(uint);
+  let meows : uint;
+  new(done: native fn(uint)) {
+    self.meows = 0u;
+    self.done = done;
+  }
+  drop { self.done(self.meows); }
+}
+
+fn main() {}