They are both abstractions that substitute an explicit operation with just a name; and thus both require that you expand your vocabulary when holding the program context in your head. Abstract at the wrong level, and you increase difficulty; abstract at the correct one, and you lower it.
Where I do think the main problem with macros is, is in debugging - because I know no macro system that maintains metadata on the written code to help explain the higher (macro) conceptual level once a stacktrace / condition / segfault / error arises.
That said, with the proliferation of distributed systems that are commonly executing where you can't connect a debugger, I've found many aren't even aware of what they are missing. Jrebel, I recall, was very popular in some circles. Today, I'm not even sure most of my colleagues have ever used a debugger in a professional context.
Macros can be great if used to overcome a syntactical limitation, in which case they can make the code more readable and compact. If it introduces barriers to reading the code it's not a good macro, and maybe unnecessary.
I would generalize to the following: Everything that increases the time required to read the code is bad if it does not reduce the amount of code by a larger fraction.
So, refactoring code into a simple function that occurs once or twice is Ok, as long as that function can be found quickly in the same context (file, class, etc.). If the context is elsewhere, though, it is bad.
Similar for anything implicit (operator overloading, conversions, fancy type classes): If you need to switch context or even know about a completely different language feature or library to understand this code, that additional effort better saves a lot of code here.