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 <[email protected]> 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@-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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
