[clang] [C] Update -Wimplicit-void-ptr-cast for null pointer constants (PR #138271)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Fri May 2 06:21:56 PDT 2025
https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/138271
>From 6360cf51134d978b1ee8b6615128922eb3726d97 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 2 May 2025 07:35:57 -0400
Subject: [PATCH 1/3] Handle null pointer constants properly
---
clang/lib/Sema/SemaExpr.cpp | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0cd86dc54b0ab..93e2e862deb8a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9818,15 +9818,36 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
((getLangOpts().C23 && RHS.get()->getType()->isNullPtrType()) ||
RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull))) {
+ AssignConvertType Ret = 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 != Compatible)
+ Ret = CompatibleVoidPtrToNonVoidPtr;
+ }
+ }
+
+
if (ConvertRHS)
RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_PRValue, &Path);
}
- return 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
@@ -13946,10 +13967,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
LHSType->isObjCObjectPointerType())))
ConvTy = Compatible;
- if (ConvTy == Compatible &&
- LHSType->isObjCObjectType())
- Diag(Loc, diag::err_objc_object_assignment)
- << LHSType;
+ 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
// right next to each other. If so, the user may have typo'd "x =+ 4"
@@ -13971,7 +13990,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
}
}
- if (ConvTy == 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
>From 19362f3caae13ef5cad3a50bc167caa4d86e0de6 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 2 May 2025 09:14:04 -0400
Subject: [PATCH 2/3] Add test coverage
---
clang/test/Sema/implicit-void-ptr-cast.c | 32 +++++++++++++++++++++---
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/clang/test/Sema/implicit-void-ptr-cast.c b/clang/test/Sema/implicit-void-ptr-cast.c
index df18eeebd9347..a469c49c36b49 100644
--- a/clang/test/Sema/implicit-void-ptr-cast.c
+++ b/clang/test/Sema/implicit-void-ptr-cast.c
@@ -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;
@@ -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;
+}
>From 24f657a9d6147d207277658f9b6252879da12283 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 2 May 2025 09:21:33 -0400
Subject: [PATCH 3/3] Corrected the rebase, oops!
---
clang/lib/Sema/SemaExpr.cpp | 8 --------
1 file changed, 8 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bea75f9444d9f..c5be7b685c3d8 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13979,11 +13979,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
LHSType->isObjCObjectPointerType())))
ConvTy = AssignConvertType::Compatible;
-<<<<<<< HEAD
if (IsAssignConvertCompatible(ConvTy) && LHSType->isObjCObjectType())
-=======
- if (ConvTy == AssignConvertType::Compatible && LHSType->isObjCObjectType())
->>>>>>> origin/main
Diag(Loc, diag::err_objc_object_assignment) << LHSType;
// If the RHS is a unary plus or minus, check to see if they = and + are
@@ -14006,11 +14002,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
}
}
-<<<<<<< HEAD
if (IsAssignConvertCompatible(ConvTy)) {
-=======
- if (ConvTy == AssignConvertType::Compatible) {
->>>>>>> origin/main
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
More information about the cfe-commits
mailing list