https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77513
Bug ID: 77513 Summary: -Wzero-as-null-pointer-constant vs 0, nullptr, NULL and __null Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: petschy at gmail dot com Target Milestone: --- Created attachment 39580 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=39580&action=edit Preprocessed source, generated with g++-7.0.0 -std=c++14 -Wzero-as-null-pointer-constant 20160907-null.cpp -E > 20160907-null.ii Yesterday I switched on the warning for a ~250kloc codebase to clean it up. Used 7.0, it was tedious but it was done. I had to replace NULLs also, not just 0s, but at that time I wasn't suspecting anything, though it seemed a bit strange. Then, tried to build on another machine with 5.4.1, and to my surprise, tons of warnings appeared. Then tried to build on my machine with 5.4.1, the same results. It turned out that NULLs are frowned upon, quite inconsistently. 5.4.1 has problems with 7 cpp files, 6.2.1 and 7.0 with just a single one. Did a grep for NULL, and as expected for a large and aging codebase, there were lots of them, but they are not treated equally. All files are c++, and compiled with the same flags. Preprocessed 2 problematic files with all three gcc versions mentioned. Diffing them revealed that there is no difference in the actual code, only what gets included due to the differing gcc versions. All NULLs were replaced with __null's by the preprocessor, which is defined in the gcc version specific stddef.h include. Crafted a test case: #include <stddef.h> char* a = 0; char* b = nullptr; char* c = __null; char* d = NULL; int main() { } $ g++-5.4.1 -std=c++14 -Wzero-as-null-pointer-constant 20160907-null.cpp 20160907-null.cpp:2:11: warning: zero as null pointer constant [-Wzero-as-null-pointer-constant] char* a = 0; ^ 20160907-null.cpp:4:11: warning: zero as null pointer constant [-Wzero-as-null-pointer-constant] char* c = __null; ^ 6.2.1 and 7.0 print exactly the same warnings. So NULL is ok, but __null is not? The end of the preprocessed source looks like this: # 2 "20160907-null.cpp" char* a = 0; char* b = nullptr; char* c = __null; char* d = # 5 "20160907-null.cpp" 3 4 __null # 5 "20160907-null.cpp" ; int main() { } c and d initialized the same except for whitespace and the two "'# 6" lines around d's __null. I naively thought that these are only to communicate line info to the compiler, but if I delete the first one: $ g++-7.0.0 -std=c++14 -Wzero-as-null-pointer-constant 20160907-null.ii 20160907-null.cpp:2:11: warning: zero as null pointer constant [-Wzero-as-null-pointer-constant] char* a = 0; ^ 20160907-null.cpp:4:11: warning: zero as null pointer constant [-Wzero-as-null-pointer-constant] char* c = __null; ^~~~~~ 20160907-null.cpp:6:10: warning: zero as null pointer constant [-Wzero-as-null-pointer-constant] int main() ^ The interpretation of __null at d changed for some reason. What is going on? It seems that the interpretation can change unpredictably, and in the problematic source files __null's are misdiagnosed even when the "# ..." lines are around them. For c++11 and later code, why is NULL defined as __null, rather than nullptr? I put a fast bandaid on my code by redefining NULL to be nullptr after the last include in the problematic files, but since the number of problematic files seems to change from gcc version to gcc version, this is rather fragile, let alone unelegant. Platform is Debian Jessie AMD64, the gcc versions: $ g++-5.4.1 -v Using built-in specs. COLLECT_GCC=g++-5.4.1 COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.4.1/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../configure --enable-languages=c,c++ --disable-multilib --program-suffix=-5.4.1 --disable-bootstrap CFLAGS='-O2 -march=native' CXXFLAGS='-O2 -march=native' Thread model: posix gcc version 5.4.1 20160829 (GCC) $ g++-6.2.1 -v Using built-in specs. COLLECT_GCC=g++-6.2.1 COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/6.2.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../configure --enable-languages=c,c++ --disable-multilib --program-suffix=-6.2.1 --disable-bootstrap CFLAGS='-O2 -march=native' CXXFLAGS='-O2 -march=native' Thread model: posix gcc version 6.2.1 20160831 (GCC) $ g++-7.0.0 -v Using built-in specs. COLLECT_GCC=g++-7.0.0 COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/7.0.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../configure --enable-languages=c,c++ --disable-multilib --program-suffix=-7.0.0 --disable-bootstrap CFLAGS='-O2 -march=native' CXXFLAGS='-O2 -march=native' Thread model: posix gcc version 7.0.0 20160831 (experimental) (GCC)