https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/185791
>From 917bcd4fbc5f0b3cb22930b6c57f54390568b80f Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Tue, 10 Mar 2026 23:27:57 +0800 Subject: [PATCH 1/2] [clang-tidy] Avoid use-anyofallof diagnostics on temporary ranges before C++20 --- .../readability/UseAnyOfAllOfCheck.cpp | 15 ++++++++ clang-tools-extra/docs/ReleaseNotes.rst | 4 +++ .../readability/use-anyofallof-cpp20.cpp | 20 +++++++++++ .../checkers/readability/use-anyofallof.cpp | 35 +++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp b/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp index 63649150b17e3..28be6b2891025 100644 --- a/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp @@ -84,11 +84,22 @@ static bool isViableLoop(const CXXForRangeStmt &S, ASTContext &Context) { }); } +static bool isIteratingOverTemporary(const Expr *Init) { + if (const auto *EWC = dyn_cast<ExprWithCleanups>(Init)) + Init = EWC->getSubExpr(); + Init = Init->IgnoreParenImpCasts(); + return isa<MaterializeTemporaryExpr>(Init) || Init->isPRValue(); +} + void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *S = Result.Nodes.getNodeAs<CXXForRangeStmt>("any_of_loop")) { if (!isViableLoop(*S, *Result.Context)) return; + if (!getLangOpts().CPlusPlus20 && + isIteratingOverTemporary(S->getRangeInit())) + return; + diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::any_of()'") << getLangOpts().CPlusPlus20; } else if (const auto *S = @@ -96,6 +107,10 @@ void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) { if (!isViableLoop(*S, *Result.Context)) return; + if (!getLangOpts().CPlusPlus20 && + isIteratingOverTemporary(S->getRangeInit())) + return; + diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::all_of()'") << getLangOpts().CPlusPlus20; } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 66290bc80f754..90f95e3b24a71 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -336,6 +336,10 @@ Changes in existing checks <clang-tidy/checks/readability/suspicious-call-argument>` check by avoiding a crash from invalid ``Abbreviations`` option. +- Improved :doc:`readability-use-anyofallof + <clang-tidy/checks/readability/use-anyofallof>` check by avoiding false + positives in pre-C++20 mode when iterating over temporary range expressions. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-cpp20.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-cpp20.cpp index c13ae002ae5b6..83f51995ece5f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-cpp20.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof-cpp20.cpp @@ -1,5 +1,7 @@ // RUN: %check_clang_tidy -std=c++20-or-later %s readability-use-anyofallof %t +#include <vector> + bool good_any_of() { int v[] = {1, 2, 3}; // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::ranges::any_of()' @@ -17,3 +19,21 @@ bool good_all_of() { return false; return true; } + +std::vector<int> get_dummy_vec(); + +bool good_any_of_temporary_vector() { + // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::ranges::any_of()' + for (int i : get_dummy_vec()) + if (i) + return true; + return false; +} + +bool good_all_of_temporary_vector() { + // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::ranges::all_of()' + for (int i : get_dummy_vec()) + if (i) + return false; + return true; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp index 7f8f16488d37a..e6f8830686ef3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp @@ -1,6 +1,9 @@ // RUN: %check_clang_tidy -std=c++14,c++17 %s readability-use-anyofallof %t -- -- -fexceptions // FIXME: Fix the checker to work in C++20 mode. +#include <utility> +#include <vector> + bool good_any_of() { int v[] = {1, 2, 3}; // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::any_of()' [readability-use-anyofallof] @@ -182,3 +185,35 @@ bool good_all_of() { return false; return true; } + +std::vector<int> get_dummy_vec(); + +bool good_any_of_temporary_vector() { + for (int i : get_dummy_vec()) + if (i) + return true; + return false; +} + +bool good_all_of_temporary_vector() { + for (int i : get_dummy_vec()) + if (i) + return false; + return true; +} + +bool good_xvalue(std::vector<int>& v) { + // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::any_of()' [readability-use-anyofallof] + for (int i : std::move(v)) + if (i) + return true; + return false; +} + +bool good_xvalue_all_of(std::vector<int>& v) { + // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::all_of()' [readability-use-anyofallof] + for (int i : std::move(v)) + if (i) + return false; + return true; +} >From fa0b249769caa1cf3e92d24974318aaddef2bada Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Wed, 11 Mar 2026 14:22:52 +0800 Subject: [PATCH 2/2] better? --- .../readability/UseAnyOfAllOfCheck.cpp | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp b/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp index 28be6b2891025..c4b94399d2345 100644 --- a/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp @@ -35,6 +35,15 @@ AST_MATCHER_P(Stmt, nextStmt, ast_matchers::internal::Matcher<Stmt>, return InnerMatcher.matches(**I, Finder, Builder); } + +/// Matches range-based loops over temporary range expressions. +AST_MATCHER(Expr, isTemporary) { + const Expr *E = &Node; + if (const auto *EWC = dyn_cast<ExprWithCleanups>(E)) + E = EWC->getSubExpr(); + E = E->IgnoreParenImpCasts(); + return isa<MaterializeTemporaryExpr>(E) || E->isPRValue(); +} } // namespace namespace tidy::readability { @@ -44,13 +53,17 @@ void UseAnyOfAllOfCheck::registerMatchers(MatchFinder *Finder) { return returnStmt(hasReturnValue(cxxBoolLiteral(equals(V)))); }; - auto ReturnsButNotTrue = + const auto ReturnsButNotTrue = returnStmt(hasReturnValue(unless(cxxBoolLiteral(equals(true))))); - auto ReturnsButNotFalse = + const auto ReturnsButNotFalse = returnStmt(hasReturnValue(unless(cxxBoolLiteral(equals(false))))); + const auto RangeInitMatcher = + getLangOpts().CPlusPlus20 ? expr() : expr(unless(isTemporary())); + Finder->addMatcher( cxxForRangeStmt( + hasRangeInit(RangeInitMatcher), nextStmt(Returns(false).bind("final_return")), hasBody(allOf(hasDescendant(Returns(true)), unless(anyOf(hasDescendant(breakStmt()), @@ -61,6 +74,7 @@ void UseAnyOfAllOfCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( cxxForRangeStmt( + hasRangeInit(RangeInitMatcher), nextStmt(Returns(true).bind("final_return")), hasBody(allOf(hasDescendant(Returns(false)), unless(anyOf(hasDescendant(breakStmt()), @@ -84,22 +98,11 @@ static bool isViableLoop(const CXXForRangeStmt &S, ASTContext &Context) { }); } -static bool isIteratingOverTemporary(const Expr *Init) { - if (const auto *EWC = dyn_cast<ExprWithCleanups>(Init)) - Init = EWC->getSubExpr(); - Init = Init->IgnoreParenImpCasts(); - return isa<MaterializeTemporaryExpr>(Init) || Init->isPRValue(); -} - void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *S = Result.Nodes.getNodeAs<CXXForRangeStmt>("any_of_loop")) { if (!isViableLoop(*S, *Result.Context)) return; - if (!getLangOpts().CPlusPlus20 && - isIteratingOverTemporary(S->getRangeInit())) - return; - diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::any_of()'") << getLangOpts().CPlusPlus20; } else if (const auto *S = @@ -107,10 +110,6 @@ void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) { if (!isViableLoop(*S, *Result.Context)) return; - if (!getLangOpts().CPlusPlus20 && - isIteratingOverTemporary(S->getRangeInit())) - return; - diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::all_of()'") << getLangOpts().CPlusPlus20; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
