[clang] [clang] Add diagnostic for usage of implicit constructor with pointer to bool convertion (PR #143990)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 26 11:32:10 PDT 2025
https://github.com/Ralender updated https://github.com/llvm/llvm-project/pull/143990
>From f2744c89892d2803a36d03579b1fd278cfd1bb44 Mon Sep 17 00:00:00 2001
From: tyker <tyker1 at outlook.com>
Date: Fri, 13 Jun 2025 00:49:00 +0200
Subject: [PATCH 1/2] [clang] Add diagnostic for usage of implicit constructor
with pointer to bool convertion
Like
```c++
struct B {
B(bool V) {}
};
void test(const B& b);
void test0(B* b) {
test(b); // HERE
}
```
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaChecking.cpp | 19 ++++++++++++
clang/test/SemaCXX/warn-bool-conversion.cpp | 31 +++++++++++++++++++
3 files changed, 53 insertions(+)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0f77083dac9df..8a17b04ad91ed 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4397,6 +4397,9 @@ def ext_ms_impcast_fn_obj : ExtWarn<
"implicit conversion between pointer-to-function and pointer-to-object is a "
"Microsoft extension">, InGroup<MicrosoftCast>;
+def warn_imp_constructor_pointer_to_bool : Warning<
+ "implicit conversion from %0 to %1 calls %q2; maybe you intended to dereference">,
+ InGroup<PointerBoolConversion>;
def warn_impcast_pointer_to_bool : Warning<
"address of %select{'%1'|function '%1'|array '%1'|lambda function pointer "
"conversion operator}0 will always evaluate to 'true'">,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8f8e1ceb7197e..d0d52f3a1fe87 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11767,6 +11767,25 @@ static void CheckImplicitArgumentConversions(Sema &S, const CallExpr *TheCall,
SourceLocation CC) {
for (unsigned I = 0, N = TheCall->getNumArgs(); I < N; ++I) {
const Expr *CurrA = TheCall->getArg(I);
+
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(CurrA))
+ // We shouldnt skip over any node here as it may be an attempt to silence
+ // the warning
+ if (auto *CCE = dyn_cast<CXXConstructExpr>(MTE->getSubExpr()))
+ if (CCE->getNumArgs() == 1) {
+ Expr *Inner = CCE->getArg(0)->IgnoreImpCasts();
+ if ((Inner->getType()->isAnyPointerType() &&
+ Inner->getType()->getPointeeType().getUnqualifiedType() ==
+ CCE->getType().getUnqualifiedType())) {
+ S.Diag(CCE->getLocation(),
+ diag::warn_imp_constructor_pointer_to_bool)
+ << Inner->getType() << CCE->getType() << CCE->getConstructor();
+ S.Diag(CCE->getConstructor()->getLocation(),
+ diag::note_entity_declared_at)
+ << CCE->getConstructor();
+ }
+ }
+
if (!IsImplicitBoolFloatConversion(S, CurrA, true))
continue;
diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp
index 18c35776b17bc..52d5315e7cb3b 100644
--- a/clang/test/SemaCXX/warn-bool-conversion.cpp
+++ b/clang/test/SemaCXX/warn-bool-conversion.cpp
@@ -234,3 +234,34 @@ namespace Template {
template void h<d>();
}
#endif // __cplusplus < 201703L
+
+namespace implicit_constructor_bool {
+
+struct B {
+ bool a;
+ B(bool V) : a(V) {} // expected-note {{'B' declared here}}
+};
+
+void test(const B& b);
+
+void test0(B* b) {
+ test(b); // expected-warning {{implicit conversion from 'B *' to 'const B' calls}}
+ test((const B&)b);
+ test(B(b));
+ test((bool)b);
+ test(static_cast<bool>(b));
+ test(*b);
+}
+
+struct C {
+ bool a;
+ explicit C(bool V) : a(V) {}
+};
+
+void testC(const C& b); // expected-note {{candidate function not viable: no known conversion from 'C *' to 'const C'}}
+
+void testC0(C* b) {
+ testC(b); // expected-error {{no matching function for call to 'testC'}}
+}
+
+}
>From 56bfa00fd3ceb4029f48b24a04a164ec689111a6 Mon Sep 17 00:00:00 2001
From: tyker <tyker1 at outlook.com>
Date: Thu, 26 Jun 2025 20:10:28 +0200
Subject: [PATCH 2/2] Address review comments + add fixit
---
clang/docs/ReleaseNotes.rst | 13 +++++++++++++
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/SemaChecking.cpp | 13 ++++++++-----
clang/test/SemaCXX/warn-bool-conversion.cpp | 6 ++++--
4 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b42d5f8425af6..0aa8a48eaab93 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -622,6 +622,19 @@ Improvements to Clang's diagnostics
- Improved the FixIts for unused lambda captures.
+- ``-Wpointer-bool-conversion`` will now also warn in the following case
+
+ .. code-block:: c
+
+ struct B {
+ B(bool V) {}
+ };
+ void test(const B& b);
+ void test0(B* b) {
+ test(b); // this will call B::B(bool) and create a new B
+ }
+
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8a17b04ad91ed..cb8662f2bc09b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4398,7 +4398,7 @@ def ext_ms_impcast_fn_obj : ExtWarn<
"Microsoft extension">, InGroup<MicrosoftCast>;
def warn_imp_constructor_pointer_to_bool : Warning<
- "implicit conversion from %0 to %1 calls %q2; maybe you intended to dereference">,
+ "implicit conversion from %0 to %1 calls %q2; did you intend to dereference ?">,
InGroup<PointerBoolConversion>;
def warn_impcast_pointer_to_bool : Warning<
"address of %select{'%1'|function '%1'|array '%1'|lambda function pointer "
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index d0d52f3a1fe87..10fa2b6588ae5 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11768,18 +11768,21 @@ static void CheckImplicitArgumentConversions(Sema &S, const CallExpr *TheCall,
for (unsigned I = 0, N = TheCall->getNumArgs(); I < N; ++I) {
const Expr *CurrA = TheCall->getArg(I);
- if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(CurrA))
+ if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(CurrA))
// We shouldnt skip over any node here as it may be an attempt to silence
// the warning
- if (auto *CCE = dyn_cast<CXXConstructExpr>(MTE->getSubExpr()))
- if (CCE->getNumArgs() == 1) {
- Expr *Inner = CCE->getArg(0)->IgnoreImpCasts();
+ if (const auto *CCE = dyn_cast<CXXConstructExpr>(MTE->getSubExpr()))
+ if (CCE->getNumArgs() == 1 &&
+ CCE->getArg(0)->getType()->isBooleanType() &&
+ !CCE->getConstructor()->isExplicit()) {
+ const Expr *Inner = CCE->getArg(0)->IgnoreImpCasts();
if ((Inner->getType()->isAnyPointerType() &&
Inner->getType()->getPointeeType().getUnqualifiedType() ==
CCE->getType().getUnqualifiedType())) {
S.Diag(CCE->getLocation(),
diag::warn_imp_constructor_pointer_to_bool)
- << Inner->getType() << CCE->getType() << CCE->getConstructor();
+ << Inner->getType() << CCE->getType() << CCE->getConstructor()
+ << FixItHint::CreateInsertion(Inner->getBeginLoc(), "*");
S.Diag(CCE->getConstructor()->getLocation(),
diag::note_entity_declared_at)
<< CCE->getConstructor();
diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp
index 52d5315e7cb3b..93090553db8fa 100644
--- a/clang/test/SemaCXX/warn-bool-conversion.cpp
+++ b/clang/test/SemaCXX/warn-bool-conversion.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-cxx11 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-cxx11 -std=c++11 %s
+// RUN: not %clang_cc1 -fsyntax-only %s -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
namespace BooleanFalse {
int* j = false;
@@ -245,7 +246,8 @@ struct B {
void test(const B& b);
void test0(B* b) {
- test(b); // expected-warning {{implicit conversion from 'B *' to 'const B' calls}}
+ test(b); // expected-warning {{implicit conversion from 'B *' to 'const B' calls 'implicit_constructor_bool::B::B'; did you intend to dereference ?}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:8-[[@LINE-1]]:8}:"*"
test((const B&)b);
test(B(b));
test((bool)b);
@@ -258,7 +260,7 @@ struct C {
explicit C(bool V) : a(V) {}
};
-void testC(const C& b); // expected-note {{candidate function not viable: no known conversion from 'C *' to 'const C'}}
+void testC(const C& b); // expected-note {{candidate function not viable: no known conversion from 'C *' to 'const C' for 1st argument; dereference the argument with *}}
void testC0(C* b) {
testC(b); // expected-error {{no matching function for call to 'testC'}}
More information about the cfe-commits
mailing list