Skip to content

Recursive macro expansion mismatch between rustc and r-a #14675

@jprochazk

Description

@jprochazk

rust-analyzer version: 0.3.1489-standalone

rustc version: rustc 1.71.0-nightly (f5559e338 2023-04-24)

relevant settings: probably none

Given the following macro:

macro_rules! get {
    ($list:ident; ) => (
        None
    );
    ($list:ident; (Marker)) => (
        Some($list[0])
    );
    ($list:ident; (Marker) $(($tail:ty))*) => (
        Some($list[0])
    );
    ($list:ident; ($head:ty) $(($tail:ty))*) => (
        get!($list; $(($tail))*)
    );
}

The output of the following snippet will be None:

fn main() {
    let test = &["test"];
    let v: Option<&'static str> = get!(test; (Test) (Marker));
    println!("{v:?}");
}

But rust-analyzer's expansion outputs Some(test[0]), which should print Some("test").

Playground link

For more context, cargo-expand expands the above snippet to:

fn main() {
    let test = &["test"];
    let v: Option<&'static str> = None;
    {
        ::std::io::_print(format_args!("{0:?}\n", v));
    };
}

If the designator of $tail is changed from ty to ident:

macro_rules! get {
    ($list:ident; ) => (
        None
    );
    ($list:ident; (Marker)) => (
        Some($list[0])
    );
    ($list:ident; (Marker) $(($tail:ident))*) => (
        Some($list[0])
    );
    ($list:ident; ($head:ident) $(($tail:ident))*) => (
        get!($list; $(($tail))*)
    );
}

Then rustc, cargo-expand, and rust-analyzer all agree that the expansion of the macro is Some(test[0]), which will print Some("test").

Playground link

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-macromacro expansionC-bugCategory: bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions