https://github.com/rniwa updated 
https://github.com/llvm/llvm-project/pull/200481

>From f3c6e2fd76a05aa15c6670811bc1a17d170ace87 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <[email protected]>
Date: Fri, 29 May 2026 11:48:52 -0700
Subject: [PATCH 1/2] [alpha.webkit.NoDeleteChecker] Returning with copy
 elision should be considered no-delete.

Ignore the destructor of CXXBindTemporaryExpr when returning a value with copy 
elision.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp          | 14 +++++++++++++-
 clang/test/Analysis/Checkers/WebKit/mock-types.h   |  1 +
 .../Checkers/WebKit/nodelete-annotation.cpp        | 12 +++++++++++-
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index f1515701cc6f3..6ce2954471e6b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -706,8 +706,20 @@ class TrivialFunctionAnalysisVisitor
 
   bool VisitReturnStmt(const ReturnStmt *RS) {
     // A return statement is allowed as long as the return value is trivial.
-    if (auto *RV = RS->getRetValue())
+    if (auto *RV = RS->getRetValue()) {
+      if (auto *ExprWithClean = dyn_cast<ExprWithCleanups>(RV)) {
+        if (ExprWithClean->isPRValue())
+          RV = ExprWithClean->getSubExpr();
+      }
+      if (auto *SubE = RV->IgnoreParenCasts()) {
+        if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(SubE)) {
+          // Ignore the destructor of BTE if copy elision is in effect.
+          if (RV->getType() == BTE->getType())
+            return Visit(BTE->getSubExpr());
+        }
+      }
       return Visit(RV);
+    }
     return true;
   }
 
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index af63268ac9695..de5c2d35f2408 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -202,6 +202,7 @@ template <typename T> struct RefPtr {
     t = o.t;
     o.t = tmp;
   }
+  operator T*() { return t; }
   T *get() const { return t; }
   T *operator->() const { return t; }
   T &operator*() const { return *t; }
diff --git a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp 
b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
index 6906afb7fa0f6..871b0afcb89fd 100644
--- a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
@@ -316,10 +316,19 @@ class Derived : public Base<Type> {
 };
 
 struct Data {
-  static Ref<Data> create() {
+  static Ref<Data> [[clang::annotate_type("webkit.nodelete")]] create() {
     return adoptRef(*new Data);
   }
 
+  static Ref<Data> [[clang::annotate_type("webkit.nodelete")]] create(double) {
+    return adoptRef(*new Data(RefCountable::create()->next()));
+    // expected-warning@-1{{A function 'create' has 
[[clang::annotate_type("webkit.nodelete")]] but it contains code that could 
destruct an object}}
+  }
+
+  static Data* [[clang::annotate_type("webkit.nodelete")]] create(int) {
+    return adoptRef(new Data); // expected-warning{{A function 'create' has 
[[clang::annotate_type("webkit.nodelete")]] but it contains code that could 
destruct an object}}
+  }
+
   void ref() {
     ++refCount;
   }
@@ -338,6 +347,7 @@ struct Data {
   
 protected:
   Data() = default;
+  Data(RefCountable*) { }
 
 private:
   unsigned refCount { 0 };

>From 934e9ec9a651a993544f56f0e8157aee924edcd5 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <[email protected]>
Date: Sat, 30 May 2026 00:46:23 -0700
Subject: [PATCH 2/2] Extend copy elision check to function arguments.

When the return value of T g() is given to f(T&&), skip the checking of the 
destructor of T in
ExprWithCleanups / CXXBindTemporaryExpr. i.e. assume no deletion of T happens 
at the end of
expression although f's function body could delete T and we do continue to 
check that.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp     | 34 +++++++++---------
 .../Analysis/Checkers/WebKit/call-args.cpp    | 17 +++++++++
 .../WebKit/nodelete-lazy-initialize.cpp       | 36 +++++++++++++++++++
 3 files changed, 70 insertions(+), 17 deletions(-)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/nodelete-lazy-initialize.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 6ce2954471e6b..aaa7ac3e4dd97 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -705,21 +705,8 @@ class TrivialFunctionAnalysisVisitor
   }
 
   bool VisitReturnStmt(const ReturnStmt *RS) {
-    // A return statement is allowed as long as the return value is trivial.
-    if (auto *RV = RS->getRetValue()) {
-      if (auto *ExprWithClean = dyn_cast<ExprWithCleanups>(RV)) {
-        if (ExprWithClean->isPRValue())
-          RV = ExprWithClean->getSubExpr();
-      }
-      if (auto *SubE = RV->IgnoreParenCasts()) {
-        if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(SubE)) {
-          // Ignore the destructor of BTE if copy elision is in effect.
-          if (RV->getType() == BTE->getType())
-            return Visit(BTE->getSubExpr());
-        }
-      }
-      return Visit(RV);
-    }
+    if (auto *RV = RS->getRetValue())
+      return VisitIgnoringTempGivenToRValue(RV);
     return true;
   }
 
