https://github.com/Ralender updated https://github.com/llvm/llvm-project/pull/143990
>From f2744c89892d2803a36d03579b1fd278cfd1bb44 Mon Sep 17 00:00:00 2001 From: tyker <tyk...@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 <tyk...@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'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits