How to deal with clang's (3.9) -Wexpansion-to-defined warning?

Walter picture Walter · Feb 6, 2017 · Viewed 9.2k times · Source

clang 3.9 has added to -Wall a the warning -Wexpansion-to-defined, which produces

macro expansion producing 'defined' has undefined behaviour

in case defined is used outside an #if expression, including the case of a macro that is then used within an #if expression. For example the following code

// in some file:
#define HAS_GNU (defined(__GNUC__) && !defined(__clang__))

// possibly in another file:
#if defined(__clang__) || HAS_GNU
/* ... */
#endif

produces

test.cc:5:27: warning: macro expansion producing 'defined' has undefined behavior [-Wexpansion-to-defined]
#if defined(__clang__) || HAS_GNU
                          ^
test.cc:3:18: note: expanded from macro 'HAS_GNU'
#define HAS_GNU (defined(__GNUC__) && !defined(__clang__))
                 ^
test.cc:5:27: warning: macro expansion producing 'defined' has undefined behavior [-Wexpansion-to-defined]
test.cc:3:40: note: expanded from macro 'HAS_GNU'
#define HAS_GNU (defined(__GNUC__) && !defined(__clang__))

So what's the 'correct' way to do that?

Answer

eerorika picture eerorika · Feb 6, 2017

You can use #if - #else macros:

#if defined(__GNUC__) && !defined(__clang__)
#define HAS_GNU 1
#else
#define HAS_GNU 0
#endif

Or, if you're willing to change the code that uses HAS_GNU, perhaps more conventional way:

#if defined(__GNUC__) && !defined(__clang__)
#define HAS_GNU
#endif

#if defined(__clang__) || defined(HAS_GNU)