[clang] 7d987f8 - [alpha.webkit.NoDeleteChecker] Allow no-delete default constructors (#201544)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 5 02:05:55 PDT 2026
Author: Ryosuke Niwa
Date: 2026-06-05T02:05:51-07:00
New Revision: 7d987f8a35a71a97754ccab804cb9966ece52e08
URL: https://github.com/llvm/llvm-project/commit/7d987f8a35a71a97754ccab804cb9966ece52e08
DIFF: https://github.com/llvm/llvm-project/commit/7d987f8a35a71a97754ccab804cb9966ece52e08.diff
LOG: [alpha.webkit.NoDeleteChecker] Allow no-delete default constructors (#201544)
This PR fixes the bug in TrivialFunctionAnalysis that it treats a
default constructor without an explicit body / definition as not
"trivial". Fixed the bug by allowing the function body to be missing
when isThisDeclarationADefinition is true.
---------
Co-authored-by: Balazs Benics <benicsbalazs at gmail.com>
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d5ed7fc78148a..cf165796c9695 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -652,22 +652,46 @@ class TrivialFunctionAnalysisVisitor
bool IsFunctionTrivial(const Decl *D) {
const Stmt **SavedOffendingStmt = std::exchange(OffendingStmt, nullptr);
auto Result = WithCachedResult(D, [&]() {
- if (auto *FnDecl = dyn_cast<FunctionDecl>(D)) {
+ auto *FnDecl = dyn_cast<FunctionDecl>(D);
+ auto *MethodDecl = dyn_cast<CXXMethodDecl>(D);
+ auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D);
+ auto *DtorDecl = dyn_cast<CXXDestructorDecl>(D);
+
+ if (FnDecl) {
if (isNoDeleteFunction(FnDecl))
return true;
- if (auto *MD = dyn_cast<CXXMethodDecl>(D); MD && MD->isVirtual())
+ if (MethodDecl && MethodDecl->isVirtual())
return false;
for (auto *Param : FnDecl->parameters()) {
if (!HasTrivialDestructor(Param))
return false;
}
}
- if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
+ if (CtorDecl) {
for (auto *CtorInit : CtorDecl->inits()) {
if (!Visit(CtorInit->getInit()))
return false;
}
}
+ // An implicit or =default special member runs no user code when it is
+ // trivial in the C++ standard sense, so it cannot delete. Such a
+ // member's synthesized body is typically absent from the AST until
+ // codegen materialises it, which the generic null-body check below
+ // would otherwise conservatively classify as non-trivial.
+ if (MethodDecl && !MethodDecl->isUserProvided()) {
+ if (CtorDecl) {
+ const CXXRecordDecl *RD = CtorDecl->getParent();
+ if ((CtorDecl->isDefaultConstructor() &&
+ RD->hasTrivialDefaultConstructor()) ||
+ (CtorDecl->isCopyConstructor() &&
+ RD->hasTrivialCopyConstructor()) ||
+ (CtorDecl->isMoveConstructor() &&
+ RD->hasTrivialMoveConstructor()))
+ return true;
+ }
+ if (DtorDecl && DtorDecl->getParent()->hasTrivialDestructor())
+ return true;
+ }
const Stmt *Body = D->getBody();
if (!Body)
return false;
diff --git a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
index a9c50cfb1f45f..06ba7c47ae91a 100644
--- a/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/nodelete-annotation.cpp
@@ -701,3 +701,61 @@ Ref<RefCountable> [[clang::annotate_type("webkit.nodelete")]] returnTypedefPrval
} // namespace returned_prvalue_typedef
+namespace create_with_default_constructor {
+
+ struct ObjectWithDefaultConstructorWithoutMemberVariables {
+ void ref() const;
+ void deref() const;
+
+ static auto [[clang::annotate_type("webkit.nodelete")]] create() {
+ return adoptRef(*new ObjectWithDefaultConstructorWithoutMemberVariables());
+ }
+ };
+
+ struct ObjectWithDefaultConstructorWithPODMemberVariables {
+ void ref() const;
+ void deref() const;
+
+ static auto [[clang::annotate_type("webkit.nodelete")]] create() {
+ return adoptRef(*new ObjectWithDefaultConstructorWithPODMemberVariables());
+ }
+
+ private:
+ int value { 0 };
+ RefCountable* ptr { nullptr };
+ };
+
+ struct ObjectWithOpaqueCtor {
+ ObjectWithOpaqueCtor();
+ };
+
+ struct ObjectWithDefaultConstructorWithOpaqueCtorMemberVariables {
+ void ref() const;
+ void deref() const;
+
+ static auto [[clang::annotate_type("webkit.nodelete")]] create() {
+ return adoptRef(*new ObjectWithDefaultConstructorWithOpaqueCtorMemberVariables());
+ // expected-warning at -1{{A function 'create' has [[clang::annotate_type("webkit.nodelete")]] but it contains code that could destruct an object}}
+ }
+
+ private:
+ ObjectWithOpaqueCtor obj;
+ };
+
+} // namespace create_with_default_constructor
+
+
+namespace trivial_implicit_ctor_in_new_expr {
+
+// 'new T()' with parens emits a CXXConstructExpr for T's implicit default
+// ctor. That ctor has no body in the AST (the synthesized body is materialised
+// only at codegen), but it is trivial by the C++ standard and runs no user
+// code, so it cannot delete. Verify the fast-path treats it as trivial.
+struct Plain { int x; };
+
+void [[clang::annotate_type("webkit.nodelete")]] valueInitNew() {
+ Plain* p = new Plain();
+ (void)p;
+}
+
+} // namespace trivial_implicit_ctor_in_new_expr
More information about the cfe-commits
mailing list