Skip to content

Commit 7fe387a

Browse files
authored
[C] Don't diagnose null pointer macros in -Wimplicit-void-ptr-cast (#140724)
This silences the diagnostic when the right-hand side is a null pointer constant that comes from a macro expansion, such as NULL. However, we do not limit to just NULL because other custom macros may expand to an implicit void * cast in C while expanding to something else in C++.
1 parent 0bc7f41 commit 7fe387a

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9966,8 +9966,13 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType,
99669966
// If there is a conversion of some kind, check to see what kind of
99679967
// pointer conversion happened so we can diagnose a C++ compatibility
99689968
// diagnostic if the conversion is invalid. This only matters if the RHS
9969-
// is some kind of void pointer.
9970-
if (Kind != CK_NoOp && !getLangOpts().CPlusPlus) {
9969+
// is some kind of void pointer. We have a carve-out when the RHS is from
9970+
// a macro expansion because the use of a macro may indicate different
9971+
// code between C and C++. Consider: char *s = NULL; where NULL is
9972+
// defined as (void *)0 in C (which would be invalid in C++), but 0 in
9973+
// C++, which is valid in C++.
9974+
if (Kind != CK_NoOp && !getLangOpts().CPlusPlus &&
9975+
!RHS.get()->getBeginLoc().isMacroID()) {
99719976
QualType CanRHS =
99729977
RHS.get()->getType().getCanonicalType().getUnqualifiedType();
99739978
QualType CanLHS = LHSType.getCanonicalType().getUnqualifiedType();

clang/test/Sema/implicit-void-ptr-cast.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,26 @@ void more(void) {
5959
b3 = (char *)0;
6060
b3 = nullptr;
6161
b3 = 0;
62+
63+
// Note that we explicitly silence the diagnostic if the RHS is from a macro
64+
// expansion. This allows for things like NULL expanding to different token
65+
// sequences depending on language mode, but applies to any macro that
66+
// expands to a valid null pointer constant.
67+
#if defined(__cplusplus)
68+
#define NULL 0
69+
#else
70+
#define NULL ((void *)0)
71+
#endif
72+
#define SOMETHING_NOT_SPELLED_NULL nullptr
73+
#define SOMETHING_THAT_IS_NOT_NULL (void *)12
74+
75+
char *ptr1 = NULL; // Ok
76+
char *ptr2 = SOMETHING_NOT_SPELLED_NULL; // Ok
77+
char *ptr3 = SOMETHING_THAT_IS_NOT_NULL; // c-warning {{implicit conversion when initializing 'char *' with an expression of type 'void *' is not permitted in C++}} \
78+
cxx-error {{cannot initialize a variable of type 'char *' with an rvalue of type 'void *'}}
79+
80+
ptr1 = NULL; // Ok
81+
ptr2 = SOMETHING_NOT_SPELLED_NULL; // Ok
82+
ptr3 = SOMETHING_THAT_IS_NOT_NULL; // c-warning {{implicit conversion when assigning to 'char *' from type 'void *' is not permitted in C++}} \
83+
cxx-error {{assigning to 'char *' from incompatible type 'void *'}}
6284
}

0 commit comments

Comments
 (0)