Move derive macro expansion into the MacroExpander

This removes the expand_derives function, and sprinkles
the functionality throughout the Invocation Collector,
Expander and Resolver.
This commit is contained in:
Josh Driver 2017-02-01 21:03:09 +10:30
parent 0a7380d7fc
commit fbdd038866
17 changed files with 378 additions and 265 deletions

View File

@ -250,6 +250,32 @@ impl<'a> base::Resolver for Resolver<'a> {
}
result
}
fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
match self.builtin_macros.get(&tname).cloned() {
Some(binding) => Ok(binding.get_macro(self)),
None => Err(Determinacy::Undetermined),
}
}
fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
let ast::Path { span, .. } = *path;
match self.resolve_macro(scope, path, false) {
Ok(ext) => match *ext {
SyntaxExtension::BuiltinDerive(..) |
SyntaxExtension::ProcMacroDerive(..) => Ok(ext),
_ => Err(Determinacy::Determined),
},
Err(Determinacy::Undetermined) if force => {
let msg = format!("cannot find derive macro `{}` in this scope", path);
let mut err = self.session.struct_span_err(span, &msg);
err.emit();
Err(Determinacy::Determined)
},
Err(err) => Err(err),
}
}
}
impl<'a> Resolver<'a> {

View File

@ -536,6 +536,9 @@ pub trait Resolver {
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy>;
fn resolve_builtin_macro(&mut self, tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy>;
fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy>;
}
#[derive(Copy, Clone, Debug)]
@ -562,6 +565,13 @@ impl Resolver for DummyResolver {
-> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
fn resolve_builtin_macro(&mut self, _tname: Name) -> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
fn resolve_derive_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
}
#[derive(Clone)]

218
src/libsyntax/ext/derive.rs Normal file
View File

@ -0,0 +1,218 @@
// Copyright 2012-2017 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.
use ast::Name;
use attr;
use ast::{self, NestedMetaItem}; use ext::base::{ExtCtxt, SyntaxExtension};
use codemap;
use ext::build::AstBuilder;
use feature_gate;
use symbol::Symbol;
use syntax_pos::Span;
pub fn derive_attr_trait<'a>(cx: &mut ExtCtxt, attr: &'a ast::Attribute)
-> Option<&'a NestedMetaItem> {
if attr.name() != "derive" {
return None;
}
if attr.value_str().is_some() {
cx.span_err(attr.span, "unexpected value in `derive`");
return None;
}
let traits = attr.meta_item_list().unwrap_or(&[]);
if traits.is_empty() {
cx.span_warn(attr.span, "empty trait list in `derive`");
return None;
}
return traits.get(0);
}
pub fn verify_derive_attrs(cx: &mut ExtCtxt, attrs: &[ast::Attribute]) {
for attr in attrs {
if attr.name() != "derive" {
continue;
}
if attr.value_str().is_some() {
cx.span_err(attr.span, "unexpected value in `derive`");
}
let traits = attr.meta_item_list().unwrap_or(&[]).to_owned();
if traits.is_empty() {
cx.span_warn(attr.span, "empty trait list in `derive`");
attr::mark_used(&attr);
continue;
}
for titem in traits {
if titem.word().is_none() {
cx.span_err(titem.span, "malformed `derive` entry");
}
}
}
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum DeriveType {
Legacy,
ProcMacro,
Builtin
}
impl DeriveType {
// Classify a derive trait name by resolving the macro.
pub fn classify(cx: &mut ExtCtxt, tname: Name) -> DeriveType {
let legacy_derive_name = Symbol::intern(&format!("derive_{}", tname));
if let Ok(_) = cx.resolver.resolve_builtin_macro(legacy_derive_name) {
return DeriveType::Legacy;
}
match cx.resolver.resolve_builtin_macro(tname) {
Ok(ext) => match *ext {
SyntaxExtension::BuiltinDerive(..) => DeriveType::Builtin,
_ => DeriveType::ProcMacro,
},
Err(_) => DeriveType::ProcMacro,
}
}
}
pub fn get_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>,
derive_type: DeriveType) -> Option<ast::Attribute> {
for i in 0..attrs.len() {
if attrs[i].name() != "derive" {
continue;
}
if attrs[i].value_str().is_some() {
continue;
}
let mut traits = attrs[i].meta_item_list().unwrap_or(&[]).to_owned();
// First, weed out malformed #[derive]
traits.retain(|titem| titem.word().is_some());
let mut titem = None;
// See if we can find a matching trait.
for j in 0..traits.len() {
let tname = match traits[j].name() {
Some(tname) => tname,
_ => continue,
};
if DeriveType::classify(cx, tname) == derive_type {
titem = Some(traits.remove(j));
break;
}
}
// If we find a trait, remove the trait from the attribute.
if let Some(titem) = titem {
if traits.len() == 0 {
attrs.remove(i);
} else {
let derive = Symbol::intern("derive");
let mitem = cx.meta_list(titem.span, derive, traits);
attrs[i] = cx.attribute(titem.span, mitem);
}
let derive = Symbol::intern("derive");
let mitem = cx.meta_list(titem.span, derive, vec![titem]);
return Some(cx.attribute(mitem.span, mitem));
}
}
return None;
}
fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
Span {
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(Symbol::intern(attr_name)),
span: Some(span),
allow_internal_unstable: true,
},
}),
..span
}
}
pub fn add_derived_markers(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) {
if attrs.is_empty() {
return;
}
let titems = attrs.iter().filter(|a| {
a.name() == "derive"
}).flat_map(|a| {
a.meta_item_list().unwrap_or(&[]).iter()
}).filter_map(|titem| {
titem.name()
}).collect::<Vec<_>>();
let span = attrs[0].span;
if !attrs.iter().any(|a| a.name() == "structural_match") &&
titems.iter().any(|t| *t == "PartialEq") && titems.iter().any(|t| *t == "Eq") {
let structural_match = Symbol::intern("structural_match");
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
let meta = cx.meta_word(span, structural_match);
attrs.push(cx.attribute(span, meta));
}
if !attrs.iter().any(|a| a.name() == "rustc_copy_clone_marker") &&
titems.iter().any(|t| *t == "Copy") && titems.iter().any(|t| *t == "Clone") {
let structural_match = Symbol::intern("rustc_copy_clone_marker");
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
let meta = cx.meta_word(span, structural_match);
attrs.push(cx.attribute(span, meta));
}
}
pub fn find_derive_attr(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>)
-> Option<ast::Attribute> {
verify_derive_attrs(cx, attrs);
get_derive_attr(cx, attrs, DeriveType::Legacy).and_then(|a| {
let titem = derive_attr_trait(cx, &a);
titem.and_then(|titem| {
let tword = titem.word().unwrap();
let tname = tword.name();
if !cx.ecfg.enable_custom_derive() {
feature_gate::emit_feature_err(
&cx.parse_sess,
"custom_derive",
titem.span,
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_CUSTOM_DERIVE
);
None
} else {
let name = Symbol::intern(&format!("derive_{}", tname));
if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
cx.span_warn(titem.span,
feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
}
let mitem = cx.meta_word(titem.span, name);
Some(cx.attribute(mitem.span, mitem))
}
})
}).or_else(|| {
get_derive_attr(cx, attrs, DeriveType::ProcMacro)
}).or_else(|| {
add_derived_markers(cx, attrs);
get_derive_attr(cx, attrs, DeriveType::Builtin)
})
}

