[clang] 436504c - [webkit.UncountedLambdaCapturesChecker] Treat every argument of std::ranges functions as noescape. (#138995)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 9 17:44:39 PDT 2025
Author: Ryosuke Niwa
Date: 2025-05-09T17:44:36-07:00
New Revision: 436504c3b9db3bd11d34ec7457b52bef43fc35cc
URL: https://github.com/llvm/llvm-project/commit/436504c3b9db3bd11d34ec7457b52bef43fc35cc
DIFF: https://github.com/llvm/llvm-project/commit/436504c3b9db3bd11d34ec7457b52bef43fc35cc.diff
LOG: [webkit.UncountedLambdaCapturesChecker] Treat every argument of std::ranges functions as noescape. (#138995)
Functions in std::ranges namespace does not store the lambada passed-in
as an arugment in heap so treat such an argument as if it has
[[noescape]] in the WebKit lambda capture checker so that we don't emit
warnings for capturing raw pointers or references to smart-pointer
capable objects.
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
index 01faa9217982d..c322f377d7ff7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
@@ -127,13 +127,22 @@ class RawPtrRefLambdaCapturesChecker
return true;
}
- // WTF::switchOn(T, F... f) is a variadic template function and couldn't
- // be annotated with NOESCAPE. We hard code it here to workaround that.
bool shouldTreatAllArgAsNoEscape(FunctionDecl *Decl) {
auto *NsDecl = Decl->getParent();
if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
return false;
- return safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn";
+ // WTF::switchOn(T, F... f) is a variadic template function and couldn't
+ // be annotated with NOESCAPE. We hard code it here to workaround that.
+ if (safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn")
+ return true;
+ // Treat every argument of functions in std::ranges as noescape.
+ if (safeGetName(NsDecl) == "ranges") {
+ if (auto *OuterDecl = NsDecl->getParent();
+ OuterDecl && isa<NamespaceDecl>(OuterDecl) &&
+ safeGetName(OuterDecl) == "std")
+ return true;
+ }
+ return false;
}
bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index 6b7593a821c64..3079f8e833fcd 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -9,6 +9,16 @@ T&& move(T& t) {
return static_cast<T&&>(t);
}
+namespace ranges {
+
+template<typename IteratorType, typename CallbackType>
+void for_each(IteratorType first, IteratorType last, CallbackType callback) {
+ for (auto it = first; !(it == last); ++it)
+ callback(*it);
+}
+
+}
+
}
namespace WTF {
@@ -416,3 +426,26 @@ void capture_copy_in_lambda(CheckedObj& checked) {
ptr->method();
});
}
+
+class Iterator {
+public:
+ Iterator(void* array, unsigned long sizeOfElement, unsigned int index);
+ Iterator(const Iterator&);
+ Iterator& operator=(const Iterator&);
+ bool operator==(const Iterator&);
+
+ Iterator& operator++();
+ void* operator*();
+
+private:
+ void* current { nullptr };
+ unsigned long sizeOfElement { 0 };
+};
+
+void ranges_for_each(RefCountable* obj) {
+ int array[] = { 1, 2, 3, 4, 5 };
+ std::ranges::for_each(Iterator(array, sizeof(*array), 0), Iterator(array, sizeof(*array), 5), [&](void* item) {
+ obj->method();
+ ++(*static_cast<unsigned*>(item));
+ });
+}
\ No newline at end of file
More information about the cfe-commits
mailing list