What can a macro do that a compiler plugin can not, and vice-versa?
By "can not", I mean that it is impossible to achieve the same purpose, not that it can be achieved in a different way.
For example, a macro can impl
some trait for a struct, compiler plugin can derive
some trait for a struct. Both of them can automatically impl
a trait for a struct.
Compiler plugin macros can do everything macro_rules!
macros can do, plus a whole lot more. Compiler plugins can register derivation macros, synthesise new identifiers, deconstruct AST nodes, parse strings, do file IO, etc., etc. Listing everything would be pointless, as it would amount to reproducing the internal compiler API, which changes on a regular basis.
About the only major limitation is that they can only access what they're invoked with, or which can be derived from what they're invoked with (aside from some extra, already existent context information): they cannot access or work with anything that doesn't already exist. Like types, or what names mean, or what value an expression has.
Well, OK, there is one thing compiler plugins can't do that macros can: work stably across different versions of the compiler. (Yet.)