[macro.names] is part of [reserved.names], which states that "If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by
this Clause, its behavior is undefined." So it is undefined behavior.
In practice, most compilers will not complain for two reasons: the first is because pre-processing normally takes place before the compiler evaluates whether a symbol is a keyword or not; it's an earlier phase of translation. And also because such declarations are only illegal if you actually use the standard library (although other libraries, like Posix or Windows, may and probably do impose similar rules).
EDIT:
Just a general comment: although there is no global statement to this
effect in the standard, there is a general, underlying principle that
violation of library constraints is undefined behavior; the intent is
that the compiler not need to know anything about the library, and that
an implementation can treat #include <vector>
exactly like
#include "MyHeader.hpp"
(except perhaps for where it looks for the
file). And the restrictions cited in the original posting are
constraints on programs using the library, and only apply to such
programs. Something like:
#define while if
int
main( int argc, char** argv )
{
int retval = 0;
while ( argc > 0 ) {
++ retval;
-- argc;
}
return retval;
}
is a perfectly well defined and legal C++ (and C) program, guaranteed to
return 1. (Of course, I'd not recommend anything like this.)