View File

@ -8,26 +8,27 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{Block, Ident, Mac_, PatKind};
use ast::{self, Block, Ident, Mac_, PatKind};
use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
use ast;
use ext::hygiene::Mark;
use ext::placeholders::{placeholder, PlaceholderExpander};
use attr::{self, HasAttrs};
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
use syntax_pos::{self, Span, ExpnId};
use config::{is_test_or_bench, StripUnconfigured};
use ext::base::*;
use ext::derive::{find_derive_attr, derive_attr_trait};
use ext::hygiene::Mark;
use ext::placeholders::{placeholder, PlaceholderExpander};
use feature_gate::{self, Features};
use fold;
use fold::*;
use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts};
use parse::parser::Parser;
use parse::token;
use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts};
use print::pprust;
use ptr::P;
use std_inject;
use symbol::Symbol;
use symbol::keywords;
use syntax_pos::{self, Span, ExpnId};
use tokenstream::{TokenTree, TokenStream};
use util::small_vector::SmallVector;
use visit::Visitor;
@ -166,6 +167,10 @@ pub enum InvocationKind {
attr: ast::Attribute,
item: Annotatable,
},
Derive {
attr: ast::Attribute,
item: Annotatable,
},
}
impl Invocation {
@ -173,6 +178,7 @@ impl Invocation {
match self.kind {
InvocationKind::Bang { span, .. } => span,
InvocationKind::Attr { ref attr, .. } => attr.span,
InvocationKind::Derive { ref attr, .. } => attr.span,
}
}
}
@ -250,6 +256,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let path = ast::Path::from_ident(attr.span, ident);
self.cx.resolver.resolve_macro(scope, &path, force)
}
InvocationKind::Derive { ref attr, .. } => {
let titem = derive_attr_trait(self.cx, &attr).unwrap();
let tname = titem.name().expect("Expected derive macro name");
let ident = Ident::with_empty_ctxt(tname);
let path = ast::Path::from_ident(attr.span, ident);
self.cx.resolver.resolve_derive_macro(scope, &path, force)
}
};
let ext = match resolution {
Ok(ext) => Some(ext),
@ -330,6 +343,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
match invoc.kind {
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
}
}
@ -486,6 +500,71 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
})
}
/// Expand a derive invocation. Returns the result of expansion.
fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
let Invocation { expansion_kind: kind, .. } = invoc;
let (attr, item) = match invoc.kind {
InvocationKind::Derive { attr, item } => (attr, item),
_ => unreachable!(),
};
attr::mark_used(&attr);
let titem = derive_attr_trait(self.cx, &attr).unwrap();
let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
let name = Symbol::intern(&format!("derive({})", tname));
let mitem = &attr.value;
self.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(attr.name()),
span: Some(attr.span),
allow_internal_unstable: false,
}
});
match *ext {
SyntaxExtension::ProcMacroDerive(ref ext) => {
let span = Span {
expn_id: self.cx.codemap().record_expansion(ExpnInfo {
call_site: mitem.span,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern(&format!("derive({})", tname))),
span: None,
allow_internal_unstable: false,
},
}),
..mitem.span
};
return kind.expect_from_annotatables(ext.expand(self.cx, span, &mitem, item));
}
SyntaxExtension::BuiltinDerive(func) => {
let span = Span {
expn_id: self.cx.codemap().record_expansion(ExpnInfo {
call_site: titem.span,
callee: NameAndSpan {
format: MacroAttribute(name),
span: None,
allow_internal_unstable: true,
},
}),
..titem.span
};
let mut items = Vec::new();
func(self.cx, span, &mitem, &item, &mut |a| {
items.push(a)
});
items.insert(0, item);
return kind.expect_from_annotatables(items);
}
_ => {
let msg = &format!("macro `{}` may not be used for derive attributes", name);
self.cx.span_err(attr.span, &msg);
kind.dummy(attr.span)
}
}
}
fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span)
-> Expansion {
let mut parser = self.cx.new_parser_from_tts(&toks.trees().cloned().collect::<Vec<_>>());
@ -595,16 +674,31 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
-> Expansion {
self.collect(kind, InvocationKind::Attr { attr: attr, item: item })
let invoc_kind = if attr.name() == "derive" {
if kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems {
self.cx.span_err(attr.span, "`derive` can be only be applied to items");
return kind.expect_from_annotatables(::std::iter::once(item));
}
InvocationKind::Derive { attr: attr, item: item }
} else {
InvocationKind::Attr { attr: attr, item: item }
};
self.collect(kind, invoc_kind)
}
// If `item` is an attr invocation, remove and return the macro attribute.
fn classify_item<T: HasAttrs>(&mut self, mut item: T) -> (T, Option<ast::Attribute>) {
let mut attr = None;
item = item.map_attrs(|mut attrs| {
attr = self.cx.resolver.find_attr_invoc(&mut attrs);
attr = self.cx.resolver.find_attr_invoc(&mut attrs).or_else(|| {
find_derive_attr(self.cx, &mut attrs)
});
attrs
});
(item, attr)
}

View File

@ -128,6 +128,7 @@ pub mod print {
pub mod ext {
pub mod base;
pub mod build;
pub mod derive;
pub mod expand;
pub mod placeholders;
pub mod hygiene;

View File

@ -54,7 +54,7 @@ impl MultiItemModifier for ProcMacroDerive {
Annotatable::Item(item) => item,
Annotatable::ImplItem(_) |
Annotatable::TraitItem(_) => {
ecx.span_err(span, "proc_macro_derive attributes may only be \
ecx.span_err(span, "proc-macro derives may only be \
applied to struct/enum items");
return Vec::new()
}
@ -63,7 +63,7 @@ impl MultiItemModifier for ProcMacroDerive {
ItemKind::Struct(..) |
ItemKind::Enum(..) => {},
_ => {
ecx.span_err(span, "proc_macro_derive attributes may only be \
ecx.span_err(span, "proc-macro derives may only be \
applied to struct/enum items");
return Vec::new()
}
@ -81,7 +81,7 @@ impl MultiItemModifier for ProcMacroDerive {
let stream = match res {
Ok(stream) => stream,
Err(e) => {
let msg = "proc_macro_derive attribute panicked";
let msg = "proc-macro derive panicked";
let mut err = ecx.struct_span_fatal(span, msg);
if let Some(s) = e.downcast_ref::<String>() {
err.help(&format!("message: {}", s));
@ -100,7 +100,7 @@ impl MultiItemModifier for ProcMacroDerive {
Ok(new_items) => new_items,
Err(_) => {
// FIXME: handle this better
let msg = "proc_macro_derive produced unparseable tokens";
let msg = "proc-macro derive produced unparseable tokens";
ecx.struct_span_fatal(span, msg).emit();
panic!(FatalError);
}

View File

@ -13,6 +13,7 @@
use deriving;
use deriving::generic::*;
use deriving::generic::ty::*;
use deriving::warn_if_deprecated;
use syntax::ast;
use syntax::ast::{Expr, MetaItem, Mutability};
@ -35,7 +36,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
mitem: &MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable)) {
deriving::warn_if_deprecated(cx, span, "Decodable");
warn_if_deprecated(cx, span, "Decodable");
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
}

View File

@ -91,6 +91,7 @@
use deriving;
use deriving::generic::*;
use deriving::generic::ty::*;
use deriving::warn_if_deprecated;
use syntax::ast::{Expr, ExprKind, MetaItem, Mutability};
use syntax::ext::base::{Annotatable, ExtCtxt};
@ -112,7 +113,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
mitem: &MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable)) {
deriving::warn_if_deprecated(cx, span, "Encodable");
warn_if_deprecated(cx, span, "Encodable");
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
}

View File

@ -11,12 +11,10 @@
//! The compiler code necessary to implement the `#[derive]` extensions.
use std::rc::Rc;
use syntax::ast::{self, MetaItem};
use syntax::attr::HasAttrs;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
@ -90,241 +88,6 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
}
}
pub fn expand_derive(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
annotatable: Annotatable)
-> Vec<Annotatable> {
debug!("expand_derive: span = {:?}", span);
debug!("expand_derive: mitem = {:?}", mitem);
debug!("expand_derive: annotatable input = {:?}", annotatable);
let mut item = match annotatable {
Annotatable::Item(item) => item,
other => {
cx.span_err(span, "`derive` can only be applied to items");
return vec![other]
}
};
let derive = Symbol::intern("derive");
let mut derive_attrs = Vec::new();
item = item.map_attrs(|attrs| {
let partition = attrs.into_iter().partition(|attr| attr.name() == derive);
derive_attrs = partition.0;
partition.1
});
// Expand `#[derive]`s after other attribute macro invocations.
if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
attrs.push(cx.attribute(span, mitem.clone()));
attrs.extend(derive_attrs);
attrs
}))];
}
let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
if mitem.value_str().is_some() {
cx.span_err(mitem.span, "unexpected value in `derive`");
}
let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
if traits.is_empty() {
cx.span_warn(mitem.span, "empty trait list in `derive`");
}
traits
};
let mut traits = get_traits(mitem, cx);
for derive_attr in derive_attrs {
traits.extend(get_traits(&derive_attr.value, cx));
}
// First, weed out malformed #[derive]
traits.retain(|titem| {
if titem.word().is_none() {
cx.span_err(titem.span, "malformed `derive` entry");
false
} else {
true
}
});
// Next, check for old-style #[derive(Foo)]
//
// These all get expanded to `#[derive_Foo]` and will get expanded first. If
// we actually add any attributes here then we return to get those expanded
// and then eventually we'll come back to finish off the other derive modes.
let mut new_attributes = Vec::new();
traits.retain(|titem| {
let tword = titem.word().unwrap();
let tname = tword.name();
if is_builtin_trait(tname) || {
let derive_mode = ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(tname));
cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| {
if let SyntaxExtension::ProcMacroDerive(_) = *ext { true } else { false }
}).unwrap_or(false)
} {
return true;
}
if !cx.ecfg.enable_custom_derive() {
feature_gate::emit_feature_err(&cx.parse_sess,
"custom_derive",
titem.span,
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_CUSTOM_DERIVE);
} else {
let name = Symbol::intern(&format!("derive_{}", tname));
if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
}
let mitem = cx.meta_word(titem.span, name);
new_attributes.push(cx.attribute(mitem.span, mitem));
}
false
});
if new_attributes.len() > 0 {
item = item.map(|mut i| {
i.attrs.extend(new_attributes);
if traits.len() > 0 {
let list = cx.meta_list(mitem.span, derive, traits);
i.attrs.push(cx.attribute(mitem.span, list));
}
i
});
return vec![Annotatable::Item(item)]
}
// Now check for macros-1.1 style custom #[derive].
//
// Expand each of them in order given, but *before* we expand any built-in
// derive modes. The logic here is to:
//
// 1. Collect the remaining `#[derive]` annotations into a list. If
// there are any left, attach a `#[derive]` attribute to the item
// that we're currently expanding with the remaining derive modes.
// 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
// 3. Expand the current item we're expanding, getting back a list of
// items that replace it.
// 4. Extend the returned list with the current list of items we've
// collected so far.
// 5. Return everything!
//
// If custom derive extensions end up threading through the `#[derive]`
// attribute, we'll get called again later on to continue expanding
// those modes.
let macros_11_derive = traits.iter()
.cloned()
.enumerate()
.filter(|&(_, ref name)| !is_builtin_trait(name.name().unwrap()))
.next();
if let Some((i, titem)) = macros_11_derive {
let tname = ast::Ident::with_empty_ctxt(titem.name().unwrap());
let path = ast::Path::from_ident(titem.span, tname);
let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
traits.remove(i);
if traits.len() > 0 {
item = item.map(|mut i| {
let list = cx.meta_list(mitem.span, derive, traits);
i.attrs.push(cx.attribute(mitem.span, list));
i
});
}
let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap());
let mitem = cx.meta_list(titem.span, derive, vec![titem]);
let item = Annotatable::Item(item);
let span = Span {
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: mitem.span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(Symbol::intern(&format!("derive({})", tname))),
span: None,
allow_internal_unstable: false,
},
}),
..mitem.span
};
if let SyntaxExtension::ProcMacroDerive(ref ext) = *ext {
return ext.expand(cx, span, &mitem, item);
} else {
unreachable!()
}
}
// Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
// any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.
// RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
// `#[structural_match]` attribute.
let (partial_eq, eq) = (Symbol::intern("PartialEq"), Symbol::intern("Eq"));
if traits.iter().any(|t| t.name() == Some(partial_eq)) &&
traits.iter().any(|t| t.name() == Some(eq)) {
let structural_match = Symbol::intern("structural_match");
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
let meta = cx.meta_word(span, structural_match);
item = item.map(|mut i| {
i.attrs.push(cx.attribute(span, meta));
i
});
}
// RFC #1521. `Clone` can assume that `Copy` types' clone implementation is
// the same as the copy implementation.
//
// Add a marker attribute here picked up during #[derive(Clone)]
let (copy, clone) = (Symbol::intern("Copy"), Symbol::intern("Clone"));
if traits.iter().any(|t| t.name() == Some(clone)) &&
traits.iter().any(|t| t.name() == Some(copy)) {
let marker = Symbol::intern("rustc_copy_clone_marker");
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
let meta = cx.meta_word(span, marker);
item = item.map(|mut i| {
i.attrs.push(cx.attribute(span, meta));
i
});
}
let mut items = Vec::new();
for titem in traits.iter() {
let tname = titem.word().unwrap().name();
let name = Symbol::intern(&format!("derive({})", tname));
let tname_cx = ast::Ident::with_empty_ctxt(titem.name().unwrap());
let mitem = cx.meta_word(titem.span, name);
let path = ast::Path::from_ident(titem.span, tname_cx);
let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
let span = Span {
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: titem.span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(name),
span: None,
allow_internal_unstable: true,
},
}),
..titem.span
};
if let SyntaxExtension::BuiltinDerive(ref func) = *ext {
let my_item = Annotatable::Item(item);
func(cx, span, &mitem, &my_item, &mut |a| {
items.push(a)
});
item = my_item.expect_item();
} else {
unreachable!();
}
}
items.insert(0, Annotatable::Item(item));
return items
}
macro_rules! derive_traits {
($( $name:expr => $func:path, )+) => {
pub fn is_builtin_trait(name: ast::Name) -> bool {

View File

@ -24,7 +24,6 @@
#![feature(staged_api)]
extern crate fmt_macros;
#[macro_use]
extern crate log;
#[macro_use]
extern crate syntax;
@ -51,7 +50,7 @@ pub mod proc_macro_impl;
use std::rc::Rc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NormalTT, MultiModifier, NamedSyntaxExtension};
use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension};
use syntax::symbol::Symbol;
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
@ -114,8 +113,6 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
register(Symbol::intern("format_args"),
NormalTT(Box::new(format::expand_format_args), None, true));
register(Symbol::intern("derive"), MultiModifier(Box::new(deriving::expand_derive)));
for (name, ext) in user_exts {
register(name, ext);
}

View File

@ -16,7 +16,7 @@ extern crate derive_bad;
#[derive(
A
)]
//~^^ ERROR: proc_macro_derive produced unparseable tokens
//~^^ ERROR: proc-macro derive produced unparseable tokens
struct A;
fn main() {}

