macro_rules! borked {
() => {
#[derive(Debug)] pub struct Good;
#[cfg_attr(not(test), derive(Debug))] pub struct Bad;
}
}
borked!();
fn main() {
println!("{:?}", Good);
println!("{:?}", Bad);
}
produces
foo.rs:12:22: 12:25 error: the trait `core::fmt::Show` is not implemented for the type `Bad` [E0277]
foo.rs:12 println!("{:?}", Bad);
^~~
I think what happens is the following:
- The first cfg stripping pass runs. At this point the macro body is just a token tree, and there's no way for cfg stripping to work out what
# [ cfg_attr ( not ( test ) ... means.
- Syntax expansion runs. The macro emits two items. One has a
derive attribute, which matches a Decorator in the syntax environment, so that extension also runs. There's no extension named cfg_attr so that attribute has no effect on expansion.
- The post-expansion cfg stripping pass runs. The second attribute turns into
#[derive(Debug)] but not in time for syntax expansion to notice it.
Previously, cfg_attr was a syntax extension, which had numerous drawbacks, but handled this case correctly.
The somewhat obvious fix is to re-run cfg_attr processing on the AST subtree produced by every macro expansion, but I'd like to think about this more. I'd also like to know whether it's something people often run into in practice.
Was mentioned on #19372. cc @sfackler, @SergioBenitez
produces
I think what happens is the following:
# [ cfg_attr ( not ( test ) ...means.deriveattribute, which matches aDecoratorin the syntax environment, so that extension also runs. There's no extension namedcfg_attrso that attribute has no effect on expansion.#[derive(Debug)]but not in time for syntax expansion to notice it.Previously,
cfg_attrwas a syntax extension, which had numerous drawbacks, but handled this case correctly.The somewhat obvious fix is to re-run
cfg_attrprocessing on the AST subtree produced by every macro expansion, but I'd like to think about this more. I'd also like to know whether it's something people often run into in practice.Was mentioned on #19372. cc @sfackler, @SergioBenitez