[clang] [webkit.UncountedLambdaCapturesChecker] Treat call_once arguments as noescape (PR #224492)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 17 18:52:28 PDT 2026
https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/224492
call_once does not store the lambda in heap so consider all its arguments as noescape.
>From d70130838b6c6f6c222abfefc55ac401ce8adf97 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Thu, 17 Sep 2026 18:50:59 -0700
Subject: [PATCH] [webkit.UncountedLambdaCapturesChecker] Treat call_once
arguments as noescape
call_once does not store the lambda in heap so consider all its arguments as noescape.
---
.../WebKit/RawPtrRefLambdaCapturesChecker.cpp | 13 ++++++++++---
clang/test/Analysis/Checkers/WebKit/mock-types.h | 13 +++++++++++++
.../Checkers/WebKit/uncounted-lambda-captures.cpp | 9 +++++++++
3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
index 43db3065dd068..a07812d3a48d5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
@@ -244,9 +244,16 @@ class RawPtrRefLambdaCapturesChecker
// workaround that.
if (Name == "WTF" && PreviousName == "switchOn")
return true;
- // Treat every argument of functions in std::ranges as noescape.
- if (Name == "std" && PreviousName == "ranges")
- return true;
+ if (Name == "std") {
+ // Treat every argument of functions in std::ranges as noescape.
+ if (PreviousName == "ranges")
+ return true;
+ // Treat every argument of call_once as noescape even though only
+ // the second argument is lambda since we can't add annotation to
+ // a std function.
+ if (PreviousName == "call_once")
+ return true;
+ }
PreviousName = Name;
}
return false;
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 9ed5ecab88c6e..46818a9642ee3 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -63,6 +63,19 @@ class unique_ptr {
explicit operator bool() const { return !!t; }
};
+struct once_flag {
+ bool did { false };
+};
+
+template<typename CallbackType, typename... Args>
+void call_once(once_flag& flag, CallbackType callback, Args&&... args)
+{
+ if (flag.did)
+ return;
+ flag.did = true;
+ callback(args...);
+}
+
namespace ranges {
template<typename IteratorType, typename CallbackType>
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index d1cc7588ed8d6..27c44af36c2d3 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -386,6 +386,7 @@ class RefCountedObj {
bool isMatch(int);
void call() const;
+ void callOnce() const;
void callLambda([[clang::noescape]] const WTF::Function<void ()>& callback) const;
void doSomeWork() const;
};
@@ -409,6 +410,14 @@ void RefCountedObj::call() const
callLambda(lambda);
}
+void RefCountedObj::callOnce() const
+{
+ static std::once_flag flag;
+ std::call_once(flag, [&]() {
+ call();
+ });
+}
+
void scope_exit(RefCountable* obj) {
auto scope = WTF::makeScopeExit([&] {
obj->method();
More information about the cfe-commits
mailing list