I'm trying to make proc-macro-error work with proc-macro-hack. Both use attribute proc-macros and both are supposed to be used on the same function. Unfortunately, they don't work well together, yet. The problem is found and I believe I can fix it, but to do that I need to detect #[proc_macro_hack] attribute.
First I thought this should work:
let is proc_macro_hack = input.attrs.iter().any(|attr| attr.is_ident("proc_macro_hack"));
But my tests show me it doesn't. It looks like attribute proc-macros aren't really listed as attributes. Are they?
Have you tried using cargo expand to check if there are any attributes left after expansion. My guess is that because of resolution/generation order they can not see each other. I forked proc-macro-error but wondered if ther was a test case or something, or if in test-crate I could just add proc-macro-hack and an abort!?
I was curious about this too, so I've created a simple test: https://github.com/Cerberuser/multiple-attrs
In this repo, I'm creating two attribute macros which expect a function definition, print all attributes they see on it to the stderr, and return the input unchanged. Here's the code:
use attr1;
use attr2;
#[attr1::attr]
#[attr2::attr]
fn _test() {}
So, it looks like that every attribute can see the ones which are after it (and modify them if necessary), but can't see anything that is before - because these attributes have already done their work.
Attributes will always expand in source order. This is already stable in that earlier attributes can modify later attributes (or even just remove them!) so the compiler team can't change it without breaking stability.
There is ongoing work to make this work properly including derive macros (which currently are required to be after any attribute macros and may or may not behave weirdly) and then document this fact as guaranteed.
Attributes can be "inert" or "active". Active attributes get removed once they're expanded, inert ones do not. Proc-macro attributes are always active.