From 66ef652559ab670b4f7c3be973e019f0d55b3644 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 24 Jun 2016 03:23:44 +0000 Subject: [PATCH 1/2] Disallow `derive` on items with type macros --- src/libsyntax_ext/deriving/generic/mod.rs | 18 ++++++++++++++---- src/test/compile-fail/issue-32950.rs | 12 ++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 647e414a7fd27..e01f4ed1f9bd2 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -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 ``, 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> { +fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name], span: Span, cx: &ExtCtxt) + -> Vec> { 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>, } - 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 => { @@ -371,11 +374,18 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec 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 diff --git a/src/test/compile-fail/issue-32950.rs b/src/test/compile-fail/issue-32950.rs index e47ebdd6a6938..e8ca1c1fa98ff 100644 --- a/src/test/compile-fail/issue-32950.rs +++ b/src/test/compile-fail/issue-32950.rs @@ -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, concat_idents!(Foo, Bar)); +#[derive(Debug)] //~ NOTE in this expansion +struct Baz( + concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros +); -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {} From a595ffaac5045eb8950785f050f9e0b76cc4f3eb Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 24 Jun 2016 03:25:37 +0000 Subject: [PATCH 2/2] Treat `MultiDecorator`s as a special case of `MultiModifier`s --- src/libsyntax/ext/expand.rs | 111 +++++++++++------------------------- 1 file changed, 33 insertions(+), 78 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 3036a88430a2b..a10d890014017 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -691,7 +691,7 @@ impl<'a> Folder for PatIdentRenamer<'a> { } fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector { - let new_items: SmallVector = match a { + match a { Annotatable::Item(it) => match it.node { ast::ItemKind::Mac(..) => { it.and_then(|it| match it.node { @@ -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 { - 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, - new_attrs: &mut Vec) -{ - 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 = 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()), - } } } @@ -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; + } + _ => {} } } } @@ -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() } } }