Closed
Description
I ran across a very curious case today... Given this procedural macro:
#![crate_type = "proc-macro"]
#![feature(proc_macro)]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(Foo, attributes(foo))]
pub fn foo(input: TokenStream) -> TokenStream {
println!("{}", input.to_string());
print_tts(input, 0);
TokenStream::empty()
}
fn print_tts(input: TokenStream, tab: usize) {
let mut t = String::new();
for _ in 0..tab {
t.push_str(" ");
}
for token in input {
match token.kind {
proc_macro::TokenNode::Group(d, others) => {
println!("{}{:?}", t, d);
print_tts(others.into(), tab + 1);
}
s => println!("{}{:?}", t, s),
}
}
}
and this expansion:
#![crate_type = "rlib"]
#![feature(proc_macro)]
#[macro_use]
extern crate foo;
#[derive(Foo)]
pub struct MyStructc {
#[cfg_attr(my_cfg, foo)]
_a: i32,
}
when compiled I get:
$ rustc +nightly foo.rs && rustc +nightly bar.rs -L .
pub struct MyStructc {
_a: i32,
}
Term(Term(pub))
Term(Term(struct))
Term(Term(MyStructc))
Brace
Op('#', Alone)
Bracket
Term(Term(cfg_attr))
Parenthesis
Term(Term(my_cfg))
Op(',', Alone)
Term(Term(foo))
Term(Term(_a))
Op(':', Alone)
Term(Term(i32))
Op(',', Alone)
which is quite curious!
The to_string()
representation has the field present (even though the --cfg
isn't supplied) and the token stream has the actual #[cfg_attr]
there.
I was actually expecting neither outcome to happen (how naive of me!) in terms of -- er, just wrong thinking here#[cfg]
processing typically happening before custom derives, but maybe that's not possible?
cc @dtolnay
cc @jseyfried
cc @nrc