Skip to content

Commit 5f24ae9

Browse files
authored
[C] Update -Wimplicit-void-ptr-cast for null pointer constants (#138271)
Null pointer constants require a bit of extra effort to handle in C. Fixes #138145
1 parent 93680b5 commit 5f24ae9

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9824,15 +9824,35 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType,
98249824
((getLangOpts().C23 && RHS.get()->getType()->isNullPtrType()) ||
98259825
RHS.get()->isNullPointerConstant(Context,
98269826
Expr::NPC_ValueDependentIsNull))) {
9827+
AssignConvertType Ret = AssignConvertType::Compatible;
98279828
if (Diagnose || ConvertRHS) {
98289829
CastKind Kind;
98299830
CXXCastPath Path;
98309831
CheckPointerConversion(RHS.get(), LHSType, Kind, Path,
98319832
/*IgnoreBaseAccess=*/false, Diagnose);
9833+
9834+
// If there is a conversion of some kind, check to see what kind of
9835+
// pointer conversion happened so we can diagnose a C++ compatibility
9836+
// diagnostic if the conversion is invalid. This only matters if the RHS
9837+
// is some kind of void pointer.
9838+
if (Kind != CK_NoOp && !getLangOpts().CPlusPlus) {
9839+
QualType CanRHS =
9840+
RHS.get()->getType().getCanonicalType().getUnqualifiedType();
9841+
QualType CanLHS = LHSType.getCanonicalType().getUnqualifiedType();
9842+
if (CanRHS->isVoidPointerType() && CanLHS->isPointerType()) {
9843+
Ret = checkPointerTypesForAssignment(*this, CanLHS, CanRHS,
9844+
RHS.get()->getExprLoc());
9845+
// Anything that's not considered perfectly compatible would be
9846+
// incompatible in C++.
9847+
if (Ret != AssignConvertType::Compatible)
9848+
Ret = AssignConvertType::CompatibleVoidPtrToNonVoidPtr;
9849+
}
9850+
}
9851+
98329852
if (ConvertRHS)
98339853
RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_PRValue, &Path);
98349854
}
9835-
return AssignConvertType::Compatible;
9855+
return Ret;
98369856
}
98379857
// C23 6.5.16.1p1: the left operand has type atomic, qualified, or
98389858
// unqualified bool, and the right operand is a pointer or its type is
@@ -13958,7 +13978,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
1395813978
LHSType->isObjCObjectPointerType())))
1395913979
ConvTy = AssignConvertType::Compatible;
1396013980

13961-
if (ConvTy == AssignConvertType::Compatible && LHSType->isObjCObjectType())
13981+
if (IsAssignConvertCompatible(ConvTy) && LHSType->isObjCObjectType())
1396213982
Diag(Loc, diag::err_objc_object_assignment) << LHSType;
1396313983

1396413984
// If the RHS is a unary plus or minus, check to see if they = and + are
@@ -13981,7 +14001,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
1398114001
}
1398214002
}
1398314003

13984-
if (ConvTy == AssignConvertType::Compatible) {
14004+
if (IsAssignConvertCompatible(ConvTy)) {
1398514005
if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) {
1398614006
// Warn about retain cycles where a block captures the LHS, but
1398714007
// not if the LHS is a simple variable into which the block is

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify=c -Wimplicit-void-ptr-cast %s
2-
// RUN: %clang_cc1 -fsyntax-only -verify=c -Wc++-compat %s
1+
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=c -Wimplicit-void-ptr-cast %s
2+
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=c -Wc++-compat %s
33
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
4-
// RUN: %clang_cc1 -fsyntax-only -verify=good %s
5-
// RUN: %clang_cc1 -fsyntax-only -verify=good -Wc++-compat -Wno-implicit-void-ptr-cast %s
4+
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=good %s
5+
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=good -Wc++-compat -Wno-implicit-void-ptr-cast %s
66
// good-no-diagnostics
77

88
typedef __typeof__(sizeof(int)) size_t;
@@ -36,3 +36,27 @@ int *other_func(void *ptr) {
3636
return ptr; // c-warning {{implicit conversion when returning 'void *' from a function with result type 'int *' is not permitted in C++}} \
3737
cxx-error {{cannot initialize return object of type 'int *' with an lvalue of type 'void *'}}
3838
}
39+
40+
void more(void) {
41+
__attribute__((address_space(0))) char *b1 = (void *)0; // c-warning {{implicit conversion when initializing '__attribute__((address_space(0))) char *' with an expression of type 'void *' is not permitted in C++}} \
42+
cxx-error {{cannot initialize a variable of type '__attribute__((address_space(0))) char *' with an rvalue of type 'void *'}}
43+
__attribute__((address_space(0))) void *b2 = (void *)0; // c-warning {{implicit conversion when initializing '__attribute__((address_space(0))) void *' with an expression of type 'void *' is not permitted in C++}} \
44+
cxx-error {{cannot initialize a variable of type '__attribute__((address_space(0))) void *' with an rvalue of type 'void *'}}
45+
char *b3 = (void *)0; // c-warning {{implicit conversion when initializing 'char *' with an expression of type 'void *' is not permitted in C++}} \
46+
cxx-error {{cannot initialize a variable of type 'char *' with an rvalue of type 'void *'}}
47+
48+
b1 = (void*)0; // c-warning {{implicit conversion when assigning to '__attribute__((address_space(0))) char *' from type 'void *' is not permitted in C++}} \
49+
cxx-error {{assigning 'void *' to '__attribute__((address_space(0))) char *' changes address space of pointer}}
50+
51+
b2 = (void*)0; // c-warning {{implicit conversion when assigning to '__attribute__((address_space(0))) void *' from type 'void *' is not permitted in C++}} \
52+
cxx-error {{assigning 'void *' to '__attribute__((address_space(0))) void *' changes address space of pointer}}
53+
b2 = (__attribute__((address_space(0))) void *)0;
54+
b2 = nullptr;
55+
b2 = 0;
56+
57+
b3 = (void*)0; // c-warning {{implicit conversion when assigning to 'char *' from type 'void *' is not permitted in C++}} \
58+
cxx-error {{assigning to 'char *' from incompatible type 'void *'}}
59+
b3 = (char *)0;
60+
b3 = nullptr;
61+
b3 = 0;
62+
}

0 commit comments

Comments
 (0)