about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lint/context.rs22
-rw-r--r--src/librustc_driver/lib.rs36
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs33
-rw-r--r--src/librustc_incremental/calculate_svh.rs3
-rw-r--r--src/librustc_lint/builtin.rs15
-rw-r--r--src/librustc_metadata/decoder.rs10
-rw-r--r--src/librustc_metadata/encoder.rs37
-rw-r--r--src/librustc_metadata/macro_import.rs12
-rw-r--r--src/librustdoc/clean/mod.rs79
-rw-r--r--src/libsyntax/attr.rs94
-rw-r--r--src/libsyntax/ext/build.rs23
-rw-r--r--src/libsyntax/ext/expand.rs5
-rw-r--r--src/libsyntax/feature_gate.rs15
-rw-r--r--src/libsyntax_ext/deriving/mod.rs19
14 files changed, 232 insertions, 171 deletions
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index ce3d72de9ae..0a1e7005f9f 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -366,19 +366,19 @@ pub fn gather_attr(attr: &ast::Attribute)
     attr::mark_used(attr);
 
     let meta = &attr.node.value;
-    let metas = match meta.node {
-        ast::MetaItemKind::List(_, ref metas) => metas,
-        _ => {
-            out.push(Err(meta.span));
-            return out;
-        }
-    };
+    let metas = if let Some(metas) = meta.meta_item_list() {
+                    metas
+                } else {
+                    out.push(Err(meta.span));
+                    return out;
+                };
 
     for meta in metas {
-        out.push(match meta.node {
-            ast::MetaItemKind::Word(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
-            _ => Err(meta.span),
-        });
+        out.push(if meta.is_word() {
+                     Ok((meta.name().clone(), level, meta.span))
+                 } else {
+                     Err(meta.span)
+                 });
     }
 
     out
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 0a8df923b84..9df1dea4567 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -95,6 +95,7 @@ use std::thread;
 use rustc::session::early_error;
 
 use syntax::{ast, json};
+use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
@@ -392,15 +393,13 @@ fn check_cfg(sopts: &config::Options,
 
     let mut saw_invalid_predicate = false;
     for item in sopts.cfg.iter() {
-        match item.node {
-            ast::MetaItemKind::List(ref pred, _) => {
-                saw_invalid_predicate = true;
-                handler.emit(&MultiSpan::new(),
-                             &format!("invalid predicate in --cfg command line argument: `{}`",
-                                      pred),
-                                errors::Level::Fatal);
-            }
-            _ => {},
+        if item.is_meta_item_list() {
+            saw_invalid_predicate = true;
+            saw_invalid_predicate = true;
+            handler.emit(&MultiSpan::new(),
+                         &format!("invalid predicate in --cfg command line argument: `{}`",
+                                  pred),
+                            errors::Level::Fatal);
         }
     }
 
@@ -649,20 +648,19 @@ impl RustcDefaultCalls {
                         if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
                             continue;
                         }
-                        match cfg.node {
-                            ast::MetaItemKind::Word(ref word) => println!("{}", word),
-                            ast::MetaItemKind::NameValue(ref name, ref value) => {
-                                println!("{}=\"{}\"", name, match value.node {
-                                    ast::LitKind::Str(ref s, _) => s,
-                                    _ => continue,
-                                });
+                        if cfg.is_word() {
+                            println!("{}", cfg.name());
+                        } else if cfg.is_value_str() {
+                            let rhs = cfg.value_str();
+                            match rhs {
+                                Some(s) => println!("{}=\"{}\"", cfg.name(), s),
+                                None => continue,
                             }
+                        } else if cfg.is_meta_item_list() {
                             // Right now there are not and should not be any
                             // MetaItemKind::List items in the configuration returned by
                             // `build_configuration`.
-                            ast::MetaItemKind::List(..) => {
-                                panic!("MetaItemKind::List encountered in default cfg")
-                            }
+                            panic!("MetaItemKind::List encountered in default cfg")
                         }
                     }
                 }
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index d38f979e33c..0d327414c8f 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -110,13 +110,13 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
             if attr.check_name(IF_THIS_CHANGED) {
                 let mut id = None;
                 for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    match meta_item.node {
-                        ast::MetaItemKind::Word(ref s) if id.is_none() => id = Some(s.clone()),
-                        _ => {
-                            self.tcx.sess.span_err(
-                                meta_item.span,
-                                &format!("unexpected meta-item {:?}", meta_item.node));
-                        }
+                    if meta_item.is_word() && id.is_none() {
+                        id = Some(meta_item.name().clone());
+                    } else {
+                        // FIXME better-encapsulate meta_item (don't directly access `node`)
+                        self.tcx.sess.span_err(
+                            meta_item.span(),
+                            &format!("unexpected meta-item {:?}", meta_item.node));
                     }
                 }
                 let id = id.unwrap_or(InternedString::new(ID));
@@ -127,16 +127,15 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
                 let mut dep_node_interned = None;
                 let mut id = None;
                 for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    match meta_item.node {
-                        ast::MetaItemKind::Word(ref s) if dep_node_interned.is_none() =>
-                            dep_node_interned = Some(s.clone()),
-                        ast::MetaItemKind::Word(ref s) if id.is_none() =>
-                            id = Some(s.clone()),
-                        _ => {
-                            self.tcx.sess.span_err(
-                                meta_item.span,
-                                &format!("unexpected meta-item {:?}", meta_item.node));
-                        }
+                    if meta_item.is_word() && dep_node_interned.is_none() {
+                        dep_node_interned = Some(meta_item.name().clone());
+                    } else if meta_item.is_word() && id.is_none() {
+                        id = Some(meta_item.name().clone());
+                    } else {
+                        // FIXME better-encapsulate meta_item (don't directly access `node`)
+                        self.tcx.sess.span_err(
+                            meta_item.span(),
+                            &format!("unexpected meta-item {:?}", meta_item.node));
                     }
                 }
                 let dep_node = match dep_node_interned {
diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs
index cbc246ac2a1..5d26bcd48a3 100644
--- a/src/librustc_incremental/calculate_svh.rs
+++ b/src/librustc_incremental/calculate_svh.rs
@@ -11,6 +11,7 @@
 //! Calculation of a Strict Version Hash for crates.  For a length
 //! comment explaining the general idea, see `librustc/middle/svh.rs`.
 
+use syntax::attr::AttributeMethods;
 use std::hash::{Hash, SipHasher, Hasher};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::svh::Svh;
@@ -69,7 +70,7 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
         // to avoid hashing the AttrId
         for attr in &krate.attrs {
             debug!("krate attr {:?}", attr);
-            attr.node.value.hash(&mut state);
+            attr.meta().hash(&mut state);
         }
 
         Svh::new(state.finish())
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 18f9733040e..a498004b390 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass};
 use std::collections::HashSet;
 
 use syntax::{ast};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr::{self, AttrMetaMethods, AttributeMethods};
 use syntax_pos::{self, Span};
 
 use rustc::hir::{self, PatKind};
@@ -299,9 +299,10 @@ impl MissingDoc {
         }
 
         let has_doc = attrs.iter().any(|a| {
-            match a.node.value.node {
-                ast::MetaItemKind::NameValue(ref name, _) if *name == "doc" => true,
-                _ => false
+            if a.is_value_str() && a.name() == "doc" {
+                true
+            } else {
+                false
             }
         });
         if !has_doc {
@@ -1094,10 +1095,10 @@ impl LintPass for UnstableFeatures {
 
 impl LateLintPass for UnstableFeatures {
     fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
-        if attr::contains_name(&[attr.node.value.clone()], "feature") {
-            if let Some(items) = attr.node.value.meta_item_list() {
+        if attr::contains_name(&[attr.meta().clone()], "feature") {
+            if let Some(items) = attr.meta().meta_item_list() {
                 for item in items {
-                    ctx.span_lint(UNSTABLE_FEATURES, item.span, "unstable feature");
+                    ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
                 }
             }
         }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 409cec282bc..63345a15e6a 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -1160,15 +1160,7 @@ fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
                 // an attribute
                 assert_eq!(meta_items.len(), 1);
                 let meta_item = meta_items.into_iter().nth(0).unwrap();
-                codemap::Spanned {
-                    node: ast::Attribute_ {
-                        id: attr::mk_attr_id(),
-                        style: ast::AttrStyle::Outer,
-                        value: meta_item,
-                        is_sugared_doc: is_sugared_doc,
-                    },
-                    span: syntax_pos::DUMMY_SP
-                }
+                attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc)
             }).collect()
         },
         None => vec![],
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 73142594235..91b1b82211a 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -44,7 +44,7 @@ use std::rc::Rc;
 use std::u32;
 use syntax::abi::Abi;
 use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::attr;
+use syntax::attr::{self,AttrMetaMethods,AttributeMethods};
 use errors::Handler;
 use syntax;
 use syntax_pos::BytePos;
@@ -1431,31 +1431,28 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
 }
 
 fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
-    match mi.node {
-      ast::MetaItemKind::Word(ref name) => {
+    if mi.is_word() {
+        let name = mi.name();
         rbml_w.start_tag(tag_meta_item_word);
-        rbml_w.wr_tagged_str(tag_meta_item_name, name);
+        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
         rbml_w.end_tag();
-      }
-      ast::MetaItemKind::NameValue(ref name, ref value) => {
-        match value.node {
-          ast::LitKind::Str(ref value, _) => {
-            rbml_w.start_tag(tag_meta_item_name_value);
-            rbml_w.wr_tagged_str(tag_meta_item_name, name);
-            rbml_w.wr_tagged_str(tag_meta_item_value, value);
-            rbml_w.end_tag();
-          }
-          _ => {/* FIXME (#623): encode other variants */ }
-        }
-      }
-      ast::MetaItemKind::List(ref name, ref items) => {
+    } else if mi.is_value_str() {
+        let name = mi.name();
+        /* FIXME (#623): support other literal kinds */
+        let value = mi.value_str().unwrap();
+        rbml_w.start_tag(tag_meta_item_name_value);
+        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
+        rbml_w.wr_tagged_str(tag_meta_item_value, &value);
+        rbml_w.end_tag();
+    } else { // it must be a list
+        let name = mi.name();
+        let items = mi.meta_item_list().unwrap();
         rbml_w.start_tag(tag_meta_item_list);
-        rbml_w.wr_tagged_str(tag_meta_item_name, name);
+        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
         for inner_item in items {
             encode_meta_item(rbml_w, &inner_item);
         }
         rbml_w.end_tag();
-      }
     }
 }
 
@@ -1464,7 +1461,7 @@ fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
     for attr in attrs {
         rbml_w.start_tag(tag_attribute);
         rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8);
-        encode_meta_item(rbml_w, &attr.node.value);
+        encode_meta_item(rbml_w, attr.meta());
         rbml_w.end_tag();
     }
     rbml_w.end_tag();
diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs
index 7dadf8d108a..4be044c1df3 100644
--- a/src/librustc_metadata/macro_import.rs
+++ b/src/librustc_metadata/macro_import.rs
@@ -60,10 +60,10 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
                     }
                     if let (Some(sel), Some(names)) = (import.as_mut(), names) {
                         for attr in names {
-                            if let ast::MetaItemKind::Word(ref name) = attr.node {
-                                sel.insert(name.clone(), attr.span);
+                            if attr.is_word() {
+                                sel.insert(attr.name().clone(), attr.span());
                             } else {
-                                span_err!(self.sess, attr.span, E0466, "bad macro import");
+                                span_err!(self.sess, attr.span(), E0466, "bad macro import");
                             }
                         }
                     }
@@ -78,10 +78,10 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
                     };
 
                     for attr in names {
-                        if let ast::MetaItemKind::Word(ref name) = attr.node {
-                            reexport.insert(name.clone(), attr.span);
+                        if attr.is_word() {
+                            reexport.insert(attr.name().clone(), attr.span());
                         } else {
-                            call_bad_macro_reexport(self.sess, attr.span);
+                            call_bad_macro_reexport(self.sess, attr.span());
                         }
                     }
                 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0211b2c9bc7..8d69c55ecf1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -498,21 +498,20 @@ pub enum Attribute {
 
 impl Clean<Attribute> for ast::MetaItem {
     fn clean(&self, cx: &DocContext) -> Attribute {
-        match self.node {
-            ast::MetaItemKind::Word(ref s) => Word(s.to_string()),
-            ast::MetaItemKind::List(ref s, ref l) => {
-                List(s.to_string(), l.clean(cx))
-            }
-            ast::MetaItemKind::NameValue(ref s, ref v) => {
-                NameValue(s.to_string(), lit_to_string(v))
-            }
-        }
+        if self.is_word() {
+            Word(self.name().to_string())
+        } else if let Some(v) = self.value_str() {
+            NameValue(self.name().to_string(), v.to_string())
+        } else { // must be a list
+            let l = self.meta_item_list().unwrap();
+              List(self.name().to_string(), l.clean(cx))
+       }
     }
 }
 
 impl Clean<Attribute> for ast::Attribute {
     fn clean(&self, cx: &DocContext) -> Attribute {
-        self.with_desugared_doc(|a| a.node.value.clean(cx))
+        self.with_desugared_doc(|a| a.meta().clean(cx))
     }
 }
 
@@ -535,6 +534,28 @@ impl attr::AttrMetaMethods for Attribute {
         }
     }
     fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
+
+    fn is_word(&self) -> bool {
+      match *self {
+        Word(_) => true,
+        _ => false,
+      }
+    }
+
+    fn is_value_str(&self) -> bool {
+      match *self {
+        NameValue(..) => true,
+        _ => false,
+      }
+    }
+
+    fn is_meta_item_list(&self) -> bool {
+      match *self {
+        List(..) => true,
+        _ => false,
+      }
+    }
+
     fn span(&self) -> syntax_pos::Span { unimplemented!() }
 }
 
@@ -2568,25 +2589,25 @@ impl ToSource for syntax_pos::Span {
     }
 }
 
-fn lit_to_string(lit: &ast::Lit) -> String {
-    match lit.node {
-        ast::LitKind::Str(ref st, _) => st.to_string(),
-        ast::LitKind::ByteStr(ref data) => format!("{:?}", data),
-        ast::LitKind::Byte(b) => {
-            let mut res = String::from("b'");
-            for c in (b as char).escape_default() {
-                res.push(c);
-            }
-            res.push('\'');
-            res
-        },
-        ast::LitKind::Char(c) => format!("'{}'", c),
-        ast::LitKind::Int(i, _t) => i.to_string(),
-        ast::LitKind::Float(ref f, _t) => f.to_string(),
-        ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(),
-        ast::LitKind::Bool(b) => b.to_string(),
-    }
-}
+// fn lit_to_string(lit: &ast::Lit) -> String {
+//     match lit.node {
+//         ast::LitKind::Str(ref st, _) => st.to_string(),
+//         ast::LitKind::ByteStr(ref data) => format!("{:?}", data),
+//         ast::LitKind::Byte(b) => {
+//             let mut res = String::from("b'");
+//             for c in (b as char).escape_default() {
+//                 res.push(c);
+//             }
+//             res.push('\'');
+//             res
+//         },
+//         ast::LitKind::Char(c) => format!("'{}'", c),
+//         ast::LitKind::Int(i, _t) => i.to_string(),
+//         ast::LitKind::Float(ref f, _t) => f.to_string(),
+//         ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(),
+//         ast::LitKind::Bool(b) => b.to_string(),
+//     }
+// }
 
 fn name_from_pat(p: &hir::Pat) -> String {
     use rustc::hir::*;
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 67f73d4dd4f..8bd3f5195cc 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -17,8 +17,8 @@ pub use self::IntType::*;
 use ast;
 use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind};
 use ast::{Expr, Item, Local, Stmt, StmtKind};
-use codemap::{spanned, dummy_spanned, Spanned};
-use syntax_pos::{Span, BytePos};
+use codemap::{respan, spanned, dummy_spanned, Spanned};
+use syntax_pos::{Span, BytePos, DUMMY_SP};
 use errors::Handler;
 use feature_gate::{Features, GatedCfg};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
@@ -92,6 +92,13 @@ pub trait AttrMetaMethods {
     /// Gets a list of inner meta items from a list MetaItem type.
     fn meta_item_list(&self) -> Option<&[P<MetaItem>]>;
 
+    /// Indicates if the attribute is a Word.
+    fn is_word(&self) -> bool;
+    /// Indicates if the attribute is a Value String.
+    fn is_value_str(&self) -> bool;
+    /// Indicates if the attribute is a Meta-Item List.
+    fn is_meta_item_list(&self) -> bool;
+
     fn span(&self) -> Span;
 }
 
@@ -108,8 +115,14 @@ impl AttrMetaMethods for Attribute {
         self.meta().value_str()
     }
     fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
-        self.node.value.meta_item_list()
+        self.meta().meta_item_list()
     }
+
+    fn is_word(&self) -> bool { self.meta().is_word() }
+    fn is_value_str(&self) -> bool { self.meta().is_value_str() }
+
+    fn is_meta_item_list(&self) -> bool { self.meta().is_meta_item_list() }
+
     fn span(&self) -> Span { self.meta().span }
 }
 
