about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-05-13 08:31:17 +0000
committerbors <bors@rust-lang.org>2015-05-13 08:31:17 +0000
commitdd9dcc1e283e32b8353062627e4bd3af2b82a7b3 (patch)
tree2c83d8577b5716beba0dc38fbb8e723f2c811d5f /src/libsyntax
parentfa433875274ff4a7c4cab7d87c1284ba782ef643 (diff)
parentc544e838de7a0f0c11c681aa0b29056bdee5cb55 (diff)
downloadrust-dd9dcc1e283e32b8353062627e4bd3af2b82a7b3.tar.gz
rust-dd9dcc1e283e32b8353062627e4bd3af2b82a7b3.zip
Auto merge of #25024 - nrc:mulit-decor, r=sfackler
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs58
-rw-r--r--src/libsyntax/ext/deriving/bounds.rs15
-rw-r--r--src/libsyntax/ext/deriving/clone.rs10
-rw-r--r--src/libsyntax/ext/deriving/cmp/eq.rs10
-rw-r--r--src/libsyntax/ext/deriving/cmp/ord.rs10
-rw-r--r--src/libsyntax/ext/deriving/cmp/partial_eq.rs10
-rw-r--r--src/libsyntax/ext/deriving/cmp/partial_ord.rs10
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs18
-rw-r--r--src/libsyntax/ext/deriving/default.rs10
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs18
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs70
-rw-r--r--src/libsyntax/ext/deriving/hash.rs10
-rw-r--r--src/libsyntax/ext/deriving/mod.rs81
-rw-r--r--src/libsyntax/ext/deriving/primitive.rs10
-rw-r--r--src/libsyntax/ext/deriving/show.rs10
-rw-r--r--src/libsyntax/ext/expand.rs263
-rw-r--r--src/libsyntax/print/pprust.rs1
17 files changed, 353 insertions, 261 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 50ab430f148..2ecefef5104 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -30,6 +30,8 @@ use std::collections::HashMap;
 use std::rc::Rc;
 use std::default::Default;
 
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemDecorator")]
 pub trait ItemDecorator {
     fn expand(&self,
               ecx: &mut ExtCtxt,
@@ -39,6 +41,9 @@ pub trait ItemDecorator {
               push: &mut FnMut(P<ast::Item>));
 }
 
+#[allow(deprecated)]
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemDecorator")]
 impl<F> ItemDecorator for F
     where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P<ast::Item>))
 {
@@ -52,6 +57,8 @@ impl<F> ItemDecorator for F
     }
 }
 
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemModifier")]
 pub trait ItemModifier {
     fn expand(&self,
               ecx: &mut ExtCtxt,
@@ -61,9 +68,13 @@ pub trait ItemModifier {
               -> P<ast::Item>;
 }
 
+#[allow(deprecated)]
+#[unstable(feature = "rustc_private")]
+#[deprecated(since = "1.0.0", reason = "replaced by MultiItemModifier")]
 impl<F> ItemModifier for F
     where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, P<ast::Item>) -> P<ast::Item>
 {
+
     fn expand(&self,
               ecx: &mut ExtCtxt,
               span: Span,
@@ -112,6 +123,16 @@ impl Annotatable {
         }
     }
 
+    pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable
+        where F: FnMut(P<ast::Item>) -> P<ast::Item>,
+              G: FnMut(Annotatable) -> Annotatable
+    {
+        match self {
+            Annotatable::Item(i) => Annotatable::Item(f(i)),
+            _ => or(self)
+        }
+    }
+
     pub fn expect_trait_item(self) -> P<ast::TraitItem> {
         match self {
             Annotatable::TraitItem(i) => i,
@@ -127,6 +148,29 @@ impl Annotatable {
     }
 }
 
+// A more flexible ItemDecorator.
+pub trait MultiItemDecorator {
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              sp: Span,
+              meta_item: &ast::MetaItem,
+              item: Annotatable,
+              push: &mut FnMut(Annotatable));
+}
+
+impl<F> MultiItemDecorator for F
+    where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable, &mut FnMut(Annotatable))
+{
+    fn expand(&self,
+              ecx: &mut ExtCtxt,
+              sp: Span,
+              meta_item: &ast::MetaItem,
+              item: Annotatable,
+              push: &mut FnMut(Annotatable)) {
+        (*self)(ecx, sp, meta_item, item, push)
+    }
+}
+
 // A more flexible ItemModifier (ItemModifier should go away, eventually, FIXME).
 // meta_item is the annotation, item is the item being modified, parent_item
 // is the impl or trait item is declared in if item is part of such a thing.
@@ -397,12 +441,22 @@ impl MacResult for DummyResult {
 pub enum SyntaxExtension {
     /// A syntax extension that is attached to an item and creates new items
     /// based upon it.
-    ///
-    /// `#[derive(...)]` is an `ItemDecorator`.
+    #[unstable(feature = "rustc_private")]
+    #[deprecated(since = "1.0.0", reason = "replaced by MultiDecorator")]
+    #[allow(deprecated)]
     Decorator(Box<ItemDecorator + 'static>),
 
+    /// A syntax extension that is attached to an item and creates new items
+    /// based upon it.
+    ///
+    /// `#[derive(...)]` is a `MultiItemDecorator`.
+    MultiDecorator(Box<MultiItemDecorator + 'static>),
+
     /// A syntax extension that is attached to an item and modifies it
     /// in-place.
+    #[unstable(feature = "rustc_private")]
+    #[deprecated(since = "1.0.0", reason = "replaced by MultiModifier")]
+    #[allow(deprecated)]
     Modifier(Box<ItemModifier + 'static>),
 
     /// A syntax extension that is attached to an item and modifies it
diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs
index eb3debeac99..0593de6db07 100644
--- a/src/libsyntax/ext/deriving/bounds.rs
+++ b/src/libsyntax/ext/deriving/bounds.rs
@@ -8,18 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item};
+use ast::MetaItem;
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
-use ptr::P;
 
 pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
                                     span: Span,
                                     _: &MetaItem,
-                                    _: &Item,
-                                    _: &mut FnMut(P<Item>))
+                                    _: Annotatable,
+                                    _: &mut FnMut(Annotatable))
 {
     cx.span_err(span, "this unsafe trait should be implemented explicitly");
 }
@@ -27,8 +26,8 @@ pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
 pub fn expand_deriving_copy(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: &MetaItem,
-                            item: &Item,
-                            push: &mut FnMut(P<Item>))
+                            item: Annotatable,
+                            push: &mut FnMut(Annotatable))
 {
     let path = Path::new(vec![
         if cx.use_std { "std" } else { "core" },
@@ -46,5 +45,5 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push);
+    trait_def.expand(cx, mitem, &item, push);
 }
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index 97fc3f0bf56..0d8fb471429 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item, Expr};
+use ast::{MetaItem, Expr};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -20,8 +20,8 @@ use ptr::P;
 pub fn expand_deriving_clone(cx: &mut ExtCtxt,
                              span: Span,
                              mitem: &MetaItem,
-                             item: &Item,
-                             push: &mut FnMut(P<Item>))
+                             item: Annotatable,
+                             push: &mut FnMut(Annotatable))
 {
     let inline = cx.meta_word(span, InternedString::new("inline"));
     let attrs = vec!(cx.attribute(span, inline));
@@ -47,7 +47,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 fn cs_clone(
diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs
index ce8f0a7b32b..bd7c7d85a37 100644
--- a/src/libsyntax/ext/deriving/cmp/eq.rs
+++ b/src/libsyntax/ext/deriving/cmp/eq.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item, Expr};
+use ast::{MetaItem, Expr};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -20,8 +20,8 @@ use ptr::P;
 pub fn expand_deriving_eq(cx: &mut ExtCtxt,
                           span: Span,
                           mitem: &MetaItem,
-                          item: &Item,
-                          push: &mut FnMut(P<Item>))
+                          item: Annotatable,
+                          push: &mut FnMut(Annotatable))
 {
     fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
         cs_same_method(
@@ -66,5 +66,5 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
         ),
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs
index 94cc0d9c493..b4caf0ec26e 100644
--- a/src/libsyntax/ext/deriving/cmp/ord.rs
+++ b/src/libsyntax/ext/deriving/cmp/ord.rs
@@ -9,9 +9,9 @@
 // except according to those terms.
 
 use ast;
-use ast::{MetaItem, Item, Expr};
+use ast::{MetaItem, Expr};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -21,8 +21,8 @@ use ptr::P;
 pub fn expand_deriving_ord(cx: &mut ExtCtxt,
                            span: Span,
                            mitem: &MetaItem,
-                           item: &Item,
-                           push: &mut FnMut(P<Item>))
+                           item: Annotatable,
+                           push: &mut FnMut(Annotatable))
 {
     let inline = cx.meta_word(span, InternedString::new("inline"));
     let attrs = vec!(cx.attribute(span, inline));
@@ -48,7 +48,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 
diff --git a/src/libsyntax/ext/deriving/cmp/partial_eq.rs b/src/libsyntax/ext/deriving/cmp/partial_eq.rs
index 61eb81c6755..5d744334745 100644
--- a/src/libsyntax/ext/deriving/cmp/partial_eq.rs
+++ b/src/libsyntax/ext/deriving/cmp/partial_eq.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item, Expr, self};
+use ast::{MetaItem, Expr, self};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -20,8 +20,8 @@ use ptr::P;
 pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
                                   span: Span,
                                   mitem: &MetaItem,
-                                  item: &Item,
-                                  push: &mut FnMut(P<Item>))
+                                  item: Annotatable,
+                                  push: &mut FnMut(Annotatable))
 {
     // structures are equal if all fields are equal, and non equal, if
     // any fields are not equal or if the enum variants are different
@@ -90,5 +90,5 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
         ),
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
diff --git a/src/libsyntax/ext/deriving/cmp/partial_ord.rs b/src/libsyntax/ext/deriving/cmp/partial_ord.rs
index dbb779decac..3ef73f6556e 100644
--- a/src/libsyntax/ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax/ext/deriving/cmp/partial_ord.rs
@@ -11,9 +11,9 @@
 pub use self::OrderingOp::*;
 
 use ast;
-use ast::{MetaItem, Item, Expr};
+use ast::{MetaItem, Expr};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -23,8 +23,8 @@ use ptr::P;
 pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
                                    span: Span,
                                    mitem: &MetaItem,
-                                   item: &Item,
-                                   push: &mut FnMut(P<Item>))
+                                   item: Annotatable,
+                                   push: &mut FnMut(Annotatable))
 {
     macro_rules! md {
         ($name:expr, $op:expr, $equal:expr) => { {
@@ -80,7 +80,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
         ],
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 #[derive(Copy, Clone)]
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 0b31f06f87d..75c9bc42ea2 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -11,9 +11,9 @@
 //! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
 
 use ast;
-use ast::{MetaItem, Item, Expr, MutMutable};
+use ast::{MetaItem, Expr, MutMutable};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -24,8 +24,8 @@ use ptr::P;
 pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
                                        span: Span,
                                        mitem: &MetaItem,
-                                       item: &Item,
-                                       push: &mut FnMut(P<Item>))
+                                       item: Annotatable,
+                                       push: &mut FnMut(Annotatable))
 {
     expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
 }
@@ -33,8 +33,8 @@ pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
 pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Item,
-                                 push: &mut FnMut(P<Item>))
+                                 item: Annotatable,
+                                 push: &mut FnMut(Annotatable))
 {
     expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
 }
@@ -42,8 +42,8 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
 fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Item,
-                                 push: &mut FnMut(P<Item>),
+                                 item: Annotatable,
+                                 push: &mut FnMut(Annotatable),
                                  krate: &'static str)
 {
     if !cx.use_std {
@@ -87,7 +87,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs
index f04eaa08dea..e9984c84e32 100644
--- a/src/libsyntax/ext/deriving/default.rs
+++ b/src/libsyntax/ext/deriving/default.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item, Expr};
+use ast::{MetaItem, Expr};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -20,8 +20,8 @@ use ptr::P;
 pub fn expand_deriving_default(cx: &mut ExtCtxt,
                                span: Span,
                                mitem: &MetaItem,
-                               item: &Item,
-                               push: &mut FnMut(P<Item>))
+                               item: Annotatable,
+                               push: &mut FnMut(Annotatable))
 {
     let inline = cx.meta_word(span, InternedString::new("inline"));
     let attrs = vec!(cx.attribute(span, inline));
@@ -46,7 +46,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
         ),
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index 92944d64933..4430c58700a 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -88,9 +88,9 @@
 //! }
 //! ```
 
-use ast::{MetaItem, Item, Expr, ExprRet, MutMutable};
+use ast::{MetaItem, Expr, ExprRet, MutMutable};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt,Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -100,8 +100,8 @@ use ptr::P;
 pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
                                        span: Span,
                                        mitem: &MetaItem,
-                                       item: &Item,
-                                       push: &mut FnMut(P<Item>))
+                                       item: Annotatable,
+                                       push: &mut FnMut(Annotatable))
 {
     expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize")
 }
@@ -109,8 +109,8 @@ pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
 pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Item,
-                                 push: &mut FnMut(P<Item>))
+                                 item: Annotatable,
+                                 push: &mut FnMut(Annotatable))
 {
     expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
 }
@@ -118,8 +118,8 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
 fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
                                  span: Span,
                                  mitem: &MetaItem,
-                                 item: &Item,
-                                 push: &mut FnMut(P<Item>),
+                                 item: Annotatable,
+                                 push: &mut FnMut(Annotatable),
                                  krate: &'static str)
 {
     if !cx.use_std {
@@ -163,7 +163,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index f7511f9753a..1525f1a822b 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -197,7 +197,7 @@ use ast::{EnumDef, Expr, Ident, Generics, StructDef};
 use ast_util;
 use attr;
 use attr::AttrMetaMethods;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use codemap::{self, DUMMY_SP};
 use codemap::Span;
@@ -380,41 +380,49 @@ impl<'a> TraitDef<'a> {
     pub fn expand(&self,
                   cx: &mut ExtCtxt,
                   mitem: &ast::MetaItem,
-                  item: &'a ast::Item,
-                  push: &mut FnMut(P<ast::Item>))
+                  item: &'a Annotatable,
+                  push: &mut FnMut(Annotatable))
     {
-        let newitem = match item.node {
-            ast::ItemStruct(ref struct_def, ref generics) => {
-                self.expand_struct_def(cx,
-                                       &**struct_def,
-                                       item.ident,
-                                       generics)
-            }
-            ast::ItemEnum(ref enum_def, ref generics) => {
-                self.expand_enum_def(cx,
-                                     enum_def,
-                                     &item.attrs[..],
-                                     item.ident,
-                                     generics)
+        match *item {
+            Annotatable::Item(ref item) => {
+                let newitem = match item.node {
+                    ast::ItemStruct(ref struct_def, ref generics) => {
+                        self.expand_struct_def(cx,
+                                               &struct_def,
+                                               item.ident,
+                                               generics)
+                    }
+                    ast::ItemEnum(ref enum_def, ref generics) => {
+                        self.expand_enum_def(cx,
+                                             enum_def,
+                                             &item.attrs,
+                                             item.ident,
+                                             generics)
+                    }
+                    _ => {
+                        cx.span_err(mitem.span,
+                                    "`derive` may only be applied to structs and enums");
+                        return;
+                    }
+                };
+                // Keep the lint attributes of the previous item to control how the
+                // generated implementations are linted
+                let mut attrs = newitem.attrs.clone();
+                attrs.extend(item.attrs.iter().filter(|a| {
+                    match &a.name()[..] {
+                        "allow" | "warn" | "deny" | "forbid" => true,
+                        _ => false,
+                    }
+                }).cloned());
+                push(Annotatable::Item(P(ast::Item {
+                    attrs: attrs,
+                    ..(*newitem).clone()
+                })))
             }
             _ => {
                 cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
-                return;
             }
-        };
-        // Keep the lint attributes of the previous item to control how the
-        // generated implementations are linted
-        let mut attrs = newitem.attrs.clone();
-        attrs.extend(item.attrs.iter().filter(|a| {
-            match &a.name()[..] {
-                "allow" | "warn" | "deny" | "forbid" => true,
-                _ => false,
-            }
-        }).cloned());
-        push(P(ast::Item {
-            attrs: attrs,
-            ..(*newitem).clone()
-        }))
+        }
     }
 
     /// Given that we are deriving a trait `DerivedTrait` for a type like:
diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs
index b9835eda791..698e788d65f 100644
--- a/src/libsyntax/ext/deriving/hash.rs
+++ b/src/libsyntax/ext/deriving/hash.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item, Expr, MutMutable};
+use ast::{MetaItem, Expr, MutMutable};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -19,8 +19,8 @@ use ptr::P;
 pub fn expand_deriving_hash(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: &MetaItem,
-                            item: &Item,
-                            push: &mut FnMut(P<Item>))
+                            item: Annotatable,
+                            push: &mut FnMut(Annotatable))
 {
 
     let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None,
@@ -52,7 +52,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    hash_trait_def.expand(cx, mitem, item, push);
+    hash_trait_def.expand(cx, mitem, &item, push);
 }
 
 fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index a3725355840..61848cca059 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -13,14 +13,13 @@
 //! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
 //! the standard library, and "std" is the core library.
 
-use ast::{Item, MetaItem, MetaWord};
+use ast::{MetaItem, MetaWord};
 use attr::AttrMetaMethods;
-use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier};
+use ext::base::{ExtCtxt, SyntaxEnv, MultiDecorator, MultiItemDecorator, MultiModifier, Annotatable};
 use ext::build::AstBuilder;
 use feature_gate;
 use codemap::Span;
 use parse::token::{intern, intern_and_get_ident};
-use ptr::P;
 
 macro_rules! pathvec {
     ($($x:ident)::+) => (
@@ -78,42 +77,48 @@ pub mod ord;
 pub mod generic;
 
 fn expand_derive(cx: &mut ExtCtxt,
-                 _: Span,
+                 span: Span,
                  mitem: &MetaItem,
-                 item: P<Item>) -> P<Item> {
-    item.map(|mut item| {
-        if mitem.value_str().is_some() {
-            cx.span_err(mitem.span, "unexpected value in `derive`");
-        }
+                 annotatable: Annotatable)
+                 -> Annotatable {
+    annotatable.map_item_or(|item| {
+        item.map(|mut item| {
+            if mitem.value_str().is_some() {
+                cx.span_err(mitem.span, "unexpected value in `derive`");
+            }
 
-        let traits = mitem.meta_item_list().unwrap_or(&[]);
-        if traits.is_empty() {
-            cx.span_warn(mitem.span, "empty trait list in `derive`");
-        }
+            let traits = mitem.meta_item_list().unwrap_or(&[]);
+            if traits.is_empty() {
+                cx.span_warn(mitem.span, "empty trait list in `derive`");
+            }
 
-        for titem in traits.iter().rev() {
-            let tname = match titem.node {
-                MetaWord(ref tname) => tname,
-                _ => {
-                    cx.span_err(titem.span, "malformed `derive` entry");
+            for titem in traits.iter().rev() {
+                let tname = match titem.node {
+                    MetaWord(ref tname) => tname,
+                    _ => {
+                        cx.span_err(titem.span, "malformed `derive` entry");
+                        continue;
+                    }
+                };
+
+                if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
+                    feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
+                                                   "custom_derive",
+                                                   titem.span,
+                                                   feature_gate::EXPLAIN_CUSTOM_DERIVE);
                     continue;
                 }
-            };
-
-            if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
-                feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
-                                               "custom_derive",
-                                               titem.span,
-                                               feature_gate::EXPLAIN_CUSTOM_DERIVE);
-                continue;
-            }
 
-            // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
-            item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
-                intern_and_get_ident(&format!("derive_{}", tname)))));
-        }
+                // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
+                item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
+                    intern_and_get_ident(&format!("derive_{}", tname)))));
+            }
 
-        item
+            item
+        })
+    }, |a| {
+        cx.span_err(span, "`derive` can only be applied to items");
+        a
     })
 }
 
