Auto merge of #25024 - nrc:mulit-decor, r=sfackler

This commit is contained in:
bors 2015-05-13 08:31:17 +00:00
commit dd9dcc1e28
22 changed files with 477 additions and 282 deletions

View File

@ -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 => {

View File

@ -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

View File

@ -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);
}

View File

@ -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(

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)]

View File

@ -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,

View File

@ -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> {

View File

@ -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,

View File

@ -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:

View File

@ -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> {

View File

@ -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`");
}
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");
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;
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`");
}
// #[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)))));
}
let traits = mitem.meta_item_list().unwrap_or(&[]);
if traits.is_empty() {
cx.span_warn(mitem.span, "empty trait list in `derive`");
}
item
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;
}
// #[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
})
}, |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 {

View File

@ -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> {

View File

@ -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

View File

@ -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 {

View File

@ -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());

View File

@ -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<ast::Item>)) {
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)
}

View File

@ -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<ast::Item>)) {
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

View File

@ -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() {}

View File

@ -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 <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)]
#![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 };
}