}
}
+ 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,
ecx: &mut ExtCtxt,
sp: Span,
meta_item: &ast::MetaItem,
- item: &Annotatable,
- push: &mut FnMut(Annotatable));
+ item: Annotatable,
+ push: &mut FnMut(Annotatable));
}
impl<F> MultiItemDecorator for F
- where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &Annotatable, &mut FnMut(Annotatable))
+ 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,
+ item: Annotatable,
push: &mut FnMut(Annotatable)) {
(*self)(ecx, sp, meta_item, item, push)
}
/// based upon it.
#[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
/// 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
// 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");
}
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" },
// 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::*;
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));
// 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::*;
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(
// 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::*;
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));
// 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::*;
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
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::*;
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) => { {
//! 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::*;
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")
}
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")
}
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 {
// 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::*;
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));
//! }
//! ```
-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::*;
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")
}
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")
}
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 {
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;
pub fn expand(&self,
cx: &mut ExtCtxt,
mitem: &ast::MetaItem,
- item: &ast::Item,
- push: &mut FnMut(P<ast::Item>))
+ item: 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(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,
+ cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
}
- }).cloned());
- push(P(ast::Item {
- attrs: attrs,
- ..(*newitem).clone()
- }))
+ }
}
/// Given that we are deriving a trait `DerivedTrait` for a type like:
// 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::*;
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,
//! 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, MetaList, MetaNameValue};
+use ast::{MetaItem, MetaWord};
use attr::AttrMetaMethods;
-use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier, Annotatable};
+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)::+) => (
fn expand_derive(cx: &mut ExtCtxt,
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
})
}
$({
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 {
// 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::*;
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));
// 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::*;
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))),
.into_iter().map(|i| i.expect_item()).collect()
}
-#[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: 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 {
}
}
-#[allow(deprecated)] // This is needed because the `Decorator` variant is used
fn expand_annotatable(a: Annotatable,
fld: &mut MacroExpander)
-> SmallVector<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()
- .map(|i| Annotatable::Item(i))));
-
- 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 anns: SmallVector<Annotatable> = SmallVector::zero();
- dec.expand(fld.cx, attr.span, &*attr.node.value, &a,
- &mut |ann| anns.push(ann));
- decorator_items.extend(anns.into_iter()
- .flat_map(|ann| expand_annotatable(ann, 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 {
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,
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,
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 {