[clang-tools-extra] [clang-tidy] Avoid readability-use-anyofallof diagnostics on temporary ranges before C++20 (PR #185791)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 10 19:46:38 PDT 2026
https://github.com/zeyi2 created https://github.com/llvm/llvm-project/pull/185791
Avoid emitting warnings in pre-C++20 mode for range-based loops over temporary range expressions. They can't be safely rewritten to `std::any_of`/`std::all_of` by reusing the range expression directly.
Closes https://github.com/llvm/llvm-project/issues/185593
>From 917bcd4fbc5f0b3cb22930b6c57f54390568b80f Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Tue, 10 Mar 2026 23:27:57 +0800
Subject: [PATCH] [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;
+}
More information about the cfe-commits
mailing list