Closed
Description
If we have an attribute macro whose input contains attributes on fields of a struct-expression, those attributes all seem to disappear before the macro is invoked.
The following repro compiles successfully if #[repro::repro] is removed, but fails with "error[E0062]: field `field` specified more than once" if the macro is present even though it does nothing.
struct C {
field: u8,
}
#[repro::repro]
const C: C = C {
#[cfg(debug_assertions)]
field: 0,
#[cfg(not(debug_assertions))]
field: 1,
};
fn main() {}
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream {
println!("{:#?}", input);
input.into_iter().collect()
}
Here is a script that reproduces the behavior as of rustc 1.42.0-nightly (212b2c7 2020-01-30)
#!/bin/bash
cargo new repro
echo >>repro/Cargo.toml '
[lib]
proc-macro = true
'
echo >repro/src/lib.rs '
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream {
println!("{:#?}", input);
input.into_iter().collect()
}
'
echo >repro/src/main.rs '
struct C {
field: u8,
}
#[repro::repro]
const C: C = C {
#[cfg(debug_assertions)]
field: 0,
#[cfg(not(debug_assertions))]
field: 1,
};
fn main() {}
'
cargo +nightly check --manifest-path repro/Cargo.toml
Here is the input token stream as received by the proc macro
TokenStream [
Ident {
ident: "const",
span: #0 bytes(0..0),
},
Ident {
ident: "C",
span: #0 bytes(0..0),
},
Punct {
ch: ':',
spacing: Alone,
span: #0 bytes(0..0),
},
Ident {
ident: "C",
span: #0 bytes(0..0),
},
Punct {
ch: '=',
spacing: Alone,
span: #0 bytes(0..0),
},
Ident {
ident: "C",
span: #0 bytes(0..0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "field",
span: #0 bytes(0..0),
},
Punct {
ch: ':',
spacing: Alone,
span: #0 bytes(0..0),
},
Literal { lit: Lit { kind: Integer, symbol: "0", suffix: None }, span: Span { lo: BytePos(0), hi: BytePos(0), ctxt: #0 } },
Punct {
ch: ',',
spacing: Alone,
span: #0 bytes(0..0),
},
Ident {
ident: "field",
span: #0 bytes(0..0),
},
Punct {
ch: ':',
spacing: Alone,
span: #0 bytes(0..0),
},
Literal { lit: Lit { kind: Integer, symbol: "1", suffix: None }, span: Span { lo: BytePos(0), hi: BytePos(0), ctxt: #0 } },
Punct {
ch: ',',
spacing: Alone,
span: #0 bytes(0..0),
},
],
span: #0 bytes(0..0),
},
Punct {
ch: ';',
spacing: Alone,
span: #0 bytes(0..0),
},
]