Skip to content

Commit 809df34

Browse files
committed
[Sema] -Wzero-as-null-pointer-constant: don't warn for system macros other than NULL.
Summary: The warning was initially introduced in D32914 by @Thakis, and the concerns were raised there, and later in rL302247 and PR33771. I do believe that it makes sense to relax the diagnostic e.g. in this case, when the expression originates from the system header, which can not be modified. This prevents adoption for the diagnostic for codebases which use pthreads (`PTHREAD_MUTEX_INITIALIZER`), gtest, etc. As @malcolm.parsons suggests, it *may* make sense to also not warn for the template types, but it is not obvious to me how to do that in here. Though, it still makes sense to complain about `NULL` macro. While there, add more tests. Reviewers: dblaikie, thakis, rsmith, rjmccall, aaron.ballman Reviewed By: thakis Subscribers: Rakete1111, hans, cfe-commits, thakis, malcolm.parsons Tags: #clang Differential Revision: https://reviews.llvm.org/D38954 llvm-svn: 316662
1 parent 83454aa commit 809df34

File tree

4 files changed

+81
-5
lines changed

4 files changed

+81
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ Improvements to Clang's diagnostics
9191
offset is nonzero. It also now warns about arithmetic on a null pointer
9292
treated as a cast from integer to pointer (GNU extension).
9393

94+
- ``-Wzero-as-null-pointer-constant`` was adjusted not to warn on null pointer
95+
constants that originate from system macros, except ``NULL`` macro.
96+
9497
Non-comprehensive list of changes in this release
9598
-------------------------------------------------
9699

clang/lib/Sema/Sema.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,12 +436,24 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
436436
}
437437

438438
void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
439+
if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
440+
E->getLocStart()))
441+
return;
442+
// nullptr only exists from C++11 on, so don't warn on its absence earlier.
443+
if (!getLangOpts().CPlusPlus11)
444+
return;
445+
439446
if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer)
440447
return;
441448
if (E->IgnoreParenImpCasts()->getType()->isNullPtrType())
442449
return;
443-
// nullptr only exists from C++11 on, so don't warn on its absence earlier.
444-
if (!getLangOpts().CPlusPlus11)
450+
451+
// If it is a macro from system header, and if the macro name is not "NULL",
452+
// do not warn.
453+
SourceLocation MaybeMacroLoc = E->getLocStart();
454+
if (Diags.getSuppressSystemWarnings() &&
455+
SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
456+
!findMacroSpelling(MaybeMacroLoc, "NULL"))
445457
return;
446458

447459
Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#define NULL (0)
2+
#define SYSTEM_MACRO (0)
3+
#define OTHER_SYSTEM_MACRO (NULL)

clang/test/SemaCXX/warn-zero-nullptr.cpp

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wzero-as-null-pointer-constant -std=c++11
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -Wzero-as-null-pointer-constant -std=c++11
2+
// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -DSYSTEM_WARNINGS -Wzero-as-null-pointer-constant -Wsystem-headers -std=c++11
3+
4+
#include <warn-zero-nullptr.h>
5+
6+
#define MACRO (0)
7+
#define MCRO(x) (x)
28

39
struct S {};
410

@@ -15,8 +21,12 @@ void* p2 = __null; // expected-warning{{zero as null pointer constant}}
1521
void (*fp2)() = __null; // expected-warning{{zero as null pointer constant}}
1622
int (S::*mp2) = __null; // expected-warning{{zero as null pointer constant}}
1723

18-
void f0(void* v = 0); // expected-warning{{zero as null pointer constant}}
19-
void f1(void* v);
24+
void f0(void* v = MACRO); // expected-warning{{zero as null pointer constant}}
25+
void f1(void* v = NULL); // expected-warning{{zero as null pointer constant}}
26+
void f2(void* v = MCRO(0)); // expected-warning{{zero as null pointer constant}}
27+
void f3(void* v = MCRO(NULL)); // expected-warning{{zero as null pointer constant}}
28+
void f4(void* v = 0); // expected-warning{{zero as null pointer constant}}
29+
void f5(void* v);
2030

2131
void g() {
2232
f1(0); // expected-warning{{zero as null pointer constant}}
@@ -32,3 +42,51 @@ struct A { operator int*() { return nullptr; } };
3242
void func() { if (nullptr == A()) {} }
3343
void func2() { if ((nullptr) == A()) {} }
3444
}
45+
46+
template <typename T> void TmplFunc0(T var) {}
47+
void Func0Test() {
48+
TmplFunc0<int>(0);
49+
TmplFunc0<int*>(0); // expected-warning {{zero as null pointer constant}}
50+
TmplFunc0<void*>(0); // expected-warning {{zero as null pointer constant}}
51+
}
52+
53+
// FIXME: this one probably should not warn.
54+
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}}
55+
void FuncTest() {
56+
TmplFunc1<int>(0);
57+
TmplFunc1<int*>(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1<int *>' required here}}
58+
TmplFunc1<void*>(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1<void *>' required here}}
59+
}
60+
61+
template<typename T>
62+
class TemplateClass0 {
63+
public:
64+
explicit TemplateClass0(T var) {}
65+
};
66+
void TemplateClass0Test() {
67+
TemplateClass0<int> a(0);
68+
TemplateClass0<int*> b(0); // expected-warning {{zero as null pointer constant}}
69+
TemplateClass0<void*> c(0); // expected-warning {{zero as null pointer constant}}
70+
}
71+
72+
template<typename T>
73+
class TemplateClass1 {
74+
public:
75+
// FIXME: this one should *NOT* warn.
76+
explicit TemplateClass1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}}
77+
};
78+
void IgnoreSubstTemplateType1() {
79+
TemplateClass1<int> a(1);
80+
TemplateClass1<int*> b(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1<int *>' required here}}
81+
TemplateClass1<void*> c(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1<void *>' required here}}
82+
}
83+
84+
#ifndef SYSTEM_WARNINGS
85+
// Do not warn on *any* other macros from system headers, even if they
86+
// expand to/their expansion contains NULL.
87+
void* sys_init = SYSTEM_MACRO;
88+
void* sys_init2 = OTHER_SYSTEM_MACRO;
89+
#else
90+
void* sys_init = SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}}
91+
void* sys_init2 = OTHER_SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}}
92+
#endif

0 commit comments

Comments
 (0)