I could tell a similar story (many, in fact) about C++'s templates. It is not entirely clear to me what exactly makes the preprocessor a bad choice. One could argue that it is too flexible, so it is possible to create a mess with it. But somehow this seems a rather weak argument for inventing another monomorphization layer, which often evolve into their own mess.
You can definitely make an incomprehensible soup out of C++ templates. C++ expression templates are a classic example. But the threshold of this is much higher than with a macro language.
Using C++ templates for a linked list type doesn't make a mess.