Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Treat MultiDecorators as a special case of MultiModifiers #34446

Merged
merged 2 commits into from Jun 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
111 changes: 33 additions & 78 deletions src/libsyntax/ext/expand.rs
Expand Up @@ -691,7 +691,7 @@ impl<'a> Folder for PatIdentRenamer<'a> {
}

fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
let new_items: SmallVector<Annotatable> = match a {
match a {
Annotatable::Item(it) => match it.node {
ast::ItemKind::Mac(..) => {
it.and_then(|it| match it.node {
Expand Down Expand Up @@ -728,63 +728,6 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
expand_impl_item(ii.unwrap(), fld).into_iter().
map(|ii| Annotatable::ImplItem(P(ii))).collect()
}
};

new_items.into_iter().flat_map(|a| decorate(a, fld)).collect()
}

fn decorate(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
let mut decorator_items = SmallVector::zero();
let mut new_attrs = Vec::new();
expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);

let mut new_items = SmallVector::one(a.fold_attrs(new_attrs));
new_items.push_all(decorator_items);
new_items
}

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 = intern(&attr.name());
match fld.cx.syntax_env.find(mname) {
Some(rc) => match *rc {
MultiDecorator(ref dec) => {
attr::mark_used(&attr);

fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(mname),
span: Some(attr.span),
// attributes can do whatever they like,
// for now.
allow_internal_unstable: true,
}
});

let mut items: SmallVector<Annotatable> = SmallVector::zero();
dec.expand(fld.cx,
attr.span,
&attr.node.value,
&a,
&mut |ann| items.push(ann));

for item in items {
for configured_item in item.fold_with(&mut fld.strip_unconfigured()) {
decorator_items.extend(expand_annotatable(configured_item, fld));
}
}

fld.cx.bt_pop();
}
_ => new_attrs.push((*attr).clone()),
},
_ => new_attrs.push((*attr).clone()),
}
}
}

Expand All @@ -793,9 +736,12 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe
item = item.map_attrs(|mut attrs| {
for i in 0..attrs.len() {
if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
if let MultiModifier(..) = *extension {
multi_modifier = Some((attrs.remove(i), extension));
break;
match *extension {
MultiModifier(..) | MultiDecorator(..) => {
multi_modifier = Some((attrs.remove(i), extension));
break;
}
_ => {}
}
}
}
Expand All @@ -804,23 +750,32 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe

match multi_modifier {
None => expand_multi_modified(item, fld),
Some((attr, extension)) => match *extension {
MultiModifier(ref mac) => {
attr::mark_used(&attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(intern(&attr.name())),
span: Some(attr.span),
// attributes can do whatever they like, for now
allow_internal_unstable: true,
}
});
let modified = mac.expand(fld.cx, attr.span, &attr.node.value, item);
fld.cx.bt_pop();
modified.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect()
}
_ => unreachable!(),
Some((attr, extension)) => {
attr::mark_used(&attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(intern(&attr.name())),
span: Some(attr.span),
// attributes can do whatever they like, for now
allow_internal_unstable: true,
}
});

let modified = match *extension {
MultiModifier(ref mac) => mac.expand(fld.cx, attr.span, &attr.node.value, item),
MultiDecorator(ref mac) => {
let mut items = Vec::new();
mac.expand(fld.cx, attr.span, &attr.node.value, &item,
&mut |item| items.push(item));
items.push(item);
items
}
_ => unreachable!(),
};

fld.cx.bt_pop();
modified.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect()
}
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/libsyntax_ext/deriving/generic/mod.rs
Expand Up @@ -345,15 +345,18 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
/// This method helps to extract all the type parameters referenced from a
/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
/// is not global and starts with `T`, or a `TyQPath`.
fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast::Ty>> {
fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name], span: Span, cx: &ExtCtxt)
-> Vec<P<ast::Ty>> {
use syntax::visit;

struct Visitor<'a> {
struct Visitor<'a, 'b: 'a> {
cx: &'a ExtCtxt<'b>,
span: Span,
ty_param_names: &'a [ast::Name],
types: Vec<P<ast::Ty>>,
}

impl<'a> visit::Visitor for Visitor<'a> {
impl<'a, 'b> visit::Visitor for Visitor<'a, 'b> {
fn visit_ty(&mut self, ty: &ast::Ty) {
match ty.node {
ast::TyKind::Path(_, ref path) if !path.global => {
Expand All @@ -371,11 +374,18 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast

visit::walk_ty(self, ty)
}

fn visit_mac(&mut self, mac: &ast::Mac) {
let span = Span { expn_id: self.span.expn_id, ..mac.span };
self.cx.span_err(span, "`derive` cannot be used on items with type macros");
}
}

let mut visitor = Visitor {
ty_param_names: ty_param_names,
types: Vec::new(),
span: span,
cx: cx,
};

visit::Visitor::visit_ty(&mut visitor, ty);
Expand Down Expand Up @@ -556,7 +566,7 @@ impl<'a> TraitDef<'a> {

let mut processed_field_types = HashSet::new();
for field_ty in field_tys {
let tys = find_type_parameters(&field_ty, &ty_param_names);
let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx);

for ty in tys {
// if we have already handled this type, skip it
Expand Down
12 changes: 6 additions & 6 deletions src/test/compile-fail/issue-32950.rs
Expand Up @@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(type_macros, concat_idents, rustc_attrs)]
#![allow(unused)]
#![feature(type_macros, concat_idents)]

#[derive(Debug)] struct FooBar;
#[derive(Debug)] struct Baz<T>(T, concat_idents!(Foo, Bar));
#[derive(Debug)] //~ NOTE in this expansion
struct Baz<T>(
concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros
);

#[rustc_error]
fn main() {} //~ ERROR compilation successful
fn main() {}