TIL(Rust): attribute proc macros still require syntactically valid items

I was experimenting with some proc-macros in Rust and was surprised that an attribute procedural macro does not prevent the Rust compiler from parsing the source item (before applying the macro) and emitting errors.

I'm not sure why does Rust tries to parse it and emits errors, as an attribute proc macro replaces the item (and thus the source item should not even matter). This is in contrast to derive proc macros, for which this behavior is completely normal, as a derive macro only adds new code.

In the end I just switched from an attribute proc macro to a function-like proc macro. It looks a bit more ugly, but does the job — with it I can support my syntax extension inside impl blocks.

An example of attribute proc macro:

// lib.rs
use proc_macro::TokenStream;

/// A macro that ignores its input and produces an empty expansion
#[proc_macro_attribute]
pub fn macro_1(_arg: TokenStream, _item: TokenStream) -> TokenStream {
    TokenStream::new()
}

// main.rs
use try_proc_macro_item::macro_1;

pub fn main() {}

#[macro_1]
struct Foo {
    foo bar baz
}

And the error that the Rust compiler produces:

$ cargo build

error: expected `:`, found `bar`
 --> src/main.rs:7:9
  |
6 | struct Foo {
  |        --- while parsing this struct
7 |     foo bar baz
  |         ^^^ expected `:`