Skip to content

$crate incorrectly substituted in attribute macro invocation containing bang macro invocation #62325

Description

@dtolnay

When an attribute macro input contains $ident, it is correctly substituted both inside and outside of a function-like macro invocation i.e. both of the $ident's in [u8; $ident + m!($ident)] would be substituted as expected.

But when an attribute macro input contains $crate, it is only substituted outside of a function-like macro. Inside, it incorrectly disintegrates into Punct('$'), Ident(crate) when the whole bang macro invocation is passed to an attribute macro (or derive macro). In the case of [u8; $crate::N + m!($crate::N)] the first $crate would be handled correctly but the second one would be passed incorrectly as two tokens. See where I put // WRONG in the output below.


Cargo.toml

[package]
name = "repro"
version = "0.0.0"
edition = "2018"
publish = false

[lib]
proc-macro = true

src/main.rs

#[macro_export]
macro_rules! repro {
    ($ident:tt) => {
        #[repro::repro]
        type T = [$crate::$ident; x!($crate::$ident)];
    };
}

repro!(N);

fn main() {}

src/lib.rs

extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream {
    println!("{:#?}", input);
    TokenStream::new()
}

Output of cargo check:

TokenStream [
    Ident {
        ident: "type",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "T",
        span: #0 bytes(0..0),
    },
    Punct {
        ch: '=',
        spacing: Alone,
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Bracket,
        stream: TokenStream [
            Ident {
                ident: "crate",
                span: #0 bytes(0..0),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #0 bytes(0..0),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #0 bytes(0..0),
            },
            Ident {
                ident: "N",
                span: #0 bytes(0..0),
            },
            Punct {
                ch: ';',
                spacing: Alone,
                span: #0 bytes(0..0),
            },
            Ident {
                ident: "x",
                span: #0 bytes(0..0),
            },
            Punct {
                ch: '!',
                spacing: Alone,
                span: #0 bytes(0..0),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Punct {                              // WRONG
                        ch: '$',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "crate",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: ':',
                        spacing: Joint,
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: ':',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "N",
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
        ],
        span: #0 bytes(0..0),
    },
    Punct {
        ch: ';',
        spacing: Alone,
        span: #0 bytes(0..0),
    },
]

Mentioning @petrochenkov who fixed my previous three $crate woes (#57089, #56622, #38016).

No activity

Activity on this issue will appear here.

Activity

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

Metadata

Metadata

Assignees

Labels

A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)C-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