about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/check_attr.rs18
-rw-r--r--src/librustc/hir/fold.rs40
-rw-r--r--src/librustc/hir/intravisit.rs12
-rw-r--r--src/librustc/hir/lowering.rs20
-rw-r--r--src/librustc/hir/map/blocks.rs6
-rw-r--r--src/librustc/hir/map/collector.rs2
-rw-r--r--src/librustc/hir/map/def_collector.rs4
-rw-r--r--src/librustc/hir/mod.rs75
-rw-r--r--src/librustc/hir/print.rs13
-rw-r--r--src/librustc/infer/error_reporting.rs4
-rw-r--r--src/librustc/lint/context.rs12
-rw-r--r--src/librustc/middle/dead.rs2
-rw-r--r--src/librustc/middle/lang_items.rs1
-rw-r--r--src/librustc/middle/recursion_limit.rs1
-rw-r--r--src/librustc/middle/stability.rs4
-rw-r--r--src/librustc/session/config.rs10
-rw-r--r--src/librustc/traits/error_reporting.rs1
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/fragments.rs1
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs8
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs1
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_driver/lib.rs13
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs38
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs1
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs15
-rw-r--r--src/librustc_lint/bad_style.rs2
-rw-r--r--src/librustc_lint/builtin.rs8
-rw-r--r--src/librustc_lint/unused.rs20
-rw-r--r--src/librustc_metadata/common.rs15
-rw-r--r--src/librustc_metadata/creader.rs1
-rw-r--r--src/librustc_metadata/decoder.rs51
-rw-r--r--src/librustc_metadata/encoder.rs37
-rw-r--r--src/librustc_metadata/macro_import.rs9
-rw-r--r--src/librustc_mir/hair/cx/mod.rs1
-rw-r--r--src/librustc_passes/ast_validation.rs23
-rw-r--r--src/librustc_passes/consts.rs3
-rw-r--r--src/librustc_passes/diagnostics.rs7
-rw-r--r--src/librustc_plugin/load.rs19
-rw-r--r--src/librustc_plugin/registry.rs5
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs27
-rw-r--r--src/librustc_resolve/check_unused.rs2
-rw-r--r--src/librustc_resolve/lib.rs1
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs17
-rw-r--r--src/librustc_trans/assert_module_sources.rs1
-rw-r--r--src/librustc_trans/back/link.rs1
-rw-r--r--src/librustc_trans/base.rs1
-rw-r--r--src/librustc_trans/consts.rs2
-rw-r--r--src/librustc_trans/symbol_names_test.rs1
-rw-r--r--src/librustc_typeck/check/intrinsic.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs27
-rw-r--r--src/librustc_typeck/check_unused.rs2
-rw-r--r--src/librustc_typeck/diagnostics.rs7
-rw-r--r--src/librustc_typeck/lib.rs11
-rw-r--r--src/librustdoc/clean/mod.rs84
-rw-r--r--src/librustdoc/test.rs3
-rw-r--r--src/librustdoc/visit_ast.rs7
-rw-r--r--src/libsyntax/ast.rs113
-rw-r--r--src/libsyntax/attr.rs387
-rw-r--r--src/libsyntax/config.rs40
-rw-r--r--src/libsyntax/diagnostic_list.rs18
-rw-r--r--src/libsyntax/ext/base.rs7
-rw-r--r--src/libsyntax/ext/build.rs59
-rw-r--r--src/libsyntax/ext/expand.rs1
-rw-r--r--src/libsyntax/feature_gate.rs57
-rw-r--r--src/libsyntax/fold.rs42
-rw-r--r--src/libsyntax/parse/attr.rs64
-rw-r--r--src/libsyntax/parse/mod.rs12
-rw-r--r--src/libsyntax/parse/parser.rs56
-rw-r--r--src/libsyntax/print/pprust.rs56
-rw-r--r--src/libsyntax/test.rs11
-rw-r--r--src/libsyntax/visit.rs9
-rw-r--r--src/libsyntax_ext/deriving/bounds.rs1
-rw-r--r--src/libsyntax_ext/deriving/clone.rs1
-rw-r--r--src/libsyntax_ext/deriving/cmp/eq.rs3
-rw-r--r--src/libsyntax_ext/deriving/cmp/ord.rs3
-rw-r--r--src/libsyntax_ext/deriving/cmp/partial_eq.rs1
-rw-r--r--src/libsyntax_ext/deriving/cmp/partial_ord.rs3
-rw-r--r--src/libsyntax_ext/deriving/debug.rs1
-rw-r--r--src/libsyntax_ext/deriving/decodable.rs7
-rw-r--r--src/libsyntax_ext/deriving/default.rs5
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs1
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs66
-rw-r--r--src/libsyntax_ext/deriving/generic/ty.rs6
-rw-r--r--src/libsyntax_ext/deriving/hash.rs1
-rw-r--r--src/libsyntax_ext/deriving/mod.rs5
-rw-r--r--src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs16
-rw-r--r--src/test/compile-fail/E0132.rs2
-rw-r--r--src/test/compile-fail/E0565-1.rs17
-rw-r--r--src/test/compile-fail/E0565.rs17
-rw-r--r--src/test/compile-fail/attr-literals.rs33
-rw-r--r--src/test/compile-fail/const-fn-mismatch.rs2
-rw-r--r--src/test/compile-fail/const-fn-not-in-trait.rs8
-rw-r--r--src/test/compile-fail/gated-attr-literals.rs44
-rw-r--r--src/test/parse-fail/suffixed-literal-meta.rs25
-rw-r--r--src/test/pretty/attr-literals.rs (renamed from src/test/parse-fail/non-str-meta.rs)16
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs2
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs4
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs102
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/plugin_args.rs4
-rw-r--r--src/test/run-pass-fulldeps/empty-struct-braces-derive.rs24
-rw-r--r--src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs58
-rw-r--r--src/test/ui/mismatched_types/const-fn-in-trait.rs25
-rw-r--r--src/test/ui/mismatched_types/const-fn-in-trait.stderr14
104 files changed, 1297 insertions, 855 deletions
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index a1c04dfcab5..21143f93a7d 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -11,7 +11,6 @@
 use session::Session;
 
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::visit;
 use syntax::visit::Visitor;
 
@@ -52,18 +51,22 @@ impl<'a> CheckAttrVisitor<'a> {
                 return;
             }
         };
+
         for word in words {
-            let word: &str = &word.name();
-            let message = match word {
+            let name = match word.name() {
+                Some(word) => word,
+                None => continue,
+            };
+
+            let message = match &*name {
                 "C" => {
                     if target != Target::Struct && target != Target::Enum {
-                            "attribute should be applied to struct or enum"
+                        "attribute should be applied to struct or enum"
                     } else {
                         continue
                     }
                 }
-                "packed" |
-                "simd" => {
+                "packed" | "simd" => {
                     if target != Target::Struct {
                         "attribute should be applied to struct"
                     } else {
@@ -74,13 +77,14 @@ impl<'a> CheckAttrVisitor<'a> {
                 "i32" | "u32" | "i64" | "u64" |
                 "isize" | "usize" => {
                     if target != Target::Enum {
-                            "attribute should be applied to enum"
+                        "attribute should be applied to enum"
                     } else {
                         continue
                     }
                 }
                 _ => continue,
             };
+
             span_err!(self.sess, attr.span, E0517, "{}", message);
         }
     }
diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs
index 0edfd16bdfd..12bc49c10da 100644
--- a/src/librustc/hir/fold.rs
+++ b/src/librustc/hir/fold.rs
@@ -12,8 +12,8 @@
 //! and returns a piece of the same type.
 
 use hir::*;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
-use syntax::ast::MetaItemKind;
+use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_};
+use syntax::ast::{NestedMetaItem, NestedMetaItemKind, MetaItem, MetaItemKind};
 use hir;
 use syntax_pos::Span;
 use syntax::codemap::{respan, Spanned};
@@ -38,6 +38,10 @@ pub trait Folder : Sized {
         noop_fold_meta_items(meta_items, self)
     }
 
+    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
+        noop_fold_meta_list_item(list_item, self)
+    }
+
     fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
         noop_fold_meta_item(meta_item, self)
     }
@@ -271,16 +275,10 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
                     ViewPathList(fld.fold_path(path),
                                  path_list_idents.move_map(|path_list_ident| {
                                      Spanned {
-                                         node: match path_list_ident.node {
-                                             PathListIdent { id, name, rename } => PathListIdent {
-                                                 id: fld.new_id(id),
-                                                 name: name,
-                                                 rename: rename,
-                                             },
-                                             PathListMod { id, rename } => PathListMod {
-                                                 id: fld.new_id(id),
-                                                 rename: rename,
-                                             },
+                                         node: PathListItem_ {
+                                             id: fld.new_id(path_list_ident.node.id),
+                                             name: path_list_ident.node.name,
+                                             rename: path_list_ident.node.rename,
                                          },
                                          span: fld.new_span(path_list_ident.span),
                                      }
@@ -486,13 +484,26 @@ pub fn noop_fold_attribute<T: Folder>(at: Attribute, fld: &mut T) -> Option<Attr
     })
 }
 
+pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T)
+    -> NestedMetaItem {
+    Spanned {
+        node: match li.node {
+            NestedMetaItemKind::MetaItem(mi) =>  {
+                NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi))
+            },
+            NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit)
+        },
+        span: fld.new_span(li.span)
+    }
+}
+
 pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
     mi.map(|Spanned { node, span }| {
         Spanned {
             node: match node {
                 MetaItemKind::Word(id) => MetaItemKind::Word(id),
                 MetaItemKind::List(id, mis) => {
-                    MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e)))
+                    MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e)))
                 }
                 MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s),
             },
@@ -577,13 +588,14 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) ->
     o_lt.map(|lt| fld.fold_lifetime(lt))
 }
 
-pub fn noop_fold_generics<T: Folder>(Generics { ty_params, lifetimes, where_clause }: Generics,
+pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics,
                                      fld: &mut T)
                                      -> Generics {
     Generics {
         ty_params: fld.fold_ty_params(ty_params),
         lifetimes: fld.fold_lifetime_defs(lifetimes),
         where_clause: fld.fold_where_clause(where_clause),
+        span: fld.new_span(span),
     }
 }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 92b95678886..bc1dff7c6fc 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -444,12 +444,12 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
     }
 }
 
-pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
-                                               _prefix: &'v Path,
-                                               item: &'v PathListItem) {
-    visitor.visit_id(item.node.id());
-    walk_opt_name(visitor, item.span, item.node.name());
-    walk_opt_name(visitor, item.span, item.node.rename());
+pub fn walk_path_list_item<'v, V>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem)
+    where V: Visitor<'v>,
+{
+    visitor.visit_id(item.node.id);
+    visitor.visit_name(item.span, item.node.name);
+    walk_opt_name(visitor, item.span, item.node.rename);
 }
 
 pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index b45610c3fe8..6739d3f662a 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -218,16 +218,10 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem {
         Spanned {
-            node: match path_list_ident.node {
-                PathListItemKind::Ident { id, name, rename } => hir::PathListIdent {
-                    id: id,
-                    name: name.name,
-                    rename: rename.map(|x| x.name),
-                },
-                PathListItemKind::Mod { id, rename } => hir::PathListMod {
-                    id: id,
-                    rename: rename.map(|x| x.name),
-                },
+            node: hir::PathListItem_ {
+                id: path_list_ident.node.id,
+                name: path_list_ident.node.name.name,
+                rename: path_list_ident.node.rename.map(|rename| rename.name),
             },
             span: path_list_ident.span,
         }
@@ -466,6 +460,7 @@ impl<'a> LoweringContext<'a> {
             ty_params: self.lower_ty_params(&g.ty_params),
             lifetimes: self.lower_lifetime_defs(&g.lifetimes),
             where_clause: self.lower_where_clause(&g.where_clause),
+            span: g.span,
         }
     }
 
@@ -643,6 +638,7 @@ impl<'a> LoweringContext<'a> {
                 let struct_def = self.lower_variant_data(struct_def);
                 hir::ItemStruct(struct_def, self.lower_generics(generics))
             }
+            ItemKind::Union(..) => panic!("`union` is not yet implemented"),
             ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
                 hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
                                      self.lower_trait_ref(trait_ref))
@@ -809,8 +805,8 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_constness(&mut self, c: Constness) -> hir::Constness {
-        match c {
+    fn lower_constness(&mut self, c: Spanned<Constness>) -> hir::Constness {
+        match c.node {
             Constness::Const => hir::Constness::Const,
             Constness::NotConst => hir::Constness::NotConst,
         }
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 50e8c6e7ab8..44872348856 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -23,13 +23,13 @@
 
 pub use self::Code::*;
 
+use hir as ast;
 use hir::map::{self, Node};
-use syntax::abi;
 use hir::{Block, FnDecl};
+use hir::intravisit::FnKind;
+use syntax::abi;
 use syntax::ast::{Attribute, Name, NodeId};
-use hir as ast;
 use syntax_pos::Span;
-use hir::intravisit::FnKind;
 
 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
 /// and a body (as well as a NodeId, a span, etc).
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index b70190181af..280c0f30485 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -120,7 +120,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                     match view_path.node {
                         ViewPathList(_, ref paths) => {
                             for path in paths {
-                                this.insert(path.node.id(), NodeItem(i));
+                                this.insert(path.node.id, NodeItem(i));
                             }
                         }
                         _ => ()
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 752b0e9a253..77567fc7a46 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -133,7 +133,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
         let def_data = match i.node {
             ItemKind::DefaultImpl(..) | ItemKind::Impl(..) =>
                 DefPathData::Impl,
-            ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) |
+            ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
@@ -164,7 +164,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> {
                         });
                     }
                 }
-                ItemKind::Struct(ref struct_def, _) => {
+                ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
                     // If this is a tuple-like struct, register the constructor.
                     if !struct_def.is_struct() {
                         this.create_def(struct_def.id(),
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 99fb2d6a449..295a49d26d0 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -20,7 +20,6 @@ pub use self::FunctionRetTy::*;
 pub use self::ForeignItem_::*;
 pub use self::Item_::*;
 pub use self::Mutability::*;
-pub use self::PathListItem_::*;
 pub use self::PrimTy::*;
 pub use self::Stmt_::*;
 pub use self::TraitItem_::*;
@@ -36,7 +35,7 @@ use hir::def::Def;
 use hir::def_id::DefId;
 use util::nodemap::{NodeMap, FnvHashSet};
 
-use syntax_pos::{BytePos, mk_sp, Span, ExpnId};
+use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, respan, Spanned};
 use syntax::abi::Abi;
 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
@@ -301,6 +300,7 @@ pub struct Generics {
     pub lifetimes: HirVec<LifetimeDef>,
     pub ty_params: HirVec<TyParam>,
     pub where_clause: WhereClause,
+    pub span: Span,
 }
 
 impl Generics {
@@ -312,6 +312,7 @@ impl Generics {
                 id: DUMMY_NODE_ID,
                 predicates: HirVec::new(),
             },
+            span: DUMMY_SP,
         }
     }
 
@@ -326,38 +327,6 @@ impl Generics {
     pub fn is_parameterized(&self) -> bool {
         self.is_lt_parameterized() || self.is_type_parameterized()
     }
-
-    // Does return a span which includes lifetimes and type parameters,
-    // not where clause.
-    pub fn span(&self) -> Option<Span> {
-        if !self.is_parameterized() {
-            None
-        } else {
-            let mut span: Option<Span> = None;
-            for lifetime in self.lifetimes.iter() {
-                if let Some(ref mut span) = span {
-                    let life_span = lifetime.lifetime.span;
-                    span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi };
-                    span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo };
-                } else {
-                    span = Some(lifetime.lifetime.span.clone());
-                }
-            }
-            for ty_param in self.ty_params.iter() {
-                if let Some(ref mut span) = span {
-                    span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo };
-                    span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi };
-                } else {
-                    span = Some(ty_param.span.clone());
-                }
-            }
-            if let Some(ref mut span) = span {
-                span.lo = span.lo - BytePos(1);
-                span.hi = span.hi + BytePos(1);
-            }
-            span
-        }
-    }
 }
 
 /// A `where` clause in a definition
@@ -1337,39 +1306,11 @@ pub struct Variant_ {
 pub type Variant = Spanned<Variant_>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum PathListItem_ {
-    PathListIdent {
-        name: Name,
-        /// renamed in list, eg `use foo::{bar as baz};`
-        rename: Option<Name>,
-        id: NodeId,
-    },
-    PathListMod {
-        /// renamed in list, eg `use foo::{self as baz};`
-        rename: Option<Name>,
-        id: NodeId,
-    },
-}
-
-impl PathListItem_ {
-    pub fn id(&self) -> NodeId {
-        match *self {
-            PathListIdent { id, .. } | PathListMod { id, .. } => id,
-        }
-    }
-
-    pub fn name(&self) -> Option<Name> {
-        match *self {
-            PathListIdent { name, .. } => Some(name),
-            PathListMod { .. } => None,
-        }
-    }
-
-    pub fn rename(&self) -> Option<Name> {
-        match *self {
-            PathListIdent { rename, .. } | PathListMod { rename, .. } => rename,
-        }
-    }
+pub struct PathListItem_ {
+    pub name: Name,
+    /// renamed in list, eg `use foo::{bar as baz};`
+    pub rename: Option<Name>,
+    pub id: NodeId,
 }
 
 pub type PathListItem = Spanned<PathListItem_>;
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 66c1bc7642c..893d6708ead 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -523,6 +523,7 @@ impl<'a> State<'a> {
                         id: ast::DUMMY_NODE_ID,
                         predicates: hir::HirVec::new(),
                     },
+                    span: syntax_pos::DUMMY_SP,
                 };
                 self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?;
             }
@@ -2133,16 +2134,7 @@ impl<'a> State<'a> {
                     self.print_path(path, false, 0)?;
                     word(&mut self.s, "::{")?;
                 }
-                self.commasep(Inconsistent, &segments[..], |s, w| {
-                    match w.node {
-                        hir::PathListIdent { name, .. } => {
-                            s.print_name(name)
-                        }
-                        hir::PathListMod { .. } => {
-                            word(&mut s.s, "self")
-                        }
-                    }
-                })?;
+                self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?;
                 word(&mut self.s, "}")
             }
         }
