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 <[email protected]>
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();

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to