https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/219074
>From 6c97725676ec27fef7810f82b6496cba6038faed Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <[email protected]> Date: Wed, 26 Aug 2026 17:02:23 -0700 Subject: [PATCH 1/3] [alpha.webkit.NoDeleteChecker] Allow a temporary Ref/RefPtr when the result is kept alive Creating a temporary Ref/RefPtr is ordinarily treated as a potentially destructive operation because the destructor could call deref for the last time and destruct the object. However, when such a temporary Ref/RefPtr is immediately converted to another Ref/RefPtr, such a destruction will never take place and therefore safe. This PR adds the logic to detect this case when handling CXXConstructExpr and allow it in alpha.webkit.NoDeleteChecker and in other WebKit checkers which check "triviality" of given code. --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 22 ++++++++++++ .../Checkers/WebKit/nodelete-annotation.cpp | 36 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index e8e404c753dcb..8c35f51e696d3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -967,6 +967,10 @@ class TrivialFunctionAnalysisVisitor Arg = Arg->IgnoreParenCasts(); if (!Arg->isPRValue()) return Visit(Arg); + if (auto *Init = dyn_cast<InitListExpr>(Arg)) { + if (Init->getNumInits() == 1) + Arg = Init->getInit(0); + } if (auto *ExprWithClean = dyn_cast<ExprWithCleanups>(Arg)) Arg = ExprWithClean->getSubExpr()->IgnoreParenCasts(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg)) { @@ -982,6 +986,24 @@ class TrivialFunctionAnalysisVisitor } bool VisitCXXConstructExpr(const CXXConstructExpr *CE) { + if (CE->getNumArgs() == 1) { + auto* InnerArg = CE->getArg(0); + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(InnerArg)) { + auto *InnerExpr = MTE->getSubExpr(); + if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(InnerExpr)) + InnerExpr = BTE->getSubExpr(); + auto InnerQT = InnerExpr->getType(); + if (!InnerQT.isNull()) { + if (auto *InnerDecl = InnerQT->getAsCXXRecordDecl()) { + auto *OuterCls = CE->getConstructor()->getParent(); + if (isRefType(safeGetName(OuterCls)) && + isRefType(safeGetName(InnerDecl))) + return Visit(InnerExpr); + } + } + } + } + for (const Expr *Arg : CE->arguments()) { if (Arg && !Visit(Arg)) return false; diff --git a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp index 06ba7c47ae91a..83ec6e704f14a 100644 --- a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp +++ b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp @@ -623,6 +623,42 @@ Ref<RefCountable> [[clang::annotate_type("webkit.nodelete")]] returnClassStatic( } // namespace copy_elision_edge_cases +namespace return_temp_ref_ptr { + +struct RefObj { + mutable unsigned m_refCount { 0 }; + void ref() const { m_refCount++; } + void deref() const { + m_refCount--; + if (!m_refCount) + delete const_cast<RefObj*>(this); + } + + static Ref<RefObj> create(int) { + return adoptRef(*new RefObj); + } +}; + +Ref<RefObj> [[clang::annotate_type("webkit.nodelete")]] returnRef() { + return RefObj::create(0); +} + +Ref<RefObj> [[clang::annotate_type("webkit.nodelete")]] returnRefWithInit() { + return { RefObj::create(0) }; +} + +RefPtr<RefObj> [[clang::annotate_type("webkit.nodelete")]] returnRefPtrSafe() { + return { RefObj::create(0) }; +} + +int val(); +RefPtr<RefObj> [[clang::annotate_type("webkit.nodelete")]] returnRefPtrUnsafe() { + return { RefObj::create(val()) }; + // expected-warning@-1{{A function 'returnRefPtrUnsafe' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}} +} + +} // namespace return_temp_ref_ptr + namespace temp_object_typecheck { struct Tracked { >From a3d1f9314e120bf47796342338e243c12c91a99d Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <[email protected]> Date: Wed, 26 Aug 2026 21:21:59 -0700 Subject: [PATCH 2/3] Fix formatting. --- clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 8c35f51e696d3..3ba37fa5f93af 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -987,7 +987,7 @@ class TrivialFunctionAnalysisVisitor bool VisitCXXConstructExpr(const CXXConstructExpr *CE) { if (CE->getNumArgs() == 1) { - auto* InnerArg = CE->getArg(0); + auto *InnerArg = CE->getArg(0); if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(InnerArg)) { auto *InnerExpr = MTE->getSubExpr(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(InnerExpr)) >From 00e46352e380febfb517026da19c6236f0093f44 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <[email protected]> Date: Thu, 27 Aug 2026 08:40:05 -0700 Subject: [PATCH 3/3] Address the review comment. --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 3ba37fa5f93af..b4e6751224595 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -971,8 +971,6 @@ class TrivialFunctionAnalysisVisitor if (Init->getNumInits() == 1) Arg = Init->getInit(0); } - if (auto *ExprWithClean = dyn_cast<ExprWithCleanups>(Arg)) - Arg = ExprWithClean->getSubExpr()->IgnoreParenCasts(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg)) { // Only elide when the temporary *is* the returned object, i.e. it has the // same smart-pointer type as the return value. Compare canonical, @@ -993,13 +991,11 @@ class TrivialFunctionAnalysisVisitor if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(InnerExpr)) InnerExpr = BTE->getSubExpr(); auto InnerQT = InnerExpr->getType(); - if (!InnerQT.isNull()) { - if (auto *InnerDecl = InnerQT->getAsCXXRecordDecl()) { - auto *OuterCls = CE->getConstructor()->getParent(); - if (isRefType(safeGetName(OuterCls)) && - isRefType(safeGetName(InnerDecl))) - return Visit(InnerExpr); - } + if (auto *InnerDecl = InnerQT->getAsCXXRecordDecl()) { + auto *OuterCls = CE->getConstructor()->getParent(); + if (isRefType(safeGetName(OuterCls)) && + isRefType(safeGetName(InnerDecl))) + return Visit(InnerExpr); } } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
