Allow proc_macro functions to whitelist specific attributes
By using a second attribute `attributes(Bar)` on proc_macro_derive, whitelist any attributes with the name `Bar` in the deriving item. This allows a proc_macro function to use custom attribtues without a custom attribute error or unused attribute lint.
This commit is contained in:
@@ -95,7 +95,8 @@ pub mod __internal {
|
|||||||
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
|
||||||
|
|||||||
@@ -624,8 +624,12 @@ impl<'a> CrateLoader<'a> {
|
|||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,20 +12,37 @@ use std::panic;
|
|||||||
|
|
||||||
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::attr::{mark_used, mark_known};
|
||||||
use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span};
|
use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span};
|
||||||
use syntax::ext::base::*;
|
use syntax::ext::base::*;
|
||||||
use syntax::fold::Folder;
|
use syntax::fold::Folder;
|
||||||
|
use syntax::parse::token::InternedString;
|
||||||
use syntax::parse::token::intern;
|
use syntax::parse::token::intern;
|
||||||
use syntax::print::pprust;
|
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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +64,7 @@ impl MultiItemModifier for CustomDerive {
|
|||||||
};
|
};
|
||||||
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,6 +72,9 @@ impl MultiItemModifier for CustomDerive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark attributes as known, and used.
|
||||||
|
MarkAttrs(&self.attrs).visit_item(&item);
|
||||||
|
|
||||||
let input_span = Span {
|
let input_span = Span {
|
||||||
expn_id: ecx.codemap().record_expansion(ExpnInfo {
|
expn_id: ecx.codemap().record_expansion(ExpnInfo {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
@@ -66,12 +86,13 @@ impl MultiItemModifier for CustomDerive {
|
|||||||
}),
|
}),
|
||||||
..item.span
|
..item.span
|
||||||
};
|
};
|
||||||
let input = __internal::new_token_stream(item);
|
|
||||||
|
let input = __internal::new_token_stream(item.clone());
|
||||||
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 +109,13 @@ impl MultiItemModifier for CustomDerive {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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: input_span }.fold_item(item)
|
||||||
}).map(Annotatable::Item).collect()
|
}).map(Annotatable::Item));
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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> {
|
||||||
@@ -133,7 +134,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 => {
|
||||||
@@ -143,38 +145,69 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
|
|||||||
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 \
|
||||||
@@ -208,8 +241,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> {
|
|||||||
//
|
//
|
||||||
// #[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"]);
|
||||||
// // ...
|
// // ...
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
@@ -238,14 +271,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 {
|
|||||||
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 {
|
|||||||
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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()
|
||||||
|
}
|
||||||
26
src/test/compile-fail-fulldeps/proc-macro/item-error.rs
Normal file
26
src/test/compile-fail-fulldeps/proc-macro/item-error.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 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() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// 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 @@ use proc_macro::TokenStream;
|
|||||||
#[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 @@ use proc_macro::TokenStream;
|
|||||||
|
|
||||||
#[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("
|
|
||||||
impl Append for A {
|
|
||||||
fn foo(&self) {}
|
fn foo(&self) {}
|
||||||
}
|
}
|
||||||
");
|
".parse().unwrap()
|
||||||
input.parse().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs
Normal file
29
src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// 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 @@ use proc_macro::TokenStream;
|
|||||||
#[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 {
|
|||||||
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");
|
||||||
|
|||||||
32
src/test/run-pass-fulldeps/proc-macro/derive-b.rs
Normal file
32
src/test/run-pass-fulldeps/proc-macro/derive-b.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// 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 @@
|
|||||||
#[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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user