First #[A] is evaluated (with the exception of A being derive and B being a cfg, in that case the cfg gets resolved first before feeding into the proc-macro attributes).
This means that #[A] gets to see#[B] (& #[C]), and can thus "process" those (and remove them), or just ignore them (and "re"-emit them).
That being said, besides #[cfg(…)] and #[doc = "…"] (i.e., /// …), there is no way to have an attribute that directly interacts with a field (at least on stable Rust). It's always rather #[A] which will manually take care of looking for #[B] and acting accordingly.
A procedural macro is just a macro that happens to be implemented using Rust code (vs. the special language for macro_rules! macros).
On the other hand, there are three flavors of macro "call-sites":
function-like (currently implementable with both macro_rules! macros and procedural macros (#[proc_macro]-annotated) (and macro macros));
They can receive any arbitrary sequence of tokens as input, but can "only" be called in item, expression, statement, pattern or type position.
derives (currently only implementable with procedural macros (#[proc_macro_derive(…)]-annotated);
They can only be fed to the special #[derive(…)] attribute, which can only be applied to a struct, enum or union definition.
attributes (same, #[proc_macro_attribute] only).
They can generally only be applied to an item [definition], such as:
the input of a #[derive(…)] (struct/enum/union) or even a type (alias) definition;
a function;
an impl block;
a(n inline!) mod (e.g., #[attr] mod foo { … });
a use statement;
a function-like macro invocation;
an extern block;
a const or static definition;
But they are planned to also be applicable to an expression, a statement, or even some types or some function parameters list (you can experiment with these things on nightly rust).
Yes, that's the difference between using #[derive(SomeDeriveMacro)] and #[some_proc_macro_attr]: while the former only gets to peek / read at the input struct/enum/union definition (including the #[B] and #[C] attrs), a proc-macro attribute acts like a function-like macro in that regard:
#[some_macro_attr]
… some item …
could always be written as:
some_function_like_macro! {
… some item …
}
in that regard, by the way, there is a proc-macro attribute that does exactly that: it takes a macro_rules! macro parameter, and just expands to a call to that macro with the item as input:
That is, the item definition is just an input given to the macro, which gets to emit whatever it wants. When you thing about this, by the way, that power is already showcased by the #[cfg(…)] attributes: they're either the identity macro (re-emitting the input as-is), or they are a "nullifying" macro which ignores its input and expand to nothingness.
In practice, however, a proc-macro will likely interact with its input, often leaving it be, or sometimes mutating it a bit, but it is important to be aware of this: that function-like and attribute macros can emit whatever they want, disregarding or mutating their input.
And, if the struct has multiple attributes, then what's the processing order of them? And the latter one would see the changed token stream from previous one?
then it depends on whatever A produces. For example A may be a macro that removes other attribute macros, in which case nothing else will be processed.
Attributes (applied to the same item) are processed in an outer-most inner-most fashion, with the attributes at the top being considered the outer ones:
#[A]
#[B]
some_item…
would be, using my macro_rules comparison:
A! {
#[B]
some_item…
}
/* if `A!` re-emits its input, then we get:
B! {
some_item…
}
*/
Since derive macro can't change its input (only append to it), this order won't matter unless the macro has side-effects, which are AFAIK discouraged anyway.
The same as above: first A is run, then compiler looks on what was emitted and takes the first remaining attribute, if there is any.