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(D)) { + auto *FnDecl = dyn_cast(D); + auto *MethodDecl = dyn_cast(D); + auto *CtorDecl = dyn_cast(D); + auto *DtorDecl = dyn_cast(D); + + if (FnDecl) { if (isNoDeleteFunction(FnDecl)) return true; - if (auto *MD = dyn_cast(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(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 [[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