
The implementation of -Wzero-as-null-pointer-constant was done before the following fix has been committed to GCC: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=752e7593b0f19af233a0b7e72daab8413662b605;hp=298434c916c14e8adca2cab8a746aee29038c5b3 As a result, clang and gcc diverge on the use of `__null` and, consequently, on the use of `NULL` on systems like Linux/macOS where `NULL` is defined as `__null`. This is a problem for compatibility between gcc and clang, particularly for code bases that support C++98 or for single-source libraries that are implemented in C, but compiled as C++ via inclusion into a C++ translation unit. Code like this can not be changed to use `nullptr`, as it needs to maintain compatibility with C before C23 or C++ before C++11, but warns on the use of `NULL` in clang. The warning `Wzero-as-null-pointer-constant` is still useful with this change, as it allows to change `0` to `NULL`, which fixes gcc warnings and helps the reader distinguish between pointers and non-pointers. Users who require a full C++11 modernization pass can still use clang-tidy for that purpose.
93 lines
3.7 KiB
C++
93 lines
3.7 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -Wzero-as-null-pointer-constant -std=c++11
|
|
// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -DSYSTEM_WARNINGS -Wzero-as-null-pointer-constant -Wsystem-headers -std=c++11
|
|
|
|
#include <warn-zero-nullptr.h>
|
|
|
|
#define MACRO (0)
|
|
#define MCRO(x) (x)
|
|
|
|
struct S {};
|
|
|
|
int (S::*mp0) = nullptr;
|
|
void (*fp0)() = nullptr;
|
|
void* p0 = nullptr;
|
|
|
|
int (S::*mp1) = 0; // expected-warning{{zero as null pointer constant}}
|
|
void (*fp1)() = 0; // expected-warning{{zero as null pointer constant}}
|
|
void* p1 = 0; // expected-warning{{zero as null pointer constant}}
|
|
|
|
// __null is not treated as an integer constant expression for GCC compatibility
|
|
void* p2 = __null;
|
|
void (*fp2)() = __null;
|
|
int (S::*mp2) = __null;
|
|
|
|
void f0(void* v = MACRO); // expected-warning{{zero as null pointer constant}}
|
|
void f1(void* v = NULL); // expected-warning{{zero as null pointer constant}}
|
|
void f2(void* v = MCRO(0)); // expected-warning{{zero as null pointer constant}}
|
|
void f3(void* v = MCRO(NULL)); // expected-warning{{zero as null pointer constant}}
|
|
void f4(void* v = 0); // expected-warning{{zero as null pointer constant}}
|
|
void f5(void* v);
|
|
|
|
void g() {
|
|
f1(0); // expected-warning{{zero as null pointer constant}}
|
|
}
|
|
|
|
// Warn on these too. Matches gcc and arguably makes sense.
|
|
void* pp = (decltype(nullptr))0; // expected-warning{{zero as null pointer constant}}
|
|
void* pp2 = static_cast<decltype(nullptr)>(0); // expected-warning{{zero as null pointer constant}}
|
|
|
|
// Shouldn't warn.
|
|
namespace pr34362 {
|
|
struct A { operator int*() { return nullptr; } };
|
|
void func() { if (nullptr == A()) {} }
|
|
void func2() { if ((nullptr) == A()) {} }
|
|
}
|
|
|
|
template <typename T> void TmplFunc0(T var) {}
|
|
void Func0Test() {
|
|
TmplFunc0<int>(0);
|
|
TmplFunc0<int*>(0); // expected-warning {{zero as null pointer constant}}
|
|
TmplFunc0<void*>(0); // expected-warning {{zero as null pointer constant}}
|
|
}
|
|
|
|
// FIXME: this one probably should not warn.
|
|
template <typename T> void TmplFunc1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}}
|
|
void FuncTest() {
|
|
TmplFunc1<int>(0);
|
|
TmplFunc1<int*>(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1<int *>' required here}}
|
|
TmplFunc1<void*>(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1<void *>' required here}}
|
|
}
|
|
|
|
template<typename T>
|
|
class TemplateClass0 {
|
|
public:
|
|
explicit TemplateClass0(T var) {}
|
|
};
|
|
void TemplateClass0Test() {
|
|
TemplateClass0<int> a(0);
|
|
TemplateClass0<int*> b(0); // expected-warning {{zero as null pointer constant}}
|
|
TemplateClass0<void*> c(0); // expected-warning {{zero as null pointer constant}}
|
|
}
|
|
|
|
template<typename T>
|
|
class TemplateClass1 {
|
|
public:
|
|
// FIXME: this one should *NOT* warn.
|
|
explicit TemplateClass1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}}
|
|
};
|
|
void IgnoreSubstTemplateType1() {
|
|
TemplateClass1<int> a(1);
|
|
TemplateClass1<int*> b(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1<int *>' required here}}
|
|
TemplateClass1<void*> c(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1<void *>' required here}}
|
|
}
|
|
|
|
#ifndef SYSTEM_WARNINGS
|
|
// Do not warn on *any* other macros from system headers, even if they
|
|
// expand to/their expansion contains NULL.
|
|
void* sys_init = SYSTEM_MACRO;
|
|
void* sys_init2 = OTHER_SYSTEM_MACRO;
|
|
#else
|
|
void* sys_init = SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}}
|
|
void* sys_init2 = OTHER_SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}}
|
|
#endif
|