`#[cfg(...)]` attribute is incorrectly removed from a function parameter inside of the derive macro
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
// my_macro proc-macro crate
use use proc_macro::TokenStream;
#[proc_macro_derive(Derive)]
pub fn derive(input: TokenStream) -> TokenStream {
eprintln!("{input}");
TokenStream::default()
}
// lib.rs
#[derive(my_macro::Derive)]
enum Enum {
X = {
fn foo(#[cfg(any())] arg1: (), arg2: ()) {}
0
},
}
I'm not sure what exactly I expected to see in the stderr output when I compile the crate. Maybe this with the #[cfg(...)] attribute left intact on the function
enum Enum { X = { fn foo(#[cfg(any())] arg1: (), arg2: ()) {} 0 }, }
or this with the #[cfg(...)] attribute completely removed togther with the syntax it was placed on:
enum Enum { X = { fn foo(arg2: ()) {} 0 }, }
Instead, the output is invalid rust code:
enum Enum { X = { fn foo(, arg2: ()) {} 0 }, }
Notice that the #[cfg(...)] was removed, but... the coma after the function parameter was not removed. This output results in an invalid token tree not parsable by syn
Meta
rustc --version --verbose:
rustc 1.81.0 (eeb90cda1 2024-09-04)
binary: rustc
commit-hash: eeb90cda1969383f56a2637cbd3037bdf598841c
commit-date: 2024-09-04
host: x86_64-unknown-linux-gnu
release: 1.81.0
LLVM version: 18.1.7
Context
Why would I ever write such code? I'd like to support conditional compilation with my proc macro that generates a builder from a function called bon. But... since it's a proc macro attribute, the #[cfg(...)] and #[cfg_attr(...)] attributes aren't automatically removed when the macro runs.
So I thought I'd workaround it by delegating to a derive macro that accepts the function item in the expression position as the first item of the block for the default value of the enum's variant. This is because derive macros benefit from automatic expansion of #[cfg(...)/cfg_attr(...)] attributes before they run. Thus, by using a derive macro wrapper I could get the results of cfg evaluation this way.
I could work around that by passing the item as an argument to the proc-macro derive... But IDEs and Rust Analyzer don't work this way. They somehow mess up span information.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with the proc-macro derive and enum example from the report, then inspect the compiler's derive-macro expansion handling for cfg attributes on function parameters. Verify the emitted token stream remains valid Rust and is parsable by syn, with the parameter and separator handled consistently when the cfg condition is removed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100