I'm not necessarily going to defend proc macros, which have a lot of problems but are also better than the alternative in many languages (like Go's over-reliance on codegen). Macros-by-example are pretty nice though, even with the special syntax.
But in Rust, you don't need to delve into any kind of macro for polymorphism like you do in C++, since Rust has a real generics system. There is vastly more C++ code that instantiates templates than Rust code that uses macros.
I was a bit unclear there—I was referring to templates, not C++ macros. I believe that concepts in C++20 have improved the situation (although I haven't personally worked with a C++20 codebase and don't know how widely adopted it is in the ecosystem).
The only thing you may complain about are error messages due to duck typing at compile time gone wrong, and even that is kind of already sorted out in C++17.
C++17 example, showing polymorphism at compile time without macros.
Naturally checking for speak() existence with enable_if, static_assert and type traits could be added, though this is an example, and nowdays we would make use of concepts anyway.
Unless this is about some particular technique I've missed, isn't this what virtual methods are for? Only place I'm aware of where you see macros-based polymorphism is in C.
Virtual methods are runtime polymporphism. Templates are compile time polymorphism, and therefore typically are faster (more inlining + avoiding virtual function call).
At least, as convuluted as C++ may be, template and compile time programming still rely on C++.