@@ -140,6 +153,18 @@ impl AttrMetaMethods for MetaItem {
             _ => None
         }
     }
+
+    fn is_word(&self) -> bool {
+        match self.node {
+            MetaItemKind::Word(_) => true,
+            _ => false,
+        }
+    }
+
+    fn is_value_str(&self) -> bool { self.value_str().is_some() }
+
+    fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() }
+
     fn span(&self) -> Span { self.span }
 }
 
@@ -150,6 +175,9 @@ impl AttrMetaMethods for P<MetaItem> {
     fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
         (**self).meta_item_list()
     }
+    fn is_word(&self) -> bool { (**self).is_word() }
+    fn is_value_str(&self) -> bool { (**self).is_value_str() }
+    fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() }
     fn span(&self) -> Span { (**self).span() }
 }
 
@@ -194,22 +222,38 @@ impl AttributeMethods for Attribute {
 pub fn mk_name_value_item_str(name: InternedString, value: InternedString)
                               -> P<MetaItem> {
     let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked));
-    mk_name_value_item(name, value_lit)
+    mk_spanned_name_value_item(DUMMY_SP, name, value_lit)
 }
 
 pub fn mk_name_value_item(name: InternedString, value: ast::Lit)
                           -> P<MetaItem> {
-    P(dummy_spanned(MetaItemKind::NameValue(name, value)))
+    mk_spanned_name_value_item(DUMMY_SP, name, value)
 }
 
 pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> {
-    P(dummy_spanned(MetaItemKind::List(name, items)))
+    mk_spanned_list_item(DUMMY_SP, name, items)
 }
 
 pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
-    P(dummy_spanned(MetaItemKind::Word(name)))
+    mk_spanned_word_item(DUMMY_SP, name)
+}
+
+pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Lit)
+                          -> P<MetaItem> {
+    P(respan(sp,MetaItemKind::NameValue(name, value)))
+}
+
+pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<P<MetaItem>>)
+                            -> P<MetaItem> {
+    P(respan(sp, MetaItemKind::List(name, items)))
 }
 
+pub fn mk_spanned_word_item(sp: Span, name: InternedString) -> P<MetaItem> {
+    P(respan(sp,MetaItemKind::Word(name)))
+}
+
+
+
 thread_local! { static NEXT_ATTR_ID: Cell<usize> = Cell::new(0) }
 
 pub fn mk_attr_id() -> AttrId {
@@ -223,21 +267,43 @@ pub fn mk_attr_id() -> AttrId {
 
 /// Returns an inner attribute with the given value.
 pub fn mk_attr_inner(id: AttrId, item: P<MetaItem>) -> Attribute {
-    dummy_spanned(Attribute_ {
-        id: id,
-        style: ast::AttrStyle::Inner,
-        value: item,
-        is_sugared_doc: false,
-    })
+    mk_spanned_attr_inner(DUMMY_SP, id, item)
 }
 
+/// Returns an innter attribute with the given value and span.
+pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: P<MetaItem>) -> Attribute {
+    respan(sp,
+           Attribute_ {
+            id: id,
+            style: ast::AttrStyle::Inner,
+            value: item,
+            is_sugared_doc: false,
+          })
+}
+
+
 /// Returns an outer attribute with the given value.
 pub fn mk_attr_outer(id: AttrId, item: P<MetaItem>) -> Attribute {
+    mk_spanned_attr_outer(DUMMY_SP, id, item)
+}
+
+/// Returns an outer attribute with the given value and span.
+pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: P<MetaItem>) -> Attribute {
+    respan(sp,
+           Attribute_ {
+            id: id,
+            style: ast::AttrStyle::Outer,
+            value: item,
+            is_sugared_doc: false,
+          })
+}
+
+pub fn mk_doc_attr_outer(id: AttrId, item: P<MetaItem>, is_sugared_doc: bool) -> Attribute {
     dummy_spanned(Attribute_ {
         id: id,
         style: ast::AttrStyle::Outer,
         value: item,
-        is_sugared_doc: false,
+        is_sugared_doc: is_sugared_doc,
     })
 }
 
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 435241f426e..5d6429f7bdf 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -1135,30 +1135,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute {
-        respan(sp, ast::Attribute_ {
-            id: attr::mk_attr_id(),
-            style: ast::AttrStyle::Outer,
-            value: mi,
-            is_sugared_doc: false,
-        })
+        attr::mk_spanned_attr_outer(sp, attr::mk_attr_id(), mi)
     }
 
     fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem> {
-        P(respan(sp, ast::MetaItemKind::Word(w)))
+        attr::mk_spanned_word_item(sp, w)
     }
