about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-07-19 21:51:37 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-07-20 01:06:16 +1000
commitcc760a647ac0094814f592d08813ebae0b3bec47 (patch)
tree75ccb57c1c05b195ed8992a66cdd4a14441fca34
parent32586faa6adb890bc25caa8b5cb692e8c37e4a89 (diff)
downloadrust-cc760a647ac0094814f592d08813ebae0b3bec47.tar.gz
rust-cc760a647ac0094814f592d08813ebae0b3bec47.zip
syntax: modernise attribute handling in syntax::attr.
This does a number of things, but especially dramatically reduce the
number of allocations performed for operations involving attributes/
meta items:

- Converts ast::meta_item & ast::attribute and other associated enums
  to CamelCase.
- Converts several standalone functions in syntax::attr into methods,
  defined on two traits AttrMetaMethods & AttributeMethods. The former
  is common to both MetaItem and Attribute since the latter is a thin
  wrapper around the former.
- Deletes functions that are unnecessary due to iterators.
- Converts other standalone functions to use iterators and the generic
  AttrMetaMethods rather than allocating a lot of new vectors (e.g. the
  old code would have to allocate a new vector to use functions that
  operated on &[meta_item] on &[attribute].)
- Moves the core algorithm of the #[cfg] matching to syntax::attr,
  similar to find_inline_attr and find_linkage_metas.

This doesn't have much of an effect on the speed of #[cfg] stripping,
despite hugely reducing the number of allocations performed; presumably
most of the time is spent in the ast folder rather than doing attribute
checks.

Also fixes the Eq instance of MetaItem_ to correctly ignore spaces, so
that `rustc --cfg 'foo(bar)'` now works.
-rw-r--r--src/librustc/back/link.rs29
-rw-r--r--src/librustc/driver/driver.rs43
-rw-r--r--src/librustc/driver/session.rs15
-rw-r--r--src/librustc/front/config.rs31
-rw-r--r--src/librustc/front/std_inject.rs16
-rw-r--r--src/librustc/front/test.rs65
-rw-r--r--src/librustc/metadata/creader.rs42
-rw-r--r--src/librustc/metadata/csearch.rs2
-rw-r--r--src/librustc/metadata/decoder.rs18
-rw-r--r--src/librustc/metadata/encoder.rs48
-rw-r--r--src/librustc/metadata/loader.rs32
-rw-r--r--src/librustc/middle/entry.rs6
-rw-r--r--src/librustc/middle/kind.rs5
-rw-r--r--src/librustc/middle/lang_items.rs19
-rw-r--r--src/librustc/middle/lint.rs34
-rw-r--r--src/librustc/middle/privacy.rs3
-rw-r--r--src/librustc/middle/reachable.rs5
-rw-r--r--src/librustc/middle/resolve.rs5
-rw-r--r--src/librustc/middle/trans/base.rs54
-rw-r--r--src/librustc/middle/trans/foreign.rs10
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/librustdoc/attr_parser.rs35
-rw-r--r--src/librustdoc/attr_pass.rs6
-rw-r--r--src/librustdoc/doc.rs8
-rw-r--r--src/librustdoc/extract.rs28
-rw-r--r--src/librustdoc/markdown_pass.rs4
-rw-r--r--src/librustdoc/markdown_writer.rs6
-rw-r--r--src/librustdoc/page_pass.rs2
-rw-r--r--src/librustdoc/pass.rs6
-rw-r--r--src/librustdoc/path_pass.rs4
-rw-r--r--src/librustdoc/sort_item_name_pass.rs6
-rw-r--r--src/librustdoc/sort_item_type_pass.rs16
-rw-r--r--src/librustdoc/sort_pass.rs18
-rw-r--r--src/librustpkg/util.rs37
-rw-r--r--src/libsyntax/ast.rs75
-rw-r--r--src/libsyntax/attr.rs446
-rw-r--r--src/libsyntax/ext/auto_encode.rs4
-rw-r--r--src/libsyntax/ext/base.rs2
-rw-r--r--src/libsyntax/ext/build.rs41
-rw-r--r--src/libsyntax/ext/deriving/clone.rs10
-rw-r--r--src/libsyntax/ext/deriving/cmp/eq.rs4
-rw-r--r--src/libsyntax/ext/deriving/cmp/ord.rs4
-rw-r--r--src/libsyntax/ext/deriving/cmp/totaleq.rs9
-rw-r--r--src/libsyntax/ext/deriving/cmp/totalord.rs4
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs4
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs4
-rw-r--r--src/libsyntax/ext/deriving/generic.rs5
-rw-r--r--src/libsyntax/ext/deriving/iter_bytes.rs4
-rw-r--r--src/libsyntax/ext/deriving/mod.rs19
-rw-r--r--src/libsyntax/ext/deriving/rand.rs4
-rw-r--r--src/libsyntax/ext/deriving/to_str.rs4
-rw-r--r--src/libsyntax/ext/deriving/zero.rs4
-rw-r--r--src/libsyntax/ext/expand.rs19
-rw-r--r--src/libsyntax/fold.rs27
-rw-r--r--src/libsyntax/parse/attr.rs56
-rw-r--r--src/libsyntax/parse/comments.rs6
-rw-r--r--src/libsyntax/parse/mod.rs6
-rw-r--r--src/libsyntax/parse/obsolete.rs6
-rw-r--r--src/libsyntax/parse/parser.rs75
-rw-r--r--src/libsyntax/print/pprust.rs37
60 files changed, 728 insertions, 811 deletions
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 98fd37d7633..6bccf7268bb 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -36,6 +36,7 @@ use std::vec;
 use syntax::ast;
 use syntax::ast_map::{path, path_mod, path_name};
 use syntax::attr;
+use syntax::attr::{AttrMetaMethods};
 use syntax::print::pprust;
 use syntax::parse::token;
 