@@ -2224,6 +2216,7 @@ impl<'a> State<'a> {
                 id: ast::DUMMY_NODE_ID,
                 predicates: hir::HirVec::new(),
             },
+            span: syntax_pos::DUMMY_SP,
         };
         self.print_fn(decl,
                       unsafety,
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 9169d299e04..0cd39882b7c 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1030,7 +1030,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                     = node_inner.expect("expect item fn");
         let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
         let (fn_decl, generics) = rebuilder.rebuild();
-        self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, &generics, span);
+        self.give_expl_lifetime_param(
+            err, &fn_decl, unsafety, constness, name, &generics, span);
     }
 
     pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
@@ -1297,6 +1298,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
             lifetimes: lifetimes.into(),
             ty_params: ty_params,
             where_clause: where_clause,
+            span: generics.span,
         }
     }
 
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 0bab919a9ae..81d3d440b56 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap;
 use std::cmp;
 use std::default::Default as StdDefault;
 use std::mem;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::token::InternedString;
 use syntax::ast;
 use syntax_pos::Span;
@@ -372,12 +372,10 @@ pub fn gather_attr(attr: &ast::Attribute)
         return out;
     };
 
-    for meta in metas {
-        out.push(if meta.is_word() {
-            Ok((meta.name().clone(), level, meta.span))
-        } else {
-            Err(meta.span)
-        });
+    for li in metas {
+        out.push(li.word().map_or(Err(li.span), |word| {
+            Ok((word.name().clone(), level, word.span))
+        }));
     }
 
     out
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index f44b149a846..824383b11af 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -294,7 +294,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
     }
 
     fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) {
-        self.lookup_and_handle_definition(item.node.id());
+        self.lookup_and_handle_definition(item.node.id);
         intravisit::walk_path_list_item(self, path, item);
     }
 }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index a209b1d1abd..d1769d5cbc5 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -30,7 +30,6 @@ use middle::weak_lang_items;
 use util::nodemap::FnvHashMap;
 
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use hir::intravisit::Visitor;
 use hir;
diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs
index 7dcd358165c..0764e817f43 100644
--- a/src/librustc/middle/recursion_limit.rs
+++ b/src/librustc/middle/recursion_limit.rs
@@ -17,7 +17,6 @@
 
 use session::Session;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 
 pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) {
     for attr in &krate.attrs {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index cbbc2c4f98f..c20fcc3fe1d 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -27,7 +27,7 @@ use syntax_pos::{Span, DUMMY_SP};
 use syntax::ast;
 use syntax::ast::{NodeId, Attribute};
 use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
-use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods};
+use syntax::attr::{self, Stability, Deprecation};
 use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
 
 use hir;
@@ -631,7 +631,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       cb: &mut FnMut(DefId, Span,
                                                      &Option<&Stability>,
                                                      &Option<DeprecationEntry>)) {
-    match tcx.expect_def(item.node.id()) {
+    match tcx.expect_def(item.node.id) {
         Def::PrimTy(..) => {}
         def => {
             maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 8a32797dbd7..562dce6a1b1 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -25,7 +25,6 @@ use middle::cstore;
 
 use syntax::ast::{self, IntTy, UintTy};
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse;
 use syntax::parse::token::InternedString;
 use syntax::feature_gate::UnstableFeatures;
@@ -1773,8 +1772,9 @@ mod tests {
     use std::path::PathBuf;
     use std::rc::Rc;
     use super::{OutputType, OutputTypes, Externs, PanicStrategy};
-    use syntax::attr;
-    use syntax::attr::AttrMetaMethods;
+    use syntax::{ast, attr};
+    use syntax::parse::token::InternedString;
+    use syntax::codemap::dummy_spanned;
 
     fn optgroups() -> Vec<OptGroup> {
         super::rustc_optgroups().into_iter()
@@ -1803,7 +1803,9 @@ mod tests {
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
         let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
         let cfg = build_configuration(&sess, cfg);
-        assert!((attr::contains_name(&cfg[..], "test")));
+        assert!(attr::contains(&cfg, &dummy_spanned(ast::MetaItemKind::Word({
+            InternedString::new("test")
+        }))));
     }
 
     // When the user supplies --test and --cfg test, don't implicitly add
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 3bdf6acdf9a..8318a29de1c 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -37,7 +37,6 @@ use util::nodemap::{FnvHashMap, FnvHashSet};
 use std::cmp;
 use std::fmt;
 use syntax::ast;
-use syntax::attr::{AttributeMethods, AttrMetaMethods};
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 759dc300372..1ea82a9c639 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -43,7 +43,7 @@ use std::rc::Rc;
 use std::slice;
 use std::vec::IntoIter;
 use syntax::ast::{self, CrateNum, Name, NodeId};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::token::InternedString;
 use syntax_pos::{DUMMY_SP, Span};
 
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index d3d6fa9eb52..a8993724e67 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -27,7 +27,6 @@ use rustc::middle::mem_categorization as mc;
 use std::mem;
 use std::rc::Rc;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::{Span, DUMMY_SP};
 
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index 31380c6f71c..887c7deb86b 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -11,7 +11,6 @@
 use borrowck::BorrowckCtxt;
 
 use syntax::ast::{self, MetaItem};
-use syntax::attr::AttrMetaMethods;
 use syntax::ptr::P;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -43,8 +42,9 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<P<MetaItem
         if attr.check_name("rustc_mir") {
             let items = attr.meta_item_list();
             for item in items.iter().flat_map(|l| l.iter()) {
-                if item.check_name(name) {
-                    return Some(item.clone())
+                match item.meta_item() {
+                    Some(mi) if mi.check_name(name) => return Some(mi.clone()),
+                    _ => continue
                 }
             }
         }
@@ -126,8 +126,6 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              bd: BD) -> DataflowResults<BD>
     where BD: BitDenotation<Idx=MovePathIndex, Ctxt=MoveDataParamEnv<'tcx>> + DataflowOperator
 {
-    use syntax::attr::AttrMetaMethods;
-
     let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
         if let Some(item) = has_rustc_mir_with(attrs, name) {
             if let Some(s) = item.value_str() {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index e8b44d85bf9..07faeee10f1 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -43,7 +43,6 @@ use std::mem;
 use std::rc::Rc;
 use std::hash::{Hash, Hasher};
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::{MultiSpan, Span};
 use errors::DiagnosticBuilder;
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 3f2f6c84da1..c6ab4578f06 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -49,7 +49,7 @@ use std::fs;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use syntax::{ast, diagnostics, visit};
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::{self, PResult, token};
 use syntax::util::node_count::NodeCounter;
 use syntax;
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 4e87c931cc1..efadf1ff488 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -95,7 +95,6 @@ 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};
@@ -655,17 +654,19 @@ impl RustcDefaultCalls {
                         if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
                             continue;
                         }
+
                         if cfg.is_word() {
                             println!("{}", cfg.name());
-                        } else if cfg.is_value_str() {
-                            if let Some(s) = cfg.value_str() {
-                                println!("{}=\"{}\"", cfg.name(), s);
-                            }
+                        } else if let Some(s) = cfg.value_str() {
+                            println!("{}=\"{}\"", cfg.name(), s);
                         } 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`.
-                            panic!("MetaItemKind::List encountered in default cfg")
+                            panic!("Found an unexpected list in cfg attribute '{}'!", cfg.name())
+                        } else {
+                            // There also shouldn't be literals.
+                            panic!("Found an unexpected literal in cfg attribute '{}'!", cfg.name())
                         }
                     }
                 }
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 420c88e89be..8df8f500371 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -56,7 +56,6 @@ use std::env;
 use std::fs::File;
 use std::io::Write;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use syntax_pos::Span;
 
@@ -116,14 +115,18 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
         for attr in self.tcx.get_attrs(def_id).iter() {
             if attr.check_name(IF_THIS_CHANGED) {
                 let mut id = None;
-                for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    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`)
-                        span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node)
+                for list_item in attr.meta_item_list().unwrap_or_default() {
+                    match list_item.word() {
+                        Some(word) if id.is_none() => {
+                            id = Some(word.name().clone())
+                        },
+                        _ => {
+                            // FIXME better-encapsulate meta_item (don't directly access `node`)
+                            span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node)
+                        }
                     }
                 }
+
                 let id = id.unwrap_or(InternedString::new(ID));
                 self.if_this_changed.entry(id)
                                     .or_insert(FnvHashSet())
@@ -131,16 +134,21 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
             } else if attr.check_name(THEN_THIS_WOULD_NEED) {
                 let mut dep_node_interned = None;
                 let mut id = None;
-                for meta_item in attr.meta_item_list().unwrap_or_default() {
-                    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`)
-                        span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node)
+                for list_item in attr.meta_item_list().unwrap_or_default() {
+                    match list_item.word() {
+                        Some(word) if dep_node_interned.is_none() => {
+                            dep_node_interned = Some(word.name().clone());
+                        },
+                        Some(word) if id.is_none() => {
+                            id = Some(word.name().clone())
+                        },
+                        _ => {
+                            // FIXME better-encapsulate meta_item (don't directly access `node`)
+                            span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node)
+                        }
                     }
                 }
+
                 let dep_node = match dep_node_interned {
                     Some(ref n) => {
                         match DepNode::from_label_string(&n[..], def_id) {
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index 42bb1a52467..b14c20ae8d4 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -28,7 +28,6 @@
 //! at the beginning.
 
 use syntax::ast;
-use syntax::attr::AttributeMethods;
 use std::hash::{Hash, SipHasher, Hasher};
 use rustc::dep_graph::DepNode;
 use rustc::hir;
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 65da3a09ecc..fda7ef207a3 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -31,8 +31,7 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::Visitor;
 use rustc_data_structures::fnv::FnvHashSet;
-use syntax::ast::{self, Attribute, MetaItem};
-use syntax::attr::AttrMetaMethods;
+use syntax::ast::{self, Attribute, NestedMetaItem};
 use syntax::parse::token::InternedString;
 use rustc::ty::TyCtxt;
 
@@ -71,13 +70,17 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
-    fn expect_associated_value(&self, item: &MetaItem) -> InternedString {
+    fn expect_associated_value(&self, item: &NestedMetaItem) -> InternedString {
         if let Some(value) = item.value_str() {
             value
         } else {
-            self.tcx.sess.span_fatal(
-                item.span,
-                &format!("associated value expected for `{}`", item.name()));
+            let msg = if let Some(name) = item.name() {
+                format!("associated value expected for `{}`", name)
+            } else {
+                "expected an associated value".to_string()
+            };
+
+            self.tcx.sess.span_fatal(item.span, &msg);
         }
     }
 
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 15914838acf..0e130c3bb66 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -14,7 +14,7 @@ use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
 
 use syntax::ast;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax_pos::Span;
 
 use rustc::hir::{self, PatKind};
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index b4a2648b5dc..a103386e2c9 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -44,8 +44,8 @@ use lint::{LintPass, LateLintPass};
 use std::collections::HashSet;
 
 use syntax::{ast};
-use syntax::attr::{self, AttrMetaMethods, AttributeMethods};
-use syntax_pos::Span;
+use syntax::attr;
+use syntax_pos::{Span};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::FnKind;
@@ -317,7 +317,7 @@ impl LateLintPass for MissingDoc {
         let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
             attr.check_name("doc") && match attr.meta_item_list() {
                 None => false,
-                Some(l) => attr::contains_name(&l[..], "hidden"),
+                Some(l) => attr::list_contains_name(&l[..], "hidden"),
             }
         });
         self.doc_hidden_stack.push(doc_hidden);
@@ -1145,7 +1145,7 @@ impl LintPass for UnstableFeatures {
 
 impl LateLintPass for UnstableFeatures {
     fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
-        if attr::contains_name(&[attr.meta().clone()], "feature") {
+        if attr.meta().check_name("feature") {
             if let Some(items) = attr.meta().meta_item_list() {
                 for item in items {
                     ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 57705301aab..924b768958d 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -18,8 +18,9 @@ use lint::{LintPass, EarlyLintPass, LateLintPass};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
 use syntax::ast;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType};
+use syntax::parse::token::keywords;
 use syntax::ptr::P;
 use syntax_pos::Span;
 
@@ -234,10 +235,13 @@ impl LintPass for UnusedAttributes {
 
 impl LateLintPass for UnusedAttributes {
     fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
+        debug!("checking attribute: {:?}", attr);
+
         // Note that check_name() marks the attribute as used if it matches.
         for &(ref name, ty, _) in KNOWN_ATTRIBUTES {
             match ty {
                 AttributeType::Whitelisted if attr.check_name(name) => {
+                    debug!("{:?} is Whitelisted", name);
                     break;
                 },
                 _ => ()
@@ -247,11 +251,13 @@ impl LateLintPass for UnusedAttributes {
         let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
         for &(ref name, ty) in plugin_attributes.iter() {
             if ty == AttributeType::Whitelisted && attr.check_name(&name) {
+                debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
                 break;
             }
         }
 
         if !attr::is_used(attr) {
+            debug!("Emitting warning for: {:?}", attr);
             cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
             // Is it a builtin attribute that must be used at the crate level?
             let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
@@ -275,6 +281,8 @@ impl LateLintPass for UnusedAttributes {
                 };
                 cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
             }
+        } else {
+            debug!("Attr was used: {:?}", attr);
         }
     }
 }
@@ -392,13 +400,9 @@ impl LateLintPass for UnusedImportBraces {
     fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
         if let hir::ItemUse(ref view_path) = item.node {
             if let hir::ViewPathList(_, ref items) = view_path.node {
-                if items.len() == 1 {
-                    if let hir::PathListIdent {ref name, ..} = items[0].node {
-                        let m = format!("braces around {} is unnecessary",
-                                        name);
-                        cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
-                                     &m[..]);
-                    }
+                if items.len() == 1 && items[0].node.name != keywords::SelfValue.name() {
+                    let msg = format!("braces around {} is unnecessary", items[0].node.name);
+                    cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
                 }
             }
         }
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
index 99a3f3b00c8..85cf41e42a2 100644
--- a/src/librustc_metadata/common.rs
+++ b/src/librustc_metadata/common.rs
@@ -45,26 +45,13 @@ pub const tag_items_closure_kind: usize = 0x2a;
 pub const tag_items_closure_ty: usize = 0x2b;
 pub const tag_def_key: usize = 0x2c;
 
-// GAP 0x2d 0x2e
+// GAP 0x2d 0x34
 
 pub const tag_index: usize = 0x110; // top-level only
 pub const tag_xref_index: usize = 0x111; // top-level only
 pub const tag_xref_data: usize = 0x112; // top-level only
-
-pub const tag_meta_item_name_value: usize = 0x2f;
-
-pub const tag_meta_item_name: usize = 0x30;
-
-pub const tag_meta_item_value: usize = 0x31;
-
 pub const tag_attributes: usize = 0x101; // top-level only
 
-pub const tag_attribute: usize = 0x32;
-
-pub const tag_meta_item_word: usize = 0x33;
-
-pub const tag_meta_item_list: usize = 0x34;
-
 // The list of crates that this crate depends on
 pub const tag_crate_deps: usize = 0x102; // top-level only
 
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 46469efea6b..7e1f3ea618c 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -36,7 +36,6 @@ use syntax::abi::Abi;
 use syntax::codemap;
 use syntax::parse;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use syntax::visit;
 use syntax_pos::{self, Span, mk_sp, Pos};
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index afcd25a79c5..7117cdb731c 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -57,7 +57,6 @@ use syntax::parse::token;
 use syntax::ast;
 use syntax::codemap;
 use syntax::print::pprust;
-use syntax::ptr::P;
 use syntax_pos::{self, Span, BytePos, NO_EXPANSION};
 
 pub type Cmd<'a> = &'a CrateMetadata;
@@ -1113,44 +1112,20 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec<ast::Name> {
     })).collect()
 }
 
-fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
-    reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let n = token::intern_and_get_ident(nd.as_str());
-        attr::mk_word_item(n)
-    }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
-        let n = token::intern_and_get_ident(nd.as_str());
-        let v = token::intern_and_get_ident(vd.as_str());
-        // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants,
-        // but currently the encoder just drops them
-        attr::mk_name_value_item_str(n, v)
-    })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let n = token::intern_and_get_ident(nd.as_str());
-        let subitems = get_meta_items(meta_item_doc);
-        attr::mk_list_item(n, subitems)
-    })).collect()
-}
-
 fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
-    match reader::maybe_get_doc(md, tag_attributes) {
-        Some(attrs_d) => {
-            reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| {
-                let is_sugared_doc = reader::doc_as_u8(
-                    reader::get_doc(attr_doc, tag_attribute_is_sugared_doc)
-                ) == 1;
-                let meta_items = get_meta_items(attr_doc);
-                // Currently it's only possible to have a single meta item on
-                // an attribute
-                assert_eq!(meta_items.len(), 1);
-                let meta_item = meta_items.into_iter().nth(0).unwrap();
-                attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc)
-            }).collect()
-        },
-        None => vec![],
-    }
+    reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| {
+        let mut decoder = reader::Decoder::new(attrs_doc);
+        let mut attrs: Vec<ast::Attribute> = decoder.read_opaque(|opaque_decoder, _| {
+            Decodable::decode(opaque_decoder)
+        }).unwrap();
+
+        // Need new unique IDs: old thread-local IDs won't map to new threads.
+        for attr in attrs.iter_mut() {
+            attr.node.id = attr::mk_attr_id();
+        }
+
+        attrs
+    })
 }
 
 fn list_crate_attributes(md: rbml::Doc, hash: &Svh,
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index f99bdf3b890..b3ac678d712 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -41,7 +41,7 @@ use std::io::{Cursor, SeekFrom};
 use std::rc::Rc;
 use std::u32;
 use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::attr::{self,AttrMetaMethods,AttributeMethods};
+use syntax::attr;
 use errors::Handler;
 use syntax;
 use syntax_pos::BytePos;
@@ -1417,40 +1417,11 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
     rbml_w.end_tag();
 }
 
-fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
-    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.end_tag();
-    } 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);
-        for inner_item in items {
-            encode_meta_item(rbml_w, &inner_item);
-        }
-        rbml_w.end_tag();
-    }
-}
-
 fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
     rbml_w.start_tag(tag_attributes);
-    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.meta());
-        rbml_w.end_tag();
-    }
+    rbml_w.emit_opaque(|opaque_encoder| {
+        attrs.encode(opaque_encoder)
+    }).unwrap();
     rbml_w.end_tag();
 }
 
diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs
index 2cd60f04e69..fa31b6f4c72 100644
--- a/src/librustc_metadata/macro_import.rs
+++ b/src/librustc_metadata/macro_import.rs
@@ -19,7 +19,6 @@ use rustc::util::nodemap::{FnvHashSet, FnvHashMap};
 use syntax::parse::token;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::ext;
 use syntax_pos::Span;
 
@@ -64,8 +63,8 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
                     }
                     if let (Some(sel), Some(names)) = (import.as_mut(), names) {
                         for attr in names {
-                            if attr.is_word() {
-                                sel.insert(attr.name().clone(), attr.span());
+                            if let Some(word) = attr.word() {
+                                sel.insert(word.name().clone(), attr.span());
                             } else {
                                 span_err!(self.sess, attr.span(), E0466, "bad macro import");
                             }
@@ -82,8 +81,8 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> {
                     };
 
                     for attr in names {
-                        if attr.is_word() {
-                            reexport.insert(attr.name().clone(), attr.span());
+                        if let Some(word) = attr.word() {
+                            reexport.insert(word.name().clone(), attr.span());
                         } else {
                             call_bad_macro_reexport(self.sess, attr.span());
                         }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index a38b429333b..1767630b81b 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -32,7 +32,6 @@ use rustc::ty::{self, Ty, TyCtxt};
 use syntax::parse::token;
 use rustc::hir;
 use rustc_const_math::{ConstInt, ConstUsize};
-use syntax::attr::AttrMetaMethods;
 
 #[derive(Copy, Clone)]
 pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 46124d0f973..dde1a4a7595 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -20,6 +20,7 @@ use rustc::lint;
 use rustc::session::Session;
 use syntax::ast::*;
 use syntax::attr;
+use syntax::codemap::Spanned;
 use syntax::parse::token::{self, keywords};
 use syntax::visit::{self, Visitor};
 use syntax_pos::Span;
@@ -69,6 +70,18 @@ impl<'a> AstValidator<'a> {
             }
         }
     }
+
+    fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
+        match constness.node {
+            Constness::Const => {
+                struct_span_err!(self.session, constness.span, E0379,
+                                 "trait fns cannot be declared const")
+                    .span_label(constness.span, &format!("trait fns cannot be const"))
+                    .emit();
+            }
+            _ => {}
+        }
+    }
 }
 
 impl<'a> Visitor for AstValidator<'a> {
@@ -146,6 +159,9 @@ impl<'a> Visitor for AstValidator<'a> {
                 self.invalid_visibility(&item.vis, item.span, None);
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, impl_item.span, None);
+                    if let ImplItemKind::Method(ref sig, _) = impl_item.node {
+                        self.check_trait_fn_not_const(sig.constness);
+                    }
                 }
             }
             ItemKind::Impl(_, _, _, None, _, _) => {
@@ -169,6 +185,13 @@ impl<'a> Visitor for AstValidator<'a> {
                     }
                 }
             }
+            ItemKind::Trait(_, _, _, ref trait_items) => {
+                for trait_item in trait_items {
+                    if let TraitItemKind::Method(ref sig, _) = trait_item.node {
+                        self.check_trait_fn_not_const(sig.constness);
+                    }
+                }
+            }
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
                 attr::first_attr_value_str_by_name(&item.attrs, "path");
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 4aae6d690c4..2d1b6e1315f 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -147,7 +147,8 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         }
 
         let mode = match fk {
-            FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => Mode::ConstFn,
+            FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _)
+                => Mode::ConstFn,
             FnKind::Method(_, m, _, _) => {
                 if m.constness == hir::Constness::Const {
                     Mode::ConstFn
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index 7049040678e..89b8aa81411 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -176,6 +176,13 @@ fn some_func() {
 ```
 "##,
 
+E0379: r##"
+Trait methods cannot be declared `const` by design. For more information, see
+[RFC 911].
+
+[RFC 911]: https://github.com/rust-lang/rfcs/pull/911
+"##,
+
 E0449: r##"
 A visibility qualifier was used when it was unnecessary. Erroneous code
 examples:
diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs
index fb68eae9647..9e56397bc99 100644
--- a/src/librustc_plugin/load.rs
+++ b/src/librustc_plugin/load.rs
@@ -20,8 +20,6 @@ use std::env;
 use std::mem;
 use std::path::PathBuf;
 use syntax::ast;
-use syntax::ptr::P;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::{Span, COMMAND_LINE_SP};
 
 /// Pointer to a registrar function.
@@ -30,7 +28,7 @@ pub type PluginRegistrarFun =
 
 pub struct PluginRegistrar {
     pub fun: PluginRegistrarFun,
-    pub args: Vec<P<ast::MetaItem>>,
+    pub args: Vec<ast::NestedMetaItem>,
 }
 
 struct PluginLoader<'a> {
@@ -69,13 +67,14 @@ pub fn load_plugins(sess: &Session,
             };
 
             for plugin in plugins {
-                if plugin.value_str().is_some() {
-                    call_malformed_plugin_attribute(sess, attr.span);
-                    continue;
+                // plugins must have a name and can't be key = value
+                match plugin.name() {
+                    Some(ref name) if !plugin.is_value_str() => {
+                        let args = plugin.meta_item_list().map(ToOwned::to_owned);
+                        loader.load_plugin(plugin.span, name, args.unwrap_or_default());
+                    },
+                    _ => call_malformed_plugin_attribute(sess, attr.span),
                 }
-
-                let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
-                loader.load_plugin(plugin.span, &plugin.name(), args);
             }
         }
     }
@@ -102,7 +101,7 @@ impl<'a> PluginLoader<'a> {
         }
     }
 
-    fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
+    fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
         let registrar = self.reader.find_plugin_registrar(span, name);
 
         if let Some((lib, svh, index)) = registrar {
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 54fa0197de4..5ae6584aed4 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -19,7 +19,6 @@ use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
 use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
 use syntax::ext::base::{MacroExpanderFn, MacroRulesTT};
 use syntax::parse::token;
-use syntax::ptr::P;
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
 use syntax_pos::Span;
@@ -41,7 +40,7 @@ pub struct Registry<'a> {
     pub sess: &'a Session,
 
     #[doc(hidden)]
-    pub args_hidden: Option<Vec<P<ast::MetaItem>>>,
+    pub args_hidden: Option<Vec<ast::NestedMetaItem>>,
 
     #[doc(hidden)]
     pub krate_span: Span,
@@ -95,7 +94,7 @@ impl<'a> Registry<'a> {
     ///
     /// Returns empty slice in case the plugin was loaded
     /// with `--extra-plugins`
-    pub fn args<'b>(&'b self) -> &'b [P<ast::MetaItem>] {
+    pub fn args<'b>(&'b self) -> &'b [ast::NestedMetaItem] {
         self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[])
     }
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 57985344652..71b00218e7c 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -32,9 +32,9 @@ use syntax::parse::token;
 
 use syntax::ast::{Block, Crate};
 use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind};
-use syntax::ast::{Mutability, PathListItemKind};
-use syntax::ast::{StmtKind, TraitItemKind};
+use syntax::ast::{Mutability, StmtKind, TraitItemKind};
 use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
+use syntax::parse::token::keywords;
 use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
@@ -130,9 +130,10 @@ impl<'b> Resolver<'b> {
                     ViewPathList(_, ref source_items) => {
                         // Make sure there's at most one `mod` import in the list.
                         let mod_spans = source_items.iter().filter_map(|item| {
-                            match item.node {
-                                PathListItemKind::Mod { .. } => Some(item.span),
-                                _ => None,
+                            if item.node.name.name == keywords::SelfValue.name() {
+                                Some(item.span)
+                            } else {
+                                None
                             }
                         }).collect::<Vec<Span>>();
 
@@ -147,10 +148,12 @@ impl<'b> Resolver<'b> {
                         }
 
                         for source_item in source_items {
-                            let (module_path, name, rename) = match source_item.node {
-                                PathListItemKind::Ident { name, rename, .. } =>
-                                    (module_path.clone(), name.name, rename.unwrap_or(name).name),
-                                PathListItemKind::Mod { rename, .. } => {
+                            let node = source_item.node;
+                            let (module_path, name, rename) = {
+                                if node.name.name != keywords::SelfValue.name() {
+                                    let rename = node.rename.unwrap_or(node.name).name;
+                                    (module_path.clone(), node.name.name, rename)
+                                } else {
                                     let name = match module_path.last() {
                                         Some(name) => *name,
                                         None => {
@@ -164,12 +167,12 @@ impl<'b> Resolver<'b> {
                                         }
                                     };
                                     let module_path = module_path.split_last().unwrap().1;
-                                    let rename = rename.map(|i| i.name).unwrap_or(name);
+                                    let rename = node.rename.map(|i| i.name).unwrap_or(name);
                                     (module_path.to_vec(), name, rename)
                                 }
                             };
                             let subclass = ImportDirectiveSubclass::single(rename, name);
-                            let (span, id) = (source_item.span, source_item.node.id());
+                            let (span, id) = (source_item.span, source_item.node.id);
                             self.add_import_directive(module_path, subclass, span, id, vis);
                         }
                     }
@@ -272,6 +275,8 @@ impl<'b> Resolver<'b> {
                 self.structs.insert(item_def_id, field_names);
             }
 
+            ItemKind::Union(..) => panic!("`union` is not yet implemented"),
+
             ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
 
             ItemKind::Trait(_, _, _, ref items) => {
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 3084d9abbe1..bc923ba29ca 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -101,7 +101,7 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> {
 
                     ViewPathList(_, ref list) => {
                         for i in list {
-                            self.check_import(i.node.id(), i.span);
+                            self.check_import(i.node.id, i.span);
                         }
                     }
                     ViewPathGlob(_) => {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 6a4a48377c7..bd97df764a7 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1618,6 +1618,7 @@ impl<'a> Resolver<'a> {
             ItemKind::Enum(_, ref generics) |
             ItemKind::Ty(_, ref generics) |
             ItemKind::Struct(_, ref generics) |
+            ItemKind::Union(_, ref generics) |
             ItemKind::Fn(_, _, _, _, ref generics, _) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
                                              |this| visit::walk_item(this, item));
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 5e967f3250f..dbe956f021e 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1102,18 +1102,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                     }
                     ast::ViewPathList(ref path, ref list) => {
                         for plid in list {
-                            match plid.node {
-                                ast::PathListItemKind::Ident { id, .. } => {
-                                    let scope = self.cur_scope;
-                                    if let Some(def_id) = self.lookup_type_ref(id) {
-                                        self.process_def_kind(id,
-                                                              plid.span,
-                                                              Some(plid.span),
-                                                              def_id,
-                                                              scope);
-                                    }
-                                }
-                                ast::PathListItemKind::Mod { .. } => (),
+                            let scope = self.cur_scope;
+                            let id = plid.node.id;
+                            if let Some(def_id) = self.lookup_type_ref(id) {
+                                let span = plid.span;
+                                self.process_def_kind(id, span, Some(span), def_id, scope);
                             }
                         }
 
diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs
index e0532e7476f..7fe6d2bbfe2 100644
--- a/src/librustc_trans/assert_module_sources.rs
+++ b/src/librustc_trans/assert_module_sources.rs
@@ -29,7 +29,6 @@
 
 use rustc::ty::TyCtxt;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 
 use {ModuleSource, ModuleTranslation};
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 9f401b13d6f..b21785c27da 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -42,7 +42,6 @@ use std::process::Command;
 use std::str;
 use flate;
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::Span;
 
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index a183fc0858a..fa10adf6c11 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -92,7 +92,6 @@ use std::rc::Rc;
 use std::str;
 use std::i32;
 use syntax_pos::{Span, DUMMY_SP};
-use syntax::attr::AttrMetaMethods;
 use syntax::attr;
 use rustc::hir;
 use syntax::ast;
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index fa1e008d496..2b6e2a23261 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -29,7 +29,7 @@ use rustc::hir;
 
 use std::ffi::{CStr, CString};
 use syntax::ast;
-use syntax::attr::{self, AttrMetaMethods};
+use syntax::attr;
 use syntax::parse::token;
 
 pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
index 9a7fe54e0d9..25c30151ad4 100644
--- a/src/librustc_trans/symbol_names_test.rs
+++ b/src/librustc_trans/symbol_names_test.rs
@@ -17,7 +17,6 @@
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor};
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 
 use common::SharedCrateContext;
 use monomorphize::Instance;
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 79b6ae0c83f..bde7f20f5e6 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -52,7 +52,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let i_n_tps = i_ty.generics.types.len();
     if i_n_tps != n_tps {
         let span = match it.node {
-            hir::ForeignItemFn(_, ref generics) => generics.span().unwrap_or(it.span),
+            hir::ForeignItemFn(_, ref generics) => generics.span,
             hir::ForeignItemStatic(_, _) => it.span
         };
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fb24971c425..8f2dc427266 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -112,7 +112,6 @@ use std::ops::Deref;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{self, Spanned};
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::parse::token::{self, InternedString, keywords};
@@ -835,13 +834,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                     check_const(ccx, &expr, trait_item.id)
                 }
                 hir::MethodTraitItem(ref sig, Some(ref body)) => {
-                    check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
-
                     check_bare_fn(ccx, &sig.decl, body, trait_item.id);
                 }
-                hir::MethodTraitItem(ref sig, None) => {
-                    check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
-                }
+                hir::MethodTraitItem(_, None) |
                 hir::ConstTraitItem(_, None) |
                 hir::TypeTraitItem(..) => {
                     // Nothing to do.
@@ -853,22 +848,6 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     }
 }
 
-fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     span: Span,
-                                     constness: hir::Constness)
-{
-    match constness {
-        hir::Constness::NotConst => {
-            // good
-        }
-        hir::Constness::Const => {
-            struct_span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const")
-                .span_label(span, &format!("trait fns cannot be const"))
-                .emit()
-        }
-    }
-}
-
 fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     def_id: DefId,
                                     item: &hir::Item) {
@@ -1026,9 +1005,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                          err.emit()
                     }
                 }
-                hir::ImplItemKind::Method(ref sig, ref body) => {
-                    check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
-
+                hir::ImplItemKind::Method(_, ref body) => {
                     let impl_method = match ty_impl_item {
                         ty::MethodTraitItem(ref mti) => mti,
                         _ => span_bug!(impl_item.span, "non-method impl-item for method")
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 2ee0927f3c8..f66f15b238e 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -49,7 +49,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
                 }
                 hir::ViewPathList(_, ref path_list) => {
                     for path_item in path_list {
-                        self.check_import(path_item.node.id(), path_item.span);
+                        self.check_import(path_item.node.id, path_item.span);
                     }
                 }
             }
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 8bb5efdcad2..3f1374db369 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3422,13 +3422,6 @@ containing the unsized type is the last and only unsized type field in the
 struct.
 "##,
 
-E0379: r##"
-Trait methods cannot be declared `const` by design. For more information, see
-[RFC 911].
-
-[RFC 911]: https://github.com/rust-lang/rfcs/pull/911
-"##,
-
 E0380: r##"
 Default impls are only allowed for traits with no methods or associated items.
 For more information see the [opt-in builtin traits RFC](https://github.com/rust
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 2a989105c9c..a5445b18e77 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -216,10 +216,10 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
                         hir::ItemFn(_, _, _, _, ref generics, _) => {
-                            if let Some(gen_span) = generics.span() {
-                                struct_span_err!(ccx.tcx.sess, gen_span, E0131,
+                            if generics.is_parameterized() {
+                                struct_span_err!(ccx.tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
-                                    .span_label(gen_span,
+                                    .span_label(generics.span,
                                                 &format!("main cannot have type parameters"))
                                     .emit();
                                 return;
@@ -269,10 +269,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                     match it.node {
                         hir::ItemFn(_,_,_,_,ref ps,_)
                         if ps.is_parameterized() => {
-                            let sp = if let Some(sp) = ps.span() { sp } else { start_span };
-                            struct_span_err!(tcx.sess, sp, E0132,
+                            struct_span_err!(tcx.sess, ps.span, E0132,
                                 "start function is not allowed to have type parameters")
-                                .span_label(sp,
+                                .span_label(ps.span,
                                             &format!("start function cannot have type parameters"))
                                 .emit();
                             return;
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index cd425b7c9eb..0af3973f78d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -26,10 +26,10 @@ pub use self::Visibility::*;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::{AttributeMethods, AttrMetaMethods};
 use syntax::codemap::Spanned;
-use syntax::parse::token::{self, InternedString, keywords};
+use syntax::parse::token::keywords;
 use syntax::ptr::P;
+use syntax::print::pprust as syntax_pprust;
 use syntax_pos::{self, DUMMY_SP, Pos};
 
 use rustc_trans::back::link;
@@ -501,11 +501,24 @@ impl Attributes for [Attribute] {
     }
 }
 
+/// This is a flattened version of the AST's Attribute + MetaItem.
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub enum Attribute {
     Word(String),
     List(String, Vec<Attribute>),
-    NameValue(String, String)
+    NameValue(String, String),
+    Literal(String),
+}
+
+impl Clean<Attribute> for ast::NestedMetaItem {
+    fn clean(&self, cx: &DocContext) -> Attribute {
+        if let Some(mi) = self.meta_item() {
+            mi.clean(cx)
+        } else { // must be a literal
+            let lit = self.literal().unwrap();
+            Literal(syntax_pprust::lit_to_string(lit))
+        }
+    }
 }
 
 impl Clean<Attribute> for ast::MetaItem {
@@ -527,50 +540,6 @@ impl Clean<Attribute> for ast::Attribute {
     }
 }
 
-// This is a rough approximation that gets us what we want.
-impl attr::AttrMetaMethods for Attribute {
-    fn name(&self) -> InternedString {
-        match *self {
-            Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
-                token::intern_and_get_ident(n)
-            }
-        }
-    }
-
-    fn value_str(&self) -> Option<InternedString> {
-        match *self {
-            NameValue(_, ref v) => {
-                Some(token::intern_and_get_ident(v))
-            }
-            _ => None,
-        }
-    }
-    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!() }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct TyParam {
     pub name: String,
@@ -2534,8 +2503,8 @@ impl Clean<Vec<Item>> for doctree::Import {
         // Don't inline doc(hidden) imports so they can be stripped at a later stage.
         let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
             &a.name()[..] == "doc" && match a.meta_item_list() {
-                Some(l) => attr::contains_name(l, "no_inline") ||
-                           attr::contains_name(l, "hidden"),
+                Some(l) => attr::list_contains_name(l, "no_inline") ||
+                           attr::list_contains_name(l, "hidden"),
                 None => false,
             }
         });
@@ -2551,7 +2520,7 @@ impl Clean<Vec<Item>> for doctree::Import {
                 let remaining = if !denied {
                     let mut remaining = vec![];
                     for path in list {
-                        match inline::try_inline(cx, path.node.id(), path.node.rename()) {
+                        match inline::try_inline(cx, path.node.id, path.node.rename) {
                             Some(items) => {
                                 ret.extend(items);
                             }
@@ -2619,17 +2588,10 @@ pub struct ViewListIdent {
 
 impl Clean<ViewListIdent> for hir::PathListItem {
     fn clean(&self, cx: &DocContext) -> ViewListIdent {
-        match self.node {
-            hir::PathListIdent { id, name, rename } => ViewListIdent {
-                name: name.clean(cx),
-                rename: rename.map(|r| r.clean(cx)),
-                source: resolve_def(cx, id)
-            },
-            hir::PathListMod { id, rename } => ViewListIdent {
-                name: "self".to_string(),
-                rename: rename.map(|r| r.clean(cx)),
-                source: resolve_def(cx, id)
-            }
+        ViewListIdent {
+            name: self.node.name.clean(cx),
+            rename: self.node.rename.map(|r| r.clean(cx)),
+            source: resolve_def(cx, self.node.id)
         }
     }
 }
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index e7edf8d1cab..beed1dc9f9e 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -140,7 +140,6 @@ pub fn run(input: &str,
 
 // Look for #![doc(test(no_crate_inject))], used by crates in the std facade
 fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
-    use syntax::attr::AttrMetaMethods;
     use syntax::print::pprust;
 
     let mut opts = TestOptions {
@@ -162,7 +161,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
         if attr.check_name("attr") {
             if let Some(l) = attr.meta_item_list() {
                 for item in l {
-                    opts.attrs.push(pprust::meta_item_to_string(item));
+                    opts.attrs.push(pprust::meta_list_item_to_string(item));
                 }
             }
         }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index f6084180f0b..6af36e24d81 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -16,7 +16,6 @@ use std::mem;
 use syntax::abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax_pos::Span;
 
 use rustc::hir::map as hir_map;
@@ -189,7 +188,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
             hir::ViewPathList(p, paths) => {
                 let mine = paths.into_iter().filter(|path| {
-                    !self.maybe_inline_local(path.node.id(), path.node.rename(),
+                    !self.maybe_inline_local(path.node.id, path.node.rename,
                                              false, om, please_inline)
                 }).collect::<hir::HirVec<hir::PathListItem>>();
 
@@ -333,8 +332,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 let node = if item.vis == hir::Public {
                     let please_inline = item.attrs.iter().any(|item| {
                         match item.meta_item_list() {
-                            Some(list) if &item.name()[..] == "doc" => {
-                                list.iter().any(|i| &i.name()[..] == "inline")
+                            Some(list) if item.check_name("doc") => {
+                                list.iter().any(|i| i.check_name("inline"))
                             }
                             _ => false,
                         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index f8a5cb0b04a..fcb99444957 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -336,7 +336,7 @@ pub struct TyParam {
     pub id: NodeId,
     pub bounds: TyParamBounds,
     pub default: Option<P<Ty>>,
-    pub span: Span
+    pub span: Span,
 }
 
 /// Represents lifetimes and type parameters attached to a declaration
@@ -346,6 +346,7 @@ pub struct Generics {
     pub lifetimes: Vec<LifetimeDef>,
     pub ty_params: P<[TyParam]>,
     pub where_clause: WhereClause,
+    pub span: Span,
 }
 
 impl Generics {
@@ -368,7 +369,8 @@ impl Default for Generics {
             where_clause: WhereClause {
                 id: DUMMY_NODE_ID,
                 predicates: Vec::new(),
-            }
+            },
+            span: DUMMY_SP,
         }
     }
 }
@@ -439,6 +441,22 @@ pub struct Crate {
     pub exported_macros: Vec<MacroDef>,
 }
 
+/// A spanned compile-time attribute list item.
+pub type NestedMetaItem = Spanned<NestedMetaItemKind>;
+
+/// Possible values inside of compile-time attribute lists.
+///
+/// E.g. the '..' in `#[name(..)]`.
+#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug, PartialEq)]
+pub enum NestedMetaItemKind {
+    /// A full MetaItem, for recursive meta items.
+    MetaItem(P<MetaItem>),
+    /// A literal.
+    ///
+    /// E.g. "foo", 64, true
+    Literal(Lit),
+}
+
 /// A spanned compile-time attribute item.
 ///
 /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
@@ -456,7 +474,7 @@ pub enum MetaItemKind {
     /// List meta item.
     ///
     /// E.g. `derive(..)` as in `#[derive(..)]`
-    List(InternedString, Vec<P<MetaItem>>),
+    List(InternedString, Vec<NestedMetaItem>),
     /// Name value meta item.
     ///
     /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
@@ -472,19 +490,21 @@ impl PartialEq for MetaItemKind {
                 Word(ref no) => (*ns) == (*no),
                 _ => false
             },
+            List(ref ns, ref miss) => match *other {
+                List(ref no, ref miso) => {
+                    ns == no &&
+                        miss.iter().all(|mi| {
+                            miso.iter().any(|x| x.node == mi.node)
+                        })
+                }
+                _ => false
+            },
             NameValue(ref ns, ref vs) => match *other {
                 NameValue(ref no, ref vo) => {
                     (*ns) == (*no) && vs.node == vo.node
                 }
                 _ => false
             },
-            List(ref ns, ref miss) => match *other {
-                List(ref no, ref miso) => {
-                    ns == no &&
-                        miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node))
-                }
-                _ => false
-            }
         }
     }
 }
@@ -1105,6 +1125,30 @@ impl LitKind {
             _ => false,
         }
     }
+
+    /// Returns true if this literal has no suffix. Note: this will return true
+    /// for literals with prefixes such as raw strings and byte strings.
+    pub fn is_unsuffixed(&self) -> bool {
+        match *self {
+            // unsuffixed variants
+            LitKind::Str(..) => true,
+            LitKind::ByteStr(..) => true,
+            LitKind::Byte(..) => true,
+            LitKind::Char(..) => true,
+            LitKind::Int(_, LitIntType::Unsuffixed) => true,
+            LitKind::FloatUnsuffixed(..) => true,
+            LitKind::Bool(..) => true,
+            // suffixed variants
+            LitKind::Int(_, LitIntType::Signed(..)) => false,
+            LitKind::Int(_, LitIntType::Unsigned(..)) => false,
+            LitKind::Float(..) => false,
+        }
+    }
+
+    /// Returns true if this literal has a suffix.
+    pub fn is_suffixed(&self) -> bool {
+        !self.is_unsuffixed()
+    }
 }
 
 // NB: If you change this, you'll probably want to change the corresponding
@@ -1120,7 +1164,7 @@ pub struct MutTy {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct MethodSig {
     pub unsafety: Unsafety,
-    pub constness: Constness,
+    pub constness: Spanned<Constness>,
     pub abi: Abi,
     pub decl: P<FnDecl>,
     pub generics: Generics,
@@ -1624,42 +1668,14 @@ pub struct Variant_ {
 pub type Variant = Spanned<Variant_>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum PathListItemKind {
-    Ident {
-        name: Ident,
-        /// renamed in list, e.g. `use foo::{bar as baz};`
-        rename: Option<Ident>,
-        id: NodeId
-    },
-    Mod {
-        /// renamed in list, e.g. `use foo::{self as baz};`
-        rename: Option<Ident>,
-        id: NodeId
-    }
-}
-
-impl PathListItemKind {
-    pub fn id(&self) -> NodeId {
-        match *self {
-            PathListItemKind::Ident { id, .. } | PathListItemKind::Mod { id, .. } => id
-        }
-    }
-
-    pub fn name(&self) -> Option<Ident> {
-        match *self {
-            PathListItemKind::Ident { name, .. } => Some(name),
-            PathListItemKind::Mod { .. } => None,
-        }
-    }
-
-    pub fn rename(&self) -> Option<Ident> {
-        match *self {
-            PathListItemKind::Ident { rename, .. } | PathListItemKind::Mod { rename, .. } => rename
-        }
-    }
+pub struct PathListItem_ {
+    pub name: Ident,
+    /// renamed in list, e.g. `use foo::{bar as baz};`
+    pub rename: Option<Ident>,
+    pub id: NodeId,
 }
 
-pub type PathListItem = Spanned<PathListItemKind>;
+pub type PathListItem = Spanned<PathListItem_>;
 
 pub type ViewPath = Spanned<ViewPath_>;
 
@@ -1846,7 +1862,7 @@ pub enum ItemKind {
     /// A function declaration (`fn` or `pub fn`).
     ///
     /// E.g. `fn foo(bar: usize) -> usize { .. }`
-    Fn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>),
+    Fn(P<FnDecl>, Unsafety, Spanned<Constness>, Abi, Generics, P<Block>),
     /// A module declaration (`mod` or `pub mod`).
     ///
     /// E.g. `mod foo;` or `mod foo { .. }`
@@ -1867,6 +1883,10 @@ pub enum ItemKind {
     ///
     /// E.g. `struct Foo<A> { x: A }`
     Struct(VariantData, Generics),
+    /// A union definition (`union` or `pub union`).
+    ///
+    /// E.g. `union Foo<A, B> { x: A, y: B }`
+    Union(VariantData, Generics), // FIXME: not yet implemented
     /// A Trait declaration (`trait` or `pub trait`).
     ///
     /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }`
@@ -1903,6 +1923,7 @@ impl ItemKind {
             ItemKind::Ty(..) => "type alias",
             ItemKind::Enum(..) => "enum",
             ItemKind::Struct(..) => "struct",
+            ItemKind::Union(..) => "union",
             ItemKind::Trait(..) => "trait",
             ItemKind::Mac(..) |
             ItemKind::Impl(..) |
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index b622f6861b3..6060ff529f2 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -15,9 +15,10 @@ pub use self::ReprAttr::*;
 pub use self::IntType::*;
 
 use ast;
-use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind};
-use ast::{Expr, Item, Local, Stmt, StmtKind};
-use codemap::{respan, spanned, dummy_spanned, Spanned};
+use ast::{AttrId, Attribute, Attribute_};
+use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
+use ast::{Lit, Expr, Item, Local, Stmt, StmtKind};
+use codemap::{respan, spanned, dummy_spanned};
 use syntax_pos::{Span, BytePos, DUMMY_SP};
 use errors::Handler;
 use feature_gate::{Features, GatedCfg};
@@ -40,6 +41,7 @@ enum AttrError {
     MissingSince,
     MissingFeature,
     MultipleStabilityLevels,
+    UnsupportedLiteral
 }
 
 fn handle_errors(diag: &Handler, span: Span, error: AttrError) {
@@ -52,10 +54,12 @@ fn handle_errors(diag: &Handler, span: Span, error: AttrError) {
         AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"),
         AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544,
                                                         "multiple stability levels"),
+        AttrError::UnsupportedLiteral => span_err!(diag, span, E0565, "unsupported literal"),
     }
 }
 
 pub fn mark_used(attr: &Attribute) {
+    debug!("Marking {:?} as used.", attr);
     let AttrId(id) = attr.node.id;
     USED_ATTRS.with(|slot| {
         let idx = (id / 64) as usize;
@@ -77,60 +81,120 @@ pub fn is_used(attr: &Attribute) -> bool {
     })
 }
 
-pub trait AttrMetaMethods {
-    fn check_name(&self, name: &str) -> bool {
-        name == &self.name()[..]
+impl NestedMetaItem {
+    /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
+    pub fn meta_item(&self) -> Option<&P<MetaItem>> {
+        match self.node {
+            NestedMetaItemKind::MetaItem(ref item) => Some(&item),
+            _ => None
+        }
+    }
+
+    /// Returns the Lit if self is a NestedMetaItemKind::Literal.
+    pub fn literal(&self) -> Option<&Lit> {
+        match self.node {
+            NestedMetaItemKind::Literal(ref lit) => Some(&lit),
+            _ => None
+        }
     }
 
-    /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`,
-    /// `#[foo="bar"]` and `#[foo(bar)]`
-    fn name(&self) -> InternedString;
+    /// Returns the Span for `self`.
+    pub fn span(&self) -> Span {
+        self.span
+    }
+
+    /// Returns true if this list item is a MetaItem with a name of `name`.
+    pub fn check_name(&self, name: &str) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
+    }
+
+    /// Returns the name of the meta item, e.g. `foo` in `#[foo]`,
+    /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
+    pub fn name(&self) -> Option<InternedString> {
+        self.meta_item().and_then(|meta_item| Some(meta_item.name()))
+    }
+
+    /// Gets the string value if self is a MetaItem and the MetaItem is a
+    /// MetaItemKind::NameValue variant containing a string, otherwise None.
+    pub fn value_str(&self) -> Option<InternedString> {
+        self.meta_item().and_then(|meta_item| meta_item.value_str())
+    }
+
+    /// Returns a MetaItem if self is a MetaItem with Kind Word.
+    pub fn word(&self) -> Option<&P<MetaItem>> {
+        self.meta_item().and_then(|meta_item| if meta_item.is_word() {
+            Some(meta_item)
+        } else {
+            None
+        })
+    }
 
-    /// Gets the string value if self is a MetaItemKind::NameValue variant
-    /// containing a string, otherwise None.
-    fn value_str(&self) -> Option<InternedString>;
     /// Gets a list of inner meta items from a list MetaItem type.
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]>;
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+        self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
+    }
 
-    /// Indicates if the attribute is a Word.
-    fn is_word(&self) -> bool;
+    /// Returns `true` if the variant is MetaItem.
+    pub fn is_meta_item(&self) -> bool {
+        self.meta_item().is_some()
+    }
 
-    /// Indicates if the attribute is a Value String.
-    fn is_value_str(&self) -> bool {
+    /// Returns `true` if the variant is Literal.
+    pub fn is_literal(&self) -> bool {
+        self.literal().is_some()
+    }
+
+    /// Returns `true` if self is a MetaItem and the meta item is a word.
+    pub fn is_word(&self) -> bool {
+        self.word().is_some()
+    }
+
+    /// Returns `true` if self is a MetaItem and the meta item is a ValueString.
+    pub fn is_value_str(&self) -> bool {
         self.value_str().is_some()
     }
 
-    /// Indicates if the attribute is a Meta-Item List.
-    fn is_meta_item_list(&self) -> bool {
+    /// Returns `true` if self is a MetaItem and the meta item is a list.
+    pub fn is_meta_item_list(&self) -> bool {
         self.meta_item_list().is_some()
     }
-
-    fn span(&self) -> Span;
 }
 
-impl AttrMetaMethods for Attribute {
-    fn check_name(&self, name: &str) -> bool {
+impl Attribute {
+    pub fn check_name(&self, name: &str) -> bool {
         let matches = name == &self.name()[..];
         if matches {
             mark_used(self);
         }
         matches
     }
-    fn name(&self) -> InternedString { self.meta().name() }
-    fn value_str(&self) -> Option<InternedString> {
+
+    pub fn name(&self) -> InternedString { self.meta().name() }
+
+    pub fn value_str(&self) -> Option<InternedString> {
         self.meta().value_str()
     }
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
+
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
         self.meta().meta_item_list()
     }
 
-    fn is_word(&self) -> bool { self.meta().is_word() }
+    pub fn is_word(&self) -> bool { self.meta().is_word() }
+
+    pub fn span(&self) -> Span { self.meta().span }
+
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
 
-    fn span(&self) -> Span { self.meta().span }
+    /// Indicates if the attribute is a Value String.
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
 }
 
-impl AttrMetaMethods for MetaItem {
-    fn name(&self) -> InternedString {
+impl MetaItem {
+    pub fn name(&self) -> InternedString {
         match self.node {
             MetaItemKind::Word(ref n) => (*n).clone(),
             MetaItemKind::NameValue(ref n, _) => (*n).clone(),
@@ -138,7 +202,7 @@ impl AttrMetaMethods for MetaItem {
         }
     }
 
-    fn value_str(&self) -> Option<InternedString> {
+    pub fn value_str(&self) -> Option<InternedString> {
         match self.node {
             MetaItemKind::NameValue(_, ref v) => {
                 match v.node {
@@ -150,53 +214,45 @@ impl AttrMetaMethods for MetaItem {
         }
     }
 
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
         match self.node {
             MetaItemKind::List(_, ref l) => Some(&l[..]),
             _ => None
         }
     }
 
-    fn is_word(&self) -> bool {
+    pub fn is_word(&self) -> bool {
         match self.node {
             MetaItemKind::Word(_) => true,
             _ => false,
         }
     }
 
-    fn span(&self) -> Span { self.span }
-}
+    pub fn span(&self) -> Span { self.span }
 
-// Annoying, but required to get test_cfg to work
-impl AttrMetaMethods for P<MetaItem> {
-    fn name(&self) -> InternedString { (**self).name() }
-    fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
-    fn meta_item_list(&self) -> Option<&[P<MetaItem>]> {
-        (**self).meta_item_list()
+    pub fn check_name(&self, name: &str) -> bool {
+        name == &self.name()[..]
     }
-    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() }
-}
 
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
 
-pub trait AttributeMethods {
-    fn meta(&self) -> &MetaItem;
-    fn with_desugared_doc<T, F>(&self, f: F) -> T where
-        F: FnOnce(&Attribute) -> T;
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
 }
 
-impl AttributeMethods for Attribute {
+impl Attribute {
     /// Extract the MetaItem from inside this Attribute.
-    fn meta(&self) -> &MetaItem {
+    pub fn meta(&self) -> &MetaItem {
         &self.node.value
     }
 
     /// Convert self to a normal #[doc="foo"] comment, if it is a
     /// comment like `///` or `/** */`. (Returns self unchanged for
     /// non-sugared doc attributes.)
-    fn with_desugared_doc<T, F>(&self, f: F) -> T where
+    pub fn with_desugared_doc<T, F>(&self, f: F) -> T where
         F: FnOnce(&Attribute) -> T,
     {
         if self.node.is_sugared_doc {
@@ -229,10 +285,14 @@ pub fn mk_name_value_item(name: InternedString, value: ast::Lit)
     mk_spanned_name_value_item(DUMMY_SP, name, value)
 }
 
-pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> {
+pub fn mk_list_item(name: InternedString, items: Vec<NestedMetaItem>) -> P<MetaItem> {
     mk_spanned_list_item(DUMMY_SP, name, items)
 }
 
+pub fn mk_list_word_item(name: InternedString) -> ast::NestedMetaItem {
+    dummy_spanned(NestedMetaItemKind::MetaItem(mk_spanned_word_item(DUMMY_SP, name)))
+}
+
 pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
     mk_spanned_word_item(DUMMY_SP, name)
 }
@@ -242,7 +302,7 @@ pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Li
     P(respan(sp, MetaItemKind::NameValue(name, value)))
 }
 
-pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<P<MetaItem>>)
+pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<NestedMetaItem>)
                             -> P<MetaItem> {
     P(respan(sp, MetaItemKind::List(name, items)))
 }
@@ -332,9 +392,17 @@ pub fn contains(haystack: &[P<MetaItem>], needle: &MetaItem) -> bool {
     })
 }
 
-pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool {
+pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool {
+    debug!("attr::list_contains_name (name={})", name);
+    items.iter().any(|item| {
+        debug!("  testing: {:?}", item.name());
+        item.check_name(name)
+    })
+}
+
+pub fn contains_name(attrs: &[Attribute], name: &str) -> bool {
     debug!("attr::contains_name (name={})", name);
-    metas.iter().any(|item| {
+    attrs.iter().any(|item| {
         debug!("  testing: {}", item.name());
         item.check_name(name)
     })
@@ -357,27 +425,6 @@ pub fn last_meta_item_value_str_by_name(items: &[P<MetaItem>], name: &str)
 
 /* Higher-level applications */
 
-pub fn sort_meta_items(items: Vec<P<MetaItem>>) -> Vec<P<MetaItem>> {
-    // This is sort of stupid here, but we need to sort by
-    // human-readable strings.
-    let mut v = items.into_iter()
-        .map(|mi| (mi.name(), mi))
-        .collect::<Vec<(InternedString, P<MetaItem>)>>();
-
-    v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
-
-    // There doesn't seem to be a more optimal way to do this
-    v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| {
-        Spanned {
-            node: match node {
-                MetaItemKind::List(n, mis) => MetaItemKind::List(n, sort_meta_items(mis)),
-                _ => node
-            },
-            span: span
-        }
-    })).collect()
-}
-
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
     first_attr_value_str_by_name(attrs, "crate_name")
 }
@@ -427,14 +474,15 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In
                 if items.len() != 1 {
                     diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); });
                     InlineAttr::None
-                } else if contains_name(&items[..], "always") {
+                } else if list_contains_name(&items[..], "always") {
                     InlineAttr::Always
-                } else if contains_name(&items[..], "never") {
+                } else if list_contains_name(&items[..], "never") {
                     InlineAttr::Never
                 } else {
                     diagnostic.map(|d| {
-                        span_err!(d, (*items[0]).span, E0535, "invalid argument");
+                        span_err!(d, items[0].span, E0535, "invalid argument");
                     });
+
                     InlineAttr::None
                 }
             }
@@ -453,27 +501,44 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
-                   sess: &ParseSess, features: Option<&Features>)
+                   sess: &ParseSess,
+                   features: Option<&Features>)
                    -> bool {
     match cfg.node {
-        ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" =>
-            mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)),
-        ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" =>
-            mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)),
-        ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => {
-            if mis.len() != 1 {
-                span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
-                return false;
+        ast::MetaItemKind::List(ref pred, ref mis) => {
+            for mi in mis.iter() {
+                if !mi.is_meta_item() {
+                    handle_errors(&sess.span_diagnostic, mi.span, AttrError::UnsupportedLiteral);
+                    return false;
+                }
+            }
+
+            // The unwraps below may look dangerous, but we've already asserted
+            // that they won't fail with the loop above.
+            match &pred[..] {
+                "any" => mis.iter().any(|mi| {
+                    cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features)
+                }),
+                "all" => mis.iter().all(|mi| {
+                    cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features)
+                }),
+                "not" => {
+                    if mis.len() != 1 {
+                        span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
+                        return false;
+                    }
+
+                    !cfg_matches(cfgs, mis[0].meta_item().unwrap(), sess, features)
+                },
+                p => {
+                    span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
+                    false
+                }
             }
-            !cfg_matches(cfgs, &mis[0], sess, features)
-        }
-        ast::MetaItemKind::List(ref pred, _) => {
-            span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", pred);
-            false
         },
         ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => {
-            if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
-                gated_cfg.check_and_emit(sess, features);
+            if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
+                gated_cfg.check_and_emit(sess, feats);
             }
             contains(cfgs, cfg)
         }
@@ -557,14 +622,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
                     let mut since = None;
                     let mut reason = None;
                     for meta in metas {
-                        match &*meta.name() {
-                            "since" => if !get(meta, &mut since) { continue 'outer },
-                            "reason" => if !get(meta, &mut reason) { continue 'outer },
-                            _ => {
-                                handle_errors(diagnostic, meta.span,
-                                              AttrError::UnknownMetaItem(meta.name()));
-                                continue 'outer
+                        if let Some(mi) = meta.meta_item() {
+                            match &*mi.name() {
+                                "since" => if !get(mi, &mut since) { continue 'outer },
+                                "reason" => if !get(mi, &mut reason) { continue 'outer },
+                                _ => {
+                                    handle_errors(diagnostic, mi.span,
+                                                  AttrError::UnknownMetaItem(mi.name()));
+                                    continue 'outer
+                                }
                             }
+                        } else {
+                            handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                            continue 'outer
                         }
                     }
 
@@ -595,15 +665,20 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
                     let mut reason = None;
                     let mut issue = None;
                     for meta in metas {
-                        match &*meta.name() {
-                            "feature" => if !get(meta, &mut feature) { continue 'outer },
-                            "reason" => if !get(meta, &mut reason) { continue 'outer },
-                            "issue" => if !get(meta, &mut issue) { continue 'outer },
-                            _ => {
-                                handle_errors(diagnostic, meta.span,
-                                              AttrError::UnknownMetaItem(meta.name()));
-                                continue 'outer
+                        if let Some(mi) = meta.meta_item() {
+                            match &*mi.name() {
+                                "feature" => if !get(mi, &mut feature) { continue 'outer },
+                                "reason" => if !get(mi, &mut reason) { continue 'outer },
+                                "issue" => if !get(mi, &mut issue) { continue 'outer },
+                                _ => {
+                                    handle_errors(diagnostic, meta.span,
+                                                  AttrError::UnknownMetaItem(mi.name()));
+                                    continue 'outer
+                                }
                             }
+                        } else {
+                            handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                            continue 'outer
                         }
                     }
 
@@ -645,14 +720,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler,
                     let mut feature = None;
                     let mut since = None;
                     for meta in metas {
-                        match &*meta.name() {
-                            "feature" => if !get(meta, &mut feature) { continue 'outer },
-                            "since" => if !get(meta, &mut since) { continue 'outer },
-                            _ => {
-                                handle_errors(diagnostic, meta.span,
-                                              AttrError::UnknownMetaItem(meta.name()));
-                                continue 'outer
+                        if let NestedMetaItemKind::MetaItem(ref mi) = meta.node {
+                            match &*mi.name() {
+                                "feature" => if !get(mi, &mut feature) { continue 'outer },
+                                "since" => if !get(mi, &mut since) { continue 'outer },
+                                _ => {
+                                    handle_errors(diagnostic, meta.span,
+                                                  AttrError::UnknownMetaItem(mi.name()));
+                                    continue 'outer
+                                }
                             }
+                        } else {
+                            handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                            continue 'outer
                         }
                     }
 
@@ -739,14 +819,19 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler,
             let mut since = None;
             let mut note = None;
             for meta in metas {
-                match &*meta.name() {
-                    "since" => if !get(meta, &mut since) { continue 'outer },
-                    "note" => if !get(meta, &mut note) { continue 'outer },
-                    _ => {
-                        handle_errors(diagnostic, meta.span,
-                                      AttrError::UnknownMetaItem(meta.name()));
-                        continue 'outer
+                if let NestedMetaItemKind::MetaItem(ref mi) = meta.node {
+                    match &*mi.name() {
+                        "since" => if !get(mi, &mut since) { continue 'outer },
+                        "note" => if !get(mi, &mut note) { continue 'outer },
+                        _ => {
+                            handle_errors(diagnostic, meta.span,
+                                          AttrError::UnknownMetaItem(mi.name()));
+                            continue 'outer
+                        }
                     }
+                } else {
+                    handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral);
+                    continue 'outer
                 }
             }
 
@@ -796,32 +881,36 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
         ast::MetaItemKind::List(ref s, ref items) if s == "repr" => {
             mark_used(attr);
             for item in items {
-                match item.node {
-                    ast::MetaItemKind::Word(ref word) => {
-                        let hint = match &word[..] {
-                            // Can't use "extern" because it's not a lexical identifier.
-                            "C" => Some(ReprExtern),
-                            "packed" => Some(ReprPacked),
-                            "simd" => Some(ReprSimd),
-                            _ => match int_type_of_word(&word) {
-                                Some(ity) => Some(ReprInt(item.span, ity)),
-                                None => {
-                                    // Not a word we recognize
-                                    span_err!(diagnostic, item.span, E0552,
-                                              "unrecognized representation hint");
-                                    None
-                                }
-                            }
-                        };
+                if !item.is_meta_item() {
+                    handle_errors(diagnostic, item.span, AttrError::UnsupportedLiteral);
+                    continue
+                }
 
-                        match hint {
-                            Some(h) => acc.push(h),
-                            None => { }
+                if let Some(mi) = item.word() {
+                    let word = &*mi.name();
+                    let hint = match word {
+                        // Can't use "extern" because it's not a lexical identifier.
+                        "C" => Some(ReprExtern),
+                        "packed" => Some(ReprPacked),
+                        "simd" => Some(ReprSimd),
+                        _ => match int_type_of_word(word) {
+                            Some(ity) => Some(ReprInt(item.span, ity)),
+                            None => {
+                                // Not a word we recognize
+                                span_err!(diagnostic, item.span, E0552,
+                                          "unrecognized representation hint");
+                                None
+                            }
                         }
+                    };
+
+                    match hint {
+                        Some(h) => acc.push(h),
+                        None => { }
                     }
-                    // Not a word:
-                    _ => span_err!(diagnostic, item.span, E0553,
-                                   "unrecognized enum representation hint"),
+                } else {
+                    span_err!(diagnostic, item.span, E0553,
+                              "unrecognized enum representation hint");
                 }
             }
         }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index a825cf866a8..69a97917652 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use attr::{AttrMetaMethods, HasAttrs};
+use attr::HasAttrs;
 use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
 use fold::Folder;
 use {fold, attr};
@@ -52,6 +52,7 @@ impl<'a> StripUnconfigured<'a> {
                 return None;
             }
         };
+
         let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
             (2, Some(cfg), Some(mi)) => (cfg, mi),
             _ => {
@@ -61,15 +62,24 @@ impl<'a> StripUnconfigured<'a> {
             }
         };
 
-        if attr::cfg_matches(self.config, &cfg, self.sess, self.features) {
-            self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
-                id: attr::mk_attr_id(),
-                style: attr.node.style,
-                value: mi.clone(),
-                is_sugared_doc: false,
-            }))
-        } else {
-            None
+        use attr::cfg_matches;
+        match (cfg.meta_item(), mi.meta_item()) {
+            (Some(cfg), Some(mi)) =>
+                if cfg_matches(self.config, &cfg, self.sess, self.features) {
+                    self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
+                        id: attr::mk_attr_id(),
+                        style: attr.node.style,
+                        value: mi.clone(),
+                        is_sugared_doc: false,
+                    }))
+                } else {
+                    None
+                },
+            _ => {
+                let msg = "unexpected literal(s) in `#[cfg_attr(<cfg pattern>, <attr>)]`";
+                self.sess.span_diagnostic.span_err(attr.span, msg);
+                None
+            }
         }
     }
 
@@ -91,7 +101,12 @@ impl<'a> StripUnconfigured<'a> {
                 return true;
             }
 
-            attr::cfg_matches(self.config, &mis[0], self.sess, self.features)
+            if !mis[0].is_meta_item() {
+                self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal");
+                return true;
+            }
+
+            attr::cfg_matches(self.config, mis[0].meta_item().unwrap(), self.sess, self.features)
         })
     }
 
@@ -165,6 +180,9 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
             ast::ItemKind::Struct(def, generics) => {
                 ast::ItemKind::Struct(fold_struct(self, def), generics)
             }
+            ast::ItemKind::Union(def, generics) => {
+                ast::ItemKind::Union(fold_struct(self, def), generics)
+            }
             ast::ItemKind::Enum(def, generics) => {
                 let variants = def.variants.into_iter().filter_map(|v| {
                     self.configure(v).map(|v| {
diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs
index 010b1d638e6..9110e989a8a 100644
--- a/src/libsyntax/diagnostic_list.rs
+++ b/src/libsyntax/diagnostic_list.rs
@@ -161,6 +161,24 @@ fn main() {}
 ```
 "##,
 
+E0565: r##"
+A literal was used in an attribute that doesn't support literals.
+
+Erroneous code example:
+
+```compile_fail,E0565
+#[inline("always")] // error: unsupported literal
+pub fn something() {}
+```
+
+Literals in attributes are new and largely unsupported. Work to support literals
+where appropriate is ongoing. Try using an unquoted name instead:
+
+```
+#[inline(always)]
+pub fn something() {}
+```
+"##,
 }
 
 register_diagnostics! {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 6ba3b92483f..43e190f5deb 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -60,13 +60,6 @@ impl HasAttrs for Annotatable {
 }
 
 impl Annotatable {
-    pub fn attrs(&self) -> &[ast::Attribute] {
-        HasAttrs::attrs(self)
-    }
-    pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
-        self.map_attrs(|_| attrs)
-    }
-
     pub fn expect_item(self) -> P<ast::Item> {
         match self {
             Annotatable::Item(i) => i,
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 5d6429f7bdf..3dcdbc89096 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -12,7 +12,7 @@ use abi::Abi;
 use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind};
 use attr;
 use syntax_pos::{Span, DUMMY_SP, Pos};
-use codemap::{respan, Spanned};
+use codemap::{dummy_spanned, respan, Spanned};
 use ext::base::ExtCtxt;
 use parse::token::{self, keywords, InternedString};
 use ptr::P;
@@ -171,9 +171,11 @@ pub trait AstBuilder {
                               span: Span,
                               ident: ast::Ident,
                               bm: ast::BindingMode) -> P<ast::Pat>;
-    fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>> ) -> P<ast::Pat>;
-    fn pat_struct(&self, span: Span,
-                  path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>> ) -> P<ast::Pat>;
+    fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat>;
+    fn pat_tuple_struct(&self, span: Span, path: ast::Path,
+                        subpats: Vec<P<ast::Pat>>) -> P<ast::Pat>;
+    fn pat_struct(&self, span: Span, path: ast::Path,
+                  field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat>;
     fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat>;
 
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat>;
@@ -277,10 +279,13 @@ pub trait AstBuilder {
     fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute;
 
     fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem>;
+
+    fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem;
+
     fn meta_list(&self,
                  sp: Span,
                  name: InternedString,
-                 mis: Vec<P<ast::MetaItem>> )
+                 mis: Vec<ast::NestedMetaItem> )
                  -> P<ast::MetaItem>;
     fn meta_name_value(&self,
                        sp: Span,
@@ -802,10 +807,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let binding_expr = self.expr_ident(sp, binding_variable);
 
         // Ok(__try_var) pattern
-        let ok_pat = self.pat_enum(sp, ok_path, vec!(binding_pat.clone()));
+        let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
 
         // Err(__try_var)  (pattern and expression resp.)
-        let err_pat = self.pat_enum(sp, err_path.clone(), vec!(binding_pat));
+        let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
         let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
                                             vec!(binding_expr.clone()));
         // return Err(__try_var)
@@ -842,18 +847,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let pat = PatKind::Ident(bm, Spanned{span: span, node: ident}, None);
         self.pat(span, pat)
     }
-    fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
-        let pat = if subpats.is_empty() {
-            PatKind::Path(None, path)
-        } else {
-            PatKind::TupleStruct(path, subpats, None)
-        };
-        self.pat(span, pat)
+    fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
+        self.pat(span, PatKind::Path(None, path))
     }
-    fn pat_struct(&self, span: Span,
-                  path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
-        let pat = PatKind::Struct(path, field_pats, false);
-        self.pat(span, pat)
+    fn pat_tuple_struct(&self, span: Span, path: ast::Path,
+                        subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
+        self.pat(span, PatKind::TupleStruct(path, subpats, None))
+    }
+    fn pat_struct(&self, span: Span, path: ast::Path,
+                  field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
+        self.pat(span, PatKind::Struct(path, field_pats, false))
     }
     fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
         self.pat(span, PatKind::Tuple(pats, None))
@@ -862,25 +865,25 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
         let some = self.std_path(&["option", "Option", "Some"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!(pat))
+        self.pat_tuple_struct(span, path, vec![pat])
     }
 
     fn pat_none(&self, span: Span) -> P<ast::Pat> {
         let some = self.std_path(&["option", "Option", "None"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!())
+        self.pat_path(span, path)
     }
 
     fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
         let some = self.std_path(&["result", "Result", "Ok"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!(pat))
+        self.pat_tuple_struct(span, path, vec![pat])
     }
 
     fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
         let some = self.std_path(&["result", "Result", "Err"]);
         let path = self.path_global(span, some);
-        self.pat_enum(span, path, vec!(pat))
+        self.pat_tuple_struct(span, path, vec![pat])
     }
 
     fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {
@@ -1016,7 +1019,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                   Vec::new(),
                   ast::ItemKind::Fn(self.fn_decl(inputs, output),
                               ast::Unsafety::Normal,
-                              ast::Constness::NotConst,
+                              dummy_spanned(ast::Constness::NotConst),
                               Abi::Rust,
                               generics,
                               body))
@@ -1141,10 +1144,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem> {
         attr::mk_spanned_word_item(sp, w)
     }
-    fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<P<ast::MetaItem>>)
+
+    fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem {
+        respan(sp, ast::NestedMetaItemKind::MetaItem(attr::mk_spanned_word_item(sp, w)))
+    }
+
+    fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<ast::NestedMetaItem>)
                  -> P<ast::MetaItem> {
         attr::mk_spanned_list_item(sp, name, mis)
     }
+
     fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind)
                        -> P<ast::MetaItem> {
         attr::mk_spanned_name_value_item(sp, name, respan(sp, value))
@@ -1178,7 +1187,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn item_use_list(&self, sp: Span, vis: ast::Visibility,
                      path: Vec<ast::Ident>, imports: &[ast::Ident]) -> P<ast::Item> {
         let imports = imports.iter().map(|id| {
-            let item = ast::PathListItemKind::Ident {
+            let item = ast::PathListItem_ {
                 name: *id,
                 rename: None,
                 id: ast::DUMMY_NODE_ID,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 26599208ec0..15ebf95d623 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -13,7 +13,6 @@ use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
 use attr::{self, HasAttrs};
-use attr::AttrMetaMethods;
 use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index dc68e064634..1e15c156356 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -26,11 +26,9 @@ use self::AttributeType::*;
 use self::AttributeGate::*;
 
 use abi::Abi;
-use ast::{NodeId, PatKind};
-use ast;
+use ast::{self, NodeId, PatKind};
 use attr;
-use attr::AttrMetaMethods;
-use codemap::CodeMap;
+use codemap::{CodeMap, Spanned};
 use syntax_pos::Span;
 use errors::Handler;
 use visit::{self, FnKind, Visitor};
@@ -280,7 +278,10 @@ declare_features! (
     (active, relaxed_adts, "1.12.0", Some(35626)),
 
     // The `!` type
-    (active, never_type, "1.13.0", Some(35121))
+    (active, never_type, "1.13.0", Some(35121)),
+
+    // Allows all literals in attribute lists and values of key-value pairs.
+    (active, attr_literals, "1.13.0", Some(34981))
 );
 
 declare_features! (
@@ -830,11 +831,34 @@ impl<'a> PostExpansionVisitor<'a> {
     }
 }
 
+fn contains_novel_literal(item: &ast::MetaItem) -> bool {
+    use ast::MetaItemKind::*;
+    use ast::NestedMetaItemKind::*;
+
+    match item.node {
+        Word(..) => false,
+        NameValue(_, ref lit) => !lit.node.is_str(),
+        List(_, ref list) => list.iter().any(|li| {
+            match li.node {
+                MetaItem(ref mi) => contains_novel_literal(&**mi),
+                Literal(_) => true,
+            }
+        }),
+    }
+}
+
 impl<'a> Visitor for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
         if !self.context.cm.span_allows_unstable(attr.span) {
+            // check for gated attributes
             self.context.check_attribute(attr, false);
         }
+
+        if contains_novel_literal(&*(attr.node.value)) {
+            gate_feature_post!(&self, attr_literals, attr.span,
+                               "non-string literals in attributes, or string \
+                               literals in top-level positions, are experimental");
+        }
     }
 
     fn visit_name(&mut self, sp: Span, name: ast::Name) {
@@ -894,7 +918,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                 for attr in &i.attrs {
                     if attr.name() == "repr" {
                         for item in attr.meta_item_list().unwrap_or(&[]) {
-                            if item.name() == "simd" {
+                            if item.check_name("simd") {
                                 gate_feature_post!(&self, repr_simd, i.span,
                                                    "SIMD types are experimental \
                                                     and possibly buggy");
@@ -1046,7 +1070,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                 _node_id: NodeId) {
         // check for const fn declarations
         match fn_kind {
-            FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
+            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => {
                 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
             }
             _ => {
@@ -1078,7 +1102,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                 if block.is_none() {
                     self.check_abi(sig.abi, ti.span);
                 }
-                if sig.constness == ast::Constness::Const {
+                if sig.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
                 }
             }
@@ -1105,7 +1129,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                                   "associated constants are experimental")
             }
             ast::ImplItemKind::Method(ref sig, _) => {
-                if sig.constness == ast::Constness::Const {
+                if sig.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
                 }
             }
@@ -1154,13 +1178,14 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F
             }
             Some(list) => {
                 for mi in list {
-                    let name = if mi.is_word() {
-                                   mi.name()
-                               } else {
-                                   span_err!(span_handler, mi.span, E0556,
-                                             "malformed feature, expected just one word");
-                                   continue
-                               };
+                    let name = if let Some(word) = mi.word() {
+                        word.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/fold.rs b/src/libsyntax/fold.rs
index b257ab98987..7500bfe9caa 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -47,6 +47,10 @@ pub trait Folder : Sized {
         noop_fold_meta_items(meta_items, self)
     }
 
+    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
+        noop_fold_meta_list_item(list_item, self)
+    }
+
     fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
         noop_fold_meta_item(meta_item, self)
     }
@@ -307,18 +311,10 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
                 ViewPathList(fld.fold_path(path),
                              path_list_idents.move_map(|path_list_ident| {
                                 Spanned {
-                                    node: match path_list_ident.node {
-                                        PathListItemKind::Ident { id, name, rename } =>
-                                            PathListItemKind::Ident {
-                                                id: fld.new_id(id),
-                                                rename: rename,
-                                                name: name
-                                            },
-                                        PathListItemKind::Mod { id, rename } =>
-                                            PathListItemKind::Mod {
-                                                id: fld.new_id(id),
-                                                rename: rename
-                                            }
+                                    node: PathListItem_ {
+                                        id: fld.new_id(path_list_ident.node.id),
+                                        rename: path_list_ident.node.rename,
+                                        name: path_list_ident.node.name,
                                     },
                                     span: fld.new_span(path_list_ident.span)
                                 }
@@ -513,12 +509,25 @@ pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
     }
 }
 
+pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T)
+    -> NestedMetaItem {
+    Spanned {
+        node: match li.node {
+            NestedMetaItemKind::MetaItem(mi) =>  {
+                NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi))
+            },
+            NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit)
+        },
+        span: fld.new_span(li.span)
+    }
+}
+
 pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
     mi.map(|Spanned {node, span}| Spanned {
         node: match node {
             MetaItemKind::Word(id) => MetaItemKind::Word(id),
             MetaItemKind::List(id, mis) => {
-                MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e)))
+                MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e)))
             }
             MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s)
         },
@@ -698,12 +707,13 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T)
     o_lt.map(|lt| fld.fold_lifetime(lt))
 }
 
-pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause}: Generics,
+pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics,
                                      fld: &mut T) -> Generics {
     Generics {
         ty_params: fld.fold_ty_params(ty_params),
         lifetimes: fld.fold_lifetime_defs(lifetimes),
         where_clause: fld.fold_where_clause(where_clause),
+        span: fld.new_span(span),
     }
 }
 
@@ -875,6 +885,10 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             let struct_def = folder.fold_variant_data(struct_def);
             ItemKind::Struct(struct_def, folder.fold_generics(generics))
         }
+        ItemKind::Union(struct_def, generics) => {
+            let struct_def = folder.fold_variant_data(struct_def);
+            ItemKind::Union(struct_def, folder.fold_generics(generics))
+        }
         ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
             ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
         }
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 2ae3236cd5a..27dd055cd3a 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -193,9 +193,26 @@ impl<'a> Parser<'a> {
         Ok(attrs)
     }
 
-    /// matches meta_item = IDENT
-    /// | IDENT = lit
-    /// | IDENT meta_seq
+    fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
+        let lit = self.parse_lit()?;
+        debug!("Checking if {:?} is unusuffixed.", lit);
+
+        if !lit.node.is_unsuffixed() {
+            let msg = "suffixed literals are not allowed in attributes";
+            self.diagnostic().struct_span_err(lit.span, msg)
+                             .help("instead of using a suffixed literal \
+                                    (1u8, 1.0f32, etc.), use an unsuffixed version \
+                                    (1, 1.0, etc.).")
+                             .emit()
+        }
+
+        Ok(lit)
+    }
+
+    /// Per RFC#1559, matches the following grammar:
+    ///
+    /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
+    /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> {
         let nt_meta = match self.token {
             token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()),
@@ -213,16 +230,7 @@ impl<'a> Parser<'a> {
         match self.token {
             token::Eq => {
                 self.bump();
-                let lit = self.parse_lit()?;
-                // FIXME #623 Non-string meta items are not serialized correctly;
-                // just forbid them for now
-                match lit.node {
-                    ast::LitKind::Str(..) => {}
-                    _ => {
-                        self.span_err(lit.span,
-                                      "non-string literals are not allowed in meta-items");
-                    }
-                }
+                let lit = self.parse_unsuffixed_lit()?;
                 let hi = self.span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit))))
             }
@@ -238,11 +246,35 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// matches meta_seq = ( COMMASEP(meta_item) )
-    fn parse_meta_seq(&mut self) -> PResult<'a, Vec<P<ast::MetaItem>>> {
+    /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
+    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
+        let sp = self.span;
+        let lo = self.span.lo;
+
+        match self.parse_unsuffixed_lit() {
+            Ok(lit) => {
+                return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::Literal(lit)))
+            }
+            Err(ref mut err) => self.diagnostic().cancel(err)
+        }
+
+        match self.parse_meta_item() {
+            Ok(mi) => {
+                return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
+            }
+            Err(ref mut err) => self.diagnostic().cancel(err)
+        }
+
+        let found = self.this_token_to_string();
+        let msg = format!("expected unsuffixed literal or identifier, found {}", found);
+        Err(self.diagnostic().struct_span_err(sp, &msg))
+    }
+
+    /// matches meta_seq = ( COMMASEP(meta_item_inner) )
+    fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
         self.parse_unspanned_seq(&token::OpenDelim(token::Paren),
                                  &token::CloseDelim(token::Paren),
                                  SeqSep::trailing_allowed(token::Comma),
-                                 |p: &mut Parser<'a>| p.parse_meta_item())
+                                 |p: &mut Parser<'a>| p.parse_meta_item_inner())
     }
 }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index cd1fdcfe9d1..af95e44a567 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -674,11 +674,11 @@ pub fn integer_lit(s: &str,
 mod tests {
     use super::*;
     use std::rc::Rc;
-    use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION};
+    use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION};
     use codemap::Spanned;
     use ast::{self, PatKind};
     use abi::Abi;
-    use attr::{first_attr_value_str_by_name, AttrMetaMethods};
+    use attr::first_attr_value_str_by_name;
     use parse;
     use parse::parser::Parser;
     use parse::token::{str_to_ident};
@@ -937,7 +937,10 @@ mod tests {
                                 variadic: false
                             }),
                                     ast::Unsafety::Normal,
-                                    ast::Constness::NotConst,
+                                    Spanned {
+                                        span: sp(0,2),
+                                        node: ast::Constness::NotConst,
+                                    },
                                     Abi::Rust,
                                     ast::Generics{ // no idea on either of these:
                                         lifetimes: Vec::new(),
@@ -945,7 +948,8 @@ mod tests {
                                         where_clause: ast::WhereClause {
                                             id: ast::DUMMY_NODE_ID,
                                             predicates: Vec::new(),
-                                        }
+                                        },
+                                        span: syntax_pos::DUMMY_SP,
                                     },
                                     P(ast::Block {
                                         stmts: vec!(ast::Stmt {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 1646246069e..92ec0fdb3de 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -39,7 +39,7 @@ use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause};
 use ast::{BinOpKind, UnOp};
 use ast;
-use codemap::{self, CodeMap, Spanned, spanned};
+use codemap::{self, CodeMap, Spanned, spanned, respan};
 use syntax_pos::{self, Span, BytePos, mk_sp};
 use errors::{self, DiagnosticBuilder};
 use ext::tt::macro_parser;
@@ -725,8 +725,8 @@ impl<'a> Parser<'a> {
                 let gt_str = Parser::token_to_string(&token::Gt);
                 let this_token_str = self.this_token_to_string();
                 Err(self.fatal(&format!("expected `{}`, found `{}`",
-                                   gt_str,
-                                   this_token_str)))
+                                        gt_str,
+                                        this_token_str)))
             }
         }
     }
@@ -4293,6 +4293,7 @@ impl<'a> Parser<'a> {
     /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
     pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         maybe_whole!(self, NtGenerics);
+        let span_lo = self.span.lo;
 
         if self.eat(&token::Lt) {
             let lifetime_defs = self.parse_lifetime_defs()?;
@@ -4315,7 +4316,8 @@ impl<'a> Parser<'a> {
                 where_clause: WhereClause {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
-                }
+                },
+                span: mk_sp(span_lo, self.last_span.hi),
             })
         } else {
             Ok(ast::Generics::default())
@@ -4768,7 +4770,7 @@ impl<'a> Parser<'a> {
     /// Parse an item-position function declaration.
     fn parse_item_fn(&mut self,
                      unsafety: Unsafety,
-                     constness: Constness,
+                     constness: Spanned<Constness>,
                      abi: abi::Abi)
                      -> PResult<'a, ItemInfo> {
         let (ident, mut generics) = self.parse_fn_header()?;
@@ -4794,18 +4796,21 @@ impl<'a> Parser<'a> {
     /// - `extern fn`
     /// - etc
     pub fn parse_fn_front_matter(&mut self)
-                                 -> PResult<'a, (ast::Constness, ast::Unsafety, abi::Abi)> {
+                                 -> PResult<'a, (Spanned<ast::Constness>,
+                                                ast::Unsafety,
+                                                abi::Abi)> {
         let is_const_fn = self.eat_keyword(keywords::Const);
+        let const_span = self.last_span;
         let unsafety = self.parse_unsafety()?;
         let (constness, unsafety, abi) = if is_const_fn {
-            (Constness::Const, unsafety, Abi::Rust)
+            (respan(const_span, Constness::Const), unsafety, Abi::Rust)
         } else {
             let abi = if self.eat_keyword(keywords::Extern) {
                 self.parse_opt_abi()?.unwrap_or(Abi::C)
             } else {
                 Abi::Rust
             };
-            (Constness::NotConst, unsafety, abi)
+            (respan(self.last_span, Constness::NotConst), unsafety, abi)
         };
         self.expect_keyword(keywords::Fn)?;
         Ok((constness, unsafety, abi))
@@ -5704,9 +5709,12 @@ impl<'a> Parser<'a> {
 
             if self.eat_keyword(keywords::Fn) {
                 // EXTERN FUNCTION ITEM
+                let fn_span = self.last_span;
                 let abi = opt_abi.unwrap_or(Abi::C);
                 let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi)?;
+                    self.parse_item_fn(Unsafety::Normal,
+                                       respan(fn_span, Constness::NotConst),
+                                       abi)?;
                 let last_span = self.last_span;
                 let item = self.mk_item(lo,
                                         last_span.hi,
@@ -5740,6 +5748,7 @@ impl<'a> Parser<'a> {
             return Ok(Some(item));
         }
         if self.eat_keyword(keywords::Const) {
+            let const_span = self.last_span;
             if self.check_keyword(keywords::Fn)
                 || (self.check_keyword(keywords::Unsafe)
                     && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) {
@@ -5751,7 +5760,9 @@ impl<'a> Parser<'a> {
                 };
                 self.bump();
                 let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(unsafety, Constness::Const, Abi::Rust)?;
+                    self.parse_item_fn(unsafety,
+                                       respan(const_span, Constness::Const),
+                                       Abi::Rust)?;
                 let last_span = self.last_span;
                 let item = self.mk_item(lo,
                                         last_span.hi,
@@ -5815,8 +5826,11 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Fn) {
             // FUNCTION ITEM
             self.bump();
+            let fn_span = self.last_span;
             let (ident, item_, extra_attrs) =
-                self.parse_item_fn(Unsafety::Normal, Constness::NotConst, Abi::Rust)?;
+                self.parse_item_fn(Unsafety::Normal,
+                                   respan(fn_span, Constness::NotConst),
+                                   Abi::Rust)?;
             let last_span = self.last_span;
             let item = self.mk_item(lo,
                                     last_span.hi,
@@ -5836,8 +5850,11 @@ impl<'a> Parser<'a> {
                 Abi::Rust
             };
             self.expect_keyword(keywords::Fn)?;
+            let fn_span = self.last_span;
             let (ident, item_, extra_attrs) =
-                self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi)?;
+                self.parse_item_fn(Unsafety::Unsafe,
+                                   respan(fn_span, Constness::NotConst),
+                                   abi)?;
             let last_span = self.last_span;
             let item = self.mk_item(lo,
                                     last_span.hi,
@@ -6038,13 +6055,16 @@ impl<'a> Parser<'a> {
                                  &token::CloseDelim(token::Brace),
                                  SeqSep::trailing_allowed(token::Comma), |this| {
             let lo = this.span.lo;
-            let node = if this.eat_keyword(keywords::SelfValue) {
-                let rename = this.parse_rename()?;
-                ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename }
+            let ident = if this.eat_keyword(keywords::SelfValue) {
+                keywords::SelfValue.ident()
             } else {
-                let ident = this.parse_ident()?;
-                let rename = this.parse_rename()?;
-                ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID }
+                this.parse_ident()?
+            };
+            let rename = this.parse_rename()?;
+            let node = ast::PathListItem_ {
+                name: ident,
+                rename: rename,
+                id: ast::DUMMY_NODE_ID
             };
             let hi = this.last_span.hi;
             Ok(spanned(lo, hi, node))
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index a77c678248b..8563d27908d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -16,7 +16,6 @@ use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 use ast::Attribute;
 use util::parser::AssocOp;
 use attr;
-use attr::{AttrMetaMethods, AttributeMethods};
 use codemap::{self, CodeMap};
 use syntax_pos::{self, BytePos};
 use errors;
@@ -120,7 +119,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
         // of the feature gate, so we fake them up here.
 
         // #![feature(prelude_import)]
-        let prelude_import_meta = attr::mk_word_item(InternedString::new("prelude_import"));
+        let prelude_import_meta = attr::mk_list_word_item(InternedString::new("prelude_import"));
         let list = attr::mk_list_item(InternedString::new("feature"),
                                       vec![prelude_import_meta]);
         let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list);
@@ -406,6 +405,10 @@ pub fn block_to_string(blk: &ast::Block) -> String {
     })
 }
 
+pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
+    to_string(|s| s.print_meta_list_item(li))
+}
+
 pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
     to_string(|s| s.print_meta_item(mi))
 }
@@ -764,6 +767,17 @@ pub trait PrintState<'a> {
         }
     }
 
+    fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()> {
+        match item.node {
+            ast::NestedMetaItemKind::MetaItem(ref mi) => {
+                self.print_meta_item(mi)
+            },
+            ast::NestedMetaItemKind::Literal(ref lit) => {
+                self.print_literal(lit)
+            }
+        }
+    }
+
     fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
         try!(self.ibox(INDENT_UNIT));
         match item.node {
@@ -780,7 +794,7 @@ pub trait PrintState<'a> {
                 try!(self.popen());
                 try!(self.commasep(Consistent,
                               &items[..],
-                              |s, i| s.print_meta_item(&i)));
+                              |s, i| s.print_meta_list_item(&i)));
                 try!(self.pclose());
             }
         }
@@ -1001,6 +1015,7 @@ impl<'a> State<'a> {
                         id: ast::DUMMY_NODE_ID,
                         predicates: Vec::new(),
                     },
+                    span: syntax_pos::DUMMY_SP,
                 };
                 try!(self.print_ty_fn(f.abi,
                                  f.unsafety,
@@ -1184,7 +1199,7 @@ impl<'a> State<'a> {
                 try!(self.print_fn(
                     decl,
                     unsafety,
-                    constness,
+                    constness.node,
                     abi,
                     Some(item.ident),
                     typarams,
@@ -1236,7 +1251,10 @@ impl<'a> State<'a> {
                 try!(self.head(&visibility_qualified(&item.vis, "struct")));
                 try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
             }
-
+            ast::ItemKind::Union(ref struct_def, ref generics) => {
+                try!(self.head(&visibility_qualified(&item.vis, "union")));
+                try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
+            }
             ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
                 try!(self.head(""));
                 try!(self.print_visibility(&item.vis));
@@ -1518,7 +1536,7 @@ impl<'a> State<'a> {
                             -> io::Result<()> {
         self.print_fn(&m.decl,
                       m.unsafety,
-                      m.constness,
+                      m.constness.node,
                       m.abi,
                       Some(ident),
                       &m.generics,
@@ -2878,26 +2896,13 @@ impl<'a> State<'a> {
                     try!(word(&mut self.s, "::{"));
                 }
                 try!(self.commasep(Inconsistent, &idents[..], |s, w| {
-                    match w.node {
-                        ast::PathListItemKind::Ident { name, rename, .. } => {
-                            try!(s.print_ident(name));
-                            if let Some(ident) = rename {
-                                try!(space(&mut s.s));
-                                try!(s.word_space("as"));
-                                try!(s.print_ident(ident));
-                            }
-                            Ok(())
-                        },
-                        ast::PathListItemKind::Mod { rename, .. } => {
-                            try!(word(&mut s.s, "self"));
-                            if let Some(ident) = rename {
-                                try!(space(&mut s.s));
-                                try!(s.word_space("as"));
-                                try!(s.print_ident(ident));
-                            }
-                            Ok(())
-                        }
+                    try!(s.print_ident(w.node.name));
+                    if let Some(ident) = w.node.rename {
+                        try!(space(&mut s.s));
+                        try!(s.word_space("as"));
+                        try!(s.print_ident(ident));
                     }
+                    Ok(())
                 }));
                 word(&mut self.s, "}")
             }
@@ -2982,6 +2987,7 @@ impl<'a> State<'a> {
                 id: ast::DUMMY_NODE_ID,
                 predicates: Vec::new(),
             },
+            span: syntax_pos::DUMMY_SP,
         };
         try!(self.print_fn(decl,
                       unsafety,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index faf6a17a150..6155ad729a2 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -19,12 +19,11 @@ use std::iter;
 use std::slice;
 use std::mem;
 use std::vec;
-use attr::AttrMetaMethods;
 use attr;
 use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
 use std::rc::Rc;
 
-use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute};
+use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned};
 use errors;
 use errors::snippet::{SnippetData};
 use config;
@@ -210,9 +209,8 @@ impl fold::Folder for EntryPointCleaner {
                 folded.map(|ast::Item {id, ident, attrs, node, vis, span}| {
                     let allow_str = InternedString::new("allow");
                     let dead_code_str = InternedString::new("dead_code");
-                    let allow_dead_code_item =
-                        attr::mk_list_item(allow_str,
-                                           vec![attr::mk_word_item(dead_code_str)]);
+                    let word_vec = vec![attr::mk_list_word_item(dead_code_str)];
+                    let allow_dead_code_item = attr::mk_list_item(allow_str, word_vec);
                     let allow_dead_code = attr::mk_attr_outer(attr::mk_attr_id(),
                                                               allow_dead_code_item);
 
@@ -413,6 +411,7 @@ fn should_panic(i: &ast::Item) -> ShouldPanic {
         Some(attr) => {
             let msg = attr.meta_item_list()
                 .and_then(|list| list.iter().find(|mi| mi.check_name("expected")))
+                .and_then(|li| li.meta_item())
                 .and_then(|mi| mi.value_str());
             ShouldPanic::Yes(msg)
         }
@@ -485,7 +484,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
     let main_body = ecx.block(sp, vec![call_test_main]);
     let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty),
                            ast::Unsafety::Normal,
-                           ast::Constness::NotConst,
+                           dummy_spanned(ast::Constness::NotConst),
                            ::abi::Abi::Rust, ast::Generics::default(), main_body);
     let main = P(ast::Item {
         ident: token::str_to_ident("main"),
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 582412119ca..efd9b027504 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -31,7 +31,7 @@ use codemap::Spanned;
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
     /// fn foo() or extern "Abi" fn foo()
-    ItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, &'a Visibility),
+    ItemFn(Ident, &'a Generics, Unsafety, Spanned<Constness>, Abi, &'a Visibility),
 
     /// fn foo(&self)
     Method(Ident, &'a MethodSig, Option<&'a Visibility>),
@@ -278,7 +278,8 @@ pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
             visitor.visit_ty(typ);
             walk_list!(visitor, visit_impl_item, impl_items);
         }
-        ItemKind::Struct(ref struct_definition, ref generics) => {
+        ItemKind::Struct(ref struct_definition, ref generics) |
+        ItemKind::Union(ref struct_definition, ref generics) => {
             visitor.visit_generics(generics);
             visitor.visit_variant_data(struct_definition, item.ident,
                                      generics, item.id, item.span);
@@ -367,8 +368,8 @@ pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
 }
 
 pub fn walk_path_list_item<V: Visitor>(visitor: &mut V, _prefix: &Path, item: &PathListItem) {
-    walk_opt_ident(visitor, item.span, item.node.name());
-    walk_opt_ident(visitor, item.span, item.node.rename());
+    visitor.visit_ident(item.span, item.node.name);
+    walk_opt_ident(visitor, item.span, item.node.rename);
 }
 
 pub fn walk_path_segment<V: Visitor>(visitor: &mut V, path_span: Span, segment: &PathSegment) {
diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs
index cfc98bf3687..efb2fe5eb3b 100644
--- a/src/libsyntax_ext/deriving/bounds.rs
+++ b/src/libsyntax_ext/deriving/bounds.rs
@@ -40,6 +40,7 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: true,
         methods: Vec::new(),
         associated_types: Vec::new(),
     };
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
index ce8ce2209d8..f1a3a1f41b1 100644
--- a/src/libsyntax_ext/deriving/clone.rs
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -80,6 +80,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
         additional_bounds: bounds,
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "clone",
                           generics: LifetimeBounds::empty(),
diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs
index 2ab0f0ff546..425a47a991b 100644
--- a/src/libsyntax_ext/deriving/cmp/eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/eq.rs
@@ -40,7 +40,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
     }
 
     let inline = cx.meta_word(span, InternedString::new("inline"));
-    let hidden = cx.meta_word(span, InternedString::new("hidden"));
+    let hidden = cx.meta_list_item_word(span, InternedString::new("hidden"));
     let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]);
     let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)];
     let trait_def = TraitDef {
@@ -50,6 +50,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "assert_receiver_is_total_eq",
                           generics: LifetimeBounds::empty(),
diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs
index 8ae77e79310..6b2e36e63b6 100644
--- a/src/libsyntax_ext/deriving/cmp/ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/ord.rs
@@ -32,6 +32,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "cmp",
                           generics: LifetimeBounds::empty(),
@@ -104,7 +105,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
         };
 
         let eq_arm = cx.arm(span,
-                            vec![cx.pat_enum(span, equals_path.clone(), vec![])],
+                            vec![cx.pat_path(span, equals_path.clone())],
                             old);
         let neq_arm = cx.arm(span,
                              vec![cx.pat_ident(span, test_id)],
diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
index f70e0cf4ac4..64b8829dad7 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
@@ -97,6 +97,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: methods,
         associated_types: Vec::new(),
     };
diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
index 10a9738742e..99d60c43c54 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
@@ -88,6 +88,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
         additional_bounds: vec![],
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: methods,
         associated_types: Vec::new(),
     };
@@ -165,7 +166,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
         };
 
         let eq_arm = cx.arm(span,
-                            vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))],
+                            vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
                             old);
         let neq_arm = cx.arm(span,
                              vec![cx.pat_ident(span, test_id)],
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index a31c695e360..b974699003b 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -35,6 +35,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "fmt",
                           generics: LifetimeBounds::empty(),
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index 9a332227053..22b9eb8e754 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -62,6 +62,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "decode",
                           generics: LifetimeBounds {
@@ -110,7 +111,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             let nfields = match *summary {
-                Unnamed(ref fields) => fields.len(),
+                Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
             let read_struct_field = cx.ident_of("read_struct_field");
@@ -193,9 +194,9 @@ fn decode_static_fields<F>(cx: &mut ExtCtxt,
     where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>
 {
     match *fields {
-        Unnamed(ref fields) => {
+        Unnamed(ref fields, is_tuple) => {
             let path_expr = cx.expr_path(outer_pat_path);
-            if fields.is_empty() {
+            if !is_tuple {
                 path_expr
             } else {
                 let fields = fields.iter()
diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs
index 9df3db938b1..b15fd2b49a6 100644
--- a/src/libsyntax_ext/deriving/default.rs
+++ b/src/libsyntax_ext/deriving/default.rs
@@ -32,6 +32,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "default",
                           generics: LifetimeBounds::empty(),
@@ -57,8 +58,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur
     return match *substr.fields {
         StaticStruct(_, ref summary) => {
             match *summary {
-                Unnamed(ref fields) => {
-                    if fields.is_empty() {
+                Unnamed(ref fields, is_tuple) => {
+                    if !is_tuple {
                         cx.expr_ident(trait_span, substr.type_ident)
                     } else {
                         let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index 940fdf03771..a4074184b6e 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -138,6 +138,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec!(
             MethodDef {
                 name: "encode",
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index cd49e7ec9d2..5c636d43a71 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -194,10 +194,9 @@ use std::vec;
 use syntax::abi::Abi;
 use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData};
 use syntax::attr;
-use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
-use syntax::codemap::{self, respan};
+use syntax::codemap::{self, dummy_spanned, respan};
 use syntax::util::move_map::MoveMap;
 use syntax::parse::token::{InternedString, keywords};
 use syntax::ptr::P;
@@ -229,6 +228,9 @@ pub struct TraitDef<'a> {
     /// Is it an `unsafe` trait?
     pub is_unsafe: bool,
 
+    /// Can this trait be derived for unions?
+    pub supports_unions: bool,
+
     pub methods: Vec<MethodDef<'a>>,
 
     pub associated_types: Vec<(ast::Ident, Ty<'a>)>,
@@ -294,8 +296,8 @@ pub struct FieldInfo<'a> {
 
 /// Fields for a static method
 pub enum StaticFields {
-    /// Tuple structs/enum variants like this.
-    Unnamed(Vec<Span>),
+    /// Tuple and unit structs/enum variants like this.
+    Unnamed(Vec<Span>, bool /*is tuple*/),
     /// Normal structs/struct variants.
     Named(Vec<(Ident, Span)>),
 }
@@ -488,7 +490,7 @@ impl<'a> TraitDef<'a> {
             }
         });
 
-        let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics
+        let Generics { mut lifetimes, ty_params, mut where_clause, span } = self.generics
             .to_generics(cx, self.span, type_ident, generics);
         let mut ty_params = ty_params.into_vec();
 
@@ -590,6 +592,7 @@ impl<'a> TraitDef<'a> {
             lifetimes: lifetimes,
             ty_params: P::from_vec(ty_params),
             where_clause: where_clause,
+            span: span,
         };
 
         // Create the reference to the trait.
@@ -623,7 +626,7 @@ impl<'a> TraitDef<'a> {
         let unused_qual = cx.attribute(self.span,
                                        cx.meta_list(self.span,
                                                     InternedString::new("allow"),
-                                                    vec![cx.meta_word(self.span,
+                                                    vec![cx.meta_list_item_word(self.span,
                                            InternedString::new("unused_qualifications"))]));
         let mut a = vec![attr, unused_qual];
         a.extend(self.attributes.iter().cloned());
@@ -901,7 +904,8 @@ impl<'a> MethodDef<'a> {
                                                 generics: fn_generics,
                                                 abi: abi,
                                                 unsafety: unsafety,
-                                                constness: ast::Constness::NotConst,
+                                                constness:
+                                                    dummy_spanned(ast::Constness::NotConst),
                                                 decl: fn_decl,
                                             },
                                             body_block),
@@ -1470,7 +1474,7 @@ impl<'a> TraitDef<'a> {
             (_, false) => Named(named_idents),
             // empty structs
             _ if struct_def.is_struct() => Named(named_idents),
-            _ => Unnamed(just_spans),
+            _ => Unnamed(just_spans, struct_def.is_tuple()),
         }
     }
 
@@ -1510,26 +1514,32 @@ impl<'a> TraitDef<'a> {
         }
 
         let subpats = self.create_subpatterns(cx, paths, mutbl);
-        let pattern = if struct_def.is_struct() {
-            let field_pats = subpats.into_iter()
-                .zip(&ident_exprs)
-                .map(|(pat, &(sp, ident, _, _))| {
-                    if ident.is_none() {
-                        cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
-                    }
-                    codemap::Spanned {
-                        span: pat.span,
-                        node: ast::FieldPat {
-                            ident: ident.unwrap(),
-                            pat: pat,
-                            is_shorthand: false,
-                        },
-                    }
-                })
-                .collect();
-            cx.pat_struct(self.span, struct_path, field_pats)
-        } else {
-            cx.pat_enum(self.span, struct_path, subpats)
+        let pattern = match *struct_def {
+            VariantData::Struct(..) => {
+                let field_pats = subpats.into_iter()
+                    .zip(&ident_exprs)
+                    .map(|(pat, &(sp, ident, _, _))| {
+                        if ident.is_none() {
+                            cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
+                        }
+                        codemap::Spanned {
+                            span: pat.span,
+                            node: ast::FieldPat {
+                                ident: ident.unwrap(),
+                                pat: pat,
+                                is_shorthand: false,
+                            },
+                        }
+                    })
+                    .collect();
+                cx.pat_struct(self.span, struct_path, field_pats)
+            }
+            VariantData::Tuple(..) => {
+                cx.pat_tuple_struct(self.span, struct_path, subpats)
+            }
+            VariantData::Unit(..) => {
+                cx.pat_path(self.span, struct_path)
+            }
         };
 
         (pattern, ident_exprs)
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index 356c54fcf31..210878b7c9f 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -207,7 +207,8 @@ fn mk_ty_param(cx: &ExtCtxt,
     cx.typaram(span, cx.ident_of(name), bounds, None)
 }
 
-fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) -> Generics {
+fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>, span: Span)
+               -> Generics {
     Generics {
         lifetimes: lifetimes,
         ty_params: P::from_vec(ty_params),
@@ -215,6 +216,7 @@ fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) -
             id: ast::DUMMY_NODE_ID,
             predicates: Vec::new(),
         },
+        span: span,
     }
 }
 
@@ -257,7 +259,7 @@ impl<'a> LifetimeBounds<'a> {
                 }
             })
             .collect();
-        mk_generics(lifetimes, ty_params)
+        mk_generics(lifetimes, ty_params, span)
     }
 }
 
diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs
index 81c8e7112db..0941ebca868 100644
--- a/src/libsyntax_ext/deriving/hash.rs
+++ b/src/libsyntax_ext/deriving/hash.rs
@@ -36,6 +36,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds::empty(),
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![MethodDef {
                           name: "hash",
                           generics: LifetimeBounds {
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index aee86b246b9..81085122e87 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -11,7 +11,6 @@
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
 use syntax::ast::{self, MetaItem};
-use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv};
 use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
 use syntax::ext::build::AstBuilder;
@@ -98,8 +97,8 @@ fn expand_derive(cx: &mut ExtCtxt,
             let mut eq_span = None;
 
             for titem in traits.iter().rev() {
-                let tname = if titem.is_word() {
-                    titem.name()
+                let tname = if let Some(word) = titem.word() {
+                    word.name()
                 } else {
                     cx.span_err(titem.span, "malformed `derive` entry");
                     continue;
diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
index a6bc9db199c..5a3412b7ed9 100644
--- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
@@ -17,7 +17,7 @@ extern crate syntax_pos;
 extern crate rustc;
 extern crate rustc_plugin;
 
-use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind};
+use syntax::ast::{self, Item, MetaItem, ItemKind};
 use syntax::ext::base::*;
 use syntax::parse::{self, token};
 use syntax::ptr::P;
@@ -62,8 +62,8 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
 }
 
 fn expand_into_foo_multi(cx: &mut ExtCtxt,
-                         sp: Span,
-                         attr: &MetaItem,
+                         _sp: Span,
+                         _attr: &MetaItem,
                          it: Annotatable) -> Annotatable {
     match it {
         Annotatable::Item(it) => {
@@ -72,7 +72,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
             }))
         }
-        Annotatable::ImplItem(it) => {
+        Annotatable::ImplItem(_) => {
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Impl(_, _, _, _, _, mut items) => {
@@ -82,7 +82,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 }
             })
         }
-        Annotatable::TraitItem(it) => {
+        Annotatable::TraitItem(_) => {
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Trait(_, _, _, mut items) => {
@@ -97,15 +97,15 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
 
 // Create a duplicate of the annotatable, based on the MetaItem
 fn expand_duplicate(cx: &mut ExtCtxt,
-                    sp: Span,
+                    _sp: Span,
                     mi: &MetaItem,
                     it: &Annotatable,
                     push: &mut FnMut(Annotatable))
 {
     let copy_name = match mi.node {
         ast::MetaItemKind::List(_, ref xs) => {
-            if let ast::MetaItemKind::Word(ref w) = xs[0].node {
-                token::str_to_ident(&w)
+            if let Some(word) = xs[0].word() {
+                token::str_to_ident(&word.name())
             } else {
                 cx.span_err(mi.span, "Expected word");
                 return;
diff --git a/src/test/compile-fail/E0132.rs b/src/test/compile-fail/E0132.rs
index 1a33fb24ca1..91ff6b85a42 100644
--- a/src/test/compile-fail/E0132.rs
+++ b/src/test/compile-fail/E0132.rs
@@ -11,7 +11,7 @@
 #![feature(start)]
 
 #[start]
-fn f<T>() {} //~ ERROR E0132
+fn f< T >() {} //~ ERROR E0132
              //~| NOTE start function cannot have type parameters
 
 fn main() {
diff --git a/src/test/compile-fail/E0565-1.rs b/src/test/compile-fail/E0565-1.rs
new file mode 100644
index 00000000000..d3e68c7c0da
--- /dev/null
+++ b/src/test/compile-fail/E0565-1.rs
@@ -0,0 +1,17 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(attr_literals)]
+
+// deprecated doesn't currently support literals
+#[deprecated("since")] //~ ERROR E0565
+fn f() {  }
+
+fn main() {  }
diff --git a/src/test/compile-fail/E0565.rs b/src/test/compile-fail/E0565.rs
new file mode 100644
index 00000000000..b2d369223e7
--- /dev/null
+++ b/src/test/compile-fail/E0565.rs
@@ -0,0 +1,17 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(attr_literals)]
+
+// repr currently doesn't support literals
+#[repr("C")] //~ ERROR E0565
+struct A {  }
+
+fn main() {  }
diff --git a/src/test/compile-fail/attr-literals.rs b/src/test/compile-fail/attr-literals.rs
new file mode 100644
index 00000000000..b5428803517
--- /dev/null
+++ b/src/test/compile-fail/attr-literals.rs
@@ -0,0 +1,33 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that literals in attributes parse just fine.
+
+#![feature(rustc_attrs, attr_literals)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown
+struct Q {  }
+
+#[rustc_error]
+fn main() { }
diff --git a/src/test/compile-fail/const-fn-mismatch.rs b/src/test/compile-fail/const-fn-mismatch.rs
index 92568b27f7c..7ea72e23779 100644
--- a/src/test/compile-fail/const-fn-mismatch.rs
+++ b/src/test/compile-fail/const-fn-mismatch.rs
@@ -21,7 +21,7 @@ trait Foo {
 
 impl Foo for u32 {
     const fn f() -> u32 { 22 }
-    //~^ ERROR E0379
+    //~^ ERROR trait fns cannot be declared const
     //~| NOTE trait fns cannot be const
 }
 
diff --git a/src/test/compile-fail/const-fn-not-in-trait.rs b/src/test/compile-fail/const-fn-not-in-trait.rs
index 191f3e02527..257d4d5ee99 100644
--- a/src/test/compile-fail/const-fn-not-in-trait.rs
+++ b/src/test/compile-fail/const-fn-not-in-trait.rs
@@ -14,8 +14,12 @@
 #![feature(const_fn)]
 
 trait Foo {
-    const fn f() -> u32; //~ ERROR trait fns cannot be declared const
-    const fn g() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
+    const fn f() -> u32;
+    //~^ ERROR trait fns cannot be declared const
+    //~| NOTE trait fns cannot be const
+    const fn g() -> u32 { 0 }
+    //~^ ERROR trait fns cannot be declared const
+    //~| NOTE trait fns cannot be const
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/gated-attr-literals.rs b/src/test/compile-fail/gated-attr-literals.rs
new file mode 100644
index 00000000000..f3132d5593e
--- /dev/null
+++ b/src/test/compile-fail/gated-attr-literals.rs
@@ -0,0 +1,44 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that literals in attributes don't parse without the feature gate.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR string literals in top-level positions, are experimental
+#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown
+#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes, or string literals in top-level positions
+#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes, or string literals in top-level positions
+#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR non-string literals in attributes
+#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown
+    //~^ ERROR string literals in top-level positions, are experimental
+#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown
+    //~^ ERROR string literals in top-level positions, are experimental
+struct Q {  }
+
+#[rustc_error]
+fn main() { }
diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs
new file mode 100644
index 00000000000..0e2840c69d3
--- /dev/null
+++ b/src/test/parse-fail/suffixed-literal-meta.rs
@@ -0,0 +1,25 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+#[foo = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u16] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u32] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1u64] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1isize] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i8] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i16] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i32] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1i64] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes
+#[foo = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes
+fn main() { }
diff --git a/src/test/parse-fail/non-str-meta.rs b/src/test/pretty/attr-literals.rs
index 3e2e69d2814..ba8c580cb0a 100644
--- a/src/test/parse-fail/non-str-meta.rs
+++ b/src/test/pretty/attr-literals.rs
@@ -8,10 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z parse-only
+// pp-exact
+// Tests literals in attributes.
 
-// Issue #623 - non-string meta items are not serialized correctly;
-// for now just forbid them
+#![feature(custom_attribute, attr_literals)]
 
-#[foo = 1] //~ ERROR: non-string literals are not allowed in meta-items
-fn main() { }
+fn main() {
+    #![hello("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))]
+    #[align = 8]
+    fn f() { }
+
+    #[vec(1, 2, 3)]
+    fn g() { }
+}
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
index 42135703b75..6b688b006bd 100644
--- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs
@@ -24,7 +24,6 @@ use syntax::ast;
 use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
 use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
-use syntax::ptr::P;
 use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
 use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
 use syntax_pos::Span;
@@ -50,6 +49,7 @@ fn expand(cx: &mut ExtCtxt,
         generics: LifetimeBounds::empty(),
         associated_types: vec![],
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![
             MethodDef {
                 name: "total_sum",
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
index eeecd0b24e2..c6174745bfc 100644
--- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
@@ -21,12 +21,11 @@ extern crate rustc;
 extern crate rustc_plugin;
 
 use syntax::ast;
-use syntax::attr::AttrMetaMethods;
 use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
 use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
 use syntax::ptr::P;
-use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure};
+use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure};
 use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching};
 use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self};
 use syntax_pos::Span;
@@ -52,6 +51,7 @@ fn expand(cx: &mut ExtCtxt,
         generics: LifetimeBounds::empty(),
         associated_types: vec![],
         is_unsafe: false,
+        supports_unions: false,
         methods: vec![
             MethodDef {
                 name: "total_sum",
diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
index 3f50811f826..46fdf911258 100644
--- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
@@ -17,8 +17,10 @@ extern crate rustc;
 extern crate rustc_plugin;
 extern crate syntax_pos;
 
-use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind};
+use syntax::ast::{self, Item, MetaItem, ItemKind};
+use syntax::codemap::DUMMY_SP;
 use syntax::ext::base::*;
+use syntax::ext::quote::rt::ToTokens;
 use syntax::parse::{self, token};
 use syntax::ptr::P;
 use syntax::tokenstream::TokenTree;
@@ -41,10 +43,13 @@ pub fn plugin_registrar(reg: &mut Registry) {
         token::intern("duplicate"),
         // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
         MultiDecorator(Box::new(expand_duplicate)));
+    reg.register_syntax_extension(
+        token::intern("caller"),
+        // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
+        MultiDecorator(Box::new(expand_caller)));
 }
 
-fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
-                   -> Box<MacResult+'static> {
+fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
     if !tts.is_empty() {
         cx.span_fatal(sp, "make_a_1 takes no arguments");
     }
@@ -52,19 +57,18 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
 }
 
 // See Issue #15750
-fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
-                   -> Box<MacResult+'static> {
+fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
     // Parse an expression and emit it unchanged.
-    let mut parser = parse::new_parser_from_tts(cx.parse_sess(),
-        cx.cfg(), tts.to_vec());
+    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());
     let expr = parser.parse_expr().unwrap();
     MacEager::expr(quote_expr!(&mut *cx, $expr))
 }
 
 fn expand_into_foo_multi(cx: &mut ExtCtxt,
-                         sp: Span,
-                         attr: &MetaItem,
-                         it: Annotatable) -> Vec<Annotatable> {
+                         _sp: Span,
+                         _attr: &MetaItem,
+                         it: Annotatable)
+                         -> Vec<Annotatable> {
     match it {
         Annotatable::Item(it) => vec![
             Annotatable::Item(P(Item {
@@ -74,7 +78,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
             Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
             Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()),
         ],
-        Annotatable::ImplItem(it) => vec![
+        Annotatable::ImplItem(_it) => vec![
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Impl(_, _, _, _, _, mut items) => {
@@ -84,7 +88,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 }
             })
         ],
-        Annotatable::TraitItem(it) => vec![
+        Annotatable::TraitItem(_it) => vec![
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Trait(_, _, _, mut items) => {
@@ -99,15 +103,14 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
 
 // Create a duplicate of the annotatable, based on the MetaItem
 fn expand_duplicate(cx: &mut ExtCtxt,
-                    sp: Span,
+                    _sp: Span,
                     mi: &MetaItem,
                     it: &Annotatable,
-                    push: &mut FnMut(Annotatable))
-{
+                    push: &mut FnMut(Annotatable)) {
     let copy_name = match mi.node {
         ast::MetaItemKind::List(_, ref xs) => {
-            if let ast::MetaItemKind::Word(ref w) = xs[0].node {
-                token::str_to_ident(&w)
+            if let Some(word) = xs[0].word() {
+                token::str_to_ident(&word.name())
             } else {
                 cx.span_err(mi.span, "Expected word");
                 return;
@@ -142,4 +145,69 @@ fn expand_duplicate(cx: &mut ExtCtxt,
     }
 }
 
+pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
+                                   token: token::Token) -> Vec<TokenTree> {
+    let mut output: Vec<TokenTree> = vec![];
+    for (i, thing) in things.iter().enumerate() {
+        output.extend(thing.to_tokens(ecx));
+        if i < things.len() - 1 {
+            output.push(TokenTree::Token(DUMMY_SP, token.clone()));
+        }
+    }
+
+    output
+}
+
+fn expand_caller(cx: &mut ExtCtxt,
+                 sp: Span,
+                 mi: &MetaItem,
+                 it: &Annotatable,
+                 push: &mut FnMut(Annotatable)) {
+    let (orig_fn_name, ret_type) = match *it {
+        Annotatable::Item(ref item) => match item.node {
+            ItemKind::Fn(ref decl, _, _, _, _, _) => {
+                (item.ident, &decl.output)
+            }
+            _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")
+        },
+        _ => cx.span_fatal(sp, "Only functions can be annotated.")
+    };
+
+    let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() {
+        if list.len() < 2 {
+            cx.span_fatal(mi.span(), "Need a function name and at least one parameter.");
+        }
+
+        let fn_name = match list[0].name() {
+            Some(name) => token::str_to_ident(&name),
+            None => cx.span_fatal(list[0].span(), "First parameter must be an ident.")
+        };
+
+        (fn_name, &list[1..])
+    } else {
+        cx.span_fatal(mi.span, "Expected list.");
+    };
+
+    let literals: Vec<ast::Lit> = arguments.iter().map(|arg| {
+        if let Some(lit) = arg.literal() {
+            lit.clone()
+        } else {
+            cx.span_fatal(arg.span(), "Expected literal.");
+        }
+    }).collect();
+
+    let arguments = token_separate(cx, literals.as_slice(), token::Comma);
+    if let ast::FunctionRetTy::Ty(ref rt) = *ret_type {
+        push(Annotatable::Item(quote_item!(cx,
+                                           fn $caller_name() -> $rt {
+                                               $orig_fn_name($arguments)
+                                           }).unwrap()))
+    } else {
+        push(Annotatable::Item(quote_item!(cx,
+                                           fn $caller_name() {
+                                               $orig_fn_name($arguments)
+                                           }).unwrap()))
+    }
+}
+
 pub fn foo() {}
diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
index f0edc0f2b12..f21c914a76c 100644
--- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
@@ -30,7 +30,7 @@ use syntax::tokenstream;
 use rustc_plugin::Registry;
 
 struct Expander {
-    args: Vec<P<ast::MetaItem>>,
+    args: Vec<ast::NestedMetaItem>,
 }
 
 impl TTMacroExpander for Expander {
@@ -38,7 +38,7 @@ impl TTMacroExpander for Expander {
                    ecx: &'cx mut ExtCtxt,
                    sp: Span,
                    _: &[tokenstream::TokenTree]) -> Box<MacResult+'cx> {
-        let args = self.args.iter().map(|i| pprust::meta_item_to_string(&*i))
+        let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
             .collect::<Vec<_>>().join(", ");
         let interned = token::intern_and_get_ident(&args[..]);
         MacEager::expr(ecx.expr_str(sp, interned))
diff --git a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
index 8d19209208d..66ffff94333 100644
--- a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
+++ b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
@@ -8,8 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// `#[derive(Trait)]` works for empty structs/variants with braces
+// `#[derive(Trait)]` works for empty structs/variants with braces or parens.
 
+#![feature(relaxed_adts)]
 #![feature(rustc_private)]
 
 extern crate serialize as rustc_serialize;
@@ -19,10 +20,15 @@ extern crate serialize as rustc_serialize;
 struct S {}
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
+         Default, Debug, RustcEncodable, RustcDecodable)]
+struct Z();
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
          Debug, RustcEncodable, RustcDecodable)]
 enum E {
     V {},
     U,
+    W(),
 }
 
 fn main() {
@@ -34,6 +40,14 @@ fn main() {
     assert!(!(s < s1));
     assert_eq!(format!("{:?}", s), "S");
 
+    let z = Z();
+    let z1 = z;
+    let z2 = z.clone();
+    assert_eq!(z, z1);
+    assert_eq!(z, z2);
+    assert!(!(z < z1));
+    assert_eq!(format!("{:?}", z), "Z");
+
     let e = E::V {};
     let e1 = e;
     let e2 = e.clone();
@@ -41,4 +55,12 @@ fn main() {
     assert_eq!(e, e2);
     assert!(!(e < e1));
     assert_eq!(format!("{:?}", e), "V");
+
+    let e = E::W();
+    let e1 = e;
+    let e2 = e.clone();
+    assert_eq!(e, e1);
+    assert_eq!(e, e2);
+    assert!(!(e < e1));
+    assert_eq!(format!("{:?}", e), "W");
 }
diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs
new file mode 100644
index 00000000000..6dc651bb653
--- /dev/null
+++ b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs
@@ -0,0 +1,58 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:macro_crate_test.rs
+// ignore-stage1
+
+#![feature(plugin, custom_attribute, attr_literals)]
+#![plugin(macro_crate_test)]
+
+#[macro_use]
+#[no_link]
+extern crate macro_crate_test;
+
+// The `caller(name, args...)` attribute emits a new nullary function named
+// `name` that calls the annotated function with `args`. As an example, consider
+// the following:
+//
+//     #[caller(simple, 1, "hello", 3.14)]
+//     fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, float) {
+//         (num, string, float)
+//     }
+//
+// This results in a function named `simple` that calls `f(1, "hello", 3.14)`.
+// As a result, the expression `simple()` evaluates to `(1, "helllo", 3.14)`.
+
+#[caller(simple, 1, "hello", 3.14)]
+#[caller(simple1, 2, "bye", 6.28)]
+#[caller(simple2, 3, "hi", 1.01)]
+fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, f32) {
+    (num, string, float)
+}
+
+#[caller(complex, true, 10)]
+#[caller(complex1, false, 15)]
+#[caller(complex2, true, 20)]
+fn g(emit: bool, num: i32) -> Option<i32> {
+    match emit {
+        true => Some(num),
+        false => None
+    }
+}
+
+fn main() {
+    assert_eq!(simple(), (1, "hello", 3.14));
+    assert_eq!(simple1(), (2, "bye", 6.28));
+    assert_eq!(simple2(), (3, "hi", 1.01));
+
+    assert_eq!(complex(), Some(10));
+    assert_eq!(complex1(), None);
+    assert_eq!(complex2(), Some(20));
+}
diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.rs b/src/test/ui/mismatched_types/const-fn-in-trait.rs
new file mode 100644
index 00000000000..5e44030eab7
--- /dev/null
+++ b/src/test/ui/mismatched_types/const-fn-in-trait.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+#![feature(const_fn)]
+
+trait Foo {
+    fn f() -> u32;
+    const fn g();
+}
+
+impl Foo for u32 {
+    const fn f() -> u32 { 22 }
+    fn g() {}
+}
+
+fn main() { }
diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr
new file mode 100644
index 00000000000..f7b7635e41a
--- /dev/null
+++ b/src/test/ui/mismatched_types/const-fn-in-trait.stderr
@@ -0,0 +1,14 @@
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/const-fn-in-trait.rs:17:5
+   |
+17 |     const fn g();
+   |     ^^^^^ trait fns cannot be const
+
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/const-fn-in-trait.rs:21:5
+   |
+21 |     const fn f() -> u32 { 22 }
+   |     ^^^^^ trait fns cannot be const
+
+error: aborting due to 2 previous errors
+