-    fn meta_list(&self,
-                 sp: Span,
-                 name: InternedString,
-                 mis: Vec<P<ast::MetaItem>> )
+    fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<P<ast::MetaItem>>)
                  -> P<ast::MetaItem> {
-        P(respan(sp, ast::MetaItemKind::List(name, mis)))
+        attr::mk_spanned_list_item(sp, name, mis)
     }
-    fn meta_name_value(&self,
-                       sp: Span,
-                       name: InternedString,
-                       value: ast::LitKind)
+    fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind)
                        -> P<ast::MetaItem> {
-        P(respan(sp, ast::MetaItemKind::NameValue(name, respan(sp, value))))
+        attr::mk_spanned_name_value_item(sp, name, respan(sp, value))
     }
 
     fn item_use(&self, sp: Span,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 18342f2e38c..5293d2ab000 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -302,9 +302,8 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool
         };
 
         if is_use {
-            match attr.node.value.node {
-                ast::MetaItemKind::Word(..) => (),
-                _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"),
+            if !attr.is_word() {
+              fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
             }
             return true;
         }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 27485ee65fc..5a718dd48e3 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1108,14 +1108,13 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F
             }
             Some(list) => {
                 for mi in list {
-                    let name = match mi.node {
-                        ast::MetaItemKind::Word(ref word) => (*word).clone(),
-                        _ => {
-                            span_err!(span_handler, mi.span, E0556,
-                                      "malformed feature, expected just one word");
-                            continue
-                        }
-                    };
+                    let name = if mi.is_word() {
+                                   mi.name()
+                               } else {
+                                   span_err!(span_handler, mi.span, E0556,
+                                             "malformed feature, expected just one word");
+                                   continue
+                               };
                     if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
                         .find(|& &(n, _, _, _)| name == n) {
                         *(setter(&mut features)) = true;
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index 80e2a923e55..e09a64e7344 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -10,7 +10,7 @@
 
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
-use syntax::ast::{self, MetaItem, MetaItemKind};
+use syntax::ast::{MetaItem, self};
 use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
 use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
@@ -98,15 +98,14 @@ fn expand_derive(cx: &mut ExtCtxt,
             let mut eq_span = None;
 
             for titem in traits.iter().rev() {
-                let tname = match titem.node {
-                    MetaItemKind::Word(ref tname) => tname,
-                    _ => {
-                        cx.span_err(titem.span, "malformed `derive` entry");
-                        continue;
-                    }
-                };
-
-                if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
+                let tname = if titem.is_word() {
+                                titem.name() }
+                            else {
+                                cx.span_err(titem.span, "malformed `derive` entry");
+                                continue;
+                            };
+
+                if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) {
                     feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
                                                    "custom_derive",
                                                    titem.span,