@@ -502,7 +503,7 @@ pub fn build_link_meta(sess: Session,
     struct ProvidedMetas {
         name: Option<@str>,
         vers: Option<@str>,
-        cmh_items: ~[@ast::meta_item]
+        cmh_items: ~[@ast::MetaItem]
     }
 
     fn provided_link_metas(sess: Session, c: &ast::crate) ->
@@ -513,18 +514,10 @@ pub fn build_link_meta(sess: Session,
         let linkage_metas = attr::find_linkage_metas(c.node.attrs);
         attr::require_unique_names(sess.diagnostic(), linkage_metas);
         for linkage_metas.iter().advance |meta| {
-            match attr::get_meta_item_value_str(*meta) {
-                Some(value) => {
-                    let item_name : &str = attr::get_meta_item_name(*meta);
-                    match item_name {
-                        // Changing attr would avoid the need for the copy
-                        // here
-                        "name" => name = Some(value),
-                        "vers" => vers = Some(value),
-                        _ => cmh_items.push(*meta)
-                    }
-                },
-                None => cmh_items.push(*meta)
+            match meta.name_str_pair() {
+                Some((n, value)) if "name" == n => name = Some(value),
+                Some((n, value)) if "vers" == n => vers = Some(value),
+                _ => cmh_items.push(*meta)
             }
         }
 
@@ -537,7 +530,7 @@ pub fn build_link_meta(sess: Session,
 
     // This calculates CMH as defined above
     fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
-                              cmh_items: ~[@ast::meta_item],
+                              cmh_items: ~[@ast::MetaItem],
                               dep_hashes: ~[@str]) -> @str {
         fn len_and_str(s: &str) -> ~str {
             fmt!("%u_%s", s.len(), s)
@@ -549,16 +542,16 @@ pub fn build_link_meta(sess: Session,
 
         let cmh_items = attr::sort_meta_items(cmh_items);
 
-        fn hash(symbol_hasher: &mut hash::State, m: &@ast::meta_item) {
+        fn hash(symbol_hasher: &mut hash::State, m: &@ast::MetaItem) {
             match m.node {
-              ast::meta_name_value(key, value) => {
+              ast::MetaNameValue(key, value) => {
                 write_string(symbol_hasher, len_and_str(key));
                 write_string(symbol_hasher, len_and_str_lit(value));
               }
-              ast::meta_word(name) => {
+              ast::MetaWord(name) => {
                 write_string(symbol_hasher, len_and_str(name));
               }
-              ast::meta_list(name, ref mis) => {
+              ast::MetaList(name, ref mis) => {
                 write_string(symbol_hasher, len_and_str(name));
                 for mis.iter().advance |m_| {
                     hash(symbol_hasher, m_);
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index e85b3239e80..796e6213921 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -34,6 +34,7 @@ use extra::getopts;
 use syntax::ast;
 use syntax::abi;
 use syntax::attr;
+use syntax::attr::{AttrMetaMethods};
 use syntax::codemap;
 use syntax::diagnostic;
 use syntax::parse;
@@ -95,12 +96,9 @@ pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
          mk(@"build_input", source_name(input))];
 }
 
-pub fn append_configuration(cfg: ast::crate_cfg, name: @str)
-                         -> ast::crate_cfg {
-    if attr::contains_name(cfg, name) {
-        cfg
-    } else {
-        vec::append_one(cfg, attr::mk_word_item(name))
+pub fn append_configuration(cfg: &mut ast::crate_cfg, name: @str) {
+    if !cfg.iter().any(|mi| mi.name() == name) {
+        cfg.push(attr::mk_word_item(name))
     }
 }
 
@@ -109,18 +107,11 @@ pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
     // Combine the configuration requested by the session (command line) with
     // some default and generated configuration items
     let default_cfg = default_configuration(sess, argv0, input);
-    let user_cfg = sess.opts.cfg.clone();
+    let mut user_cfg = sess.opts.cfg.clone();
     // If the user wants a test runner, then add the test cfg
-    let user_cfg = if sess.opts.test {
-        append_configuration(user_cfg, @"test")
-    } else {
-        user_cfg
-    };
-
+    if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
     // If the user requested GC, then add the GC cfg
-    let user_cfg = append_configuration(
-        user_cfg,
-        if sess.opts.gc { @"gc" } else { @"nogc" });
+    append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
     return vec::append(user_cfg, default_cfg);
 }
 
@@ -130,7 +121,7 @@ fn parse_cfgspecs(cfgspecs: ~[~str],
     do cfgspecs.consume_iter().transform |s| {
         let sess = parse::new_parse_sess(Some(demitter));
         parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
-    }.collect()
+    }.collect::<ast::crate_cfg>()
 }
 
 pub enum input {
@@ -215,6 +206,7 @@ pub fn compile_rest(sess: Session,
         crate = time(time_passes, ~"configuration 2", ||
                      front::config::strip_unconfigured_items(crate));
 
+
         crate = time(time_passes, ~"maybe building test harness", ||
                      front::test::modify_for_testing(sess, crate));
     }
@@ -870,7 +862,7 @@ pub struct OutputFilenames {
 pub fn build_output_filenames(input: &input,
                               odir: &Option<Path>,
                               ofile: &Option<Path>,
-                              attrs: &[ast::attribute],
+                              attrs: &[ast::Attribute],
                               sess: Session)
                            -> @OutputFilenames {
     let obj_path;
@@ -912,12 +904,10 @@ pub fn build_output_filenames(input: &input,
           let linkage_metas = attr::find_linkage_metas(attrs);
           if !linkage_metas.is_empty() {
               // But if a linkage meta is present, that overrides
-              let maybe_matches = attr::find_meta_items_by_name(linkage_metas, "name");
-              if !maybe_matches.is_empty() {
-                  match attr::get_meta_item_value_str(maybe_matches[0]) {
-                      Some(s) => stem = s,
-                      _ => ()
-                  }
+              let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
+              match maybe_name.chain(|m| m.value_str()) {
+                  Some(s) => stem = s,
+                  _ => ()
               }
               // If the name is missing, we just default to the filename
               // version
@@ -1011,7 +1001,8 @@ mod test {
             @"rustc", matches, diagnostic::emit);
         let sess = build_session(sessopts, diagnostic::emit);
         let cfg = build_configuration(sess, @"whatever", &str_input(@""));
-        let test_items = attr::find_meta_items_by_name(cfg, "test");
-        assert_eq!(test_items.len(), 1u);
+        let mut test_items = cfg.iter().filter(|m| "test" == m.name());
+        assert!(test_items.next().is_some());
+        assert!(test_items.next().is_none());
     }
 }
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 7579616b4ce..6bdab3ad715 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -369,7 +369,7 @@ pub fn building_library(req_crate_type: crate_type,
             match syntax::attr::first_attr_value_str_by_name(
                 crate.node.attrs,
                 "crate_type") {
-              Some(s) if "lib" == s => true,
+              Some(s) => "lib" == s,
               _ => false
             }
         }
@@ -395,18 +395,11 @@ mod test {
     use driver::session::{unknown_crate};
 
     use syntax::ast;
+    use syntax::attr;
     use syntax::codemap;
 
-    fn make_crate_type_attr(t: @str) -> ast::attribute {
-        codemap::respan(codemap::dummy_sp(), ast::attribute_ {
-            style: ast::attr_outer,
-            value: @codemap::respan(codemap::dummy_sp(),
-                ast::meta_name_value(
-                    @"crate_type",
-                    codemap::respan(codemap::dummy_sp(),
-                                     ast::lit_str(t)))),
-            is_sugared_doc: false
-        })
+    fn make_crate_type_attr(t: @str) -> ast::Attribute {
+        attr::mk_attr(attr::mk_name_value_item_str(@"crate_type", t))
     }
 
     fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate {
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
index 88524781191..c8049ef8cfd 100644
--- a/src/librustc/front/config.rs
+++ b/src/librustc/front/config.rs
@@ -12,7 +12,7 @@
 use std::option;
 use syntax::{ast, fold, attr};
 
-type in_cfg_pred = @fn(attrs: &[ast::attribute]) -> bool;
+type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool;
 
 struct Context {
     in_cfg: in_cfg_pred
@@ -175,31 +175,6 @@ fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool {
 
 // Determine if an item should be translated in the current crate
 // configuration based on the item's attributes
-fn in_cfg(cfg: &[@ast::meta_item], attrs: &[ast::attribute]) -> bool {
-    metas_in_cfg(cfg, attr::attr_metas(attrs))
-}
-
-pub fn metas_in_cfg(cfg: &[@ast::meta_item],
-                    metas: &[@ast::meta_item]) -> bool {
-    // The "cfg" attributes on the item
-    let cfg_metas = attr::find_meta_items_by_name(metas, "cfg");
-
-    // Pull the inner meta_items from the #[cfg(meta_item, ...)]  attributes,
-    // so we can match against them. This is the list of configurations for
-    // which the item is valid
-    let cfg_metas = cfg_metas.consume_iter()
-        .filter_map(|i| attr::get_meta_item_list(i))
-        .collect::<~[~[@ast::meta_item]]>();
-
-    if cfg_metas.iter().all(|c| c.is_empty()) { return true; }
-
-    cfg_metas.iter().any(|cfg_meta| {
-        cfg_meta.iter().all(|cfg_mi| {
-            match cfg_mi.node {
-                ast::meta_list(s, ref it) if "not" == s
-                    => it.iter().all(|mi| !attr::contains(cfg, *mi)),
-                _ => attr::contains(cfg, *cfg_mi)
-            }
-        })
-    })
+fn in_cfg(cfg: &[@ast::MetaItem], attrs: &[ast::Attribute]) -> bool {
+    attr::test_cfg(cfg, attrs.iter().transform(|x| *x))
 }
diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs
index 6865428cd69..7ddba6ec7b2 100644
--- a/src/librustc/front/std_inject.rs
+++ b/src/librustc/front/std_inject.rs
@@ -30,10 +30,10 @@ pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::crate)
 }
 
 fn use_std(crate: &ast::crate) -> bool {
-    !attr::attrs_contains_name(crate.node.attrs, "no_std")
+    !attr::contains_name(crate.node.attrs, "no_std")
 }
-fn no_prelude(attrs: &[ast::attribute]) -> bool {
-    attr::attrs_contains_name(attrs, "no_implicit_prelude")
+fn no_prelude(attrs: &[ast::Attribute]) -> bool {
+    attr::contains_name(attrs, "no_implicit_prelude")
 }
 
 fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate {
@@ -48,14 +48,8 @@ fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate {
                 node: ast::view_item_extern_mod(
                         sess.ident_of("std"), ~[], n1),
                 attrs: ~[
-                    spanned(ast::attribute_ {
-                        style: ast::attr_inner,
-                        value: @spanned(ast::meta_name_value(
-                            @"vers",
-                            spanned(ast::lit_str(STD_VERSION.to_managed()))
-                        )),
-                        is_sugared_doc: false
-                    })
+                    attr::mk_attr(
+                        attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
                 ],
                 vis: ast::private,
                 span: dummy_sp()
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index e83c5ff6d10..020ad731d5a 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -23,6 +23,7 @@ use syntax::ext::base::ExtCtxt;
 use syntax::fold;
 use syntax::print::pprust;
 use syntax::{ast, ast_util};
+use syntax::attr::AttrMetaMethods;
 
 type node_id_gen = @fn() -> ast::node_id;
 
@@ -50,8 +51,7 @@ pub fn modify_for_testing(sess: session::Session,
     // We generate the test harness when building in the 'test'
     // configuration, either with the '--test' or '--cfg test'
     // command line options.
-    let should_test = attr::contains(crate.node.config,
-                                     attr::mk_word_item(@"test"));
+    let should_test = attr::contains_name(crate.node.config, "test");
 
     if should_test {
         generate_test_harness(sess, crate)
@@ -95,8 +95,8 @@ fn strip_test_functions(crate: &ast::crate) -> @ast::crate {
     // When not compiling with --test we should not compile the
     // #[test] functions
     do config::strip_items(crate) |attrs| {
-        !attr::contains_name(attr::attr_metas(attrs), "test") &&
-        !attr::contains_name(attr::attr_metas(attrs), "bench")
+        !attr::contains_name(attrs, "test") &&
+        !attr::contains_name(attrs, "bench")
     }
 }
 
@@ -111,7 +111,7 @@ fn fold_mod(cx: @mut TestCtxt,
         if !*cx.sess.building_library {
             @ast::item {
                 attrs: do item.attrs.iter().filter_map |attr| {
-                    if "main" != attr::get_attr_name(attr) {
+                    if "main" != attr.name() {
                         Some(*attr)
                     } else {
                         None
@@ -180,8 +180,7 @@ fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold)
 }
 
 fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
-    let has_test_attr = !attr::find_attrs_by_name(i.attrs,
-                                                  "test").is_empty();
+    let has_test_attr = attr::contains_name(i.attrs, "test");
 
     fn has_test_signature(i: @ast::item) -> bool {
         match &i.node {
@@ -205,11 +204,12 @@ fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
             "functions used as tests must have signature fn() -> ()."
         );
     }
+
     return has_test_attr && has_test_signature(i);
 }
 
 fn is_bench_fn(i: @ast::item) -> bool {
-    let has_bench_attr = !attr::find_attrs_by_name(i.attrs, "bench").is_empty();
+    let has_bench_attr = attr::contains_name(i.attrs, "bench");
 
     fn has_test_signature(i: @ast::item) -> bool {
         match i.node {
@@ -233,21 +233,17 @@ fn is_bench_fn(i: @ast::item) -> bool {
 }
 
 fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool {
-    let ignoreattrs = attr::find_attrs_by_name(i.attrs, "ignore");
-    let ignoreitems = attr::attr_metas(ignoreattrs);
-    return if !ignoreitems.is_empty() {
-        let cfg_metas = ignoreitems.consume_iter()
-            .filter_map(|i| attr::get_meta_item_list(i))
-            .collect::<~[~[@ast::meta_item]]>()
-            .concat_vec();
-        config::metas_in_cfg(cx.crate.node.config.clone(), cfg_metas)
-    } else {
-        false
+    do i.attrs.iter().any |attr| {
+        // check ignore(cfg(foo, bar))
+        "ignore" == attr.name() && match attr.meta_item_list() {
+            Some(ref cfgs) => attr::test_cfg(cx.crate.node.config, cfgs.iter().transform(|x| *x)),
+            None => true
+        }
     }
 }
 
 fn should_fail(i: @ast::item) -> bool {
-    !attr::find_attrs_by_name(i.attrs, "should_fail").is_empty()
+    attr::contains_name(i.attrs, "should_fail")
 }
 
 fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod {
@@ -278,19 +274,15 @@ mod __test {
 */
 
 fn mk_std(cx: &TestCtxt) -> ast::view_item {
-    let vers = ast::lit_str(@"0.8-pre");
-    let vers = nospan(vers);
-    let mi = ast::meta_name_value(@"vers", vers);
-    let mi = nospan(mi);
-    let id_std = cx.sess.ident_of("extra");
-    let vi = if is_std(cx) {
+    let id_extra = cx.sess.ident_of("extra");
+    let vi = if is_extra(cx) {
         ast::view_item_use(
-            ~[@nospan(ast::view_path_simple(id_std,
-                                            path_node(~[id_std]),
+            ~[@nospan(ast::view_path_simple(id_extra,
+                                            path_node(~[id_extra]),
                                             cx.sess.next_node_id()))])
     } else {
-        ast::view_item_extern_mod(id_std, ~[@mi],
-                           cx.sess.next_node_id())
+        let mi = attr::mk_name_value_item_str(@"vers", @"0.8-pre");
+        ast::view_item_extern_mod(id_extra, ~[mi], cx.sess.next_node_id())
     };
     ast::view_item {
         node: vi,
@@ -377,15 +369,12 @@ fn mk_tests(cx: &TestCtxt) -> @ast::item {
     )).get()
 }
 
-fn is_std(cx: &TestCtxt) -> bool {
-    let is_std = {
-        let items = attr::find_linkage_metas(cx.crate.node.attrs);
-        match attr::last_meta_item_value_str_by_name(items, "name") {
-          Some(s) if "extra" == s => true,
-          _ => false
-        }
-    };
-    return is_std;
+fn is_extra(cx: &TestCtxt) -> bool {
+    let items = attr::find_linkage_metas(cx.crate.node.attrs);
+    match attr::last_meta_item_value_str_by_name(items, "name") {
+        Some(s) if "extra" == s => true,
+        _ => false
+    }
 }
 
 fn mk_test_descs(cx: &TestCtxt) -> @ast::expr {
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index dea263532b2..16b5ecad5b7 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -18,6 +18,7 @@ use metadata::loader;
 
 use std::hashmap::HashMap;
 use syntax::attr;
+use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{span, dummy_sp};
 use syntax::diagnostic::span_handler;
 use syntax::parse::token;
@@ -59,7 +60,7 @@ struct cache_entry {
     cnum: int,
     span: span,
     hash: @str,
-    metas: @~[@ast::meta_item]
+    metas: @~[@ast::MetaItem]
 }
 
 fn dump_crates(crate_cache: &[cache_entry]) {
@@ -123,10 +124,9 @@ struct Env {
 
 fn visit_crate(e: &Env, c: &ast::crate) {
     let cstore = e.cstore;
-    let link_args = attr::find_attrs_by_name(c.node.attrs, "link_args");
 
-    for link_args.iter().advance |a| {
-        match attr::get_meta_item_value_str(attr::attr_meta(*a)) {
+    for c.node.attrs.iter().filter(|m| "link_args" == m.name()).advance |a| {
+        match a.value_str() {
           Some(ref linkarg) => {
             cstore::add_used_link_args(cstore, *linkarg);
           }
@@ -160,13 +160,17 @@ fn visit_item(e: &Env, i: @ast::item) {
 
         let cstore = e.cstore;
         let mut already_added = false;
-        let link_args = attr::find_attrs_by_name(i.attrs, "link_args");
+        let link_args = i.attrs.iter()
+            .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None})
+            .collect::<~[&ast::Attribute]>();
 
         match fm.sort {
             ast::named => {
-                let foreign_name =
-                    match attr::first_attr_value_str_by_name(i.attrs,
-                                                             "link_name") {
+                let link_name = i.attrs.iter()
+                    .find_(|at| "link_name" == at.name())
+                    .chain(|at| at.value_str());
+
+                let foreign_name = match link_name {
                         Some(nn) => {
                             if nn.is_empty() {
                                 e.diag.span_fatal(
@@ -178,7 +182,7 @@ fn visit_item(e: &Env, i: @ast::item) {
                         }
                         None => token::ident_to_str(&i.ident)
                     };
-                if attr::find_attrs_by_name(i.attrs, "nolink").is_empty() {
+                if !attr::contains_name(i.attrs, "nolink") {
                     already_added =
                         !cstore::add_used_library(cstore, foreign_name);
                 }
@@ -190,8 +194,8 @@ fn visit_item(e: &Env, i: @ast::item) {
             ast::anonymous => { /* do nothing */ }
         }
 
-        for link_args.iter().advance |a| {
-            match attr::get_meta_item_value_str(attr::attr_meta(*a)) {
+        for link_args.iter().advance |m| {
+            match m.value_str() {
                 Some(linkarg) => {
                     cstore::add_used_link_args(cstore, linkarg);
                 }
@@ -203,21 +207,21 @@ fn visit_item(e: &Env, i: @ast::item) {
     }
 }
 
-fn metas_with(ident: @str, key: @str, mut metas: ~[@ast::meta_item])
-    -> ~[@ast::meta_item] {
-    let name_items = attr::find_meta_items_by_name(metas, key);
-    if name_items.is_empty() {
+fn metas_with(ident: @str, key: @str, mut metas: ~[@ast::MetaItem])
+    -> ~[@ast::MetaItem] {
+    // Check if key isn't there yet.
+    if !attr::contains_name(metas, key) {
         metas.push(attr::mk_name_value_item_str(key, ident));
     }
     metas
 }
 
-fn metas_with_ident(ident: @str, metas: ~[@ast::meta_item])
-    -> ~[@ast::meta_item] {
+fn metas_with_ident(ident: @str, metas: ~[@ast::MetaItem])
+    -> ~[@ast::MetaItem] {
     metas_with(ident, @"name", metas)
 }
 
-fn existing_match(e: &Env, metas: &[@ast::meta_item], hash: &str)
+fn existing_match(e: &Env, metas: &[@ast::MetaItem], hash: &str)
                -> Option<int> {
     for e.crate_cache.iter().advance |c| {
         if loader::metadata_matches(*c.metas, metas)
@@ -230,7 +234,7 @@ fn existing_match(e: &Env, metas: &[@ast::meta_item], hash: &str)
 
 fn resolve_crate(e: @mut Env,
                  ident: ast::ident,
-                 metas: ~[@ast::meta_item],
+                 metas: ~[@ast::MetaItem],
                  hash: @str,
                  span: span)
               -> ast::crate_num {
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index f336b0f4e4c..2fc4ba8a1bd 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -151,7 +151,7 @@ pub fn get_static_methods_if_impl(cstore: @mut cstore::CStore,
 
 pub fn get_item_attrs(cstore: @mut cstore::CStore,
                       def_id: ast::def_id,
-                      f: &fn(~[@ast::meta_item])) {
+                      f: &fn(~[@ast::MetaItem])) {
     let cdata = cstore::get_crate_data(cstore, def_id.crate);
     decoder::get_item_attrs(cdata, def_id.node, f)
 }
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index caa170605de..f8c6c6288ac 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -966,7 +966,7 @@ pub fn get_static_methods_if_impl(intr: @ident_interner,
 
 pub fn get_item_attrs(cdata: cmd,
                       node_id: ast::node_id,
-                      f: &fn(~[@ast::meta_item])) {
+                      f: &fn(~[@ast::MetaItem])) {
 
     let item = lookup_item(node_id, cdata.data);
     for reader::tagged_docs(item, tag_attributes) |attributes| {
@@ -1073,8 +1073,8 @@ fn item_family_to_str(fam: Family) -> ~str {
     }
 }
 
-fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
-    let mut items: ~[@ast::meta_item] = ~[];
+fn get_meta_items(md: ebml::Doc) -> ~[@ast::MetaItem] {
+    let mut items: ~[@ast::MetaItem] = ~[];
     for reader::tagged_docs(md, tag_meta_item_word) |meta_item_doc| {
         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
         let n = nd.as_str_slice().to_managed();
@@ -1085,7 +1085,7 @@ fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
         let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
         let n = nd.as_str_slice().to_managed();
         let v = vd.as_str_slice().to_managed();
-        // FIXME (#623): Should be able to decode meta_name_value variants,
+        // FIXME (#623): Should be able to decode MetaNameValue variants,
         // but currently the encoder just drops them
         items.push(attr::mk_name_value_item_str(n, v));
     };
@@ -1098,8 +1098,8 @@ fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
     return items;
 }
 
-fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] {
-    let mut attrs: ~[ast::attribute] = ~[];
+fn get_attributes(md: ebml::Doc) -> ~[ast::Attribute] {
+    let mut attrs: ~[ast::Attribute] = ~[];
     match reader::maybe_get_doc(md, tag_attributes) {
       option::Some(attrs_d) => {
         for reader::tagged_docs(attrs_d, tag_attribute) |attr_doc| {
@@ -1110,8 +1110,8 @@ fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] {
             let meta_item = meta_items[0];
             attrs.push(
                 codemap::spanned {
-                    node: ast::attribute_ {
-                        style: ast::attr_outer,
+                    node: ast::Attribute_ {
+                        style: ast::AttrOuter,
                         value: meta_item,
                         is_sugared_doc: false,
                     },
@@ -1145,7 +1145,7 @@ fn list_crate_attributes(intr: @ident_interner, md: ebml::Doc, hash: &str,
     out.write_str("\n\n");
 }
 
-pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::attribute] {
+pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::Attribute] {
     return get_attributes(reader::Doc(data));
 }
 
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index ab42e84e2ac..86c470b09ed 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -36,6 +36,7 @@ use syntax::ast;
 use syntax::ast_map;
 use syntax::ast_util::*;
 use syntax::attr;
+use syntax::attr::AttrMetaMethods;
 use syntax::diagnostic::span_handler;
 use syntax::opt_vec::OptVec;
 use syntax::opt_vec;
@@ -821,10 +822,11 @@ fn purity_static_method_family(p: purity) -> char {
 }
 
 
-fn should_inline(attrs: &[attribute]) -> bool {
-    match attr::find_inline_attr(attrs) {
-        attr::ia_none | attr::ia_never  => false,
-        attr::ia_hint | attr::ia_always => true
+fn should_inline(attrs: &[Attribute]) -> bool {
+    use syntax::attr::*;
+    match find_inline_attr(attrs) {
+        InlineNone | InlineNever  => false,
+        InlineHint | InlineAlways => true
     }
 }
 
@@ -1313,16 +1315,16 @@ fn write_int(writer: @io::Writer, &n: &int) {
     writer.write_be_u32(n as u32);
 }
 
-fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) {
+fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @MetaItem) {
     match mi.node {
-      meta_word(name) => {
+      MetaWord(name) => {
         ebml_w.start_tag(tag_meta_item_word);
         ebml_w.start_tag(tag_meta_item_name);
         ebml_w.writer.write(name.as_bytes());
         ebml_w.end_tag();
         ebml_w.end_tag();
       }
-      meta_name_value(name, value) => {
+      MetaNameValue(name, value) => {
         match value.node {
           lit_str(value) => {
             ebml_w.start_tag(tag_meta_item_name_value);
@@ -1337,7 +1339,7 @@ fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) {
           _ => {/* FIXME (#623): encode other variants */ }
         }
       }
-      meta_list(name, ref items) => {
+      MetaList(name, ref items) => {
         ebml_w.start_tag(tag_meta_item_list);
         ebml_w.start_tag(tag_meta_item_name);
         ebml_w.writer.write(name.as_bytes());
@@ -1350,7 +1352,7 @@ fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) {
     }
 }
 
-fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) {
+fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[Attribute]) {
     ebml_w.start_tag(tag_attributes);
     for attrs.iter().advance |attr| {
         ebml_w.start_tag(tag_attribute);
@@ -1365,10 +1367,10 @@ fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) {
 // 'name' and 'vers' items, so if the user didn't provide them we will throw
 // them in anyway with default values.
 fn synthesize_crate_attrs(ecx: &EncodeContext,
-                          crate: &crate) -> ~[attribute] {
+                          crate: &crate) -> ~[Attribute] {
 
-    fn synthesize_link_attr(ecx: &EncodeContext, items: ~[@meta_item]) ->
-       attribute {
+    fn synthesize_link_attr(ecx: &EncodeContext, items: ~[@MetaItem]) ->
+       Attribute {
 
         assert!(!ecx.link_meta.name.is_empty());
         assert!(!ecx.link_meta.vers.is_empty());
@@ -1380,29 +1382,29 @@ fn synthesize_crate_attrs(ecx: &EncodeContext,
             attr::mk_name_value_item_str(@"vers",
                                          ecx.link_meta.vers);
 
-        let other_items =
-            {
-                let tmp = attr::remove_meta_items_by_name(items, "name");
-                attr::remove_meta_items_by_name(tmp, "vers")
-            };
+        let mut meta_items = ~[name_item, vers_item];
 
-        let meta_items = vec::append(~[name_item, vers_item], other_items);
+        for items.iter()
+            .filter(|mi| "name" != mi.name() && "vers" != mi.name())
+            .advance |&mi| {
+            meta_items.push(mi);
+        }
         let link_item = attr::mk_list_item(@"link", meta_items);
 
         return attr::mk_attr(link_item);
     }
 
-    let mut attrs: ~[attribute] = ~[];
+    let mut attrs = ~[];
     let mut found_link_attr = false;
     for crate.node.attrs.iter().advance |attr| {
         attrs.push(
-            if "link" != attr::get_attr_name(attr)  {
+            if "link" != attr.name()  {
                 *attr
             } else {
-                match attr.node.value.node {
-                  meta_list(_, ref l) => {
+                match attr.meta_item_list() {
+                  Some(l) => {
                     found_link_attr = true;;
-                    synthesize_link_attr(ecx, (*l).clone())
+                    synthesize_link_attr(ecx, l.to_owned())
                   }
                   _ => *attr
                 }
diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs
index 5cf69e26a50..d6687b4313a 100644
--- a/src/librustc/metadata/loader.rs
+++ b/src/librustc/metadata/loader.rs
@@ -22,6 +22,7 @@ use syntax::parse::token;
 use syntax::parse::token::ident_interner;
 use syntax::print::pprust;
 use syntax::{ast, attr};
+use syntax::attr::AttrMetaMethods;
 
 use std::cast;
 use std::io;
@@ -46,7 +47,7 @@ pub struct Context {
     filesearch: @FileSearch,
     span: span,
     ident: ast::ident,
-    metas: ~[@ast::meta_item],
+    metas: ~[@ast::MetaItem],
     hash: @str,
     os: os,
     is_static: bool,
@@ -55,7 +56,7 @@ pub struct Context {
 
 pub fn load_library_crate(cx: &Context) -> (~str, @~[u8]) {
     match find_library_crate(cx) {
-      Some(ref t) => return (/*bad*/(*t).clone()),
+      Some(t) => t,
       None => {
         cx.diag.span_fatal(cx.span,
                            fmt!("can't find crate for `%s`",
@@ -140,15 +141,11 @@ fn find_library_crate_aux(
         }
 }
 
-pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @str {
+pub fn crate_name_from_metas(metas: &[@ast::MetaItem]) -> @str {
     for metas.iter().advance |m| {
-        match m.node {
-            ast::meta_name_value(s, ref l) if s == @"name" =>
-                match l.node {
-                    ast::lit_str(s) => return s,
-                    _ => ()
-                },
-            _ => ()
+        match m.name_str_pair() {
+            Some((name, s)) if "name" == name => { return s; }
+            _ => {}
         }
     }
     fail!("expected to find the crate name")
@@ -156,7 +153,7 @@ pub fn crate_name_from_metas(metas: &[@ast::meta_item]) -> @str {
 
 pub fn note_linkage_attrs(intr: @ident_interner,
                           diag: @span_handler,
-                          attrs: ~[ast::attribute]) {
+                          attrs: ~[ast::Attribute]) {
     let r = attr::find_linkage_metas(attrs);
     for r.iter().advance |mi| {
         diag.handler().note(fmt!("meta: %s", pprust::meta_item_to_str(*mi,intr)));
@@ -164,7 +161,7 @@ pub fn note_linkage_attrs(intr: @ident_interner,
 }
 
 fn crate_matches(crate_data: @~[u8],
-                 metas: &[@ast::meta_item],
+                 metas: &[@ast::MetaItem],
                  hash: @str) -> bool {
     let attrs = decoder::get_crate_attributes(crate_data);
     let linkage_metas = attr::find_linkage_metas(attrs);
@@ -175,18 +172,15 @@ fn crate_matches(crate_data: @~[u8],
     metadata_matches(linkage_metas, metas)
 }
 
-pub fn metadata_matches(extern_metas: &[@ast::meta_item],
-                        local_metas: &[@ast::meta_item]) -> bool {
+pub fn metadata_matches(extern_metas: &[@ast::MetaItem],
+                        local_metas: &[@ast::MetaItem]) -> bool {
 
     debug!("matching %u metadata requirements against %u items",
            local_metas.len(), extern_metas.len());
 
-    for local_metas.iter().advance |needed| {
-        if !attr::contains(extern_metas, *needed) {
-            return false;
-        }
+    do local_metas.iter().all |needed| {
+        attr::contains(extern_metas, *needed)
     }
-    return true;
 }
 
 fn get_metadata_section(os: os,
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 9bcfab0773f..6f23f94b25e 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -13,9 +13,9 @@ use driver::session;
 use driver::session::Session;
 use syntax::parse::token::special_idents;
 use syntax::ast::{crate, node_id, item, item_fn};
+use syntax::attr;
 use syntax::codemap::span;
 use syntax::visit::{default_visitor, mk_vt, vt, Visitor, visit_crate, visit_item};
-use syntax::attr::{attrs_contains_name};
 use syntax::ast_map;
 use std::util;
 
@@ -90,7 +90,7 @@ fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
                 }
             }
 
-            if attrs_contains_name(item.attrs, "main") {
+            if attr::contains_name(item.attrs, "main") {
                 if ctxt.attr_main_fn.is_none() {
                     ctxt.attr_main_fn = Some((item.id, item.span));
                 } else {
@@ -100,7 +100,7 @@ fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) {
                 }
             }
 
-            if attrs_contains_name(item.attrs, "start") {
+            if attr::contains_name(item.attrs, "start") {
                 if ctxt.start_fn.is_none() {
                     ctxt.start_fn = Some((item.id, item.span));
                 } else {
diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs
index deafe85a2c9..b19b7652a91 100644
--- a/src/librustc/middle/kind.rs
+++ b/src/librustc/middle/kind.rs
@@ -17,7 +17,7 @@ use util::ppaux::{Repr, ty_to_str};
 use util::ppaux::UserString;
 
 use syntax::ast::*;
-use syntax::attr::attrs_contains_name;
+use syntax::attr;
 use syntax::codemap::span;
 use syntax::print::pprust::expr_to_str;
 use syntax::{visit, ast_util};
@@ -113,7 +113,7 @@ fn check_block(block: &blk, (cx, visitor): (Context, visit::vt<Context>)) {
 
 fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
     // If this is a destructor, check kinds.
-    if !attrs_contains_name(item.attrs, "unsafe_destructor") {
+    if !attr::contains_name(item.attrs, "unsafe_destructor") {
         match item.node {
             item_impl(_, Some(ref trait_ref), ref self_type, _) => {
                 match cx.tcx.def_map.find(&trait_ref.ref_id) {
@@ -574,4 +574,3 @@ pub fn check_cast_for_escaping_regions(
         cx.tcx.region_maps.is_subregion_of(r_sub, r_sup)
     }
 }
-
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index a49e50d5c38..da557c07906 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -23,9 +23,9 @@
 use driver::session::Session;
 use metadata::csearch::each_lang_item;
 use metadata::cstore::iter_crate_data;
-use syntax::ast::{crate, def_id, lit_str, meta_item};
-use syntax::ast::{meta_list, meta_name_value, meta_word};
+use syntax::ast::{crate, def_id, MetaItem};
 use syntax::ast_util::local_def;
+use syntax::attr::AttrMetaMethods;
 use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor};
 use syntax::visit::visit_crate;
 
@@ -360,17 +360,12 @@ impl<'self> LanguageItemCollector<'self> {
 
     pub fn match_and_collect_meta_item(&mut self,
                                        item_def_id: def_id,
-                                       meta_item: &meta_item) {
-        match meta_item.node {
-            meta_name_value(key, literal) => {
-                match literal.node {
-                    lit_str(value) => {
-                        self.match_and_collect_item(item_def_id, key, value);
-                    }
-                    _ => {} // Skip.
-                }
+                                       meta_item: &MetaItem) {
+        match meta_item.name_str_pair() {
+            Some((key, value)) => {
+                self.match_and_collect_item(item_def_id, key, value);
             }
-            meta_word(*) | meta_list(*) => {} // Skip.
+            None => {} // skip
         }
     }
 
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 486939be58d..2e6696e02fc 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -26,6 +26,7 @@ use std::u64;
 use std::u8;
 use extra::smallintmap::SmallIntMap;
 use syntax::attr;
+use syntax::attr::AttrMetaMethods;
 use syntax::codemap::span;
 use syntax::codemap;
 use syntax::{ast, visit, ast_util};
@@ -417,7 +418,7 @@ impl Context {
      * current lint context, call the provided function, then reset the
      * lints in effect to their previous state.
      */
-    fn with_lint_attrs(@mut self, attrs: &[ast::attribute], f: &fn()) {
+    fn with_lint_attrs(@mut self, attrs: &[ast::Attribute], f: &fn()) {
         // Parse all of the lint attributes, and then add them all to the
         // current dictionary of lint information. Along the way, keep a history
         // of what we changed so we can roll everything back after invoking the
@@ -454,18 +455,14 @@ impl Context {
         }
 
         // detect doc(hidden)
-        let mut doc_hidden = false;
-        let r = attr::find_attrs_by_name(attrs, "doc");
-        for r.iter().advance |attr| {
-            match attr::get_meta_item_list(attr.node.value) {
-                Some(s) => {
-                    if attr::find_meta_items_by_name(s, "hidden").len() > 0 {
-                        doc_hidden = true;
-                    }
+        let mut doc_hidden = do attrs.iter().any |attr| {
+            "doc" == attr.name() &&
+                match attr.meta_item_list() {
+                    Some(l) => attr::contains_name(l, "hidden"),
+                    None    => false // not of the form #[doc(...)]
                 }
-                None => {}
-            }
-        }
+        };
+
         if doc_hidden && !self.doc_hidden {
             self.doc_hidden = true;
         } else {
@@ -517,16 +514,15 @@ impl Context {
 }
 
 pub fn each_lint(sess: session::Session,
-                 attrs: &[ast::attribute],
-                 f: &fn(@ast::meta_item, level, @str) -> bool) -> bool {
+                 attrs: &[ast::Attribute],
+                 f: &fn(@ast::MetaItem, level, @str) -> bool) -> bool {
     let xs = [allow, warn, deny, forbid];
     for xs.iter().advance |&level| {
         let level_name = level_to_str(level);
-        let attrs = attr::find_attrs_by_name(attrs, level_name);
-        for attrs.iter().advance |attr| {
+        for attrs.iter().filter(|m| level_name == m.name()).advance |attr| {
             let meta = attr.node.value;
             let metas = match meta.node {
-                ast::meta_list(_, ref metas) => metas,
+                ast::MetaList(_, ref metas) => metas,
                 _ => {
                     sess.span_err(meta.span, "malformed lint attribute");
                     loop;
@@ -534,7 +530,7 @@ pub fn each_lint(sess: session::Session,
             };
             for metas.iter().advance |meta| {
                 match meta.node {
-                    ast::meta_word(lintname) => {
+                    ast::MetaWord(lintname) => {
                         if !f(*meta, level, lintname) {
                             return false;
                         }
@@ -1035,7 +1031,7 @@ fn lint_unnecessary_allocations() -> visit::vt<@mut Context> {
 }
 
 fn lint_missing_doc() -> visit::vt<@mut Context> {
-    fn check_attrs(cx: @mut Context, attrs: &[ast::attribute],
+    fn check_attrs(cx: @mut Context, attrs: &[ast::Attribute],
                    sp: span, msg: &str) {
         // If we're building a test harness, then warning about documentation is
         // probably not really relevant right now
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 036c0751483..69c5392f002 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -376,8 +376,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt,
         visit_item: |item, (method_map, visitor)| {
             // Do not check privacy inside items with the resolve_unexported
             // attribute. This is used for the test runner.
-            if !attr::contains_name(attr::attr_metas(item.attrs),
-                                    "!resolve_unexported") {
+            if !attr::contains_name(item.attrs, "!resolve_unexported") {
                 visit::visit_item(item, (method_map, visitor));
             }
         },
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index a0ba9ac5a88..d11ac758f6e 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -31,8 +31,8 @@ use syntax::visit;
 
 // Returns true if the given set of attributes contains the `#[inline]`
 // attribute.
-fn attributes_specify_inlining(attrs: &[attribute]) -> bool {
-    attr::attrs_contains_name(attrs, "inline")
+fn attributes_specify_inlining(attrs: &[Attribute]) -> bool {
+    attr::contains_name(attrs, "inline")
 }
 
 // Returns true if the given set of generics implies that the item it's
@@ -431,4 +431,3 @@ pub fn find_reachable(tcx: ty::ctxt,
     // Return the set of reachable symbols.
     reachable_context.reachable_symbols
 }
-
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 80078eba239..fa839092212 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -26,7 +26,7 @@ use syntax::ast_util::{def_id_of_def, local_def};
 use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
 use syntax::ast_util::{Privacy, Public, Private};
 use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy};
-use syntax::attr::{attr_metas, contains_name};
+use syntax::attr;
 use syntax::parse::token;
 use syntax::parse::token::ident_interner;
 use syntax::parse::token::special_idents;
@@ -3494,8 +3494,7 @@ impl Resolver {
         // Items with the !resolve_unexported attribute are X-ray contexts.
         // This is used to allow the test runner to run unexported tests.
         let orig_xray_flag = self.xray_context;
-        if contains_name(attr_metas(item.attrs),
-                         "!resolve_unexported") {
+        if attr::contains_name(item.attrs, "!resolve_unexported") {
             self.xray_context = Xray;
         }
 
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 588b0b5c75f..04a016524bd 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -79,6 +79,7 @@ use syntax::ast::ident;
 use syntax::ast_map::{path, path_elt_to_str, path_name};
 use syntax::ast_util::{local_def};
 use syntax::attr;
+use syntax::attr::AttrMetaMethods;
 use syntax::codemap::span;
 use syntax::parse::token;
 use syntax::parse::token::{special_idents};
@@ -464,13 +465,14 @@ pub fn set_inline_hint(f: ValueRef) {
     }
 }
 
-pub fn set_inline_hint_if_appr(attrs: &[ast::attribute],
+pub fn set_inline_hint_if_appr(attrs: &[ast::Attribute],
                                llfn: ValueRef) {
-    match attr::find_inline_attr(attrs) {
-      attr::ia_hint => set_inline_hint(llfn),
-      attr::ia_always => set_always_inline(llfn),
-      attr::ia_never => set_no_inline(llfn),
-      attr::ia_none => { /* fallthrough */ }
+    use syntax::attr::*;
+    match find_inline_attr(attrs) {
+        InlineHint   => set_inline_hint(llfn),
+        InlineAlways => set_always_inline(llfn),
+        InlineNever  => set_no_inline(llfn),
+        InlineNone   => { /* fallthrough */ }
     }
 }
 
@@ -1845,7 +1847,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
                      self_arg: self_arg,
                      param_substs: Option<@param_substs>,
                      id: ast::node_id,
-                     attributes: &[ast::attribute],
+                     attributes: &[ast::Attribute],
                      output_type: ty::t,
                      maybe_load_env: &fn(fn_ctxt),
                      finish: &fn(block)) {
@@ -1868,7 +1870,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
     let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
 
     // Set the fixed stack segment flag if necessary.
-    if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
+    if attr::contains_name(attributes, "fixed_stack_segment") {
         set_no_inline(fcx.llfn);
         set_fixed_stack_segment(fcx.llfn);
     }
@@ -1926,7 +1928,7 @@ pub fn trans_fn(ccx: @mut CrateContext,
                 self_arg: self_arg,
                 param_substs: Option<@param_substs>,
                 id: ast::node_id,
-                attrs: &[ast::attribute]) {
+                attrs: &[ast::Attribute]) {
 
     let the_path_str = path_str(ccx.sess, path);
     let _s = StatRecorder::new(ccx, the_path_str);
@@ -2196,23 +2198,17 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
           // Do static_assert checking. It can't really be done much earlier because we need to get
           // the value of the bool out of LLVM
           for item.attrs.iter().advance |attr| {
-              match attr.node.value.node {
-                  ast::meta_word(x) => {
-                      if x.slice(0, x.len()) == "static_assert" {
-                          if m == ast::m_mutbl {
-                              ccx.sess.span_fatal(expr.span,
-                                                  "cannot have static_assert \
-                                                   on a mutable static");
-                          }
-                          let v = ccx.const_values.get_copy(&item.id);
-                          unsafe {
-                              if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
-                                  ccx.sess.span_fatal(expr.span, "static assertion failed");
-                              }
-                          }
+              if "static_assert" == attr.name() {
+                  if m == ast::m_mutbl {
+                      ccx.sess.span_fatal(expr.span,
+                                          "cannot have static_assert on a mutable static");
+                  }
+                  let v = ccx.const_values.get_copy(&item.id);
+                  unsafe {
+                      if !(llvm::LLVMConstIntGetZExtValue(v) as bool) {
+                          ccx.sess.span_fatal(expr.span, "static assertion failed");
                       }
-                  },
-                  _ => ()
+                  }
               }
           }
       },
@@ -2258,7 +2254,7 @@ pub fn register_fn(ccx: @mut CrateContext,
                    sp: span,
                    path: path,
                    node_id: ast::node_id,
-                   attrs: &[ast::attribute])
+                   attrs: &[ast::Attribute])
                 -> ValueRef {
     let t = ty::node_id_to_type(ccx.tcx, node_id);
     register_fn_full(ccx, sp, path, node_id, attrs, t)
@@ -2268,7 +2264,7 @@ pub fn register_fn_full(ccx: @mut CrateContext,
                         sp: span,
                         path: path,
                         node_id: ast::node_id,
-                        attrs: &[ast::attribute],
+                        attrs: &[ast::Attribute],
                         node_type: ty::t)
                      -> ValueRef {
     let llfty = type_of_fn_from_ty(ccx, node_type);
@@ -2280,7 +2276,7 @@ pub fn register_fn_fuller(ccx: @mut CrateContext,
                           sp: span,
                           path: path,
                           node_id: ast::node_id,
-                          attrs: &[ast::attribute],
+                          attrs: &[ast::Attribute],
                           node_type: ty::t,
                           cc: lib::llvm::CallConv,
                           fn_ty: Type)
@@ -2289,7 +2285,7 @@ pub fn register_fn_fuller(ccx: @mut CrateContext,
            node_id,
            ast_map::path_to_str(path, token::get_ident_interner()));
 
-    let ps = if attr::attrs_contains_name(attrs, "no_mangle") {
+    let ps = if attr::contains_name(attrs, "no_mangle") {
         path_elt_to_str(*path.last(), token::get_ident_interner())
     } else {
         mangle_exported_name(ccx, path, node_type)
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index f7d0e71387b..355e2f57b2c 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -351,10 +351,10 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
                         cc: lib::llvm::CallConv) {
         let llwrapfn = get_item_val(ccx, id);
         let tys = shim_types(ccx, id);
-        if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") {
+        if attr::contains_name(foreign_item.attrs, "rust_stack") {
             build_direct_fn(ccx, llwrapfn, foreign_item,
                             &tys, cc);
-        } else if attr::attrs_contains_name(foreign_item.attrs, "fast_ffi") {
+        } else if attr::contains_name(foreign_item.attrs, "fast_ffi") {
             build_fast_ffi_fn(ccx, llwrapfn, foreign_item, &tys, cc);
         } else {
             let llshimfn = build_shim_fn(ccx, foreign_item, &tys, cc);
@@ -546,7 +546,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
                        item: &ast::foreign_item,
                        path: ast_map::path,
                        substs: @param_substs,
-                       attributes: &[ast::attribute],
+                       attributes: &[ast::Attribute],
                        ref_id: Option<ast::node_id>) {
     debug!("trans_intrinsic(item.ident=%s)", ccx.sess.str_of(item.ident));
 
@@ -624,7 +624,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
     set_always_inline(fcx.llfn);
 
     // Set the fixed stack segment flag if necessary.
-    if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
+    if attr::contains_name(attributes, "fixed_stack_segment") {
         set_fixed_stack_segment(fcx.llfn);
     }
 
@@ -1146,7 +1146,7 @@ pub fn register_foreign_fn(ccx: @mut CrateContext,
                            sp: span,
                            path: ast_map::path,
                            node_id: ast::node_id,
-                           attrs: &[ast::attribute])
+                           attrs: &[ast::Attribute])
                            -> ValueRef {
     let _icx = push_ctxt("foreign::register_foreign_fn");
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 50f331f7e7d..a2edba7f3d7 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3966,7 +3966,7 @@ pub fn has_attr(tcx: ctxt, did: def_id, attr: &str) -> bool {
                 &ast_map::node_item(@ast::item {
                     attrs: ref attrs,
                     _
-                }, _)) => attr::attrs_contains_name(*attrs, attr),
+                }, _)) => attr::contains_name(*attrs, attr),
             _ => tcx.sess.bug(fmt!("has_attr: %? is not an item",
                                    did))
         }
diff --git a/src/librustdoc/attr_parser.rs b/src/librustdoc/attr_parser.rs
index e61f8d6d743..f8eff69cc8f 100644
--- a/src/librustdoc/attr_parser.rs
+++ b/src/librustdoc/attr_parser.rs
@@ -18,24 +18,20 @@ an AST's attributes.
 
 use syntax::ast;
 use syntax::attr;
+use syntax::attr::{AttrMetaMethods, AttributeMethods};
 
 pub struct CrateAttrs {
     name: Option<~str>
 }
 
-fn doc_metas(
-    attrs: ~[ast::attribute]
-) -> ~[@ast::meta_item] {
-
-    let doc_attrs = attr::find_attrs_by_name(attrs, "doc");
-    let doc_metas = do doc_attrs.map |attr| {
-        attr::attr_meta(attr::desugar_doc_attr(attr))
-    };
-
-    return doc_metas;
+fn doc_metas(attrs: ~[ast::Attribute]) -> ~[@ast::MetaItem] {
+    attrs.iter()
+        .filter(|at| "doc" == at.name())
+        .transform(|at| at.desugar_doc().meta())
+        .collect()
 }
 
-pub fn parse_crate(attrs: ~[ast::attribute]) -> CrateAttrs {
+pub fn parse_crate(attrs: ~[ast::Attribute]) -> CrateAttrs {
     let link_metas = attr::find_linkage_metas(attrs);
     let name = attr::last_meta_item_value_str_by_name(link_metas, "name");
 
@@ -44,10 +40,10 @@ pub fn parse_crate(attrs: ~[ast::attribute]) -> CrateAttrs {
     }
 }
 
-pub fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> {
+pub fn parse_desc(attrs: ~[ast::Attribute]) -> Option<~str> {
     let doc_strs = do doc_metas(attrs).consume_iter().filter_map |meta| {
-        attr::get_meta_item_value_str(meta).map(|s| s.to_owned())
-    }.collect::<~[~str]>();
+        meta.value_str()
+    }.collect::<~[@str]>();
     if doc_strs.is_empty() {
         None
     } else {
@@ -55,14 +51,11 @@ pub fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> {
     }
 }
 
-pub fn parse_hidden(attrs: ~[ast::attribute]) -> bool {
+pub fn parse_hidden(attrs: ~[ast::Attribute]) -> bool {
     let r = doc_metas(attrs);
     do r.iter().any |meta| {
-        match attr::get_meta_item_list(*meta) {
-            Some(metas) => {
-                let hiddens = attr::find_meta_items_by_name(metas, "hidden");
-                !hiddens.is_empty()
-            }
+        match meta.meta_item_list() {
+            Some(metas) => attr::contains_name(metas, "hidden"),
             None => false
         }
     }
@@ -74,7 +67,7 @@ mod test {
     use syntax;
     use super::{parse_hidden, parse_crate, parse_desc};
 
-    fn parse_attributes(source: @str) -> ~[ast::attribute] {
+    fn parse_attributes(source: @str) -> ~[ast::Attribute] {
         use syntax::parse;
         use syntax::parse::attr::parser_attr;
 
diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs
index cc274e26f5b..697a699915e 100644
--- a/src/librustdoc/attr_pass.rs
+++ b/src/librustdoc/attr_pass.rs
@@ -68,7 +68,7 @@ fn fold_crate(
     doc::CrateDoc {
         topmod: doc::ModDoc {
             item: doc::ItemDoc {
-                name: attrs.name.clone().get_or_default(doc.topmod.name()),
+                name: attrs.name.clone().get_or_default(doc.topmod.name_()),
                 .. doc.topmod.item.clone()
             },
             .. doc.topmod.clone()
@@ -102,7 +102,7 @@ fn fold_item(
 fn parse_item_attrs<T:Send>(
     srv: astsrv::Srv,
     id: doc::AstId,
-    parse_attrs: ~fn(a: ~[ast::attribute]) -> T) -> T {
+    parse_attrs: ~fn(a: ~[ast::Attribute]) -> T) -> T {
     do astsrv::exec(srv) |ctxt| {
         let attrs = match ctxt.ast_map.get_copy(&id) {
             ast_map::node_item(item, _) => item.attrs.clone(),
@@ -249,7 +249,7 @@ mod test {
     #[test]
     fn should_replace_top_module_name_with_crate_name() {
         let doc = mk_doc(~"#[link(name = \"bond\")];");
-        assert!(doc.cratemod().name() == ~"bond");
+        assert!(doc.cratemod().name_() == ~"bond");
     }
 
     #[test]
diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs
index 9d173e271eb..cca898feba2 100644
--- a/src/librustdoc/doc.rs
+++ b/src/librustdoc/doc.rs
@@ -355,7 +355,11 @@ impl Item for StructDoc {
 
 pub trait ItemUtils {
     fn id(&self) -> AstId;
-    fn name(&self) -> ~str;
+    /// FIXME #5898: This conflicts with
+    /// syntax::attr::AttrMetaMethods.name; This rustdoc seems to be on
+    /// the way out so I'm making this one look bad rather than the
+    /// new methods in attr.
+    fn name_(&self) -> ~str;
     fn path(&self) -> ~[~str];
     fn brief(&self) -> Option<~str>;
     fn desc(&self) -> Option<~str>;
@@ -367,7 +371,7 @@ impl<A:Item> ItemUtils for A {
         self.item().id
     }
 
-    fn name(&self) -> ~str {
+    fn name_(&self) -> ~str {
         self.item().name.clone()
     }
 
diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs
index 095066b1647..c027ba7e2f2 100644
--- a/src/librustdoc/extract.rs
+++ b/src/librustdoc/extract.rs
@@ -298,21 +298,21 @@ mod test {
     #[test]
     fn extract_mods() {
         let doc = mk_doc(@"mod a { mod b { } mod c { } }");
-        assert!(doc.cratemod().mods()[0].name() == ~"a");
-        assert!(doc.cratemod().mods()[0].mods()[0].name() == ~"b");
-        assert!(doc.cratemod().mods()[0].mods()[1].name() == ~"c");
+        assert!(doc.cratemod().mods()[0].name_() == ~"a");
+        assert!(doc.cratemod().mods()[0].mods()[0].name_() == ~"b");
+        assert!(doc.cratemod().mods()[0].mods()[1].name_() == ~"c");
     }
 
     #[test]
     fn extract_fns_from_foreign_mods() {
         let doc = mk_doc(@"extern { fn a(); }");
-        assert!(doc.cratemod().nmods()[0].fns[0].name() == ~"a");
+        assert!(doc.cratemod().nmods()[0].fns[0].name_() == ~"a");
     }
 
     #[test]
     fn extract_mods_deep() {
         let doc = mk_doc(@"mod a { mod b { mod c { } } }");
-        assert!(doc.cratemod().mods()[0].mods()[0].mods()[0].name() ==
+        assert!(doc.cratemod().mods()[0].mods()[0].mods()[0].name_() ==
             ~"c");
     }
 
@@ -328,8 +328,8 @@ mod test {
             @"fn a() { } \
               mod b { fn c() {
              } }");
-        assert!(doc.cratemod().fns()[0].name() == ~"a");
-        assert!(doc.cratemod().mods()[0].fns()[0].name() == ~"c");
+        assert!(doc.cratemod().fns()[0].name_() == ~"a");
+        assert!(doc.cratemod().mods()[0].fns()[0].name_() == ~"c");
     }
 
     #[test]
@@ -343,7 +343,7 @@ mod test {
         let source = @"";
         let ast = parse::from_str(source);
         let doc = extract(ast, ~"burp");
-        assert!(doc.cratemod().name() == ~"burp");
+        assert!(doc.cratemod().name_() == ~"burp");
     }
 
     #[test]
@@ -351,7 +351,7 @@ mod test {
         let source = ~"";
         do astsrv::from_str(source) |srv| {
             let doc = from_srv(srv, ~"name");
-            assert!(doc.cratemod().name() == ~"name");
+            assert!(doc.cratemod().name_() == ~"name");
         }
     }
 
@@ -359,14 +359,14 @@ mod test {
     fn should_extract_const_name_and_id() {
         let doc = mk_doc(@"static a: int = 0;");
         assert!(doc.cratemod().consts()[0].id() != 0);
-        assert!(doc.cratemod().consts()[0].name() == ~"a");
+        assert!(doc.cratemod().consts()[0].name_() == ~"a");
     }
 
     #[test]
     fn should_extract_enums() {
         let doc = mk_doc(@"enum e { v }");
         assert!(doc.cratemod().enums()[0].id() != 0);
-        assert!(doc.cratemod().enums()[0].name() == ~"e");
+        assert!(doc.cratemod().enums()[0].name_() == ~"e");
     }
 
     #[test]
@@ -378,7 +378,7 @@ mod test {
     #[test]
     fn should_extract_traits() {
         let doc = mk_doc(@"trait i { fn f(); }");
-        assert!(doc.cratemod().traits()[0].name() == ~"i");
+        assert!(doc.cratemod().traits()[0].name_() == ~"i");
     }
 
     #[test]
@@ -396,13 +396,13 @@ mod test {
     #[test]
     fn should_extract_tys() {
         let doc = mk_doc(@"type a = int;");
-        assert!(doc.cratemod().types()[0].name() == ~"a");
+        assert!(doc.cratemod().types()[0].name_() == ~"a");
     }
 
     #[test]
     fn should_extract_structs() {
         let doc = mk_doc(@"struct Foo { field: () }");
-        assert!(doc.cratemod().structs()[0].name() == ~"Foo");
+        assert!(doc.cratemod().structs()[0].name_() == ~"Foo");
     }
 
     #[test]
diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs
index a1f4ddf986b..84b8febd33f 100644
--- a/src/librustdoc/markdown_pass.rs
+++ b/src/librustdoc/markdown_pass.rs
@@ -172,7 +172,7 @@ pub fn header_kind(doc: doc::ItemTag) -> ~str {
 }
 
 pub fn header_name(doc: doc::ItemTag) -> ~str {
-    let fullpath = (doc.path() + &[doc.name()]).connect("::");
+    let fullpath = (doc.path() + &[doc.name_()]).connect("::");
     match &doc {
         &doc::ModTag(_) if doc.id() != syntax::ast::crate_node_id => {
             fullpath
@@ -200,7 +200,7 @@ pub fn header_name(doc: doc::ItemTag) -> ~str {
             fmt!("%s for %s%s", trait_part, *self_ty, bounds)
         }
         _ => {
-            doc.name()
+            doc.name_()
         }
     }
 }
diff --git a/src/librustdoc/markdown_writer.rs b/src/librustdoc/markdown_writer.rs
index 74ce1b650bc..c13e85ea716 100644
--- a/src/librustdoc/markdown_writer.rs
+++ b/src/librustdoc/markdown_writer.rs
@@ -159,12 +159,12 @@ pub fn make_filename(
                 config.output_style == config::DocPerMod {
                 ~"index"
             } else {
-                assert!(doc.topmod.name() != ~"");
-                doc.topmod.name()
+                assert!(doc.topmod.name_() != ~"");
+                doc.topmod.name_()
             }
           }
           doc::ItemPage(doc) => {
-            (doc.path() + &[doc.name()]).connect("_")
+            (doc.path() + &[doc.name_()]).connect("_")
           }
         }
     };
diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs
index 4f1ce45cb60..7526b9557b2 100644
--- a/src/librustdoc/page_pass.rs
+++ b/src/librustdoc/page_pass.rs
@@ -174,7 +174,7 @@ mod test {
     fn should_make_a_page_for_every_mod() {
         let doc = mk_doc(~"mod a { }");
         // hidden __std_macros module at the start.
-        assert_eq!(doc.pages.mods()[0].name(), ~"a");
+        assert_eq!(doc.pages.mods()[0].name_(), ~"a");
     }
 
     #[test]
diff --git a/src/librustdoc/pass.rs b/src/librustdoc/pass.rs
index 0654e1bbd1a..aadc1b31acc 100644
--- a/src/librustdoc/pass.rs
+++ b/src/librustdoc/pass.rs
@@ -48,7 +48,7 @@ fn test_run_passes() {
                 doc::CratePage(doc::CrateDoc{
                     topmod: doc::ModDoc{
                         item: doc::ItemDoc {
-                            name: doc.cratemod().name() + "two",
+                            name: doc.cratemod().name_() + "two",
                             .. doc.cratemod().item.clone()
                         },
                         items: ~[],
@@ -67,7 +67,7 @@ fn test_run_passes() {
                 doc::CratePage(doc::CrateDoc{
                     topmod: doc::ModDoc{
                         item: doc::ItemDoc {
-                            name: doc.cratemod().name() + "three",
+                            name: doc.cratemod().name_() + "three",
                             .. doc.cratemod().item.clone()
                         },
                         items: ~[],
@@ -91,6 +91,6 @@ fn test_run_passes() {
         ];
         let doc = extract::from_srv(srv.clone(), ~"one");
         let doc = run_passes(srv, doc, passes);
-        assert_eq!(doc.cratemod().name(), ~"onetwothree");
+        assert_eq!(doc.cratemod().name_(), ~"onetwothree");
     }
 }
diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs
index 413df2f3358..1b7b6d578b9 100644
--- a/src/librustdoc/path_pass.rs
+++ b/src/librustdoc/path_pass.rs
@@ -68,7 +68,7 @@ fn fold_item(fold: &fold::Fold<Ctxt>, doc: doc::ItemDoc) -> doc::ItemDoc {
 fn fold_mod(fold: &fold::Fold<Ctxt>, doc: doc::ModDoc) -> doc::ModDoc {
     let is_topmod = doc.id() == ast::crate_node_id;
 
-    if !is_topmod { fold.ctxt.path.push(doc.name()); }
+    if !is_topmod { fold.ctxt.path.push(doc.name_()); }
     let doc = fold::default_any_fold_mod(fold, doc);
     if !is_topmod { fold.ctxt.path.pop(); }
 
@@ -79,7 +79,7 @@ fn fold_mod(fold: &fold::Fold<Ctxt>, doc: doc::ModDoc) -> doc::ModDoc {
 }
 
 fn fold_nmod(fold: &fold::Fold<Ctxt>, doc: doc::NmodDoc) -> doc::NmodDoc {
-    fold.ctxt.path.push(doc.name());
+    fold.ctxt.path.push(doc.name_());
     let doc = fold::default_seq_fold_nmod(fold, doc);
     fold.ctxt.path.pop();
 
diff --git a/src/librustdoc/sort_item_name_pass.rs b/src/librustdoc/sort_item_name_pass.rs
index 5ad0c5606d9..8c7267e0b21 100644
--- a/src/librustdoc/sort_item_name_pass.rs
+++ b/src/librustdoc/sort_item_name_pass.rs
@@ -17,7 +17,7 @@ use sort_pass;
 
 pub fn mk_pass() -> Pass {
     fn by_item_name(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
-        (*item1).name() <= (*item2).name()
+        (*item1).name_() <= (*item2).name_()
     }
     sort_pass::mk_pass(~"sort_item_name", by_item_name)
 }
@@ -32,7 +32,7 @@ fn test() {
         let doc = extract::from_srv(srv.clone(), ~"");
         let doc = (mk_pass().f)(srv.clone(), doc);
         // hidden __std_macros module at the start.
-        assert_eq!(doc.cratemod().items[1].name(), ~"y");
-        assert_eq!(doc.cratemod().items[2].name(), ~"z");
+        assert_eq!(doc.cratemod().items[1].name_(), ~"y");
+        assert_eq!(doc.cratemod().items[2].name_(), ~"z");
     }
 }
diff --git a/src/librustdoc/sort_item_type_pass.rs b/src/librustdoc/sort_item_type_pass.rs
index b37be5482ac..366cc83df27 100644
--- a/src/librustdoc/sort_item_type_pass.rs
+++ b/src/librustdoc/sort_item_type_pass.rs
@@ -54,14 +54,14 @@ fn test() {
         let doc = extract::from_srv(srv.clone(), ~"");
         let doc = (mk_pass().f)(srv.clone(), doc);
         // hidden __std_macros module at the start.
-        assert_eq!(doc.cratemod().items[0].name(), ~"iconst");
-        assert_eq!(doc.cratemod().items[1].name(), ~"itype");
-        assert_eq!(doc.cratemod().items[2].name(), ~"ienum");
-        assert_eq!(doc.cratemod().items[3].name(), ~"istruct");
-        assert_eq!(doc.cratemod().items[4].name(), ~"itrait");
-        assert_eq!(doc.cratemod().items[5].name(), ~"__extensions__");
-        assert_eq!(doc.cratemod().items[6].name(), ~"ifn");
+        assert_eq!(doc.cratemod().items[0].name_(), ~"iconst");
+        assert_eq!(doc.cratemod().items[1].name_(), ~"itype");
+        assert_eq!(doc.cratemod().items[2].name_(), ~"ienum");
+        assert_eq!(doc.cratemod().items[3].name_(), ~"istruct");
+        assert_eq!(doc.cratemod().items[4].name_(), ~"itrait");
+        assert_eq!(doc.cratemod().items[5].name_(), ~"__extensions__");
+        assert_eq!(doc.cratemod().items[6].name_(), ~"ifn");
         // hidden __std_macros module fits here.
-        assert_eq!(doc.cratemod().items[8].name(), ~"imod");
+        assert_eq!(doc.cratemod().items[8].name_(), ~"imod");
     }
 }
diff --git a/src/librustdoc/sort_pass.rs b/src/librustdoc/sort_pass.rs
index 5119f1e3bfc..a6aa9480f38 100644
--- a/src/librustdoc/sort_pass.rs
+++ b/src/librustdoc/sort_pass.rs
@@ -68,7 +68,7 @@ fn fold_mod(
 #[test]
 fn test() {
     fn name_lteq(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
-        (*item1).name() <= (*item2).name()
+        (*item1).name_() <= (*item2).name_()
     }
 
     let source = ~"mod z { mod y { } fn x() { } } mod w { }";
@@ -76,10 +76,10 @@ fn test() {
         let doc = extract::from_srv(srv.clone(), ~"");
         let doc = (mk_pass(~"", name_lteq).f)(srv.clone(), doc);
         // hidden __std_macros module at the start.
-        assert_eq!(doc.cratemod().mods()[1].name(), ~"w");
-        assert_eq!(doc.cratemod().mods()[2].items[0].name(), ~"x");
-        assert_eq!(doc.cratemod().mods()[2].items[1].name(), ~"y");
-        assert_eq!(doc.cratemod().mods()[2].name(), ~"z");
+        assert_eq!(doc.cratemod().mods()[1].name_(), ~"w");
+        assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"x");
+        assert_eq!(doc.cratemod().mods()[2].items[1].name_(), ~"y");
+        assert_eq!(doc.cratemod().mods()[2].name_(), ~"z");
     }
 }
 
@@ -94,10 +94,10 @@ fn should_be_stable() {
         let doc = extract::from_srv(srv.clone(), ~"");
         let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
         // hidden __std_macros module at the start.
-        assert_eq!(doc.cratemod().mods()[1].items[0].name(), ~"b");
-        assert_eq!(doc.cratemod().mods()[2].items[0].name(), ~"d");
+        assert_eq!(doc.cratemod().mods()[1].items[0].name_(), ~"b");
+        assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"d");
         let doc = (mk_pass(~"", always_eq).f)(srv.clone(), doc);
-        assert_eq!(doc.cratemod().mods()[1].items[0].name(), ~"b");
-        assert_eq!(doc.cratemod().mods()[2].items[0].name(), ~"d");
+        assert_eq!(doc.cratemod().mods()[1].items[0].name_(), ~"b");
+        assert_eq!(doc.cratemod().mods()[2].items[0].name_(), ~"d");
     }
 }
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index d2f5e00513c..13f3ce84071 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -14,11 +14,9 @@ use rustc::metadata::filesearch;
 use extra::getopts::groups::getopts;
 use syntax::ast_util::*;
 use syntax::codemap::{dummy_sp, spanned};
-use syntax::codemap::dummy_spanned;
 use syntax::ext::base::ExtCtxt;
 use syntax::{ast, attr, codemap, diagnostic, fold};
-use syntax::ast::{meta_name_value, meta_list};
-use syntax::attr::{mk_attr};
+use syntax::attr::AttrMetaMethods;
 use rustc::back::link::output_type_exe;
 use rustc::driver::driver::compile_upto;
 use rustc::driver::session::{lib_crate, bin_crate};
@@ -81,7 +79,7 @@ fn fold_mod(_ctx: @mut ReadyCtx,
     fn strip_main(item: @ast::item) -> @ast::item {
         @ast::item {
             attrs: do item.attrs.iter().filter_map |attr| {
-                if "main" != attr::get_attr_name(attr) {
+                if "main" != attr.name() {
                     Some(*attr)
                 } else {
                     None
@@ -104,25 +102,27 @@ fn fold_item(ctx: @mut ReadyCtx,
              fold: @fold::ast_fold) -> Option<@ast::item> {
     ctx.path.push(item.ident);
 
-    let attrs = attr::find_attrs_by_name(item.attrs, "pkg_do");
+    let mut cmds = ~[];
+    let mut had_pkg_do = false;
 
-    if attrs.len() > 0 {
-        let mut cmds = ~[];
-
-        for attrs.iter().advance |attr| {
+    for item.attrs.iter().advance |attr| {
+        if "pkg_do" == attr.name() {
+            had_pkg_do = true;
             match attr.node.value.node {
-                ast::meta_list(_, ref mis) => {
+                ast::MetaList(_, ref mis) => {
                     for mis.iter().advance |mi| {
                         match mi.node {
-                            ast::meta_word(cmd) => cmds.push(cmd.to_owned()),
+                            ast::MetaWord(cmd) => cmds.push(cmd.to_owned()),
                             _ => {}
                         };
                     }
                 }
                 _ => cmds.push(~"build")
-            };
+            }
         }
+    }
 
+    if had_pkg_do {
         ctx.fns.push(ListenerFn {
             cmds: cmds,
             span: item.span,
@@ -245,14 +245,13 @@ pub fn compile_input(ctxt: &Ctx,
             _     => pkg_id.short_name.clone()
         };
         debug!("Injecting link name: %s", short_name_to_use);
+        let link_options =
+            ~[attr::mk_name_value_item_str(@"name", short_name_to_use.to_managed()),
+              attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())];
+
         crate = @codemap::respan(crate.span, ast::crate_ {
-            attrs: ~[mk_attr(@dummy_spanned(
-                meta_list(@"link",
-                 ~[@dummy_spanned(meta_name_value(@"name",
-                                      mk_string_lit(short_name_to_use.to_managed()))),
-                   @dummy_spanned(meta_name_value(@"vers",
-                         mk_string_lit(pkg_id.version.to_str().to_managed())))])))],
-            ..crate.node.clone()});
+            attrs: ~[attr::mk_attr(attr::mk_list_item(@"link", link_options))],
+            .. crate.node.clone()});
     }
 
     debug!("calling compile_crate_from_input, out_dir = %s,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 7fa2c2700c9..f2974423a1a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -193,26 +193,51 @@ pub enum def {
 }
 
 
-// The set of meta_items that define the compilation environment of the crate,
+// The set of MetaItems that define the compilation environment of the crate,
 // used to drive conditional compilation
-pub type crate_cfg = ~[@meta_item];
+pub type crate_cfg = ~[@MetaItem];
 
 pub type crate = spanned<crate_>;
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct crate_ {
     module: _mod,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     config: crate_cfg,
 }
 
-pub type meta_item = spanned<meta_item_>;
+pub type MetaItem = spanned<MetaItem_>;
 
-#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub enum meta_item_ {
-    meta_word(@str),
-    meta_list(@str, ~[@meta_item]),
-    meta_name_value(@str, lit),
+#[deriving(Clone, Encodable, Decodable, IterBytes)]
+pub enum MetaItem_ {
+    MetaWord(@str),
+    MetaList(@str, ~[@MetaItem]),
+    MetaNameValue(@str, lit),
+}
+
+// can't be derived because the MetaList requires an unordered comparison
+impl Eq for MetaItem_ {
+    fn eq(&self, other: &MetaItem_) -> bool {
+        match *self {
+            MetaWord(ref ns) => match *other {
+                MetaWord(ref no) => (*ns) == (*no),
+                _ => false
+            },
+            MetaNameValue(ref ns, ref vs) => match *other {
+                MetaNameValue(ref no, ref vo) => {
+                    (*ns) == (*no) && vs.node == vo.node
+                }
+                _ => false
+            },
+            MetaList(ref ns, ref miss) => match *other {
+                MetaList(ref no, ref miso) => {
+                    ns == no &&
+                        miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node))
+                }
+                _ => false
+            }
+        }
+    }
 }
 
 //pub type blk = spanned<blk_>;
@@ -622,7 +647,7 @@ pub type ty_field = spanned<ty_field_>;
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct ty_method {
     ident: ident,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     purity: purity,
     decl: fn_decl,
     generics: Generics,
@@ -833,7 +858,7 @@ pub type explicit_self = spanned<explicit_self_>;
 #[deriving(Eq, Encodable, Decodable,IterBytes)]
 pub struct method {
     ident: ident,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     generics: Generics,
     explicit_self: explicit_self,
     purity: purity,
@@ -886,7 +911,7 @@ pub struct enum_def {
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct variant_ {
     name: ident,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     kind: variant_kind,
     id: node_id,
     disr_expr: Option<@expr>,
@@ -925,34 +950,34 @@ pub enum view_path_ {
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct view_item {
     node: view_item_,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     vis: visibility,
     span: span,
 }
 
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum view_item_ {
-    view_item_extern_mod(ident, ~[@meta_item], node_id),
+    view_item_extern_mod(ident, ~[@MetaItem], node_id),
     view_item_use(~[@view_path]),
 }
 
 // Meta-data associated with an item
-pub type attribute = spanned<attribute_>;
+pub type Attribute = spanned<Attribute_>;
 
-// Distinguishes between attributes that decorate items and attributes that
+// Distinguishes between Attributes that decorate items and Attributes that
 // are contained as statements within items. These two cases need to be
 // distinguished for pretty-printing.
 #[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-pub enum attr_style {
-    attr_outer,
-    attr_inner,
+pub enum AttrStyle {
+    AttrOuter,
+    AttrInner,
 }
 
 // doc-comments are promoted to attributes that have is_sugared_doc = true
 #[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-pub struct attribute_ {
-    style: attr_style,
-    value: @meta_item,
+pub struct Attribute_ {
+    style: AttrStyle,
+    value: @MetaItem,
     is_sugared_doc: bool,
 }
 
@@ -990,7 +1015,7 @@ pub struct struct_field_ {
     kind: struct_field_kind,
     id: node_id,
     ty: Ty,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
 }
 
 pub type struct_field = spanned<struct_field_>;
@@ -1016,7 +1041,7 @@ pub struct struct_def {
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub struct item {
     ident: ident,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     id: node_id,
     node: item_,
     vis: visibility,
@@ -1044,7 +1069,7 @@ pub enum item_ {
 #[deriving(Eq, Encodable, Decodable,IterBytes)]
 pub struct foreign_item {
     ident: ident,
-    attrs: ~[attribute],
+    attrs: ~[Attribute],
     node: foreign_item_,
     id: node_id,
     span: span,
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 7dd01a54f7a..3c560d211fd 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -8,313 +8,256 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Functions dealing with attributes and meta_items
+// Functions dealing with attributes and meta items
 
 use extra;
 
 use ast;
+use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
 use codemap::{spanned, dummy_spanned};
-use attr;
 use codemap::BytePos;
 use diagnostic::span_handler;
 use parse::comments::{doc_comment_style, strip_doc_comment_decoration};
 
 use std::hashmap::HashSet;
-/* Constructors */
-
-pub fn mk_name_value_item_str(name: @str, value: @str)
-                           -> @ast::meta_item {
-    let value_lit = dummy_spanned(ast::lit_str(value));
-    mk_name_value_item(name, value_lit)
-}
-
-pub fn mk_name_value_item(name: @str, value: ast::lit)
-        -> @ast::meta_item {
-    @dummy_spanned(ast::meta_name_value(name, value))
-}
-
-pub fn mk_list_item(name: @str, items: ~[@ast::meta_item]) ->
-   @ast::meta_item {
-    @dummy_spanned(ast::meta_list(name, items))
-}
 
-pub fn mk_word_item(name: @str) -> @ast::meta_item {
-    @dummy_spanned(ast::meta_word(name))
+pub trait AttrMetaMethods {
+    // This could be changed to `fn check_name(&self, name: @str) ->
+    // bool` which would facilitate a side table recording which
+    // attributes/meta items are used/unused.
+
+    /// Retrieve the name of the meta item, e.g. foo in #[foo],
+    /// #[foo="bar"] and #[foo(bar)]
+    fn name(&self) -> @str;
+
+    /**
+     * Gets the string value if self is a MetaNameValue variant
+     * containing a string, otherwise None.
+     */
+    fn value_str(&self) -> Option<@str>;
+    /// Gets a list of inner meta items from a list MetaItem type.
+    fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]>;
+
+    /**
+     * If the meta item is a name-value type with a string value then returns
+     * a tuple containing the name and string value, otherwise `None`
+     */
+    fn name_str_pair(&self) -> Option<(@str, @str)>;
 }
 
-pub fn mk_attr(item: @ast::meta_item) -> ast::attribute {
-    dummy_spanned(ast::attribute_ { style: ast::attr_inner,
-                                    value: item,
-                                    is_sugared_doc: false })
+impl AttrMetaMethods for Attribute {
+    fn name(&self) -> @str { self.meta().name() }
+    fn value_str(&self) -> Option<@str> { self.meta().value_str() }
+    fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> {
+        self.node.value.meta_item_list()
+    }
+    fn name_str_pair(&self) -> Option<(@str, @str)> { self.meta().name_str_pair() }
 }
 
-pub fn mk_sugared_doc_attr(text: @str,
-                           lo: BytePos, hi: BytePos) -> ast::attribute {
-    let style = doc_comment_style(text);
-    let lit = spanned(lo, hi, ast::lit_str(text));
-    let attr = ast::attribute_ {
-        style: style,
-        value: @spanned(lo, hi, ast::meta_name_value(@"doc", lit)),
-        is_sugared_doc: true
-    };
-    spanned(lo, hi, attr)
-}
+impl AttrMetaMethods for MetaItem {
+    fn name(&self) -> @str {
+        match self.node {
+            MetaWord(n) => n,
+            MetaNameValue(n, _) => n,
+            MetaList(n, _) => n
+        }
+    }
 
-/* Conversion */
+    fn value_str(&self) -> Option<@str> {
+        match self.node {
+            MetaNameValue(_, ref v) => {
+                match v.node {
+                    ast::lit_str(s) => Some(s),
+                    _ => None,
+                }
+            },
+            _ => None
+        }
+    }
 
-pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
-    attr.node.value
-}
+    fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> {
+        match self.node {
+            MetaList(_, ref l) => Some(l.as_slice()),
+            _ => None
+        }
+    }
 
-// Get the meta_items from inside a vector of attributes
-pub fn attr_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
-    do attrs.map |a| { attr_meta(*a) }
+    pub fn name_str_pair(&self) -> Option<(@str, @str)> {
+        self.value_str().map_consume(|s| (self.name(), s))
+    }
 }
 
-pub fn desugar_doc_attr(attr: &ast::attribute) -> ast::attribute {
-    if attr.node.is_sugared_doc {
-        let comment = get_meta_item_value_str(attr.node.value).get();
-        let meta = mk_name_value_item_str(@"doc",
-                                     strip_doc_comment_decoration(comment).to_managed());
-        mk_attr(meta)
-    } else {
-        *attr
+// Annoying, but required to get test_cfg to work
+impl AttrMetaMethods for @MetaItem {
+    fn name(&self) -> @str { (**self).name() }
+    fn value_str(&self) -> Option<@str> { (**self).value_str() }
+    fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> {
+        (**self).meta_item_list()
     }
+    fn name_str_pair(&self) -> Option<(@str, @str)> { (**self).name_str_pair() }
 }
 
-/* Accessors */
 
-pub fn get_attr_name(attr: &ast::attribute) -> @str {
-    get_meta_item_name(attr.node.value)
+pub trait AttributeMethods {
+    fn meta(&self) -> @MetaItem;
+    fn desugar_doc(&self) -> Attribute;
 }
 
-pub fn get_meta_item_name(meta: @ast::meta_item) -> @str {
-    match meta.node {
-        ast::meta_word(n) => n,
-        ast::meta_name_value(n, _) => n,
-        ast::meta_list(n, _) => n,
+impl AttributeMethods for Attribute {
+    /// Extract the MetaItem from inside this Attribute.
+    pub fn meta(&self) -> @MetaItem {
+        self.node.value
     }
-}
 
-/**
- * Gets the string value if the meta_item is a meta_name_value variant
- * containing a string, otherwise none
- */
-pub fn get_meta_item_value_str(meta: @ast::meta_item) -> Option<@str> {
-    match meta.node {
-        ast::meta_name_value(_, v) => {
-            match v.node {
-                ast::lit_str(s) => Some(s),
-                _ => None,
-            }
-        },
-        _ => None
+    /// Convert self to a normal #[doc="foo"] comment, if it is a
+    /// comment like `///` or `/** */`. (Returns self unchanged for
+    /// non-sugared doc attributes.)
+    pub fn desugar_doc(&self) -> Attribute {
+        if self.node.is_sugared_doc {
+            let comment = self.value_str().get();
+            let meta = mk_name_value_item_str(@"doc",
+                                              strip_doc_comment_decoration(comment).to_managed());
+            mk_attr(meta)
+        } else {
+            *self
+        }
     }
 }
 
-/// Gets a list of inner meta items from a list meta_item type
-pub fn get_meta_item_list(meta: @ast::meta_item)
-                       -> Option<~[@ast::meta_item]> {
-    match meta.node {
-        ast::meta_list(_, ref l) => Some(/* FIXME (#2543) */ (*l).clone()),
-        _ => None
-    }
-}
+/* Constructors */
 
-/**
- * If the meta item is a nam-value type with a string value then returns
- * a tuple containing the name and string value, otherwise `none`
- */
-pub fn get_name_value_str_pair(item: @ast::meta_item)
-                            -> Option<(@str, @str)> {
-    match attr::get_meta_item_value_str(item) {
-      Some(value) => {
-        let name = attr::get_meta_item_name(item);
-        Some((name, value))
-      }
-      None => None
-    }
+pub fn mk_name_value_item_str(name: @str, value: @str) -> @MetaItem {
+    let value_lit = dummy_spanned(ast::lit_str(value));
+    mk_name_value_item(name, value_lit)
 }
 
-
-/* Searching */
-
-/// Search a list of attributes and return only those with a specific name
-pub fn find_attrs_by_name(attrs: &[ast::attribute], name: &str) ->
-   ~[ast::attribute] {
-    do attrs.iter().filter_map |a| {
-        if name == get_attr_name(a) {
-            Some(*a)
-        } else {
-            None
-        }
-    }.collect()
+pub fn mk_name_value_item(name: @str, value: ast::lit) -> @MetaItem {
+    @dummy_spanned(MetaNameValue(name, value))
 }
 
-/// Search a list of meta items and return only those with a specific name
-pub fn find_meta_items_by_name(metas: &[@ast::meta_item], name: &str) ->
-   ~[@ast::meta_item] {
-    let mut rs = ~[];
-    for metas.iter().advance |mi| {
-        if name == get_meta_item_name(*mi) {
-            rs.push(*mi)
-        }
-    }
-    rs
+pub fn mk_list_item(name: @str, items: ~[@MetaItem]) -> @MetaItem {
+    @dummy_spanned(MetaList(name, items))
 }
 
-/**
- * Returns true if a list of meta items contains another meta item. The
- * comparison is performed structurally.
- */
-pub fn contains(haystack: &[@ast::meta_item],
-                needle: @ast::meta_item) -> bool {
-    for haystack.iter().advance |item| {
-        if eq(*item, needle) { return true; }
-    }
-    return false;
+pub fn mk_word_item(name: @str) -> @MetaItem {
+    @dummy_spanned(MetaWord(name))
 }
 
-fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
-    match a.node {
-        ast::meta_word(ref na) => match b.node {
-            ast::meta_word(ref nb) => (*na) == (*nb),
-            _ => false
-        },
-        ast::meta_name_value(ref na, va) => match b.node {
-            ast::meta_name_value(ref nb, vb) => {
-                (*na) == (*nb) && va.node == vb.node
-            }
-            _ => false
-        },
-        ast::meta_list(ref na, ref misa) => match b.node {
-            ast::meta_list(ref nb, ref misb) => {
-                if na != nb { return false; }
-                for misa.iter().advance |mi| {
-                    if !misb.iter().any(|x| x == mi) { return false; }
-                }
-                true
-            }
-            _ => false
-        }
-    }
+pub fn mk_attr(item: @MetaItem) -> Attribute {
+    dummy_spanned(Attribute_ {
+        style: ast::AttrInner,
+        value: item,
+        is_sugared_doc: false,
+    })
 }
 
-pub fn contains_name(metas: &[@ast::meta_item], name: &str) -> bool {
-    let matches = find_meta_items_by_name(metas, name);
-    matches.len() > 0u
+pub fn mk_sugared_doc_attr(text: @str, lo: BytePos, hi: BytePos) -> Attribute {
+    let style = doc_comment_style(text);
+    let lit = spanned(lo, hi, ast::lit_str(text));
+    let attr = Attribute_ {
+        style: style,
+        value: @spanned(lo, hi, MetaNameValue(@"doc", lit)),
+        is_sugared_doc: true
+    };
+    spanned(lo, hi, attr)
 }
 
-pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
-    !find_attrs_by_name(attrs, name).is_empty()
+/* Searching */
+/// Check if `needle` occurs in `haystack` by a structural
+/// comparison. This is slightly subtle, and relies on ignoring the
+/// span included in the `==` comparison a plain MetaItem.
+pub fn contains(haystack: &[@ast::MetaItem],
+                needle: @ast::MetaItem) -> bool {
+    debug!("attr::contains (name=%s)", needle.name());
+    do haystack.iter().any |item| {
+        debug!("  testing: %s", item.name());
+        item.node == needle.node
+    }
 }
 
-pub fn first_attr_value_str_by_name(attrs: &[ast::attribute], name: &str)
-                                 -> Option<@str> {
-
-    let mattrs = find_attrs_by_name(attrs, name);
-    if mattrs.len() > 0 {
-        get_meta_item_value_str(attr_meta(mattrs[0]))
-    } else {
-        None
+pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool {
+    debug!("attr::contains_name (name=%s)", name);
+    do metas.iter().any |item| {
+        debug!("  testing: %s", item.name());
+        name == item.name()
     }
 }
 
-fn last_meta_item_by_name(items: &[@ast::meta_item], name: &str)
-    -> Option<@ast::meta_item> {
-
-    let items = attr::find_meta_items_by_name(items, name);
-    items.last_opt().map(|item| **item)
+pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str)
+                                 -> Option<@str> {
+    attrs.iter()
+        .find_(|at| name == at.name())
+        .chain(|at| at.value_str())
 }
 
-pub fn last_meta_item_value_str_by_name(items: &[@ast::meta_item], name: &str)
+pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str)
                                      -> Option<@str> {
-
-    match last_meta_item_by_name(items, name) {
-        Some(item) => {
-            match attr::get_meta_item_value_str(item) {
-                Some(value) => Some(value),
-                None => None
-            }
-        },
-        None => None
-    }
+    items.rev_iter().find_(|mi| name == mi.name()).chain(|i| i.value_str())
 }
 
-pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: &str)
-    -> Option<~[@ast::meta_item]> {
-
-    match last_meta_item_by_name(items, name) {
-      Some(item) => attr::get_meta_item_list(item),
-      None => None
-    }
-}
-
-
 /* Higher-level applications */
 
-pub fn sort_meta_items(items: &[@ast::meta_item]) -> ~[@ast::meta_item] {
-    // This is sort of stupid here, converting to a vec of mutables and back
-    let mut v = items.to_owned();
-    do extra::sort::quick_sort(v) |ma, mb| {
-        get_meta_item_name(*ma) <= get_meta_item_name(*mb)
+pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] {
+    // This is sort of stupid here, but we need to sort by
+    // human-readable strings.
+    let mut v = items.iter()
+        .transform(|&mi| (mi.name(), mi))
+        .collect::<~[(@str, @MetaItem)]>();
+
+    do extra::sort::quick_sort(v) |&(a, _), &(b, _)| {
+        a <= b
     }
 
     // There doesn't seem to be a more optimal way to do this
-    do v.map |m| {
+    do v.consume_iter().transform |(_, m)| {
         match m.node {
-            ast::meta_list(n, ref mis) => {
+            MetaList(n, ref mis) => {
                 @spanned {
-                    node: ast::meta_list(n, sort_meta_items(*mis)),
-                    .. /*bad*/ (**m).clone()
+                    node: MetaList(n, sort_meta_items(*mis)),
+                    .. /*bad*/ (*m).clone()
                 }
             }
-            _ => *m
+            _ => m
         }
-    }
-}
-
-pub fn remove_meta_items_by_name(items: ~[@ast::meta_item], name: &str) ->
-   ~[@ast::meta_item] {
-    items.consume_iter().filter(|item| name != get_meta_item_name(*item)).collect()
+    }.collect()
 }
 
 /**
  * From a list of crate attributes get only the meta_items that affect crate
  * linkage
  */
-pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
-    do find_attrs_by_name(attrs, "link").flat_map |attr| {
-        match attr.node.value.node {
-            ast::meta_list(_, ref items) => {
-                /* FIXME (#2543) */ (*items).clone()
-            }
-            _ => ~[]
+pub fn find_linkage_metas(attrs: &[Attribute]) -> ~[@MetaItem] {
+    let mut result = ~[];
+    for attrs.iter().filter(|at| "link" == at.name()).advance |attr| {
+        match attr.meta().node {
+            MetaList(_, ref items) => result.push_all(*items),
+            _ => ()
         }
     }
+    result
 }
 
 #[deriving(Eq)]
-pub enum inline_attr {
-    ia_none,
-    ia_hint,
-    ia_always,
-    ia_never,
+pub enum InlineAttr {
+    InlineNone,
+    InlineHint,
+    InlineAlways,
+    InlineNever,
 }
 
 /// True if something like #[inline] is found in the list of attrs.
-pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
+pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
     // FIXME (#2809)---validate the usage of #[inline] and #[inline]
-    do attrs.iter().fold(ia_none) |ia,attr| {
+    do attrs.iter().fold(InlineNone) |ia,attr| {
         match attr.node.value.node {
-          ast::meta_word(s) if "inline" == s => ia_hint,
-          ast::meta_list(s, ref items) if "inline" == s => {
-            if !find_meta_items_by_name(*items, "always").is_empty() {
-                ia_always
-            } else if !find_meta_items_by_name(*items, "never").is_empty() {
-                ia_never
+          MetaWord(n) if "inline" == n => InlineHint,
+          MetaList(n, ref items) if "inline" == n => {
+            if contains_name(*items, "always") {
+                InlineAlways
+            } else if contains_name(*items, "never") {
+                InlineNever
             } else {
-                ia_hint
+                InlineHint
             }
           }
           _ => ia
@@ -322,12 +265,59 @@ pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr {
     }
 }
 
+/// Tests if any `cfg(...)` meta items in `metas` match `cfg`. e.g.
+///
+/// test_cfg(`[foo="a", bar]`, `[cfg(foo), cfg(bar)]`) == true
+/// test_cfg(`[foo="a", bar]`, `[cfg(not(bar))]`) == false
+/// test_cfg(`[foo="a", bar]`, `[cfg(bar, foo="a")]`) == true
+/// test_cfg(`[foo="a", bar]`, `[cfg(bar, foo="b")]`) == false
+pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>>
+    (cfg: &[@MetaItem], mut metas: It) -> bool {
+    // having no #[cfg(...)] attributes counts as matching.
+    let mut no_cfgs = true;
+
+    // this would be much nicer as a chain of iterator adaptors, but
+    // this doesn't work.
+    let some_cfg_matches = do metas.any |mi| {
+        debug!("testing name: %s", mi.name());
+        if "cfg" == mi.name() { // it is a #[cfg()] attribute
+            debug!("is cfg");
+            no_cfgs = false;
+             // only #[cfg(...)] ones are understood.
+            match mi.meta_item_list() {
+                Some(cfg_meta) => {
+                    debug!("is cfg(...)");
+                    do cfg_meta.iter().all |cfg_mi| {
+                        debug!("cfg(%s[...])", cfg_mi.name());
+                        match cfg_mi.node {
+                            ast::MetaList(s, ref not_cfgs) if "not" == s => {
+                                debug!("not!");
+                                // inside #[cfg(not(...))], so these need to all
+                                // not match.
+                                not_cfgs.iter().all(|mi| {
+                                    debug!("cfg(not(%s[...]))", mi.name());
+                                    !contains(cfg, *mi)
+                                })
+                            }
+                            _ => contains(cfg, *cfg_mi)
+                        }
+                    }
+                }
+                None => false
+            }
+        } else {
+            false
+        }
+    };
+    debug!("test_cfg (no_cfgs=%?, some_cfg_matches=%?)", no_cfgs, some_cfg_matches);
+    no_cfgs || some_cfg_matches
+}
 
 pub fn require_unique_names(diagnostic: @span_handler,
-                            metas: &[@ast::meta_item]) {
+                            metas: &[@MetaItem]) {
     let mut set = HashSet::new();
     for metas.iter().advance |meta| {
-        let name = get_meta_item_name(*meta);
+        let name = meta.name();
 
         // FIXME: How do I silence the warnings? --pcw (#2619)
         if !set.insert(name) {
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index 64d2644b383..4ada7f7479b 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -17,7 +17,7 @@ use ext::base::*;
 pub fn expand_auto_encode(
     cx: @ExtCtxt,
     span: span,
-    _mitem: @ast::meta_item,
+    _mitem: @ast::MetaItem,
     in_items: ~[@ast::item]
 ) -> ~[@ast::item] {
     cx.span_err(span, "`#[auto_encode]` is deprecated, use `#[deriving(Encodable)]` instead");
@@ -27,7 +27,7 @@ pub fn expand_auto_encode(
 pub fn expand_auto_decode(
     cx: @ExtCtxt,
     span: span,
-    _mitem: @ast::meta_item,
+    _mitem: @ast::MetaItem,
     in_items: ~[@ast::item]
 ) -> ~[@ast::item] {
     cx.span_err(span, "`#[auto_decode]` is deprecated, use `#[deriving(Decodable)]` instead");
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 230640767c9..c71ea78bba5 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -36,7 +36,7 @@ pub struct MacroDef {
 
 pub type ItemDecorator = @fn(@ExtCtxt,
                              span,
-                             @ast::meta_item,
+                             @ast::MetaItem,
                              ~[@ast::item])
                           -> ~[@ast::item];
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 59754f5519e..df5f3d8d895 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -163,7 +163,7 @@ pub trait AstBuilder {
 
     // items
     fn item(&self, span: span,
-            name: ident, attrs: ~[ast::attribute], node: ast::item_) -> @ast::item;
+            name: ident, attrs: ~[ast::Attribute], node: ast::item_) -> @ast::item;
 
     fn arg(&self, span: span, name: ident, ty: ast::Ty) -> ast::arg;
     // XXX unused self
@@ -199,7 +199,7 @@ pub trait AstBuilder {
     fn item_struct(&self, span: span, name: ident, struct_def: ast::struct_def) -> @ast::item;
 
     fn item_mod(&self, span: span,
-                name: ident, attrs: ~[ast::attribute],
+                name: ident, attrs: ~[ast::Attribute],
                 vi: ~[ast::view_item], items: ~[@ast::item]) -> @ast::item;
 
     fn item_ty_poly(&self,
@@ -209,11 +209,11 @@ pub trait AstBuilder {
                     generics: Generics) -> @ast::item;
     fn item_ty(&self, span: span, name: ident, ty: ast::Ty) -> @ast::item;
 
-    fn attribute(&self, sp: span, mi: @ast::meta_item) -> ast::attribute;
+    fn attribute(&self, sp: span, mi: @ast::MetaItem) -> ast::Attribute;
 
-    fn meta_word(&self, sp: span, w: @str) -> @ast::meta_item;
-    fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::meta_item]) -> @ast::meta_item;
-    fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::meta_item;
+    fn meta_word(&self, sp: span, w: @str) -> @ast::MetaItem;
+    fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem;
+    fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::MetaItem;
 
     fn view_use(&self, sp: span,
                 vis: ast::visibility, vp: ~[@ast::view_path]) -> ast::view_item;
@@ -657,7 +657,7 @@ impl AstBuilder for @ExtCtxt {
     }
 
     fn item(&self, span: span,
-            name: ident, attrs: ~[ast::attribute], node: ast::item_) -> @ast::item {
+            name: ident, attrs: ~[ast::Attribute], node: ast::item_) -> @ast::item {
         // XXX: Would be nice if our generated code didn't violate
         // Rust coding conventions
         @ast::item { ident: name,
@@ -754,7 +754,7 @@ impl AstBuilder for @ExtCtxt {
     }
 
     fn item_mod(&self, span: span, name: ident,
-                attrs: ~[ast::attribute],
+                attrs: ~[ast::Attribute],
                 vi: ~[ast::view_item],
                 items: ~[@ast::item]) -> @ast::item {
         self.item(
@@ -777,23 +777,22 @@ impl AstBuilder for @ExtCtxt {
         self.item_ty_poly(span, name, ty, ast_util::empty_generics())
     }
 
-    fn attribute(&self, sp: span, mi: @ast::meta_item) -> ast::attribute {
-        respan(sp,
-               ast::attribute_ {
-                   style: ast::attr_outer,
-                   value: mi,
-                   is_sugared_doc: false
-               })
+    fn attribute(&self, sp: span, mi: @ast::MetaItem) -> ast::Attribute {
+        respan(sp, ast::Attribute_ {
+            style: ast::AttrOuter,
+            value: mi,
+            is_sugared_doc: false,
+        })
     }
 
-    fn meta_word(&self, sp: span, w: @str) -> @ast::meta_item {
-        @respan(sp, ast::meta_word(w))
+    fn meta_word(&self, sp: span, w: @str) -> @ast::MetaItem {
+        @respan(sp, ast::MetaWord(w))
     }
-    fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::meta_item]) -> @ast::meta_item {
-        @respan(sp, ast::meta_list(name, mis))
+    fn meta_list(&self, sp: span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem {
+        @respan(sp, ast::MetaList(name, mis))
     }
-    fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::meta_item {
-        @respan(sp, ast::meta_name_value(name, respan(sp, value)))
+    fn meta_name_value(&self, sp: span, name: @str, value: ast::lit_) -> @ast::MetaItem {
+        @respan(sp, ast::MetaNameValue(name, respan(sp, value)))
     }
 
     fn view_use(&self, sp: span,
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index edaf2b8cae6..02dcb2cdbc9 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -16,7 +16,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_clone(cx: @ExtCtxt,
                              span: span,
-                             mitem: @meta_item,
+                             mitem: @MetaItem,
                              in_items: ~[@item])
                           -> ~[@item] {
     let trait_def = TraitDef {
@@ -40,9 +40,9 @@ pub fn expand_deriving_clone(cx: @ExtCtxt,
 }
 
 pub fn expand_deriving_deep_clone(cx: @ExtCtxt,
-                                 span: span,
-                                 mitem: @meta_item,
-                                 in_items: ~[@item])
+                                  span: span,
+                                  mitem: @MetaItem,
+                                  in_items: ~[@item])
     -> ~[@item] {
     let trait_def = TraitDef {
         path: Path::new(~["std", "clone", "DeepClone"]),
diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs
index cea88bb7bbb..a7d9db59130 100644
--- a/src/libsyntax/ext/deriving/cmp/eq.rs
+++ b/src/libsyntax/ext/deriving/cmp/eq.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -16,7 +16,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_eq(cx: @ExtCtxt,
                           span: span,
-                          mitem: @meta_item,
+                          mitem: @MetaItem,
                           in_items: ~[@item]) -> ~[@item] {
     // structures are equal if all fields are equal, and non equal, if
     // any fields are not equal or if the enum variants are different
diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs
index 3b9691cd42c..d532eedd291 100644
--- a/src/libsyntax/ext/deriving/cmp/ord.rs
+++ b/src/libsyntax/ext/deriving/cmp/ord.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast;
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -17,7 +17,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_ord(cx: @ExtCtxt,
                            span: span,
-                           mitem: @meta_item,
+                           mitem: @MetaItem,
                            in_items: ~[@item]) -> ~[@item] {
     macro_rules! md (
         ($name:expr, $op:expr, $equal:expr) => {
diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs
index 70ac4d3d4c1..8285de1d561 100644
--- a/src/libsyntax/ext/deriving/cmp/totaleq.rs
+++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs
@@ -8,17 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 
 pub fn expand_deriving_totaleq(cx: @ExtCtxt,
-                          span: span,
-                          mitem: @meta_item,
-                          in_items: ~[@item]) -> ~[@item] {
-
+                               span: span,
+                               mitem: @MetaItem,
+                               in_items: ~[@item]) -> ~[@item] {
     fn cs_equals(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
         cs_and(|cx, span, _, _| cx.expr_bool(span, false),
                cx, span, substr)
diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs
index 84d7320fe1c..01dacdfe453 100644
--- a/src/libsyntax/ext/deriving/cmp/totalord.rs
+++ b/src/libsyntax/ext/deriving/cmp/totalord.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -17,7 +17,7 @@ use std::cmp::{Ordering, Equal, Less, Greater};
 
 pub fn expand_deriving_totalord(cx: @ExtCtxt,
                                 span: span,
-                                mitem: @meta_item,
+                                mitem: @MetaItem,
                                 in_items: ~[@item]) -> ~[@item] {
     let trait_def = TraitDef {
         path: Path::new(~["std", "cmp", "TotalOrd"]),
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 405f9e3438b..bde0a345b10 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -16,7 +16,7 @@ encodable.rs for more.
 use std::vec;
 use std::uint;
 
-use ast::{meta_item, item, expr, m_mutbl};
+use ast::{MetaItem, item, expr, m_mutbl};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -24,7 +24,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_decodable(cx: @ExtCtxt,
                                  span: span,
-                                 mitem: @meta_item,
+                                 mitem: @MetaItem,
                                  in_items: ~[@item]) -> ~[@item] {
     let trait_def = TraitDef {
         path: Path::new_(~["extra", "serialize", "Decodable"], None,
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index 5514fd0b6ab..1f969b4e078 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -75,7 +75,7 @@ would yield functions like:
     }
 */
 
-use ast::{meta_item, item, expr, m_imm, m_mutbl};
+use ast::{MetaItem, item, expr, m_imm, m_mutbl};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -83,7 +83,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_encodable(cx: @ExtCtxt,
                                  span: span,
-                                 mitem: @meta_item,
+                                 mitem: @MetaItem,
                                  in_items: ~[@item]) -> ~[@item] {
     let trait_def = TraitDef {
         path: Path::new_(~["extra", "serialize", "Encodable"], None,
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index a50f4d70f0e..04bbe5ae1d6 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -281,7 +281,7 @@ pub type EnumNonMatchFunc<'self> =
 impl<'self> TraitDef<'self> {
     pub fn expand(&self, cx: @ExtCtxt,
                   span: span,
-                  _mitem: @ast::meta_item,
+                  _mitem: @ast::MetaItem,
                   in_items: ~[@ast::item]) -> ~[@ast::item] {
         let mut result = ~[];
         for in_items.iter().advance |item| {
@@ -361,7 +361,8 @@ impl<'self> TraitDef<'self> {
         let doc_attr = cx.attribute(
             span,
             cx.meta_name_value(span,
-                               @"doc", ast::lit_str(@"Automatically derived.")));
+                               @"doc",
+                               ast::lit_str(@"Automatically derived.")));
         cx.item(
             span,
             ::parse::token::special_idents::clownshoes_extensions,
diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs
index be13e103a72..57a4f0899b5 100644
--- a/src/libsyntax/ext/deriving/iter_bytes.rs
+++ b/src/libsyntax/ext/deriving/iter_bytes.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{meta_item, item, expr, and};
+use ast::{MetaItem, item, expr, and};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -17,7 +17,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_iter_bytes(cx: @ExtCtxt,
                                   span: span,
-                                  mitem: @meta_item,
+                                  mitem: @MetaItem,
                                   in_items: ~[@item]) -> ~[@item] {
     let trait_def = TraitDef {
         path: Path::new(~["std", "to_bytes", "IterBytes"]),
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index 537d9efbb26..cde7dcc5dbe 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -18,7 +18,8 @@ library.
 
 */
 
-use ast::{enum_def, ident, item, Generics, meta_item, struct_def};
+use ast::{enum_def, ident, item, Generics, struct_def};
+use ast::{MetaItem, MetaList, MetaNameValue, MetaWord};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use codemap::span;
@@ -58,26 +59,24 @@ pub type ExpandDerivingEnumDefFn<'self> = &'self fn(@ExtCtxt,
 
 pub fn expand_meta_deriving(cx: @ExtCtxt,
                             _span: span,
-                            mitem: @meta_item,
+                            mitem: @MetaItem,
                             in_items: ~[@item])
                          -> ~[@item] {
-    use ast::{meta_list, meta_name_value, meta_word};
-
     match mitem.node {
-        meta_name_value(_, ref l) => {
+        MetaNameValue(_, ref l) => {
             cx.span_err(l.span, "unexpected value in `deriving`");
             in_items
         }
-        meta_word(_) | meta_list(_, []) => {
+        MetaWord(_) | MetaList(_, []) => {
             cx.span_warn(mitem.span, "empty trait list in `deriving`");
             in_items
         }
-        meta_list(_, ref titems) => {
+        MetaList(_, ref titems) => {
             do titems.rev_iter().fold(in_items) |in_items, &titem| {
                 match titem.node {
-                    meta_name_value(tname, _) |
-                    meta_list(tname, _) |
-                    meta_word(tname) => {
+                    MetaNameValue(tname, _) |
+                    MetaList(tname, _) |
+                    MetaWord(tname) => {
                         macro_rules! expand(($func:path) => ($func(cx, titem.span,
                                                                    titem, in_items)));
                         match tname.as_slice() {
diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs
index 823f21401ca..2966a8c114d 100644
--- a/src/libsyntax/ext/deriving/rand.rs
+++ b/src/libsyntax/ext/deriving/rand.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast;
-use ast::{meta_item, item, expr, ident};
+use ast::{MetaItem, item, expr, ident};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::{AstBuilder, Duplicate};
@@ -19,7 +19,7 @@ use std::vec;
 
 pub fn expand_deriving_rand(cx: @ExtCtxt,
                             span: span,
-                            mitem: @meta_item,
+                            mitem: @MetaItem,
                             in_items: ~[@item])
     -> ~[@item] {
     let trait_def = TraitDef {
diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs
index c9d63d2c416..9b544eb0796 100644
--- a/src/libsyntax/ext/deriving/to_str.rs
+++ b/src/libsyntax/ext/deriving/to_str.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast;
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -17,7 +17,7 @@ use ext::deriving::generic::*;
 
 pub fn expand_deriving_to_str(cx: @ExtCtxt,
                               span: span,
-                              mitem: @meta_item,
+                              mitem: @MetaItem,
                               in_items: ~[@item])
     -> ~[@item] {
     let trait_def = TraitDef {
diff --git a/src/libsyntax/ext/deriving/zero.rs b/src/libsyntax/ext/deriving/zero.rs
index 5bee804d582..3c9e842473c 100644
--- a/src/libsyntax/ext/deriving/zero.rs
+++ b/src/libsyntax/ext/deriving/zero.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{meta_item, item, expr};
+use ast::{MetaItem, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
@@ -18,7 +18,7 @@ use std::vec;
 
 pub fn expand_deriving_zero(cx: @ExtCtxt,
                             span: span,
-                            mitem: @meta_item,
+                            mitem: @MetaItem,
                             in_items: ~[@item])
     -> ~[@item] {
     let trait_def = TraitDef {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 2f1d320fef7..e78254f11f5 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -14,6 +14,7 @@ use ast::{illegal_ctxt};
 use ast;
 use ast_util::{new_rename, new_mark, resolve};
 use attr;
+use attr::AttrMetaMethods;
 use codemap;
 use codemap::{span, ExpnInfo, NameAndSpan};
 use ext::base::*;
@@ -126,7 +127,7 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
     // the item into a new set of items.
     let new_items = do vec::flat_map(module_.items) |item| {
         do item.attrs.rev_iter().fold(~[*item]) |items, attr| {
-            let mname = attr::get_attr_name(attr);
+            let mname = attr.name();
 
             match (*extsbox).find(&intern(mname)) {
               Some(@SE(ItemDecorator(dec_fn))) => {
@@ -196,8 +197,8 @@ pub fn expand_item(extsbox: @mut SyntaxEnv,
 }
 
 // does this attribute list contain "macro_escape" ?
-pub fn contains_macro_escape (attrs: &[ast::attribute]) -> bool {
-    attrs.iter().any(|attr| "macro_escape" == attr::get_attr_name(attr))
+pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
+    attr::contains_name(attrs, "macro_escape")
 }
 
 // Support for item-position macro invocations, exactly the same
@@ -793,7 +794,7 @@ pub fn new_ident_resolver() ->
 mod test {
     use super::*;
     use ast;
-    use ast::{attribute_, attr_outer, meta_word, empty_ctxt};
+    use ast::{Attribute_, AttrOuter, MetaWord, empty_ctxt};
     use codemap;
     use codemap::spanned;
     use parse;
@@ -883,14 +884,14 @@ mod test {
         assert_eq!(contains_macro_escape (attrs2),false);
     }
 
-    // make a "meta_word" outer attribute with the given name
-    fn make_dummy_attr(s: @str) -> ast::attribute {
+    // make a MetaWord outer attribute with the given name
+    fn make_dummy_attr(s: @str) -> ast::Attribute {
         spanned {
             span:codemap::dummy_sp(),
-            node: attribute_ {
-                style: attr_outer,
+            node: Attribute_ {
+                style: AttrOuter,
                 value: @spanned {
-                    node: meta_word(s),
+                    node: MetaWord(s),
                     span: codemap::dummy_sp(),
                 },
                 is_sugared_doc: false,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index cfd858eed47..63cb3cf38f6 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -74,35 +74,34 @@ pub type ast_fold_fns = @AstFoldFns;
 /* some little folds that probably aren't useful to have in ast_fold itself*/
 
 //used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
-fn fold_meta_item_(mi: @meta_item, fld: @ast_fold) -> @meta_item {
+fn fold_meta_item_(mi: @MetaItem, fld: @ast_fold) -> @MetaItem {
     @spanned {
         node:
             match mi.node {
-                meta_word(id) => meta_word(id),
-                meta_list(id, ref mis) => {
+                MetaWord(id) => MetaWord(id),
+                MetaList(id, ref mis) => {
                     let fold_meta_item = |x| fold_meta_item_(x, fld);
-                    meta_list(
+                    MetaList(
                         id,
                         mis.map(|e| fold_meta_item(*e))
                     )
                 }
-                meta_name_value(id, s) => {
-                    meta_name_value(id, s)
-                }
+                MetaNameValue(id, s) => MetaNameValue(id, s)
             },
         span: fld.new_span(mi.span) }
 }
 //used in noop_fold_item and noop_fold_crate
-fn fold_attribute_(at: attribute, fld: @ast_fold) -> attribute {
+fn fold_attribute_(at: Attribute, fld: @ast_fold) -> Attribute {
     spanned {
-        node: ast::attribute_ {
+        span: fld.new_span(at.span),
+        node: ast::Attribute_ {
             style: at.node.style,
             value: fold_meta_item_(at.node.value, fld),
-            is_sugared_doc: at.node.is_sugared_doc,
-        },
-        span: fld.new_span(at.span),
+            is_sugared_doc: at.node.is_sugared_doc
+        }
     }
 }
+
 //used in noop_fold_foreign_item and noop_fold_fn_decl
 fn fold_arg_(a: arg, fld: @ast_fold) -> arg {
     ast::arg {
@@ -936,11 +935,11 @@ impl ast_fold for AstFoldFns {
 }
 
 pub trait AstFoldExtensions {
-    fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute];
+    fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute];
 }
 
 impl AstFoldExtensions for @ast_fold {
-    fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute] {
+    fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute] {
         attrs.map(|x| fold_attribute_(*x, *self))
     }
 }
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 85c7d5de064..8cce5f15e67 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -17,32 +17,32 @@ use parse::parser::Parser;
 
 // a parser that can parse attributes.
 pub trait parser_attr {
-    fn parse_outer_attributes(&self) -> ~[ast::attribute];
-    fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute;
+    fn parse_outer_attributes(&self) -> ~[ast::Attribute];
+    fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute;
     fn parse_attribute_naked(
         &self,
-        style: ast::attr_style,
+        style: ast::AttrStyle,
         lo: BytePos
-    ) -> ast::attribute;
+    ) -> ast::Attribute;
     fn parse_inner_attrs_and_next(&self) ->
-        (~[ast::attribute], ~[ast::attribute]);
-    fn parse_meta_item(&self) -> @ast::meta_item;
-    fn parse_meta_seq(&self) -> ~[@ast::meta_item];
-    fn parse_optional_meta(&self) -> ~[@ast::meta_item];
+        (~[ast::Attribute], ~[ast::Attribute]);
+    fn parse_meta_item(&self) -> @ast::MetaItem;
+    fn parse_meta_seq(&self) -> ~[@ast::MetaItem];
+    fn parse_optional_meta(&self) -> ~[@ast::MetaItem];
 }
 
 impl parser_attr for Parser {
 
     // Parse attributes that appear before an item
-    fn parse_outer_attributes(&self) -> ~[ast::attribute] {
-        let mut attrs: ~[ast::attribute] = ~[];
+    fn parse_outer_attributes(&self) -> ~[ast::Attribute] {
+        let mut attrs: ~[ast::Attribute] = ~[];
         loop {
             match *self.token {
               token::POUND => {
                 if self.look_ahead(1, |t| *t != token::LBRACKET) {
                     break;
                 }
-                attrs.push(self.parse_attribute(ast::attr_outer));
+                attrs.push(self.parse_attribute(ast::AttrOuter));
               }
               token::DOC_COMMENT(s) => {
                 let attr = ::attr::mk_sugared_doc_attr(
@@ -50,7 +50,7 @@ impl parser_attr for Parser {
                     self.span.lo,
                     self.span.hi
                 );
-                if attr.node.style != ast::attr_outer {
+                if attr.node.style != ast::AttrOuter {
                   self.fatal("expected outer comment");
                 }
                 attrs.push(attr);
@@ -63,20 +63,20 @@ impl parser_attr for Parser {
     }
 
     // matches attribute = # attribute_naked
-    fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute {
+    fn parse_attribute(&self, style: ast::AttrStyle) -> ast::Attribute {
         let lo = self.span.lo;
         self.expect(&token::POUND);
         return self.parse_attribute_naked(style, lo);
     }
 
     // matches attribute_naked = [ meta_item ]
-    fn parse_attribute_naked(&self, style: ast::attr_style, lo: BytePos) ->
-        ast::attribute {
+    fn parse_attribute_naked(&self, style: ast::AttrStyle, lo: BytePos) ->
+        ast::Attribute {
         self.expect(&token::LBRACKET);
         let meta_item = self.parse_meta_item();
         self.expect(&token::RBRACKET);
         let hi = self.span.hi;
-        return spanned(lo, hi, ast::attribute_ { style: style,
+        return spanned(lo, hi, ast::Attribute_ { style: style,
                                                  value: meta_item, is_sugared_doc: false }); }
 
     // Parse attributes that appear after the opening of an item, each
@@ -90,9 +90,9 @@ impl parser_attr for Parser {
     // you can make the 'next' field an Option, but the result is going to be
     // more useful as a vector.
     fn parse_inner_attrs_and_next(&self) ->
-        (~[ast::attribute], ~[ast::attribute]) {
-        let mut inner_attrs: ~[ast::attribute] = ~[];
-        let mut next_outer_attrs: ~[ast::attribute] = ~[];
+        (~[ast::Attribute], ~[ast::Attribute]) {
+        let mut inner_attrs: ~[ast::Attribute] = ~[];
+        let mut next_outer_attrs: ~[ast::Attribute] = ~[];
         loop {
             match *self.token {
               token::POUND => {
@@ -100,7 +100,7 @@ impl parser_attr for Parser {
                     // This is an extension
                     break;
                 }
-                let attr = self.parse_attribute(ast::attr_inner);
+                let attr = self.parse_attribute(ast::AttrInner);
                 if *self.token == token::SEMI {
                     self.bump();
                     inner_attrs.push(attr);
@@ -108,7 +108,7 @@ impl parser_attr for Parser {
                     // It's not really an inner attribute
                     let outer_attr =
                         spanned(attr.span.lo, attr.span.hi,
-                            ast::attribute_ { style: ast::attr_outer,
+                            ast::Attribute_ { style: ast::AttrOuter,
                                               value: attr.node.value,
                                               is_sugared_doc: false });
                     next_outer_attrs.push(outer_attr);
@@ -122,7 +122,7 @@ impl parser_attr for Parser {
                     self.span.hi
                 );
                 self.bump();
-                if attr.node.style == ast::attr_inner {
+                if attr.node.style == ast::AttrInner {
                   inner_attrs.push(attr);
                 } else {
                   next_outer_attrs.push(attr);
@@ -138,7 +138,7 @@ impl parser_attr for Parser {
     // matches meta_item = IDENT
     // | IDENT = lit
     // | IDENT meta_seq
-    fn parse_meta_item(&self) -> @ast::meta_item {
+    fn parse_meta_item(&self) -> @ast::MetaItem {
         let lo = self.span.lo;
         let name = self.id_to_str(self.parse_ident());
         match *self.token {
@@ -146,29 +146,29 @@ impl parser_attr for Parser {
                 self.bump();
                 let lit = self.parse_lit();
                 let hi = self.span.hi;
-                @spanned(lo, hi, ast::meta_name_value(name, lit))
+                @spanned(lo, hi, ast::MetaNameValue(name, lit))
             }
             token::LPAREN => {
                 let inner_items = self.parse_meta_seq();
                 let hi = self.span.hi;
-                @spanned(lo, hi, ast::meta_list(name, inner_items))
+                @spanned(lo, hi, ast::MetaList(name, inner_items))
             }
             _ => {
                 let hi = self.last_span.hi;
-                @spanned(lo, hi, ast::meta_word(name))
+                @spanned(lo, hi, ast::MetaWord(name))
             }
         }
     }
 
     // matches meta_seq = ( COMMASEP(meta_item) )
-    fn parse_meta_seq(&self) -> ~[@ast::meta_item] {
+    fn parse_meta_seq(&self) -> ~[@ast::MetaItem] {
         self.parse_seq(&token::LPAREN,
                        &token::RPAREN,
                        seq_sep_trailing_disallowed(token::COMMA),
                        |p| p.parse_meta_item()).node
     }
 
-    fn parse_optional_meta(&self) -> ~[@ast::meta_item] {
+    fn parse_optional_meta(&self) -> ~[@ast::MetaItem] {
         match *self.token {
             token::LPAREN => self.parse_meta_seq(),
             _ => ~[]
diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs
index 83af5bade3a..6daeb1b3e1e 100644
--- a/src/libsyntax/parse/comments.rs
+++ b/src/libsyntax/parse/comments.rs
@@ -44,12 +44,12 @@ pub fn is_doc_comment(s: &str) -> bool {
     s.starts_with("/*!")
 }
 
-pub fn doc_comment_style(comment: &str) -> ast::attr_style {
+pub fn doc_comment_style(comment: &str) -> ast::AttrStyle {
     assert!(is_doc_comment(comment));
     if comment.starts_with("//!") || comment.starts_with("/*!") {
-        ast::attr_inner
+        ast::AttrInner
     } else {
-        ast::attr_outer
+        ast::AttrOuter
     }
 }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 410849b4482..c7a65c80de1 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -115,7 +115,7 @@ pub fn parse_item_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::crate_cfg,
-    attrs: ~[ast::attribute],
+    attrs: ~[ast::Attribute],
     sess: @mut ParseSess
 ) -> Option<@ast::item> {
     let p = new_parser_from_source_str(
@@ -132,7 +132,7 @@ pub fn parse_meta_from_source_str(
     source: @str,
     cfg: ast::crate_cfg,
     sess: @mut ParseSess
-) -> @ast::meta_item {
+) -> @ast::MetaItem {
     let p = new_parser_from_source_str(
         sess,
         cfg,
@@ -146,7 +146,7 @@ pub fn parse_stmt_from_source_str(
     name: @str,
     source: @str,
     cfg: ast::crate_cfg,
-    attrs: ~[ast::attribute],
+    attrs: ~[ast::Attribute],
     sess: @mut ParseSess
 ) -> @ast::stmt {
     let p = new_parser_from_source_str(
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index b014c5668b6..6d7fd3390fa 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -17,7 +17,7 @@ Obsolete syntax that becomes too hard to parse can be
 removed.
 */
 
-use ast::{expr, expr_lit, lit_nil, attribute};
+use ast::{expr, expr_lit, lit_nil, Attribute};
 use ast;
 use codemap::{span, respan};
 use parse::parser::Parser;
@@ -88,7 +88,7 @@ pub trait ParserObsoleteMethods {
     fn eat_obsolete_ident(&self, ident: &str) -> bool;
     fn try_parse_obsolete_struct_ctor(&self) -> bool;
     fn try_parse_obsolete_with(&self) -> bool;
-    fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool;
+    fn try_parse_obsolete_priv_section(&self, attrs: &[Attribute]) -> bool;
 }
 
 impl ParserObsoleteMethods for Parser {
@@ -322,7 +322,7 @@ impl ParserObsoleteMethods for Parser {
         }
     }
 
-    pub fn try_parse_obsolete_priv_section(&self, attrs: &[attribute])
+    pub fn try_parse_obsolete_priv_section(&self, attrs: &[Attribute])
                                            -> bool {
         if self.is_keyword(keywords::Priv) &&
                 self.look_ahead(1, |t| *t == token::LBRACE) {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index fb5d3b5262c..7e1d5bff4df 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -15,7 +15,7 @@ use ast::{CallSugar, NoSugar, DoSugar, ForSugar};
 use ast::{TyBareFn, TyClosure};
 use ast::{RegionTyParamBound, TraitTyParamBound};
 use ast::{provided, public, purity};
-use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer};
+use ast::{_mod, add, arg, arm, Attribute, bind_by_ref, bind_infer};
 use ast::{bitand, bitor, bitxor, blk};
 use ast::{blk_check_mode, box};
 use ast::{crate, crate_cfg, decl, decl_item};
@@ -109,12 +109,12 @@ enum restriction {
 }
 
 type arg_or_capture_item = Either<arg, ()>;
-type item_info = (ident, item_, Option<~[attribute]>);
+type item_info = (ident, item_, Option<~[Attribute]>);
 
 pub enum item_or_view_item {
     // Indicates a failure to parse any kind of item. The attributes are
     // returned.
-    iovi_none(~[attribute]),
+    iovi_none(~[Attribute]),
     iovi_item(@item),
     iovi_foreign_item(@foreign_item),
     iovi_view_item(view_item)
@@ -242,8 +242,8 @@ macro_rules! maybe_whole (
 )
 
 
-fn maybe_append(lhs: ~[attribute], rhs: Option<~[attribute]>)
-             -> ~[attribute] {
+fn maybe_append(lhs: ~[Attribute], rhs: Option<~[Attribute]>)
+             -> ~[Attribute] {
     match rhs {
         None => lhs,
         Some(ref attrs) => vec::append(lhs, (*attrs))
@@ -252,7 +252,7 @@ fn maybe_append(lhs: ~[attribute], rhs: Option<~[attribute]>)
 
 
 struct ParsedItemsAndViewItems {
-    attrs_remaining: ~[attribute],
+    attrs_remaining: ~[Attribute],
     view_items: ~[view_item],
     items: ~[@item],
     foreign_items: ~[@foreign_item]
@@ -2959,7 +2959,7 @@ impl Parser {
     // parse a structure field
     fn parse_name_and_ty(&self,
                          pr: visibility,
-                         attrs: ~[attribute]) -> @struct_field {
+                         attrs: ~[Attribute]) -> @struct_field {
         let lo = self.span.lo;
         if !is_plain_ident(&*self.token) {
             self.fatal("expected ident");
@@ -2977,7 +2977,7 @@ impl Parser {
 
     // parse a statement. may include decl.
     // precondition: any attributes are parsed already
-    pub fn parse_stmt(&self, item_attrs: ~[attribute]) -> @stmt {
+    pub fn parse_stmt(&self, item_attrs: ~[Attribute]) -> @stmt {
         maybe_whole!(self, nt_stmt);
 
         fn check_expected_item(p: &Parser, found_attrs: bool) {
@@ -3091,7 +3091,7 @@ impl Parser {
 
     // parse a block. Inner attrs are allowed.
     fn parse_inner_attrs_and_block(&self)
-        -> (~[attribute], blk) {
+        -> (~[Attribute], blk) {
 
         maybe_whole!(pair_empty self, nt_block);
 
@@ -3115,7 +3115,7 @@ impl Parser {
 
     // parse the rest of a block expression or function body
     fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode,
-                         first_item_attrs: ~[attribute]) -> blk {
+                         first_item_attrs: ~[Attribute]) -> blk {
         let mut stmts = ~[];
         let mut expr = None;
 
@@ -3594,7 +3594,7 @@ impl Parser {
 
     fn mk_item(&self, lo: BytePos, hi: BytePos, ident: ident,
                node: item_, vis: visibility,
-               attrs: ~[attribute]) -> @item {
+               attrs: ~[Attribute]) -> @item {
         @ast::item { ident: ident,
                      attrs: attrs,
                      id: self.get_id(),
@@ -3825,7 +3825,7 @@ impl Parser {
     // parse a structure field declaration
     pub fn parse_single_struct_field(&self,
                                      vis: visibility,
-                                     attrs: ~[attribute])
+                                     attrs: ~[Attribute])
                                      -> @struct_field {
         if self.eat_obsolete_ident("let") {
             self.obsolete(*self.last_span, ObsoleteLet);
@@ -3894,7 +3894,7 @@ impl Parser {
     // attributes (of length 0 or 1), parse all of the items in a module
     fn parse_mod_items(&self,
                        term: token::Token,
-                       first_item_attrs: ~[attribute])
+                       first_item_attrs: ~[Attribute])
                        -> _mod {
         // parse all of the items up to closing or an attribute.
         // view items are legal here.
@@ -3953,7 +3953,7 @@ impl Parser {
     }
 
     // parse a `mod <foo> { ... }` or `mod <foo>;` item
-    fn parse_item_mod(&self, outer_attrs: &[ast::attribute]) -> item_info {
+    fn parse_item_mod(&self, outer_attrs: &[Attribute]) -> item_info {
         let id_span = *self.span;
         let id = self.parse_ident();
         if *self.token == token::SEMI {
@@ -3972,11 +3972,10 @@ impl Parser {
         }
     }
 
-    fn push_mod_path(&self, id: ident, attrs: &[ast::attribute]) {
+    fn push_mod_path(&self, id: ident, attrs: &[Attribute]) {
         let default_path = token::interner_get(id.name);
-        let file_path = match ::attr::first_attr_value_str_by_name(
-            attrs, "path") {
-
+        let file_path = match ::attr::first_attr_value_str_by_name(attrs,
+                                                                   "path") {
             Some(d) => d,
             None => default_path
         };
@@ -3990,14 +3989,13 @@ impl Parser {
     // read a module from a source file.
     fn eval_src_mod(&self,
                     id: ast::ident,
-                    outer_attrs: &[ast::attribute],
+                    outer_attrs: &[ast::Attribute],
                     id_sp: span)
-                    -> (ast::item_, ~[ast::attribute]) {
+                    -> (ast::item_, ~[ast::Attribute]) {
         let prefix = Path(self.sess.cm.span_to_filename(*self.span));
         let prefix = prefix.dir_path();
         let mod_path_stack = &*self.mod_path_stack;
         let mod_path = Path(".").push_many(*mod_path_stack);
-        let default_path = token::interner_get(id.name).to_owned() + ".rs";
         let file_path = match ::attr::first_attr_value_str_by_name(
                 outer_attrs, "path") {
             Some(d) => {
@@ -4008,7 +4006,7 @@ impl Parser {
                     path
                 }
             }
-            None => mod_path.push(default_path)
+            None => mod_path.push(token::interner_get(id.name) + ".rs") // default
         };
 
         self.eval_src_mod_from_path(prefix,
@@ -4020,8 +4018,8 @@ impl Parser {
     fn eval_src_mod_from_path(&self,
                               prefix: Path,
                               path: Path,
-                              outer_attrs: ~[ast::attribute],
-                              id_sp: span) -> (ast::item_, ~[ast::attribute]) {
+                              outer_attrs: ~[ast::Attribute],
+                              id_sp: span) -> (ast::item_, ~[ast::Attribute]) {
 
         let full_path = if path.is_absolute {
             path
@@ -4057,17 +4055,10 @@ impl Parser {
         let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs);
         self.sess.included_mod_stack.pop();
         return (ast::item_mod(m0), mod_attrs);
-
-        fn cdir_path_opt(default: @str, attrs: ~[ast::attribute]) -> @str {
-            match ::attr::first_attr_value_str_by_name(attrs, "path") {
-                Some(d) => d,
-                None => default
-            }
-        }
     }
 
     // parse a function declaration from a foreign module
-    fn parse_item_foreign_fn(&self,  attrs: ~[attribute]) -> @foreign_item {
+    fn parse_item_foreign_fn(&self,  attrs: ~[Attribute]) -> @foreign_item {
         let lo = self.span.lo;
         let vis = self.parse_visibility();
         let purity = self.parse_fn_purity();
@@ -4085,7 +4076,7 @@ impl Parser {
 
     // parse a const definition from a foreign module
     fn parse_item_foreign_const(&self, vis: ast::visibility,
-                                attrs: ~[attribute]) -> @foreign_item {
+                                attrs: ~[Attribute]) -> @foreign_item {
         let lo = self.span.lo;
 
         // XXX: Obsolete; remove after snap.
@@ -4130,7 +4121,7 @@ impl Parser {
     fn parse_foreign_mod_items(&self,
                                sort: ast::foreign_mod_sort,
                                abis: AbiSet,
-                               first_item_attrs: ~[attribute])
+                               first_item_attrs: ~[Attribute])
                                -> foreign_mod {
         let ParsedItemsAndViewItems {
             attrs_remaining: attrs_remaining,
@@ -4156,7 +4147,7 @@ impl Parser {
                               lo: BytePos,
                               opt_abis: Option<AbiSet>,
                               visibility: visibility,
-                              attrs: ~[attribute],
+                              attrs: ~[Attribute],
                               items_allowed: bool)
                               -> item_or_view_item {
         let mut must_be_named_mod = false;
@@ -4430,7 +4421,7 @@ impl Parser {
     // NB: this function no longer parses the items inside an
     // extern mod.
     fn parse_item_or_view_item(&self,
-                               attrs: ~[attribute],
+                               attrs: ~[Attribute],
                                macros_allowed: bool)
                                -> item_or_view_item {
         maybe_whole!(iovi self, nt_item);
@@ -4562,7 +4553,7 @@ impl Parser {
 
     // parse a foreign item; on failure, return iovi_none.
     fn parse_foreign_item(&self,
-                          attrs: ~[attribute],
+                          attrs: ~[Attribute],
                           macros_allowed: bool)
                           -> item_or_view_item {
         maybe_whole!(iovi self, nt_item);
@@ -4587,7 +4578,7 @@ impl Parser {
     // this is the fall-through for parsing items.
     fn parse_macro_use_or_failure(
         &self,
-        attrs: ~[attribute],
+        attrs: ~[Attribute],
         macros_allowed: bool,
         lo : BytePos,
         visibility : visibility
@@ -4649,7 +4640,7 @@ impl Parser {
         return iovi_none(attrs);
     }
 
-    pub fn parse_item(&self, attrs: ~[attribute]) -> Option<@ast::item> {
+    pub fn parse_item(&self, attrs: ~[Attribute]) -> Option<@ast::item> {
         match self.parse_item_or_view_item(attrs, true) {
             iovi_none(_) =>
                 None,
@@ -4786,7 +4777,7 @@ impl Parser {
     // parse a view item.
     fn parse_view_item(
         &self,
-        attrs: ~[attribute],
+        attrs: ~[Attribute],
         vis: visibility
     ) -> view_item {
         let lo = self.span.lo;
@@ -4812,7 +4803,7 @@ impl Parser {
     // - mod_items uses extern_mod_allowed = true
     // - block_tail_ uses extern_mod_allowed = false
     fn parse_items_and_view_items(&self,
-                                  first_item_attrs: ~[attribute],
+                                  first_item_attrs: ~[Attribute],
                                   mut extern_mod_allowed: bool,
                                   macros_allowed: bool)
                                   -> ParsedItemsAndViewItems {
@@ -4894,7 +4885,7 @@ impl Parser {
 
     // Parses a sequence of foreign items. Stops when it finds program
     // text that can't be parsed as an item
-    fn parse_foreign_items(&self, first_item_attrs: ~[attribute],
+    fn parse_foreign_items(&self, first_item_attrs: ~[Attribute],
                            macros_allowed: bool)
         -> ParsedItemsAndViewItems {
         let mut attrs = vec::append(first_item_attrs,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index f1412994865..42966edfc0b 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -14,7 +14,7 @@ use ast;
 use ast_util;
 use opt_vec::OptVec;
 use opt_vec;
-use attr;
+use attr::{AttrMetaMethods, AttributeMethods};
 use codemap::{CodeMap, BytePos};
 use codemap;
 use diagnostic;
@@ -212,11 +212,11 @@ pub fn block_to_str(blk: &ast::blk, intr: @ident_interner) -> ~str {
     }
 }
 
-pub fn meta_item_to_str(mi: &ast::meta_item, intr: @ident_interner) -> ~str {
+pub fn meta_item_to_str(mi: &ast::MetaItem, intr: @ident_interner) -> ~str {
     to_str(mi, print_meta_item, intr)
 }
 
-pub fn attribute_to_str(attr: &ast::attribute, intr: @ident_interner) -> ~str {
+pub fn attribute_to_str(attr: &ast::Attribute, intr: @ident_interner) -> ~str {
     to_str(attr, print_attribute, intr)
 }
 
@@ -352,7 +352,7 @@ pub fn commasep_exprs(s: @ps, b: breaks, exprs: &[@ast::expr]) {
     commasep_cmnt(s, b, exprs, |p, &e| print_expr(p, e), |e| e.span);
 }
 
-pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::attribute]) {
+pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::Attribute]) {
     print_inner_attributes(s, attrs);
     for _mod.view_items.iter().advance |vitem| {
         print_view_item(s, vitem);
@@ -361,7 +361,7 @@ pub fn print_mod(s: @ps, _mod: &ast::_mod, attrs: &[ast::attribute]) {
 }
 
 pub fn print_foreign_mod(s: @ps, nmod: &ast::foreign_mod,
-                         attrs: &[ast::attribute]) {
+                         attrs: &[ast::Attribute]) {
     print_inner_attributes(s, attrs);
     for nmod.view_items.iter().advance |vitem| {
         print_view_item(s, vitem);
@@ -843,22 +843,22 @@ pub fn print_method(s: @ps, meth: &ast::method) {
     print_block_with_attrs(s, &meth.body, meth.attrs);
 }
 
-pub fn print_outer_attributes(s: @ps, attrs: &[ast::attribute]) {
+pub fn print_outer_attributes(s: @ps, attrs: &[ast::Attribute]) {
     let mut count = 0;
     for attrs.iter().advance |attr| {
         match attr.node.style {
-          ast::attr_outer => { print_attribute(s, attr); count += 1; }
+          ast::AttrOuter => { print_attribute(s, attr); count += 1; }
           _ => {/* fallthrough */ }
         }
     }
     if count > 0 { hardbreak_if_not_bol(s); }
 }
 
-pub fn print_inner_attributes(s: @ps, attrs: &[ast::attribute]) {
+pub fn print_inner_attributes(s: @ps, attrs: &[ast::Attribute]) {
     let mut count = 0;
     for attrs.iter().advance |attr| {
         match attr.node.style {
-          ast::attr_inner => {
+          ast::AttrInner => {
             print_attribute(s, attr);
             if !attr.node.is_sugared_doc {
                 word(s.s, ";");
@@ -871,16 +871,15 @@ pub fn print_inner_attributes(s: @ps, attrs: &[ast::attribute]) {
     if count > 0 { hardbreak_if_not_bol(s); }
 }
 
-pub fn print_attribute(s: @ps, attr: &ast::attribute) {
+pub fn print_attribute(s: @ps, attr: &ast::Attribute) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, attr.span.lo);
     if attr.node.is_sugared_doc {
-        let meta = attr::attr_meta(*attr);
-        let comment = attr::get_meta_item_value_str(meta).get();
+        let comment = attr.value_str().get();
         word(s.s, comment);
     } else {
         word(s.s, "#[");
-        print_meta_item(s, attr.node.value);
+        print_meta_item(s, attr.meta());
         word(s.s, "]");
     }
 }
@@ -927,7 +926,7 @@ pub fn print_block_unclosed_indent(s: @ps, blk: &ast::blk, indented: uint) {
 
 pub fn print_block_with_attrs(s: @ps,
                               blk: &ast::blk,
-                              attrs: &[ast::attribute]) {
+                              attrs: &[ast::Attribute]) {
     print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs,
                                   true);
 }
@@ -946,7 +945,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
                                       blk: &ast::blk,
                                       embedded: embed_type,
                                       indented: uint,
-                                      attrs: &[ast::attribute],
+                                      attrs: &[ast::Attribute],
                                       close_box: bool) {
     match blk.rules {
       ast::unsafe_blk => word_space(s, "unsafe"),
@@ -1793,16 +1792,16 @@ pub fn print_generics(s: @ps, generics: &ast::Generics) {
     }
 }
 
-pub fn print_meta_item(s: @ps, item: &ast::meta_item) {
+pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
     ibox(s, indent_unit);
     match item.node {
-      ast::meta_word(name) => word(s.s, name),
-      ast::meta_name_value(name, value) => {
+      ast::MetaWord(name) => word(s.s, name),
+      ast::MetaNameValue(name, value) => {
         word_space(s, name);
         word_space(s, "=");
         print_literal(s, @value);
       }
-      ast::meta_list(name, ref items) => {
+      ast::MetaList(name, ref items) => {
         word(s.s, name);
         popen(s);
         commasep(s,