View File

@ -14,7 +14,7 @@
extern crate derive_panic;
#[derive(A)]
//~^ ERROR: proc_macro_derive attribute panicked
//~^ ERROR: proc-macro derive panicked
//~| HELP: message: nope!
struct Foo;

View File

@ -11,7 +11,7 @@
// ignore-tidy-linelength
#[derive(Eqr)]
//~^ ERROR `#[derive]` for custom traits is not stable enough for use. It is deprecated and will be removed in v1.15 (see issue #29644)
//~^ ERROR cannot find derive macro `Eqr` in this scope
struct Foo;
pub fn main() {}

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[derive(FromPrimitive)] //~ERROR `#[derive]` for custom traits is not stable
#[derive(FromPrimitive)] //~ERROR cannot find derive macro `FromPrimitive` in this scope
enum Foo {}
fn main() {}

View File

@ -16,5 +16,5 @@ fn main() {
foo!(0); // Check that we report errors at macro definition, not expansion.
let _: cfg!(foo) = (); //~ ERROR non-type macro in type position
derive!(); //~ ERROR `derive` can only be used in attributes
derive!(); //~ ERROR macro undefined: 'derive!'
}

View File

@ -14,9 +14,11 @@
#![feature(asm)]
#![feature(trace_macros, concat_idents)]
#[derive(Default, //~ ERROR
Zero)] //~ ERROR
enum CantDeriveThose {}
#[derive(Zero)] //~ ERROR
struct CantDeriveThis;
#[derive(Default)] //~ ERROR
enum OrDeriveThis {}
fn main() {
doesnt_exist!(); //~ ERROR

View File

@ -1,4 +1,4 @@
error: proc_macro_derive attribute panicked
error: proc-macro derive panicked
--> $DIR/issue-36935.rs:17:15
|
17 | #[derive(Foo, Bar)]