Author: Vinayak Dev Date: 2024-02-29T09:09:39-05:00 New Revision: 6f7d824b804b272335d55f5b899295db833f3829
URL: https://github.com/llvm/llvm-project/commit/6f7d824b804b272335d55f5b899295db833f3829 DIFF: https://github.com/llvm/llvm-project/commit/6f7d824b804b272335d55f5b899295db833f3829.diff LOG: [Clang][Sema]: Diagnose lambda to bool implicit casts (#83152) Adds diagnostics for lambda expressions being cast to boolean values, which results in the expression always evaluating to true. Earlier, Clang allowed compilation of such erroneous programs, but now emits a warning through `-Wpointer-bool-conversion`. Fixes #82512 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaChecking.cpp clang/test/CXX/drs/dr18xx.cpp clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm clang/test/SemaCXX/warn-bool-conversion.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7e16b9f0c67dbd..a5c6b80c4e99e1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -192,6 +192,9 @@ Improvements to Clang's diagnostics - Clang now diagnoses declarative nested name specifiers that name alias templates. +- Clang now diagnoses lambda function expressions being implicitly cast to boolean values, under ``-Wpointer-bool-conversion``. + Fixes `#82512 <https://github.com/llvm/llvm-project/issues/82512>`_. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 378b537e029710..ff88c4f293abfd 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4127,8 +4127,8 @@ def ext_ms_impcast_fn_obj : ExtWarn< "Microsoft extension">, InGroup<MicrosoftCast>; def warn_impcast_pointer_to_bool : Warning< - "address of%select{| function| array}0 '%1' will always evaluate to " - "'true'">, + "address of %select{'%1'|function '%1'|array '%1'|lambda function pointer " + "conversion operator}0 will always evaluate to 'true'">, InGroup<PointerBoolConversion>; def warn_cast_nonnull_to_bool : Warning< "nonnull %select{function call|parameter}0 '%1' will evaluate to " diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 979b63884359fc..35d453e013e84b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -16544,6 +16544,17 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, } } + // Complain if we are converting a lambda expression to a boolean value + if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) { + if (const auto *MRecordDecl = MCallExpr->getRecordDecl(); + MRecordDecl && MRecordDecl->isLambda()) { + Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool) + << /*LambdaPointerConversionOperatorType=*/3 + << MRecordDecl->getSourceRange() << Range << IsEqual; + return; + } + } + // Expect to find a single Decl. Skip anything more complicated. ValueDecl *D = nullptr; if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) { diff --git a/clang/test/CXX/drs/dr18xx.cpp b/clang/test/CXX/drs/dr18xx.cpp index a7cee4ef8902f9..e78730e8992cf8 100644 --- a/clang/test/CXX/drs/dr18xx.cpp +++ b/clang/test/CXX/drs/dr18xx.cpp @@ -282,6 +282,7 @@ namespace dr1837 { // dr1837: 3.3 struct A { int f(); bool b = [] { + // since-cxx11-warning@-1 {{address of lambda function pointer conversion operator will always evaluate to 'true'}} struct Local { static_assert(sizeof(this->f()) == sizeof(int), ""); }; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm index cb56f6816ad036..e93c37f3b9ae12 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm @@ -65,10 +65,10 @@ void nesting() { namespace overloading { void bool_conversion() { - if ([](){}) { + if ([](){}) { // expected-warning{{address of lambda function pointer conversion operator will always evaluate to 'true'}} } - bool b = []{}; + bool b = []{}; // expected-warning{{address of lambda function pointer conversion operator will always evaluate to 'true'}} b = (bool)[]{}; } @@ -108,8 +108,9 @@ void call_with_lambda() { using decltype(a)::operator id<void(*)()>; // expected-note {{here}} } extern d; - bool r1 = c; - bool r2 = d; // expected-error {{private}} + bool r1 = c; // expected-warning{{address of lambda function pointer conversion operator will always evaluate to 'true'}} + bool r2 = d; // expected-error {{private}} \ + expected-warning{{address of lambda function pointer conversion operator will always evaluate to 'true'}} } namespace PR13117 { diff --git a/clang/test/SemaCXX/warn-bool-conversion.cpp b/clang/test/SemaCXX/warn-bool-conversion.cpp index c81d52d864f2d2..9e8cf0e4f8944a 100644 --- a/clang/test/SemaCXX/warn-bool-conversion.cpp +++ b/clang/test/SemaCXX/warn-bool-conversion.cpp @@ -81,6 +81,18 @@ struct S2 { bool f5(); bool f6(int); +#if __cplusplus >= 201103L +auto f7 = []{}; +auto f8 = [](){}; + +void foo() { + bool b; + b = f7; // expected-warning {{address of lambda function pointer conversion operator will always evaluate to 'true'}} + b = f8; // expected-warning {{address of lambda function pointer conversion operator will always evaluate to 'true'}} + bool is_true = [](){ return true; }; + // expected-warning@-1{{address of lambda function pointer conversion operator will always evaluate to 'true'}} +} +#endif void bar() { bool b; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits