diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index 322b5d3a8cf27..04df464129541 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -14,8 +14,8 @@ use lint::{LintPassObject, LintId, Lint}; use session::Session; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; -use syntax::ext::base::{IdentTT, Decorator, Modifier, MultiModifier, MacroRulesTT}; -use syntax::ext::base::MacroExpanderFn; +use syntax::ext::base::{IdentTT, Decorator, Modifier, MultiModifier, MultiDecorator}; +use syntax::ext::base::{MacroExpanderFn, MacroRulesTT}; use syntax::codemap::Span; use syntax::parse::token; use syntax::ptr::P; @@ -84,6 +84,7 @@ impl<'a> Registry<'a> { /// Register a syntax extension of any kind. /// /// This is the most general hook into `libsyntax`'s expansion behavior. + #[allow(deprecated)] pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) { self.syntax_exts.push((name, match extension { NormalTT(ext, _, allow_internal_unstable) => { @@ -93,6 +94,7 @@ impl<'a> Registry<'a> { IdentTT(ext, Some(self.krate_span), allow_internal_unstable) } Decorator(ext) => Decorator(ext), + MultiDecorator(ext) => MultiDecorator(ext), Modifier(ext) => Modifier(ext), MultiModifier(ext) => MultiModifier(ext), MacroRulesTT => { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 50ab430f148ca..2ecefef51045e 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)); } +#[allow(deprecated)] +#[unstable(feature = "rustc_private")] +#[deprecated(since = "1.0.0", reason = "replaced by MultiItemDecorator")] impl ItemDecorator for F where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P)) { @@ -52,6 +57,8 @@ impl 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; } +#[allow(deprecated)] +#[unstable(feature = "rustc_private")] +#[deprecated(since = "1.0.0", reason = "replaced by MultiItemModifier")] impl ItemModifier for F where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, P) -> P { + fn expand(&self, ecx: &mut ExtCtxt, span: Span, @@ -112,6 +123,16 @@ impl Annotatable { } } + pub fn map_item_or(self, mut f: F, mut or: G) -> Annotatable + where F: FnMut(P) -> P, + G: FnMut(Annotatable) -> Annotatable + { + match self { + Annotatable::Item(i) => Annotatable::Item(f(i)), + _ => or(self) + } + } + pub fn expect_trait_item(self) -> P { 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 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), + /// A syntax extension that is attached to an item and creates new items + /// based upon it. + /// + /// `#[derive(...)]` is a `MultiItemDecorator`. + MultiDecorator(Box), + /// 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), /// 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 eb3debeac9901..0593de6db07a7 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)) + _: 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: 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 97fc3f0bf5600..0d8fb47142937 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: 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 ce8f0a7b32b90..bd7c7d85a375f 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: Annotatable, + push: &mut FnMut(Annotatable)) { fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { 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 94cc0d9c493f2..b4caf0ec26e27 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: 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 61eb81c6755e2..5d744334745d3 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: 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 dbb779decace2..3ef73f6556e30 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: 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 0b31f06f87d06..75c9bc42ea2bf 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: 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: 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: 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 f04eaa08dead1..e9984c84e322f 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: 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 { diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 92944d649332f..4430c58700af3 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: 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: 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: 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 f7511f9753aa1..1525f1a822bec 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)) + 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 b9835eda791f7..698e788d65f00 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: 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 { diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index a37253558405f..61848cca059ce 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) -> P { - 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)) { + 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 a972cfe135511..4fe9aefa1a4df 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: 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 { diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index 3ce1f6f12ceab..dc634df2073a4 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: 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 05499959b7585..d71557bd7372d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -477,58 +477,6 @@ pub fn expand_item(it: P, fld: &mut MacroExpander) .into_iter().map(|i| i.expect_item()).collect() } -fn expand_item_modifiers(mut it: P, fld: &mut MacroExpander) - -> P { - // 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> = 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 = 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, - fld: &MacroExpander) - -> (Vec, Vec) { - 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, Vec) { + 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, Vec) { - 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, + new_attrs: &mut Vec) +{ + 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 = 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 = 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, + fld: &mut MacroExpander) + -> P { + // 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, fld: &mut MacroExpander) -> SmallVector> { match ii.node { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 5c1f6cc12f59e..5a002dd790fee 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()); diff --git a/src/test/auxiliary/custom_derive_plugin.rs b/src/test/auxiliary/custom_derive_plugin.rs index 78381395dc92c..0edbeb2d02ca4 100644 --- a/src/test/auxiliary/custom_derive_plugin.rs +++ b/src/test/auxiliary/custom_derive_plugin.rs @@ -19,7 +19,7 @@ extern crate rustc; use syntax::ast; use syntax::codemap::Span; -use syntax::ext::base::{Decorator, ExtCtxt}; +use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; use syntax::ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; @@ -31,14 +31,14 @@ use rustc::plugin::Registry; pub fn plugin_registrar(reg: &mut Registry) { reg.register_syntax_extension( token::intern("derive_TotalSum"), - Decorator(box expand)); + MultiDecorator(box expand)); } fn expand(cx: &mut ExtCtxt, span: Span, mitem: &ast::MetaItem, - item: &ast::Item, - push: &mut FnMut(P)) { + item: Annotatable, + push: &mut FnMut(Annotatable)) { let trait_def = TraitDef { span: span, attributes: vec![], @@ -70,5 +70,5 @@ fn expand(cx: &mut ExtCtxt, ], }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, &item, push) } diff --git a/src/test/auxiliary/custom_derive_plugin_attr.rs b/src/test/auxiliary/custom_derive_plugin_attr.rs index 445aa743a77fe..92963b2812dd8 100644 --- a/src/test/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/auxiliary/custom_derive_plugin_attr.rs @@ -20,7 +20,7 @@ extern crate rustc; use syntax::ast; use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; -use syntax::ext::base::{Decorator, ExtCtxt}; +use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; use syntax::ext::deriving::generic::{Substructure, Struct, EnumMatching}; @@ -33,14 +33,14 @@ use rustc::plugin::Registry; pub fn plugin_registrar(reg: &mut Registry) { reg.register_syntax_extension( token::intern("derive_TotalSum"), - Decorator(box expand)); + MultiDecorator(box expand)); } fn expand(cx: &mut ExtCtxt, span: Span, mitem: &ast::MetaItem, - item: &ast::Item, - push: &mut FnMut(P)) { + item: Annotatable, + push: &mut FnMut(Annotatable)) { let trait_def = TraitDef { span: span, attributes: vec![], @@ -61,7 +61,7 @@ fn expand(cx: &mut ExtCtxt, ], }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand(cx, mitem, &item, push) } // Mostly copied from syntax::ext::deriving::hash diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs index 54aac5195aee3..53a6672d4888d 100644 --- a/src/test/auxiliary/macro_crate_test.rs +++ b/src/test/auxiliary/macro_crate_test.rs @@ -10,23 +10,20 @@ // force-host -#![feature(plugin_registrar, quote)] -#![feature(box_syntax, rustc_private)] +#![feature(plugin_registrar, quote, rustc_private)] extern crate syntax; extern crate rustc; -use syntax::ast::{self, TokenTree, Item, MetaItem}; +use syntax::ast::{self, TokenTree, Item, MetaItem, ImplItem, TraitItem}; use syntax::codemap::Span; use syntax::ext::base::*; -use syntax::parse::token; -use syntax::parse; +use syntax::parse::{self, token}; use syntax::ptr::P; use rustc::plugin::Registry; #[macro_export] macro_rules! exported_macro { () => (2) } - macro_rules! unexported_macro { () => (3) } #[plugin_registrar] @@ -41,6 +38,10 @@ pub fn plugin_registrar(reg: &mut Registry) { token::intern("into_multi_foo"), // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiModifier(Box::new(expand_into_foo_multi))); + reg.register_syntax_extension( + token::intern("duplicate"), + // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + MultiDecorator(Box::new(expand_duplicate))); } fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) @@ -103,4 +104,49 @@ 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, + mi: &MetaItem, + it: Annotatable, + push: &mut FnMut(Annotatable)) +{ + let copy_name = match mi.node { + ast::MetaItem_::MetaList(_, ref xs) => { + if let ast::MetaItem_::MetaWord(ref w) = xs[0].node { + token::str_to_ident(&w) + } else { + cx.span_err(mi.span, "Expected word"); + return; + } + } + _ => { + cx.span_err(mi.span, "Expected list"); + return; + } + }; + + // Duplicate the item but replace its ident by the MetaItem + match it.clone() { + Annotatable::Item(it) => { + let mut new_it = (*it).clone(); + new_it.attrs.clear(); + new_it.ident = copy_name; + push(Annotatable::Item(P(new_it))); + } + Annotatable::ImplItem(it) => { + let mut new_it = (*it).clone(); + new_it.attrs.clear(); + new_it.ident = copy_name; + push(Annotatable::ImplItem(P(new_it))); + } + Annotatable::TraitItem(tt) => { + let mut new_it = (*tt).clone(); + new_it.attrs.clear(); + new_it.ident = copy_name; + push(Annotatable::TraitItem(P(new_it))); + } + } +} + pub fn foo() {} diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs new file mode 100644 index 0000000000000..3c215b6ca48dd --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-crate-multi-decorator.rs @@ -0,0 +1,55 @@ +// 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 or the MIT license +// , 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)] +#![plugin(macro_crate_test)] + +#[macro_use] +#[no_link] +extern crate macro_crate_test; + +// The duplicate macro will create a copy of the item with the given identifier. + +#[duplicate(MyCopy)] +struct MyStruct { + number: i32 +} + +trait TestTrait { + #[duplicate(TestType2)] + type TestType; + + #[duplicate(required_fn2)] + fn required_fn(&self); + + #[duplicate(provided_fn2)] + fn provided_fn(&self) { } +} + +impl TestTrait for MyStruct { + #[duplicate(TestType2)] + type TestType = f64; + + #[duplicate(required_fn2)] + fn required_fn(&self) { } +} + +fn main() { + let s = MyStruct { number: 42 }; + s.required_fn(); + s.required_fn2(); + s.provided_fn(); + s.provided_fn2(); + + let s = MyCopy { number: 42 }; +}