Skip to content

[C] Update -Wimplicit-void-ptr-cast for null pointer constants #138271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9824,15 +9824,35 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType,
((getLangOpts().C23 && RHS.get()->getType()->isNullPtrType()) ||
RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull))) {
AssignConvertType Ret = AssignConvertType::Compatible;
if (Diagnose || ConvertRHS) {
CastKind Kind;
CXXCastPath Path;
CheckPointerConversion(RHS.get(), LHSType, Kind, Path,
/*IgnoreBaseAccess=*/false, Diagnose);

// If there is a conversion of some kind, check to see what kind of
// pointer conversion happened so we can diagnose a C++ compatibility
// diagnostic if the conversion is invalid. This only matters if the RHS
// is some kind of void pointer.
if (Kind != CK_NoOp && !getLangOpts().CPlusPlus) {
QualType CanRHS =
RHS.get()->getType().getCanonicalType().getUnqualifiedType();
QualType CanLHS = LHSType.getCanonicalType().getUnqualifiedType();
if (CanRHS->isVoidPointerType() && CanLHS->isPointerType()) {
Ret = checkPointerTypesForAssignment(*this, CanLHS, CanRHS,
RHS.get()->getExprLoc());
// Anything that's not considered perfectly compatible would be
// incompatible in C++.
if (Ret != AssignConvertType::Compatible)
Ret = AssignConvertType::CompatibleVoidPtrToNonVoidPtr;
}
}

if (ConvertRHS)
RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_PRValue, &Path);
}
return AssignConvertType::Compatible;
return Ret;
}
// C23 6.5.16.1p1: the left operand has type atomic, qualified, or
// unqualified bool, and the right operand is a pointer or its type is
Expand Down Expand Up @@ -13958,7 +13978,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
LHSType->isObjCObjectPointerType())))
ConvTy = AssignConvertType::Compatible;

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

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

if (ConvTy == AssignConvertType::Compatible) {
if (IsAssignConvertCompatible(ConvTy)) {
if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) {
// Warn about retain cycles where a block captures the LHS, but
// not if the LHS is a simple variable into which the block is
Expand Down
32 changes: 28 additions & 4 deletions clang/test/Sema/implicit-void-ptr-cast.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify=c -Wimplicit-void-ptr-cast %s
// RUN: %clang_cc1 -fsyntax-only -verify=c -Wc++-compat %s
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=c -Wimplicit-void-ptr-cast %s
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=c -Wc++-compat %s
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
// RUN: %clang_cc1 -fsyntax-only -verify=good %s
// RUN: %clang_cc1 -fsyntax-only -verify=good -Wc++-compat -Wno-implicit-void-ptr-cast %s
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=good %s
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=good -Wc++-compat -Wno-implicit-void-ptr-cast %s
// good-no-diagnostics

typedef __typeof__(sizeof(int)) size_t;
Expand Down Expand Up @@ -36,3 +36,27 @@ int *other_func(void *ptr) {
return ptr; // c-warning {{implicit conversion when returning 'void *' from a function with result type 'int *' is not permitted in C++}} \
cxx-error {{cannot initialize return object of type 'int *' with an lvalue of type 'void *'}}
}

void more(void) {
__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++}} \
cxx-error {{cannot initialize a variable of type '__attribute__((address_space(0))) char *' with an rvalue of type 'void *'}}
__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++}} \
cxx-error {{cannot initialize a variable of type '__attribute__((address_space(0))) void *' with an rvalue of type 'void *'}}
char *b3 = (void *)0; // c-warning {{implicit conversion when initializing 'char *' with an expression of type 'void *' is not permitted in C++}} \
cxx-error {{cannot initialize a variable of type 'char *' with an rvalue of type 'void *'}}

b1 = (void*)0; // c-warning {{implicit conversion when assigning to '__attribute__((address_space(0))) char *' from type 'void *' is not permitted in C++}} \
cxx-error {{assigning 'void *' to '__attribute__((address_space(0))) char *' changes address space of pointer}}

b2 = (void*)0; // c-warning {{implicit conversion when assigning to '__attribute__((address_space(0))) void *' from type 'void *' is not permitted in C++}} \
cxx-error {{assigning 'void *' to '__attribute__((address_space(0))) void *' changes address space of pointer}}
b2 = (__attribute__((address_space(0))) void *)0;
b2 = nullptr;
b2 = 0;

b3 = (void*)0; // c-warning {{implicit conversion when assigning to 'char *' from type 'void *' is not permitted in C++}} \
cxx-error {{assigning to 'char *' from incompatible type 'void *'}}
b3 = (char *)0;
b3 = nullptr;
b3 = 0;
}