@@ -124,24 +129,24 @@ macro_rules! derive_traits {
             $({
                 struct DeriveExtension;
 
-                impl ItemDecorator for DeriveExtension {
+                impl MultiItemDecorator for DeriveExtension {
                     fn expand(&self,
                               ecx: &mut ExtCtxt,
                               sp: Span,
                               mitem: &MetaItem,
-                              item: &Item,
-                              push: &mut FnMut(P<Item>)) {
+                              annotatable: Annotatable,
+                              push: &mut FnMut(Annotatable)) {
                         warn_if_deprecated(ecx, sp, $name);
-                        $func(ecx, sp, mitem, item, push);
+                        $func(ecx, sp, mitem, annotatable, push);
                     }
                 }
 
                 env.insert(intern(concat!("derive_", $name)),
-                           Decorator(Box::new(DeriveExtension)));
+                           MultiDecorator(Box::new(DeriveExtension)));
             })+
 
             env.insert(intern("derive"),
-                       Modifier(Box::new(expand_derive)));
+                       MultiModifier(Box::new(expand_derive)));
         }
 
         fn is_builtin_trait(name: &str) -> bool {
diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs
index a972cfe1355..4fe9aefa1a4 100644
--- a/src/libsyntax/ext/deriving/primitive.rs
+++ b/src/libsyntax/ext/deriving/primitive.rs
@@ -8,10 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{MetaItem, Item, Expr};
+use ast::{MetaItem, Expr};
 use ast;
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -21,8 +21,8 @@ use ptr::P;
 pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                       span: Span,
                                       mitem: &MetaItem,
-                                      item: &Item,
-                                      push: &mut FnMut(P<Item>))
+                                      item: Annotatable,
+                                      push: &mut FnMut(Annotatable))
 {
     let inline = cx.meta_word(span, InternedString::new("inline"));
     let attrs = vec!(cx.attribute(span, inline));
@@ -67,7 +67,7 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
         associated_types: Vec::new(),
     };
 
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs
index 3ce1f6f12ce..dc634df2073 100644
--- a/src/libsyntax/ext/deriving/show.rs
+++ b/src/libsyntax/ext/deriving/show.rs
@@ -9,9 +9,9 @@
 // except according to those terms.
 
 use ast;
-use ast::{MetaItem, Item, Expr,};
+use ast::{MetaItem, Expr,};
 use codemap::Span;
-use ext::base::ExtCtxt;
+use ext::base::{ExtCtxt, Annotatable};
 use ext::build::AstBuilder;
 use ext::deriving::generic::*;
 use ext::deriving::generic::ty::*;
@@ -21,8 +21,8 @@ use ptr::P;
 pub fn expand_deriving_show(cx: &mut ExtCtxt,
                             span: Span,
                             mitem: &MetaItem,
-                            item: &Item,
-                            push: &mut FnMut(P<Item>))
+                            item: Annotatable,
+                            push: &mut FnMut(Annotatable))
 {
     // &mut ::std::fmt::Formatter
     let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))),
@@ -49,7 +49,7 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt,
         ],
         associated_types: Vec::new(),
     };
-    trait_def.expand(cx, mitem, item, push)
+    trait_def.expand(cx, mitem, &item, push)
 }
 
 /// We use the debug builders to do the heavy lifting here
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 05499959b75..d71557bd737 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -477,58 +477,6 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
         .into_iter().map(|i| i.expect_item()).collect()
 }
 
-fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
-                         -> P<ast::Item> {
-    // partition the attributes into ItemModifiers and others
-    let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
-
-    // update the attrs, leave everything else alone. Is this mutation really a good idea?
-    it = P(ast::Item {
-        attrs: other_attrs,
-        ..(*it).clone()
-    });
-
-    if modifiers.is_empty() {
-        let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
-        return it.expect_item();
-    }
-
-    for attr in &modifiers {
-        let mname = attr.name();
-
-        match fld.cx.syntax_env.find(&intern(&mname)) {
-            Some(rc) => match *rc {
-                Modifier(ref mac) => {
-                    attr::mark_used(attr);
-                    fld.cx.bt_push(ExpnInfo {
-                        call_site: attr.span,
-                        callee: NameAndSpan {
-                            name: mname.to_string(),
-                            format: MacroAttribute,
-                            span: None,
-                            // attributes can do whatever they like,
-                            // for now
-                            allow_internal_unstable: true,
-                        }
-                    });
-                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
-                    fld.cx.bt_pop();
-                }
-                _ => unreachable!()
-            },
-            _ => unreachable!()
-        }
-    }
-
-    // Expansion may have added new ItemModifiers.
-    // It is possible, that an item modifier could expand to a multi-modifier or
-    // vice versa. In this case we will expand all modifiers before multi-modifiers,
-    // which might give an odd ordering. However, I think it is unlikely that the
-    // two kinds will be mixed, and I old-style multi-modifiers should be deprecated
-    // anyway.
-    expand_item_modifiers(it, fld)
-}
-
 /// Expand item_underscore
 fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
     match item {
@@ -1090,48 +1038,7 @@ fn expand_annotatable(a: Annotatable,
 
     let mut decorator_items = SmallVector::zero();
     let mut new_attrs = Vec::new();
-    for attr in a.attrs() {
-        let mname = attr.name();
-
-        match fld.cx.syntax_env.find(&intern(&mname)) {
-            Some(rc) => match *rc {
-                Decorator(ref dec) => {
-                    let it = match a {
-                        Annotatable::Item(ref it) => it,
-                        // ItemDecorators are only implemented for Items.
-                        _ => break,
-                    };
-
-                    attr::mark_used(attr);
-
-                    fld.cx.bt_push(ExpnInfo {
-                        call_site: attr.span,
-                        callee: NameAndSpan {
-                            name: mname.to_string(),
-                            format: MacroAttribute,
-                            span: Some(attr.span),
-                            // attributes can do whatever they like,
-                            // for now.
-                            allow_internal_unstable: true,
-                        }
-                    });
-
-                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
-                    // but that double-mut-borrows fld
-                    let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
-                    dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
-                               &mut |item| items.push(item));
-                    decorator_items.extend(
-                        items.into_iter()
-                             .flat_map(|item| expand_item(item, fld).into_iter()));
-
-                    fld.cx.bt_pop();
-                }
-                _ => new_attrs.push((*attr).clone()),
-            },
-            _ => new_attrs.push((*attr).clone()),
-        }
-    }
+    expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
 
     let mut new_items: SmallVector<Annotatable> = match a {
         Annotatable::Item(it) => match it.node {
@@ -1185,38 +1092,105 @@ fn expand_annotatable(a: Annotatable,
         }
     };
 
-    new_items.push_all(decorator_items.into_iter().map(|i| Annotatable::Item(i)).collect());
+    new_items.push_all(decorator_items);
     new_items
 }
 
-// partition the attributes into ItemModifiers and others
-fn modifiers(attrs: &Vec<ast::Attribute>,
-             fld: &MacroExpander)
-             -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
-    attrs.iter().cloned().partition(|attr| {
-        match fld.cx.syntax_env.find(&intern(&attr.name())) {
-            Some(rc) => match *rc {
-                Modifier(_) => true,
-                _ => false
-            },
-            _ => false
+// Partition a set of attributes into one kind of attribute, and other kinds.
+macro_rules! partition {
+    ($fn_name: ident, $variant: ident) => {
+        #[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
+        fn $fn_name(attrs: &[ast::Attribute],
+                    fld: &MacroExpander)
+                     -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
+            attrs.iter().cloned().partition(|attr| {
+                match fld.cx.syntax_env.find(&intern(&attr.name())) {
+                    Some(rc) => match *rc {
+                        $variant(..) => true,
+                        _ => false
+                    },
+                    _ => false
+                }
+            })
         }
-    })
+    }
 }
 
-// partition the attributes into MultiModifiers and others
-fn multi_modifiers(attrs: &[ast::Attribute],
-                   fld: &MacroExpander)
-                   -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
-    attrs.iter().cloned().partition(|attr| {
-        match fld.cx.syntax_env.find(&intern(&attr.name())) {
+partition!(modifiers, Modifier);
+partition!(multi_modifiers, MultiModifier);
+
+
+#[allow(deprecated)] // The `allow` is needed because the `Decorator` variant is used.
+fn expand_decorators(a: Annotatable,
+                     fld: &mut MacroExpander,
+                     decorator_items: &mut SmallVector<Annotatable>,
+                     new_attrs: &mut Vec<ast::Attribute>)
+{
+    for attr in a.attrs() {
+        let mname = attr.name();
+        match fld.cx.syntax_env.find(&intern(&mname)) {
             Some(rc) => match *rc {
-                MultiModifier(_) => true,
-                _ => false
+                Decorator(ref dec) => {
+                    attr::mark_used(&attr);
+
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.to_string(),
+                            format: MacroAttribute,
+                            span: Some(attr.span),
+                            // attributes can do whatever they like,
+                            // for now.
+                            allow_internal_unstable: true,
+                        }
+                    });
+
+                    // we'd ideally decorator_items.push_all(expand_item(item, fld)),
+                    // but that double-mut-borrows fld
+                    let mut items: SmallVector<Annotatable> = SmallVector::zero();
+                    dec.expand(fld.cx,
+                               attr.span,
+                               &attr.node.value,
+                               &a.clone().expect_item(),
+                               &mut |item| items.push(Annotatable::Item(item)));
+                    decorator_items.extend(items.into_iter()
+                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
+
+                    fld.cx.bt_pop();
+                }
+                MultiDecorator(ref dec) => {
+                    attr::mark_used(&attr);
+
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.to_string(),
+                            format: MacroAttribute,
+                            span: Some(attr.span),
+                            // attributes can do whatever they like,
+                            // for now.
+                            allow_internal_unstable: true,
+                        }
+                    });
+
+                    // we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
+                    // but that double-mut-borrows fld
+                    let mut items: SmallVector<Annotatable> = SmallVector::zero();
+                    dec.expand(fld.cx,
+                               attr.span,
+                               &attr.node.value,
+                               a.clone(),
+                               &mut |ann| items.push(ann));
+                    decorator_items.extend(items.into_iter()
+                        .flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
+
+                    fld.cx.bt_pop();
+                }
+                _ => new_attrs.push((*attr).clone()),
             },
-            _ => false
+            _ => new_attrs.push((*attr).clone()),
         }
-    })
+    }
 }
 
 fn expand_item_multi_modifier(mut it: Annotatable,
@@ -1243,7 +1217,7 @@ fn expand_item_multi_modifier(mut it: Annotatable,
                         callee: NameAndSpan {
                             name: mname.to_string(),
                             format: MacroAttribute,
-                            span: None,
+                            span: Some(attr.span),
                             // attributes can do whatever they like,
                             // for now
                             allow_internal_unstable: true,
@@ -1262,6 +1236,59 @@ fn expand_item_multi_modifier(mut it: Annotatable,
     expand_item_multi_modifier(it, fld)
 }
 
+#[allow(deprecated)] // This is needed because the `ItemModifier` trait is used
+fn expand_item_modifiers(mut it: P<ast::Item>,
+                         fld: &mut MacroExpander)
+                         -> P<ast::Item> {
+    // partition the attributes into ItemModifiers and others
+    let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
+
+    // update the attrs, leave everything else alone. Is this mutation really a good idea?
+    it = P(ast::Item {
+        attrs: other_attrs,
+        ..(*it).clone()
+    });
+
+    if modifiers.is_empty() {
+        let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
+        return it.expect_item();
+    }
+
+    for attr in &modifiers {
+        let mname = attr.name();
+
+        match fld.cx.syntax_env.find(&intern(&mname)) {
+            Some(rc) => match *rc {
+                Modifier(ref mac) => {
+                    attr::mark_used(attr);
+                    fld.cx.bt_push(ExpnInfo {
+                        call_site: attr.span,
+                        callee: NameAndSpan {
+                            name: mname.to_string(),
+                            format: MacroAttribute,
+                            span: Some(attr.span),
+                            // attributes can do whatever they like,
+                            // for now
+                            allow_internal_unstable: true,
+                        }
+                    });
+                    it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
+                    fld.cx.bt_pop();
+                }
+                _ => unreachable!()
+            },
+            _ => unreachable!()
+        }
+    }
+
+    // Expansion may have added new ItemModifiers.
+    // It is possible, that an item modifier could expand to a multi-modifier or
+    // vice versa. In this case we will expand all modifiers before multi-modifiers,
+    // which might give an odd ordering. However, I think it is unlikely that the
+    // two kinds will be mixed, and old-style multi-modifiers are deprecated.
+    expand_item_modifiers(it, fld)
+}
+
 fn expand_impl_item(ii: P<ast::ImplItem>, fld: &mut MacroExpander)
                  -> SmallVector<P<ast::ImplItem>> {
     match ii.node {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5c1f6cc12f5..5a002dd790f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -799,7 +799,6 @@ impl<'a> State<'a> {
         word(&mut self.s, ";")
     }
 
-
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
         try!(self.hardbreak_if_not_bol());