@@ -899,15 +886,28 @@ class TrivialFunctionAnalysisVisitor
 
   bool checkArguments(const CallExpr *CE) {
     for (const Expr *Arg : CE->arguments()) {
-      if (Arg && !Visit(Arg))
+      if (Arg && !VisitIgnoringTempGivenToRValue(Arg))
         return false;
     }
     return true;
   }
 
+  bool VisitIgnoringTempGivenToRValue(const Expr* Arg) {
+    Arg = Arg->IgnoreParenCasts();
+    if (!Arg->isPRValue())
+      return Visit(Arg);
+    if (auto *ExprWithClean = dyn_cast<ExprWithCleanups>(Arg))
+      Arg = ExprWithClean->getSubExpr()->IgnoreParenCasts();
+    if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg)) {
+      if (Arg->getType() == BTE->getType())
+        return Visit(BTE->getSubExpr());
+    }
+    return Visit(Arg);
+  }
+
   bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
     for (const Expr *Arg : CE->arguments()) {
-      if (Arg && !Visit(Arg))
+      if (Arg && !VisitIgnoringTempGivenToRValue(Arg))
         return false;
     }
 
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args.cpp
index f15991134c58a..bcd3a9592d55d 100644
--- a/clang/test/Analysis/Checkers/WebKit/call-args.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/call-args.cpp
@@ -557,4 +557,21 @@ namespace call_with_weak_ptr {
     weakPtr->method();
     // expected-warning@-1{{Call argument for 'this' parameter is uncounted 
and unsafe}}
   }
+
+  struct Provider {
+    RefCountableWithWeakPtr* provide();
+  };
+  int intValue();
+
+  struct Container {
+    Container(Provider& provider)
+      : m_weakPtr(provider.provide())
+      , m_value(intValue())
+    { }
+
+  private:
+    WeakPtr<RefCountableWithWeakPtr> m_weakPtr;
+    int m_value;
+  };
+
 }
diff --git a/clang/test/Analysis/Checkers/WebKit/nodelete-lazy-initialize.cpp 
b/clang/test/Analysis/Checkers/WebKit/nodelete-lazy-initialize.cpp
new file mode 100644
index 0000000000000..aabe949aae07d
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/nodelete-lazy-initialize.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.NoDeleteChecker 
-verify %s
+
+#include "mock-types.h"
+
+void crash();
+
+template<typename T, typename U>
+[[clang::suppress]] inline void [[clang::annotate_type("webkit.nodelete")]] 
lazyInitialize(const RefPtr<T>& ptr, Ref<U>&& obj)
+{
+    if (ptr)
+        crash();
+    const_cast<RefPtr<T>&>(ptr) = WTF::move(obj);
+}
+
+struct RefObj {
+  static Ref<RefObj> [[clang::annotate_type("webkit.nodelete")]] create(int = 
0);
+  void ref() const;
+  void deref() const;
+  int value() const;
+};
+
+struct Container {
+
+  void [[clang::annotate_type("webkit.nodelete")]] foo() {
+    if (!m_bar)
+      lazyInitialize(m_bar, RefObj::create());
+  }
+
+  void [[clang::annotate_type("webkit.nodelete")]] bar() {
+    if (!m_bar)
+      lazyInitialize(m_bar, RefObj::create(RefObj::create()->value()));
+      // expected-warning@-1{{A function 'bar' has 
[[clang::annotate_type("webkit.nodelete")]] but it contains code that could 
destruct an object}}
+  }
+
+  const RefPtr<RefObj> m_bar;
+};

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

Reply via email to