]> git.lizzy.rs Git - rust.git/commitdiff
Support attributes on class ctors and dtors
authorTim Chevalier <chevalier@alum.wellesley.edu>
Tue, 17 Jul 2012 02:16:19 +0000 (19:16 -0700)
committerTim Chevalier <chevalier@alum.wellesley.edu>
Tue, 17 Jul 2012 19:40:59 +0000 (12:40 -0700)
Closes #2660

src/libsyntax/ast.rs
src/libsyntax/ast_map.rs
src/libsyntax/ast_util.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/rustc/middle/astencode.rs
src/rustc/middle/trans/reachable.rs
src/test/run-pass/class-attributes-1.rs [new file with mode: 0644]
src/test/run-pass/class-attributes-2.rs [new file with mode: 0644]

index 0e70a58b33b1e4650ca8d295aad6d1d72070e877..65ff9245fd189330a1995d2b591f6fdb0c9e4bbf 100644 (file)
@@ -657,6 +657,7 @@ enum class_mutability { class_mutable, class_immutable }
 
 #[auto_serialize]
 type class_ctor_ = {id: node_id,
+                    attrs: ~[attribute],
                     self_id: node_id,
                     dec: fn_decl,
                     body: blk};
@@ -666,6 +667,7 @@ enum class_mutability { class_mutable, class_immutable }
 
 #[auto_serialize]
 type class_dtor_ = {id: node_id,
+                    attrs: ~[attribute],
                     self_id: node_id,
                     body: blk};
 
index 7f1899792d705492803b4ad3d6b1165190cd2c5e..4820ac2f4a91d724ddf38f1fc3466898cb8e1157 100644 (file)
@@ -126,8 +126,9 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
         cx.local_id += 1u;
     }
     alt fk {
-      visit::fk_ctor(nm, tps, self_id, parent_id) {
+      visit::fk_ctor(nm, attrs, tps, self_id, parent_id) {
           let ct = @{node: {id: id,
+                            attrs: attrs,
                             self_id: self_id,
                             dec: /* FIXME (#2543) */ copy decl,
                             body: /* FIXME (#2543) */ copy body},
@@ -136,16 +137,15 @@ fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
                                       /* FIXME (#2543) */ copy tps,
                                       ct, parent_id,
                                       @/* FIXME (#2543) */ copy cx.path));
-       }
-      visit::fk_dtor(tps, self_id, parent_id) {
-          let dt = @{node: {id: id, self_id: self_id,
+      }
+      visit::fk_dtor(tps, attrs, self_id, parent_id) {
+          let dt = @{node: {id: id, attrs: attrs, self_id: self_id,
                      body: /* FIXME (#2543) */ copy body}, span: sp};
           cx.map.insert(id, node_dtor(/* FIXME (#2543) */ copy tps, dt,
                                       parent_id,
                                       @/* FIXME (#2543) */ copy cx.path));
-       }
-
-       _ {}
+      }
+      _ {}
     }
     visit::visit_fn(fk, decl, body, sp, id, cx, v);
 }
