mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #39442 - keeperofdakeys:expand-derives, r=jseyfried
Expand derive macros in the MacroExpander This removes the expand_derives function, and sprinkles the functionality throughout the Invocation Collector, Expander and Resolver. Fixes https://github.com/rust-lang/rust/issues/39326 r? @jseyfried
This commit is contained in:
commit
805a99e6cb
@ -584,7 +584,7 @@ impl<'a> CrateLoader<'a> {
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro::__internal::Registry;
|
||||
use rustc_back::dynamic_lib::DynamicLibrary;
|
||||
use syntax_ext::deriving::custom::CustomDerive;
|
||||
use syntax_ext::deriving::custom::ProcMacroDerive;
|
||||
use syntax_ext::proc_macro_impl::AttrProcMacro;
|
||||
|
||||
let path = match dylib {
|
||||
@ -616,8 +616,8 @@ impl<'a> CrateLoader<'a> {
|
||||
expand: fn(TokenStream) -> TokenStream,
|
||||
attributes: &[&'static str]) {
|
||||
let attrs = attributes.iter().cloned().map(Symbol::intern).collect();
|
||||
let derive = SyntaxExtension::CustomDerive(
|
||||
Box::new(CustomDerive::new(expand, attrs))
|
||||
let derive = SyntaxExtension::ProcMacroDerive(
|
||||
Box::new(ProcMacroDerive::new(expand, attrs))
|
||||
);
|
||||
self.0.push((Symbol::intern(trait_name), Rc::new(derive)));
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ impl<'a> Resolver<'a> {
|
||||
"an `extern crate` loading macros must be at the crate root");
|
||||
} else if !self.use_extern_macros && !used &&
|
||||
self.session.cstore.dep_kind(module.def_id().unwrap().krate).macros_only() {
|
||||
let msg = "custom derive crates and `#[no_link]` crates have no effect without \
|
||||
let msg = "proc macro crates and `#[no_link]` crates have no effect without \
|
||||
`#[macro_use]`";
|
||||
self.session.span_warn(item.span, msg);
|
||||
used = true; // Avoid the normal unused extern crate warning
|
||||
|
@ -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> {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
|
||||
|
||||
use ast::{self, Attribute, Name, PatKind};
|
||||
use ast::{self, Attribute, Name, PatKind, MetaItem};
|
||||
use attr::HasAttrs;
|
||||
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
|
||||
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
||||
@ -471,6 +471,9 @@ impl MacResult for DummyResult {
|
||||
}
|
||||
}
|
||||
|
||||
pub type BuiltinDeriveFn =
|
||||
for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
|
||||
|
||||
/// An enum representing the different kinds of syntax extensions.
|
||||
pub enum SyntaxExtension {
|
||||
/// A syntax extension that is attached to an item and creates new items
|
||||
@ -507,7 +510,14 @@ pub enum SyntaxExtension {
|
||||
///
|
||||
IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),
|
||||
|
||||
CustomDerive(Box<MultiItemModifier>),
|
||||
/// An attribute-like procedural macro. TokenStream -> TokenStream.
|
||||
/// The input is the annotated item.
|
||||
/// Allows generating code to implement a Trait for a given struct
|
||||
/// or enum item.
|
||||
ProcMacroDerive(Box<MultiItemModifier>),
|
||||
|
||||
/// An attribute-like procedural macro that derives a builtin trait.
|
||||
BuiltinDerive(BuiltinDeriveFn),
|
||||
}
|
||||
|
||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||
@ -526,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)]
|
||||
@ -552,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
218
src/libsyntax/ext/derive.rs
Normal 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)
|
||||
})
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,7 +384,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
|
||||
self.parse_expansion(tok_result, kind, name, attr.span)
|
||||
}
|
||||
SyntaxExtension::CustomDerive(_) => {
|
||||
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
||||
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
|
||||
kind.dummy(attr.span)
|
||||
}
|
||||
@ -440,7 +454,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
return kind.dummy(span);
|
||||
}
|
||||
|
||||
SyntaxExtension::CustomDerive(..) => {
|
||||
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
||||
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
|
||||
return kind.dummy(span);
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -32,18 +32,18 @@ impl<'a> Visitor<'a> for MarkAttrs<'a> {
|
||||
fn visit_mac(&mut self, _mac: &Mac) {}
|
||||
}
|
||||
|
||||
pub struct CustomDerive {
|
||||
pub struct ProcMacroDerive {
|
||||
inner: fn(TokenStream) -> TokenStream,
|
||||
attrs: Vec<ast::Name>,
|
||||
}
|
||||
|
||||
impl CustomDerive {
|
||||
pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> CustomDerive {
|
||||
CustomDerive { inner: inner, attrs: attrs }
|
||||
impl ProcMacroDerive {
|
||||
pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> ProcMacroDerive {
|
||||
ProcMacroDerive { inner: inner, attrs: attrs }
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiItemModifier for CustomDerive {
|
||||
impl MultiItemModifier for ProcMacroDerive {
|
||||
fn expand(&self,
|
||||
ecx: &mut ExtCtxt,
|
||||
span: Span,
|
||||
@ -54,7 +54,7 @@ impl MultiItemModifier for CustomDerive {
|
||||
Annotatable::Item(item) => item,
|
||||
Annotatable::ImplItem(_) |
|
||||
Annotatable::TraitItem(_) => {
|
||||
ecx.span_err(span, "custom 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 CustomDerive {
|
||||
ItemKind::Struct(..) |
|
||||
ItemKind::Enum(..) => {},
|
||||
_ => {
|
||||
ecx.span_err(span, "custom 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 CustomDerive {
|
||||
let stream = match res {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
let msg = "custom 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 CustomDerive {
|
||||
Ok(new_items) => new_items,
|
||||
Err(_) => {
|
||||
// FIXME: handle this better
|
||||
let msg = "custom derive produced unparseable tokens";
|
||||
let msg = "proc-macro derive produced unparseable tokens";
|
||||
ecx.struct_span_fatal(span, msg).emit();
|
||||
panic!(FatalError);
|
||||
}
|
||||
|
@ -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,6 +36,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut FnMut(Annotatable)) {
|
||||
warn_if_deprecated(cx, span, "Decodable");
|
||||
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
|
||||
}
|
||||
|
||||
|
@ -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,6 +113,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut FnMut(Annotatable)) {
|
||||
warn_if_deprecated(cx, span, "Encodable");
|
||||
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,11 @@
|
||||
|
||||
//! The compiler code necessary to implement the `#[derive]` extensions.
|
||||
|
||||
use syntax::ast::{self, MetaItem};
|
||||
use syntax::attr::HasAttrs;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap;
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
|
||||
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;
|
||||
@ -89,234 +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::CustomDerive(_) = *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::CustomDerive(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 mitem = cx.meta_word(titem.span, name);
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
let my_item = Annotatable::Item(item);
|
||||
expand_builtin(&tname.as_str(), cx, span, &mitem, &my_item, &mut |a| {
|
||||
items.push(a);
|
||||
});
|
||||
item = my_item.expect_item();
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -326,21 +97,13 @@ macro_rules! derive_traits {
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_builtin(name: &str,
|
||||
ecx: &mut ExtCtxt,
|
||||
span: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Annotatable,
|
||||
push: &mut FnMut(Annotatable)) {
|
||||
match name {
|
||||
$(
|
||||
$name => {
|
||||
warn_if_deprecated(ecx, span, $name);
|
||||
$func(ecx, span, mitem, item, push);
|
||||
}
|
||||
)*
|
||||
_ => panic!("not a builtin derive mode: {}", name),
|
||||
}
|
||||
pub fn register_builtin_derives(resolver: &mut Resolver) {
|
||||
$(
|
||||
resolver.add_ext(
|
||||
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
|
||||
Rc::new(SyntaxExtension::BuiltinDerive($func))
|
||||
);
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@
|
||||
#![feature(staged_api)]
|
||||
|
||||
extern crate fmt_macros;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate syntax;
|
||||
@ -51,12 +50,14 @@ 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,
|
||||
user_exts: Vec<NamedSyntaxExtension>,
|
||||
enable_quotes: bool) {
|
||||
deriving::register_builtin_derives(resolver);
|
||||
|
||||
let mut register = |name, ext| {
|
||||
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
|
||||
};
|
||||
@ -112,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);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
use deriving;
|
||||
|
||||
struct CustomDerive {
|
||||
struct ProcMacroDerive {
|
||||
trait_name: ast::Name,
|
||||
function_name: Ident,
|
||||
span: Span,
|
||||
@ -40,7 +40,7 @@ struct AttrProcMacro {
|
||||
}
|
||||
|
||||
struct CollectProcMacros<'a> {
|
||||
derives: Vec<CustomDerive>,
|
||||
derives: Vec<ProcMacroDerive>,
|
||||
attr_macros: Vec<AttrProcMacro>,
|
||||
in_root: bool,
|
||||
handler: &'a errors::Handler,
|
||||
@ -176,7 +176,7 @@ impl<'a> CollectProcMacros<'a> {
|
||||
};
|
||||
|
||||
if self.in_root && item.vis == ast::Visibility::Public {
|
||||
self.derives.push(CustomDerive {
|
||||
self.derives.push(ProcMacroDerive {
|
||||
span: item.span,
|
||||
trait_name: trait_name,
|
||||
function_name: item.ident,
|
||||
@ -319,7 +319,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
||||
// }
|
||||
// }
|
||||
fn mk_registrar(cx: &mut ExtCtxt,
|
||||
custom_derives: &[CustomDerive],
|
||||
custom_derives: &[ProcMacroDerive],
|
||||
custom_attrs: &[AttrProcMacro]) -> P<ast::Item> {
|
||||
let eid = cx.codemap().record_expansion(ExpnInfo {
|
||||
call_site: DUMMY_SP,
|
||||
|
@ -16,7 +16,7 @@ extern crate derive_bad;
|
||||
#[derive(
|
||||
A
|
||||
)]
|
||||
//~^^ ERROR: custom derive produced unparseable tokens
|
||||
//~^^ ERROR: proc-macro derive produced unparseable tokens
|
||||
struct A;
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,7 +14,7 @@
|
||||
extern crate derive_panic;
|
||||
|
||||
#[derive(A)]
|
||||
//~^ ERROR: custom derive attribute panicked
|
||||
//~^ ERROR: proc-macro derive panicked
|
||||
//~| HELP: message: nope!
|
||||
struct Foo;
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
extern crate derive_a;
|
||||
//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
|
||||
//~^ WARN proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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!'
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#[no_link]
|
||||
extern crate empty_struct;
|
||||
//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
|
||||
//~^ WARN proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
|
||||
|
||||
fn main() {
|
||||
empty_struct::XEmpty1; //~ ERROR cannot find value `XEmpty1` in module `empty_struct`
|
||||
|
43
src/test/pretty/attr-derive.rs
Normal file
43
src/test/pretty/attr-derive.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2012 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:derive-foo.rs
|
||||
// ignore-stage1
|
||||
// pp-exact
|
||||
// Testing that both the inner item and next outer item are
|
||||
// preserved, and that the first outer item parsed in main is not
|
||||
// accidentally carried over to each inner function
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_foo;
|
||||
|
||||
#[derive(Foo)]
|
||||
struct X;
|
||||
|
||||
#[derive(Foo)]
|
||||
#[Bar]
|
||||
struct Y;
|
||||
|
||||
#[derive(Foo)]
|
||||
struct WithRef {
|
||||
x: X,
|
||||
#[Bar]
|
||||
y: Y,
|
||||
}
|
||||
|
||||
#[derive(Foo)]
|
||||
enum Enum {
|
||||
|
||||
#[Bar]
|
||||
Asdf,
|
||||
Qwerty,
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -1,51 +0,0 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// pp-exact
|
||||
// Testing that both the inner item and next outer item are
|
||||
// preserved, and that the first outer item parsed in main is not
|
||||
// accidentally carried over to each inner function
|
||||
|
||||
#![feature(custom_attribute)]
|
||||
#![feature(custom_derive)]
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct X;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct WithRef<'a, T: 'a> {
|
||||
#[serde(skip_deserializing)]
|
||||
t: Option<&'a T>,
|
||||
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
|
||||
x: X,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum EnumWith<T> {
|
||||
Unit,
|
||||
Newtype(
|
||||
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
|
||||
X),
|
||||
Tuple(T,
|
||||
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
|
||||
X),
|
||||
Struct {
|
||||
t: T,
|
||||
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
|
||||
x: X,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Tuple<T>(T,
|
||||
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
|
||||
X);
|
||||
|
||||
fn main() { }
|
22
src/test/pretty/auxiliary/derive-foo.rs
Normal file
22
src/test/pretty/auxiliary/derive-foo.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(Foo, attributes(Bar))]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
"".parse().unwrap()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
error: custom derive attribute panicked
|
||||
error: proc-macro derive panicked
|
||||
--> $DIR/issue-36935.rs:17:15
|
||||
|
|
||||
17 | #[derive(Foo, Bar)]
|
||||
|
Loading…
Reference in New Issue
Block a user