As far as I can tell, doing
#define HAVE_FOO_BAR defined(FOO) && defined(BAR) #if HAVE_FOO ... #endif
has undefined behavior per [cpp.cond]p4. In practice, it can have different behavior in gcc and Visual Studio – see the comment in PPExpressions.cpp. So we should warn on this.
One problem is that this also applies to function-like macros. While the example above can be written like
#if defined(FOO) && defined(BAR) #defined HAVE_FOO 1 #else #define HAVE_FOO 0 #endif
there is no easy way to rewrite a function-like macro like #define FOO(x) (defined __foo_##x && __foo_##x). Function-like macros like this are used in practice, and compilers seem to not have differing behavior in that case. So make this a default-on warning only for object-like macros and an extension warning that only shows up with pedantic for function-like macros. (But it's undefined behavior in both cases.)
Move this down to the end of the function, after we've checked that we have a syntactically valid defined operator, to avoid duplicate diagnostics on a case like: