-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
rust-analyzer version: rust-analyzer version: 0.4.2738-standalone [[redacted home dir]/.vscode-insiders/extensions/rust-lang.rust-analyzer-0.4.2738-linux-x64/server/rust-analyzer]
rustc version: rustc 1.93.0-nightly (b84478a1c 2025-11-30)
editor or extension: VSCode pre-release (also occurs on release version)
relevant settings: N/A
code snippet to reproduce:
use test_helper::Foo;
#[derive(Foo)]
pub struct Bar {
x: u8,
}
fn main() {
println!("Hello, world!");
}
// crate test_helper
// --proc-macro
use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
#[proc_macro_derive(Foo)]
pub fn foo(attrs: TokenStream) -> TokenStream {
let tt_str = format!("{attrs:?}");
[
TokenTree::Ident(Ident::new("core", Span::mixed_site())),
TokenTree::Punct(Punct::new(':', proc_macro::Spacing::Joint)),
TokenTree::Punct(Punct::new(':', proc_macro::Spacing::Alone)),
TokenTree::Ident(Ident::new("compile_error", Span::mixed_site())),
TokenTree::Punct(Punct::new('!', proc_macro::Spacing::Alone)),
TokenTree::Group(Group::new(
proc_macro::Delimiter::Parenthesis,
[TokenTree::Literal(Literal::string(&tt_str))]
.into_iter()
.collect(),
)),
TokenTree::Punct(Punct::new(';', proc_macro::Spacing::Alone)),
]
.into_iter()
.collect()
}The behaviour of the above code is as follows:
On rustc, it produces a compile_error with roughly the following output (which is expected per the reference):
error: TokenStream [Ident { ident: "pub", span: #0 bytes(38..41) }, Ident { ident: "struct", span: #0 bytes(42..48) }, Ident { ident: "Bar", span: #0 bytes(49..52) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "x", span: #0 bytes(59..60) }, Punct { ch: ':', spacing: Alone, span: #0 bytes(60..61) }, Ident { ident: "u8", span: #0 bytes(62..64) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(64..65) }], span: #0 bytes(53..67) }]
--> src/main.rs:3:10
|
3 | #[derive(Foo)]
| ^^^
|
= note: this error originates in the derive macro `Foo` (in Nightly builds, run with -Z macro-backtrace for more info)On rust-analyzer, it produces a different compile_error, which demonstrates a different (and incorrect) input TokenStream:
TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "pub", span: /* simplified */), ctx: SyntaxContext(4294967036) } }, Ident { ident: "struct", span: /* simplified */), ctx: SyntaxContext(4294967036) } }, Ident { ident: "Bar", span: /* simplified */), ctx: SyntaxContext(4294967036) } }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "x", span: /* simplified */), ctx: SyntaxContext(4294967036) } }, Punct { ch: ':', spacing: Alone, span: /* simplified */), ctx: SyntaxContext(4294967036) } }, Ident { ident: "u8", span: /* simplified */), ctx: SyntaxContext(4294967036) } }, Punct { ch: ',', spacing: Alone, span: /* simplified */), ctx: SyntaxContext(4294967036) } }], span: /* simplified */), ctx: SyntaxContext(4294967036) } }], span: /* simplified */), ctx: SyntaxContext(4294967036) } }](Span markers simplified manually to avoid unnecessary clutter).
In the above, rustc passes the Foo definition directly, while r-a encloses it in a None delimited group (which is both unnecessary and incorrect - None groups are for delimiting the contents of expanded non-literal metavariables (like $expr, $item, or $stmt) only).
Note that while this is a contrived example and only meaningfully differs in compiler diagnostics, the added None group where not expected can affect the ability to parse some of the input. As an example, I get unsupported type errors using the bitfield_struct crate on rust-analyzer only, which I can only assume is caused by the same bug and the macro not being forgiving about None groups arround the type names (which it expects to be literal identifiers).