Skip to content

#[cfg(...)] attribute is incorrectly removed from a function parameter inside of the derive macro #130004

Open

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-cfgArea: `cfg` conditional compilationA-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-proc-macrosArea: Procedural macrosC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions