提交 5ebd7c50 编写于 作者: E Eduard-Mihai Burtescu 提交者: GitHub

Rollup merge of #37614 - keeperofdakeys:proc_macro, r=jseyfried

macros 1.1: Allow proc_macro functions to declare attributes to be mark as used

This PR allows proc macro functions to declare attribute names that should be marked as used when attached to the deriving item. There are a few questions for this PR.

- Currently this uses a separate attribute named `#[proc_macro_attributes(..)]`, is this the best choice?
- In order to make this work, the `check_attribute` function had to be modified to not error on attributes marked as used. This is a pretty large change in semantics, is there a better way to do this?
- I've got a few clones where I don't know if I need them (like turning `item` into a `TokenStream`), can these be avoided?
- Is switching to `MultiItemDecorator` the right thing here?

Also fixes https://github.com/rust-lang/rust/issues/37563.
...@@ -95,7 +95,8 @@ pub fn token_stream_items(stream: TokenStream) -> Vec<P<ast::Item>> { ...@@ -95,7 +95,8 @@ pub fn token_stream_items(stream: TokenStream) -> Vec<P<ast::Item>> {
pub trait Registry { pub trait Registry {
fn register_custom_derive(&mut self, fn register_custom_derive(&mut self,
trait_name: &str, trait_name: &str,
expand: fn(TokenStream) -> TokenStream); expand: fn(TokenStream) -> TokenStream,
attributes: &[&'static str]);
} }
// Emulate scoped_thread_local!() here essentially // Emulate scoped_thread_local!() here essentially
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
use syntax::parse::token::keywords; use syntax::parse::token::keywords;
use syntax::ptr::P; use syntax::ptr::P;
use syntax_pos::Span; use syntax_pos::Span;
...@@ -245,7 +245,7 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { ...@@ -245,7 +245,7 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
debug!("checking attribute: {:?}", attr); debug!("checking attribute: {:?}", attr);
// Note that check_name() marks the attribute as used if it matches. // Note that check_name() marks the attribute as used if it matches.
for &(ref name, ty, _) in KNOWN_ATTRIBUTES { for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
match ty { match ty {
AttributeType::Whitelisted if attr.check_name(name) => { AttributeType::Whitelisted if attr.check_name(name) => {
debug!("{:?} is Whitelisted", name); debug!("{:?} is Whitelisted", name);
...@@ -267,7 +267,7 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { ...@@ -267,7 +267,7 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
debug!("Emitting warning for: {:?}", attr); debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level? // Is it a builtin attribute that must be used at the crate level?
let known_crate = KNOWN_ATTRIBUTES.iter() let known_crate = BUILTIN_ATTRIBUTES.iter()
.find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel) .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
.is_some(); .is_some();
......
...@@ -624,8 +624,12 @@ fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, pa ...@@ -624,8 +624,12 @@ fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, pa
impl Registry for MyRegistrar { impl Registry for MyRegistrar {
fn register_custom_derive(&mut self, fn register_custom_derive(&mut self,
trait_name: &str, trait_name: &str,
expand: fn(TokenStream) -> TokenStream) { expand: fn(TokenStream) -> TokenStream,
let derive = SyntaxExtension::CustomDerive(Box::new(CustomDerive::new(expand))); attributes: &[&'static str]) {
let attrs = attributes.iter().map(|s| InternedString::new(s)).collect();
let derive = SyntaxExtension::CustomDerive(
Box::new(CustomDerive::new(expand, attrs))
);
self.0.push((intern(trait_name), derive)); self.0.push((intern(trait_name), derive));
} }
} }
......
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
use std::collections::HashSet; use std::collections::HashSet;
thread_local! { thread_local! {
static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new()) static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new());
static KNOWN_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new());
} }
enum AttrError { enum AttrError {
...@@ -81,6 +82,29 @@ pub fn is_used(attr: &Attribute) -> bool { ...@@ -81,6 +82,29 @@ pub fn is_used(attr: &Attribute) -> bool {
}) })
} }
pub fn mark_known(attr: &Attribute) {
debug!("Marking {:?} as known.", attr);
let AttrId(id) = attr.node.id;
KNOWN_ATTRS.with(|slot| {
let idx = (id / 64) as usize;
let shift = id % 64;
if slot.borrow().len() <= idx {
slot.borrow_mut().resize(idx + 1, 0);
}
slot.borrow_mut()[idx] |= 1 << shift;
});
}
pub fn is_known(attr: &Attribute) -> bool {
let AttrId(id) = attr.node.id;
KNOWN_ATTRS.with(|slot| {
let idx = (id / 64) as usize;
let shift = id % 64;
slot.borrow().get(idx).map(|bits| bits & (1 << shift) != 0)
.unwrap_or(false)
})
}
impl NestedMetaItem { impl NestedMetaItem {
/// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
pub fn meta_item(&self) -> Option<&P<MetaItem>> { pub fn meta_item(&self) -> Option<&P<MetaItem>> {
......
...@@ -421,11 +421,11 @@ fn f(features: &Features) -> bool { ...@@ -421,11 +421,11 @@ fn f(features: &Features) -> bool {
} }
pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> { pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect() BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
} }
// Attributes that have a special meaning to rustc or rustdoc // Attributes that have a special meaning to rustc or rustdoc
pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
// Normal attributes // Normal attributes
("warn", Normal, Ungated), ("warn", Normal, Ungated),
...@@ -800,12 +800,12 @@ impl<'a> Context<'a> { ...@@ -800,12 +800,12 @@ impl<'a> Context<'a> {
fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
debug!("check_attribute(attr = {:?})", attr); debug!("check_attribute(attr = {:?})", attr);
let name = &*attr.name(); let name = &*attr.name();
for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES { for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
if n == name { if n == name {
if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
gate_feature_fn!(self, has_feature, attr.span, name, desc); gate_feature_fn!(self, has_feature, attr.span, name, desc);
} }
debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage); debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage);
return; return;
} }
} }
...@@ -825,6 +825,8 @@ fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { ...@@ -825,6 +825,8 @@ fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
are reserved for internal compiler diagnostics"); are reserved for internal compiler diagnostics");
} else if name.starts_with("derive_") { } else if name.starts_with("derive_") {
gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
} else if attr::is_known(attr) {
debug!("check_attribute: {:?} is known", name);
} else { } else {
// Only run the custom attribute lint during regular // Only run the custom attribute lint during regular
// feature gate checking. Macro gating runs // feature gate checking. Macro gating runs
......
...@@ -12,20 +12,35 @@ ...@@ -12,20 +12,35 @@
use errors::FatalError; use errors::FatalError;
use proc_macro::{TokenStream, __internal}; use proc_macro::{TokenStream, __internal};
use syntax::ast::{self, ItemKind}; use syntax::ast::{self, ItemKind, Attribute};
use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span}; use syntax::attr::{mark_used, mark_known};
use syntax::codemap::Span;
use syntax::ext::base::*; use syntax::ext::base::*;
use syntax::fold::Folder; use syntax::fold::Folder;
use syntax::parse::token::intern; use syntax::parse::token::InternedString;
use syntax::print::pprust; use syntax::visit::Visitor;
struct MarkAttrs<'a>(&'a [InternedString]);
impl<'a> Visitor for MarkAttrs<'a> {
fn visit_attribute(&mut self, attr: &Attribute) {
if self.0.contains(&attr.name()) {
mark_used(attr);
mark_known(attr);
}
}
}
pub struct CustomDerive { pub struct CustomDerive {
inner: fn(TokenStream) -> TokenStream, inner: fn(TokenStream) -> TokenStream,
attrs: Vec<InternedString>,
} }
impl CustomDerive { impl CustomDerive {
pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive { pub fn new(inner: fn(TokenStream) -> TokenStream,
CustomDerive { inner: inner } attrs: Vec<InternedString>)
-> CustomDerive {
CustomDerive { inner: inner, attrs: attrs }
} }
} }
...@@ -33,7 +48,7 @@ impl MultiItemModifier for CustomDerive { ...@@ -33,7 +48,7 @@ impl MultiItemModifier for CustomDerive {
fn expand(&self, fn expand(&self,
ecx: &mut ExtCtxt, ecx: &mut ExtCtxt,
span: Span, span: Span,
meta_item: &ast::MetaItem, _meta_item: &ast::MetaItem,
item: Annotatable) item: Annotatable)
-> Vec<Annotatable> { -> Vec<Annotatable> {
let item = match item { let item = match item {
...@@ -47,7 +62,7 @@ fn expand(&self, ...@@ -47,7 +62,7 @@ fn expand(&self,
}; };
match item.node { match item.node {
ItemKind::Struct(..) | ItemKind::Struct(..) |
ItemKind::Enum(..) => {} ItemKind::Enum(..) => {},
_ => { _ => {
ecx.span_err(span, "custom derive attributes may only be \ ecx.span_err(span, "custom derive attributes may only be \
applied to struct/enum items"); applied to struct/enum items");
...@@ -55,23 +70,15 @@ fn expand(&self, ...@@ -55,23 +70,15 @@ fn expand(&self,
} }
} }
let input_span = Span { // Mark attributes as known, and used.
expn_id: ecx.codemap().record_expansion(ExpnInfo { MarkAttrs(&self.attrs).visit_item(&item);
call_site: span,
callee: NameAndSpan { let input = __internal::new_token_stream(item.clone());
format: MacroAttribute(intern(&pprust::meta_item_to_string(meta_item))),
span: Some(span),
allow_internal_unstable: true,
},
}),
..item.span
};
let input = __internal::new_token_stream(item);
let res = __internal::set_parse_sess(&ecx.parse_sess, || { let res = __internal::set_parse_sess(&ecx.parse_sess, || {
let inner = self.inner; let inner = self.inner;
panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input))) panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
}); });
let item = match res { let new_items = match res {
Ok(stream) => __internal::token_stream_items(stream), Ok(stream) => __internal::token_stream_items(stream),
Err(e) => { Err(e) => {
let msg = "custom derive attribute panicked"; let msg = "custom derive attribute panicked";
...@@ -88,12 +95,13 @@ fn expand(&self, ...@@ -88,12 +95,13 @@ fn expand(&self,
} }
}; };
// Right now we have no knowledge of spans at all in custom derive let mut res = vec![Annotatable::Item(item)];
// macros, everything is just parsed as a string. Reassign all spans to // Reassign spans of all expanded items to the input `item`
// the input `item` for better errors here. // for better errors here.
item.into_iter().flat_map(|item| { res.extend(new_items.into_iter().flat_map(|item| {
ChangeSpan { span: input_span }.fold_item(item) ChangeSpan { span: span }.fold_item(item)
}).map(Annotatable::Item).collect() }).map(Annotatable::Item));
res
} }
} }
...@@ -30,6 +30,7 @@ struct CustomDerive { ...@@ -30,6 +30,7 @@ struct CustomDerive {
trait_name: InternedString, trait_name: InternedString,
function_name: Ident, function_name: Ident,
span: Span, span: Span,
attrs: Vec<InternedString>,
} }
struct CollectCustomDerives<'a> { struct CollectCustomDerives<'a> {
...@@ -144,7 +145,8 @@ fn visit_item(&mut self, item: &ast::Item) { ...@@ -144,7 +145,8 @@ fn visit_item(&mut self, item: &ast::Item) {
} }
// Once we've located the `#[proc_macro_derive]` attribute, verify // Once we've located the `#[proc_macro_derive]` attribute, verify
// that it's of the form `#[proc_macro_derive(Foo)]` // that it's of the form `#[proc_macro_derive(Foo)]` or
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
let list = match attr.meta_item_list() { let list = match attr.meta_item_list() {
Some(list) => list, Some(list) => list,
None => { None => {
...@@ -154,38 +156,69 @@ fn visit_item(&mut self, item: &ast::Item) { ...@@ -154,38 +156,69 @@ fn visit_item(&mut self, item: &ast::Item) {
return return
} }
}; };
if list.len() != 1 { if list.len() != 1 && list.len() != 2 {
self.handler.span_err(attr.span(), self.handler.span_err(attr.span(),
"attribute must only have one argument"); "attribute must have either one or two arguments");
return return
} }
let attr = &list[0]; let trait_attr = &list[0];
let trait_name = match attr.name() { let attributes_attr = list.get(1);
let trait_name = match trait_attr.name() {
Some(name) => name, Some(name) => name,
_ => { _ => {
self.handler.span_err(attr.span(), "not a meta item"); self.handler.span_err(trait_attr.span(), "not a meta item");
return return
} }
}; };
if !attr.is_word() { if !trait_attr.is_word() {
self.handler.span_err(attr.span(), "must only be one word"); self.handler.span_err(trait_attr.span(), "must only be one word");
} }
if deriving::is_builtin_trait(&trait_name) { if deriving::is_builtin_trait(&trait_name) {
self.handler.span_err(attr.span(), self.handler.span_err(trait_attr.span(),
"cannot override a built-in #[derive] mode"); "cannot override a built-in #[derive] mode");
} }
if self.derives.iter().any(|d| d.trait_name == trait_name) { if self.derives.iter().any(|d| d.trait_name == trait_name) {
self.handler.span_err(attr.span(), self.handler.span_err(trait_attr.span(),
"derive mode defined twice in this crate"); "derive mode defined twice in this crate");
} }
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
if !attr.check_name("attributes") {
self.handler.span_err(attr.span(), "second argument must be `attributes`")
}
attr.meta_item_list().unwrap_or_else(|| {
self.handler.span_err(attr.span(),
"attribute must be of form: \
`attributes(foo, bar)`");
&[]
}).into_iter().filter_map(|attr| {
let name = match attr.name() {
Some(name) => name,
_ => {
self.handler.span_err(attr.span(), "not a meta item");
return None;
},
};
if !attr.is_word() {
self.handler.span_err(attr.span(), "must only be one word");
return None;
}
Some(name)
}).collect()
} else {
Vec::new()
};
if self.in_root { if self.in_root {
self.derives.push(CustomDerive { self.derives.push(CustomDerive {
span: item.span, span: item.span,
trait_name: trait_name, trait_name: trait_name,
function_name: item.ident, function_name: item.ident,
attrs: proc_attrs,
}); });
} else { } else {
let msg = "functions tagged with `#[proc_macro_derive]` must \ let msg = "functions tagged with `#[proc_macro_derive]` must \
...@@ -219,8 +252,8 @@ fn visit_mac(&mut self, mac: &ast::Mac) { ...@@ -219,8 +252,8 @@ fn visit_mac(&mut self, mac: &ast::Mac) {
// //
// #[plugin_registrar] // #[plugin_registrar]
// fn registrar(registrar: &mut Registry) { // fn registrar(registrar: &mut Registry) {
// registrar.register_custom_derive($name_trait1, ::$name1); // registrar.register_custom_derive($name_trait1, ::$name1, &[]);
// registrar.register_custom_derive($name_trait2, ::$name2); // registrar.register_custom_derive($name_trait2, ::$name2, &["attribute_name"]);
// // ... // // ...
// } // }
// } // }
...@@ -249,14 +282,18 @@ fn mk_registrar(cx: &mut ExtCtxt, ...@@ -249,14 +282,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
let stmts = custom_derives.iter().map(|cd| { let stmts = custom_derives.iter().map(|cd| {
let path = cx.path_global(cd.span, vec![cd.function_name]); let path = cx.path_global(cd.span, vec![cd.function_name]);
let trait_name = cx.expr_str(cd.span, cd.trait_name.clone()); let trait_name = cx.expr_str(cd.span, cd.trait_name.clone());
(path, trait_name) let attrs = cx.expr_vec_slice(
}).map(|(path, trait_name)| { span,
cd.attrs.iter().map(|s| cx.expr_str(cd.span, s.clone())).collect::<Vec<_>>()
);
(path, trait_name, attrs)
}).map(|(path, trait_name, attrs)| {
let registrar = cx.expr_ident(span, registrar); let registrar = cx.expr_ident(span, registrar);
let ufcs_path = cx.path(span, vec![proc_macro, __internal, registry, let ufcs_path = cx.path(span, vec![proc_macro, __internal, registry,
register_custom_derive]); register_custom_derive]);
cx.expr_call(span, cx.expr_call(span,
cx.expr_path(ufcs_path), cx.expr_path(ufcs_path),
vec![registrar, trait_name, cx.expr_path(path)]) vec![registrar, trait_name, cx.expr_path(path), attrs])
}).map(|expr| { }).map(|expr| {
cx.stmt_expr(expr) cx.stmt_expr(expr)
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
......
...@@ -33,8 +33,8 @@ pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream { ...@@ -33,8 +33,8 @@ pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
input input
} }
#[proc_macro_derive(b, c)] #[proc_macro_derive(b, c, d)]
//~^ ERROR: attribute must only have one argument //~^ ERROR: attribute must have either one or two arguments
pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
input input
} }
...@@ -44,3 +44,21 @@ pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { ...@@ -44,3 +44,21 @@ pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
input input
} }
#[proc_macro_derive(f, attributes(g = "h"))]
//~^ ERROR: must only be one word
pub fn foo6(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
input
}
#[proc_macro_derive(i, attributes(j(k)))]
//~^ ERROR: must only be one word
pub fn foo7(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
input
}
#[proc_macro_derive(l, attributes(m), n)]
//~^ ERROR: attribute must have either one or two arguments
pub fn foo8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
input
}
// 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.
// force-host
// no-prefer-dynamic
#![feature(proc_macro)]
#![feature(proc_macro_lib)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(B, attributes(B))]
pub fn derive_b(input: TokenStream) -> TokenStream {
"".parse().unwrap()
}
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
extern crate derive_unstable_2; extern crate derive_unstable_2;
#[derive(Unstable)] #[derive(Unstable)]
struct A;
//~^ ERROR: reserved for internal compiler //~^ ERROR: reserved for internal compiler
struct A;
fn main() { fn main() {
foo(); foo();
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
extern crate derive_unstable; extern crate derive_unstable;
#[derive(Unstable)] #[derive(Unstable)]
struct A;
//~^ ERROR: use of unstable library feature //~^ ERROR: use of unstable library feature
struct A;
fn main() { fn main() {
unsafe { foo(); } unsafe { foo(); }
......
// 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.
// aux-build:derive-b.rs
#![feature(proc_macro)]
#![allow(warnings)]
#[macro_use]
extern crate derive_b;
#[derive(B)]
struct A {
a: &u64
//~^ ERROR: missing lifetime specifier
}
fn main() {
}
// 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.
// aux-build:derive-b.rs
#![feature(proc_macro)]
#![allow(warnings)]
#[macro_use]
extern crate derive_b;
#[derive(B)]
#[B]
#[C] //~ ERROR: The attribute `C` is currently unknown to the compiler
#[B(D)]
#[B(E = "foo")]
struct B;
fn main() {}
...@@ -21,13 +21,12 @@ ...@@ -21,13 +21,12 @@
#[proc_macro_derive(AddImpl)] #[proc_macro_derive(AddImpl)]
// #[cfg(proc_macro)] // #[cfg(proc_macro)]
pub fn derive(input: TokenStream) -> TokenStream { pub fn derive(input: TokenStream) -> TokenStream {
(input.to_string() + " "impl B {
impl B {
fn foo(&self) {} fn foo(&self) {}
} }
fn foo() {} fn foo() {}
mod bar { pub fn foo() {} } mod bar { pub fn foo() {} }
").parse().unwrap() ".parse().unwrap()
} }
...@@ -21,11 +21,8 @@ ...@@ -21,11 +21,8 @@
#[proc_macro_derive(Append)] #[proc_macro_derive(Append)]
pub fn derive_a(input: TokenStream) -> TokenStream { pub fn derive_a(input: TokenStream) -> TokenStream {
let mut input = input.to_string(); "impl Append for A {
input.push_str(" fn foo(&self) {}
impl Append for A { }
fn foo(&self) {} ".parse().unwrap()
}
");
input.parse().unwrap()
} }
...@@ -23,5 +23,5 @@ pub fn derive(input: TokenStream) -> TokenStream { ...@@ -23,5 +23,5 @@ pub fn derive(input: TokenStream) -> TokenStream {
let input = input.to_string(); let input = input.to_string();
assert!(input.contains("struct A;")); assert!(input.contains("struct A;"));
assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]")); assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]"));
"#[derive(Debug, PartialEq, Eq, Copy, Clone)] struct A;".parse().unwrap() "".parse().unwrap()
} }
// 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"]
#![feature(proc_macro)]
#![feature(proc_macro_lib)]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(B, attributes(B, C))]
pub fn derive(input: TokenStream) -> TokenStream {
let input = input.to_string();
assert!(input.contains("#[B]"));
assert!(input.contains("struct B {"));
assert!(input.contains("#[C]"));
assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]"));
"".parse().unwrap()
}
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#[proc_macro_derive(AToB)] #[proc_macro_derive(AToB)]
pub fn derive1(input: TokenStream) -> TokenStream { pub fn derive1(input: TokenStream) -> TokenStream {
println!("input1: {:?}", input.to_string()); println!("input1: {:?}", input.to_string());
assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n"); assert_eq!(input.to_string(), "struct A;\n");
"#[derive(BToC)] struct B;".parse().unwrap() "#[derive(BToC)] struct B;".parse().unwrap()
} }
......
...@@ -24,8 +24,6 @@ pub fn derive(input: TokenStream) -> TokenStream { ...@@ -24,8 +24,6 @@ pub fn derive(input: TokenStream) -> TokenStream {
let input = input.to_string(); let input = input.to_string();
assert!(input.contains("struct A;")); assert!(input.contains("struct A;"));
r#" r#"
struct A;
impl A { impl A {
fn a(&self) { fn a(&self) {
panic!("hello"); panic!("hello");
......
// 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.
// aux-build:derive-b.rs
// ignore-stage1
#![feature(proc_macro)]
#[macro_use]
extern crate derive_b;
#[derive(Debug, PartialEq, B, Eq, Copy, Clone)]
#[B]
struct B {
#[C]
a: u64
}
fn main() {
B { a: 3 };
assert_eq!(B { a: 3 }, B { a: 3 });
let b = B { a: 3 };
let _d = b;
let _e = b;
}
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#[macro_use] #[macro_use]
extern crate derive_same_struct; extern crate derive_same_struct;
#[derive(AToB, BToC)] #[derive(AToB)]
struct A; struct A;
fn main() { fn main() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册