index 49478779fbadf59ebb9b889250ab958e9493373b..7a0a0725d956cc347630480cf6f2ddedd8c6f448 100644 (file)
@@ -464,13 +464,13 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
             vfn(id);
 
             alt fk {
-              visit::fk_ctor(nm, tps, self_id, parent_id) {
+              visit::fk_ctor(nm, _, tps, self_id, parent_id) {
                 vec::iter(tps, |tp| vfn(tp.id));
                 vfn(id);
                 vfn(self_id);
                 vfn(parent_id.node);
               }
-              visit::fk_dtor(tps, self_id, parent_id) {
+              visit::fk_dtor(tps, _, self_id, parent_id) {
                 vec::iter(tps, |tp| vfn(tp.id));
                 vfn(id);
                 vfn(self_id);
index 53bb9510acdeac1c19603e448a9be417755d85f7..f802d176e40d2378b75ce63dabe0fe5f0043369f 100644 (file)
@@ -16,6 +16,7 @@
 export fold_ty_param;
 export fold_ty_params;
 export fold_fn_decl;
+export extensions;
 
 iface ast_fold {
     fn fold_crate(crate) -> crate;
@@ -701,6 +702,12 @@ fn new_span(span: span) -> span {
     }
 }
 
+impl extensions for ast_fold {
+    fn fold_attributes(attrs: ~[attribute]) -> ~[attribute] {
+        attrs.map(|x| fold_attribute_(x, self))
+    }
+}
+
 fn make_fold(afp: ast_fold_precursor) -> ast_fold {
     afp as ast_fold
 }
index dcc8f7430cab251a99bbaf217ce832273486af8a..74210f74d4d71782e19cf5eff2351a7ed1d01322 100644 (file)
@@ -96,8 +96,8 @@ enum pexpr {
   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),
+enum class_contents { ctor_decl(fn_decl, ~[attribute], blk, codemap::span),
+                      dtor_decl(blk, ~[attribute], codemap::span),
                       members(~[@class_member]) }
 
 type arg_or_capture_item = either<arg, capture_item>;
@@ -2145,31 +2145,34 @@ fn parse_item_class() -> item_info {
         self.expect(token::LBRACE);
         let mut ms: ~[@class_member] = ~[];
         let ctor_id = self.get_id();
-        let mut the_ctor : option<(fn_decl, blk, codemap::span)> = none;
-        let mut the_dtor : option<(blk, codemap::span)> = none;
+        let mut the_ctor : option<(fn_decl, ~[attribute], blk,
+                                   codemap::span)> = none;
+        let mut the_dtor : option<(blk, ~[attribute], codemap::span)> = none;
         while self.token != token::RBRACE {
             alt self.parse_class_item(class_path) {
-              ctor_decl(a_fn_decl, blk, s) {
-                the_ctor = some((a_fn_decl, blk, s));
+              ctor_decl(a_fn_decl, attrs, blk, s) {
+                the_ctor = some((a_fn_decl, attrs, blk, s));
               }
-              dtor_decl(blk, s) {
-                the_dtor = some((blk, s));
+              dtor_decl(blk, attrs, s) {
+                the_dtor = some((blk, attrs, s));
               }
               members(mms) { ms = vec::append(ms, mms); }
             }
         }
         let actual_dtor = do option::map(the_dtor) |dtor| {
-            let (d_body, d_s) = dtor;
+            let (d_body, d_attrs, d_s) = dtor;
             {node: {id: self.get_id(),
+                    attrs: d_attrs,
                     self_id: self.get_id(),
                     body: d_body},
              span: d_s}};
         self.bump();
         alt the_ctor {
-          some((ct_d, ct_b, ct_s)) {
+          some((ct_d, ct_attrs, ct_b, ct_s)) {
             (class_name,
              item_class(ty_params, traits, ms, {
                  node: {id: ctor_id,
+                        attrs: ct_attrs,
                         self_id: self.get_id(),
                         dec: ct_d,
                         body: ct_b},
@@ -2198,35 +2201,27 @@ fn parse_single_class_item(vis: visibility)
         }
     }
 
-    fn parse_ctor(result_ty: ast::ty_) -> class_contents {
-        // FIXME (#2660): Can ctors/dtors have attrs?
+    fn parse_ctor(attrs: ~[attribute],
+                  result_ty: ast::ty_) -> class_contents {
         let lo = self.last_span.lo;
         let (decl_, _) = self.parse_fn_decl(impure_fn, |p| p.parse_arg());
         let decl = {output: @{id: self.get_id(),
                               node: result_ty, span: decl_.output.span}
                     with decl_};
         let body = self.parse_block();
-        ctor_decl(decl, body, mk_sp(lo, self.last_span.hi))
+        ctor_decl(decl, attrs, body, mk_sp(lo, self.last_span.hi))
     }
 
-    fn parse_dtor() -> class_contents {
-        // FIXME (#2660): Can ctors/dtors have attrs?
+    fn parse_dtor(attrs: ~[attribute]) -> class_contents {
         let lo = self.last_span.lo;
         let body = self.parse_block();
-        dtor_decl(body, mk_sp(lo, self.last_span.hi))
+        dtor_decl(body, attrs, mk_sp(lo, self.last_span.hi))
     }
 
     fn parse_class_item(class_name_with_tps: @path)
         -> class_contents {
-        if self.eat_keyword(~"new") {
-            // result type is always the type of the class
-            ret self.parse_ctor(ty_path(class_name_with_tps,
-                                        self.get_id()));
-        }
-        else if self.eat_keyword(~"drop") {
-            ret self.parse_dtor();
-        }
-        else if self.eat_keyword(~"priv") {
+
+        if self.eat_keyword(~"priv") {
             self.expect(token::LBRACE);
             let mut results = ~[];
             while self.token != token::RBRACE {
@@ -2235,9 +2230,19 @@ fn parse_class_item(class_name_with_tps: @path)
             self.bump();
             ret members(results);
         }
+
+        let attrs = self.parse_outer_attributes();
+
+        if self.eat_keyword(~"new") {
+            // result type is always the type of the class
+           ret self.parse_ctor(attrs, ty_path(class_name_with_tps,
+                                        self.get_id()));
+        }
+        else if self.eat_keyword(~"drop") {
+           ret self.parse_dtor(attrs);
+        }
         else {
-            // Probably need to parse attrs
-            ret members(~[self.parse_single_class_item(public)]);
+           ret members(~[self.parse_single_class_item(public)]);
         }
     }
 
index 937a46a05d394c01d26bb0ee4da1b7b240229d75..b8cbeabef1579a2efbcb163c7ace827328fdf290 100644 (file)
@@ -195,7 +195,7 @@ fn head(s: ps, w: ~str) {
     // outer-box is consistent
     cbox(s, indent_unit);
     // head-box is inconsistent
-    ibox(s, str::len(w) + 1u);
+    ibox(s, str::len(w) + 1);
     // keyword that starts the head
     word_nbsp(s, w);
 }
@@ -500,13 +500,19 @@ fn print_item(s: ps, &&item: @ast::item) {
           bopen(s);
           hardbreak_if_not_bol(s);
           maybe_print_comment(s, ctor.span.lo);
-          head(s, ~"new");
-          print_fn_args_and_ret(s, ctor.node.dec, ~[]);
+          print_outer_attributes(s, ctor.node.attrs);
+          /* Doesn't call head because there shouldn't be a space after new */
+          cbox(s, indent_unit);
+          ibox(s, 4);
+          word(s.s, ~"new(");
+          print_fn_args(s, ctor.node.dec, ~[]);
+          word(s.s, ~")");
           space(s.s);
           print_block(s, ctor.node.body);
           do option::iter(m_dtor) |dtor| {
             hardbreak_if_not_bol(s);
             maybe_print_comment(s, dtor.span.lo);
+            print_outer_attributes(s, dtor.node.attrs);
             head(s, ~"drop");
             print_block(s, dtor.node.body);
           }
index b6822186b25525fb73b139e9c34b2463e5a8e0bd..ead8e981d7a1b6900457f6d016e2b8b209c1a3c1 100644 (file)
@@ -17,9 +17,9 @@ enum fn_kind {
     fk_method(ident, ~[ty_param], @method),
     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 */,
+    fk_ctor(ident, ~[attribute], ~[ty_param], node_id /* self id */,
             def_id /* parent class id */), // class constructor
-    fk_dtor(~[ty_param], node_id /* self id */,
+    fk_dtor(~[ty_param], ~[attribute], node_id /* self id */,
             def_id /* parent class id */) // class destructor
 
 }
@@ -27,7 +27,7 @@ enum fn_kind {
 fn name_of_fn(fk: fn_kind) -> ident {
     alt fk {
       fk_item_fn(name, _) | fk_method(name, _, _)
-          | fk_ctor(name, _, _, _) { /* FIXME (#2543) */ copy name }
+          | fk_ctor(name, _, _, _, _) { /* FIXME (#2543) */ copy name }
       fk_anon(*) | fk_fn_block(*) { @~"anon" }
       fk_dtor(*)                  { @~"drop" }
     }
@@ -36,7 +36,7 @@ fn name_of_fn(fk: fn_kind) -> ident {
 fn tps_of_fn(fk: fn_kind) -> ~[ty_param] {
     alt fk {
       fk_item_fn(_, tps) | fk_method(_, tps, _)
-              | fk_ctor(_, tps, _, _) | fk_dtor(tps, _, _) {
+          | fk_ctor(_, _, tps, _, _) | fk_dtor(tps, _, _, _) {
           /* FIXME (#2543) */ copy tps
       }
       fk_anon(*) | fk_fn_block(*) { ~[] }
@@ -271,16 +271,17 @@ fn visit_method_helper<E>(m: @method, e: E, v: vt<E>) {
 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(fk_ctor(/* FIXME (#2543) */ copy nm,
+                       ctor.node.attrs,
                        /* FIXME (#2543) */ copy tps,
-                       ctor.node.self_id, parent_id), ctor.node.dec,
-               ctor.node.body, ctor.span, ctor.node.id, e, v)
+                       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(/* FIXME (#2543) */ copy tps, dtor.node.self_id,
-                       parent_id), ast_util::dtor_dec(),
+    v.visit_fn(fk_dtor(/* FIXME (#2543) */ copy tps, dtor.node.attrs,
+                       dtor.node.self_id, parent_id), ast_util::dtor_dec(),
                dtor.node.body, dtor.span, dtor.node.id, e, v)
 
 }
index 2211f62f2357291c68562086f8763f03e5a8c829..3b7eb8e241c0da8e28adc214afdf3b43075c54b4 100644 (file)
@@ -3,6 +3,7 @@
 import dvec::extensions;
 import syntax::ast;
 import syntax::fold;
+import syntax::fold::*;
 import syntax::visit;
 import syntax::ast_map;
 import syntax::ast_util;
@@ -295,21 +296,25 @@ fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
       }
       ast::ii_ctor(ctor, nm, tps, parent_id) {
         let ctor_body = fld.fold_block(ctor.node.body);
+        let ctor_attrs = fld.fold_attributes(ctor.node.attrs);
         let ctor_decl = fold::fold_fn_decl(ctor.node.dec, fld);
         let new_params = fold::fold_ty_params(tps, fld);
         let ctor_id = fld.new_id(ctor.node.id);
         let new_parent = xcx.tr_def_id(parent_id);
-        ast::ii_ctor({node: {body: ctor_body, dec: ctor_decl, id: ctor_id
+        ast::ii_ctor({node: {body: ctor_body, attrs: ctor_attrs,
+                dec: ctor_decl, id: ctor_id
                               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 dtor_attrs = fld.fold_attributes(dtor.node.attrs);
         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}
+        ast::ii_dtor({node: {id: dtor_id, attrs: dtor_attrs,
+                self_id: new_self, body: dtor_body}
                         with dtor},
           nm, new_params, new_parent)
       }
index 7a371e7a5fde88b70373501517bca9cba1235591..847febdef8646885e65ef0140a5f67f31f9f2acb 100644 (file)
@@ -111,10 +111,14 @@ fn traverse_public_item(cx: ctx, item: @item) {
       }
       item_class(tps, _traits, items, ctor, m_dtor) {
         cx.rmap.insert(ctor.node.id, ());
+        if tps.len() > 0u || attr::find_inline_attr(ctor.node.attrs)
+                 != attr::ia_none {
+            traverse_inline_body(cx, ctor.node.body);
+        }
         do option::iter(m_dtor) |dtor| {
             cx.rmap.insert(dtor.node.id, ());
-            // dtors don't have attrs
-            if tps.len() > 0u {
+            if tps.len() > 0u || attr::find_inline_attr(dtor.node.attrs)
+                     != attr::ia_none {
                 traverse_inline_body(cx, dtor.node.body);
             }
         }
diff --git a/src/test/run-pass/class-attributes-1.rs b/src/test/run-pass/class-attributes-1.rs
new file mode 100644 (file)
index 0000000..36e1ca6
--- /dev/null
@@ -0,0 +1,11 @@
+// pp-exact - Make sure we actually print the attributes
+
+class cat {
+    #[cat_maker]
+    new(name: ~str) { self.name = name; }
+    #[cat_dropper]
+    drop { #error["%s landed on hir feet", self.name]; }
+    let name: ~str;
+}
+
+fn main() { let _kitty = cat(~"Spotty"); }
diff --git a/src/test/run-pass/class-attributes-2.rs b/src/test/run-pass/class-attributes-2.rs
new file mode 100644 (file)
index 0000000..8c75d7f
--- /dev/null
@@ -0,0 +1,17 @@
+class cat {
+  let name: ~str;
+  #[cat_maker]
+  /**
+     Maybe it should technically be a kitten_maker.
+  */
+  new(name: ~str) { self.name = name; }
+  #[cat_dropper]
+  /**
+     Actually, cats don't always land on their feet when you drop them.
+  */
+  drop { #error("%s landed on hir feet", self.name); }
+}
+
+fn main() {
+  let _kitty = cat(~"Spotty");
+}