https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/200481
Ignore the destructor of CXXBindTemporaryExpr when returning a value with copy elision. >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] [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 }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
