Open showier-drastic opened 3 months ago
First of all, this macro does something exceedingly cursed, which IMO we should officially not support, because those who use this pattern deserve a punishment.
Jokes aside, the macro reuse the same attribute for both proc macro attribute and derive helper attribute. Somehow, rustc seams to bless this pattern. I bet this wasn't done knowingly, and I'm not sure whether the language team would be happy to commit to this, but rustc allows that so we are obliged :(
I'm not entirely sure of this, but it seems what is really happening is that bilge
just happens to insert a macro before some derive macros, and rust-analyzer
has a bug where it repeats derive macros once for every non-derive macro evaluation:
#[proc_macro_attribute]
pub fn test_attr(_: TokenStream, b: TokenStream) -> TokenStream {
println!("Test Attr");
b
}
#[proc_macro_derive(TestDerive)]
pub fn test_derive(_: TokenStream) -> TokenStream {
println!("Test Derive");
TokenStream::new()
}
#[proc_macro_derive(TestDerive2)]
pub fn test_derive_2(_: TokenStream) -> TokenStream {
println!("Test Derive 2");
TokenStream::new()
}
#[derive(TestDerive, TestDerive2)]
#[test_attr]
#[test_attr]
struct _Foo {
f: u8,
}
$ cargo test
Compiling test_proc_macros v0.1.0 (/home/alexkl/src/test_proc_macros)
Test Derive
Test Derive 2
Test Attr
Test Attr
$ rust-analyzer diagnostics .
2024-11-22T23:04:15.004046Z ERROR proc-macro tried to print : Test Derive
2024-11-22T23:04:15.004331Z ERROR proc-macro tried to print : Test Derive 2
2024-11-22T23:04:15.004582Z ERROR proc-macro tried to print : Test Attr
2024-11-22T23:04:15.004942Z ERROR proc-macro tried to print : Test Derive
2024-11-22T23:04:15.005137Z ERROR proc-macro tried to print : Test Derive 2
2024-11-22T23:04:15.005355Z ERROR proc-macro tried to print : Test Attr
2024-11-22T23:04:15.005586Z ERROR proc-macro tried to print : Test Derive
2024-11-22T23:04:15.005753Z ERROR proc-macro tried to print : Test Derive 2
This seems pretty terrible for performance as it evaluates the macros num_attributes * num_derive_attributes
times.
After each evaluation of an attribute, the attribute is stripped, and the set of derives is evaluated once more. This is why the bilge
crate has the "false positive error", because what it wants to do is this:
// Original Code
#[bitsize(2)]
#[derive(DebugBits, Copy)]
struct Example {}
// Step 1
#[derive(DebugBits)] // While this is evaluated, it has access to `bitsize_internal(2)`
#[bitsize_internal(2)]
#[derive(Copy)]
struct Example {}
// Step 2
#[bitsize_internal(2)]
#[derive(Copy)]
struct Example {}
impl Debug for Example {/* Makes use of bitsize 2 */}
// Step 3
#[derive(Copy)] // Doesn't need bitsize 2, and should be implemented on the final struct.
struct Example { /* Rewritten fields */ }
impl Debug for Example {/* Makes use of bitsize 2 */}
// Done
struct Example { /* Rewritten fields */ }
impl Debug for Example {/* Makes use of bitsize 2 */}
impl Copy for Example { }
But, with rust-analyzer
what really happens is that when #[bitsize_internal]
is being evaluated in Step 2->3, #[derive(DebugBits)]
happens again, this time without access to #[bitsize(2)]
.
rust-analyzer version:
rust-analyzer version: 0.3.2070-standalone (0daeb5c0b 2024-08-10) [/Users/user/.vscode/extensions/rust-lang.rust-analyzer-0.3.2070-darwin-arm64/server/rust-analyzer]
rustc version:
rustc 1.80.1 (3f5fd8dd4 2024-08-06)
editor or extension:
VSCode v0.3.2070
relevant settings: No special settings
repository link (if public, optional): https://github.com/showier-drastic/bilge-test
I'm using bilge. This library provides the
#[bitsize(3)]
macro. The code in the repo above compiles successfully without errors, but rust analyzer complains about it, every time#[bitsize]
is used:Upstream issue: https://github.com/hecatia-elegua/bilge/issues/92
code snippet to reproduce: