From b5729bd60095fb5ca884936775e031cf19900760 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Mon, 16 Jul 2012 19:16:19 -0700 Subject: [PATCH] Support attributes on class ctors and dtors Closes #2660 --- src/libsyntax/ast.rs | 2 + src/libsyntax/ast_map.rs | 14 +++--- src/libsyntax/ast_util.rs | 4 +- src/libsyntax/fold.rs | 7 +++ src/libsyntax/parse/parser.rs | 59 ++++++++++++++----------- src/libsyntax/print/pprust.rs | 12 +++-- src/libsyntax/visit.rs | 17 +++---- src/rustc/middle/astencode.rs | 9 +++- src/rustc/middle/trans/reachable.rs | 8 +++- src/test/run-pass/class-attributes-1.rs | 11 +++++ src/test/run-pass/class-attributes-2.rs | 17 +++++++ 11 files changed, 109 insertions(+), 51 deletions(-) create mode 100644 src/test/run-pass/class-attributes-1.rs create mode 100644 src/test/run-pass/class-attributes-2.rs diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0e70a58b33b1..65ff9245fd18 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -657,6 +657,7 @@ type class_ctor = spanned; #[auto_serialize] type class_ctor_ = {id: node_id, + attrs: ~[attribute], self_id: node_id, dec: fn_decl, body: blk}; @@ -666,6 +667,7 @@ type class_dtor = spanned; #[auto_serialize] type class_dtor_ = {id: node_id, + attrs: ~[attribute], self_id: node_id, body: blk}; diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 7f1899792d70..4820ac2f4a91 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -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); } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 49478779fbad..7a0a0725d956 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 53bb9510acde..f802d176e40d 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -16,6 +16,7 @@ export wrap; 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 @@ impl of ast_fold for ast_fold_precursor { } } +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 } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dcc8f7430cab..74210f74d4d7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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; @@ -2145,31 +2145,34 @@ class parser { 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 @@ class parser { } } - 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 @@ class parser { 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)]); } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 937a46a05d39..b8cbeabef157 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index b6822186b255..ead8e981d7a1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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(m: @method, e: E, v: vt) { fn visit_class_ctor_helper(ctor: class_ctor, nm: ident, tps: ~[ty_param], parent_id: def_id, e: E, v: vt) { 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(dtor: class_dtor, tps: ~[ty_param], parent_id: def_id, e: E, v: vt) { - 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) } diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 2211f62f2357..3b7eb8e241c0 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -3,6 +3,7 @@ import util::ppaux::ty_to_str; 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) } diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs index 7a371e7a5fde..847febdef864 100644 --- a/src/rustc/middle/trans/reachable.rs +++ b/src/rustc/middle/trans/reachable.rs @@ -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 index 000000000000..36e1ca621f93 --- /dev/null +++ b/src/test/run-pass/class-attributes-1.rs @@ -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 index 000000000000..8c75d7f6b5a9 --- /dev/null +++ b/src/test/run-pass/class-attributes-2.rs @@ -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"); +}