From 7c625d8ffc20b92fff9e1690cd2484fcb6498183 Mon Sep 17 00:00:00 2001 From: Marcin Swiderski Date: Tue, 5 Oct 2010 05:37:00 +0000 Subject: [PATCH] Added support for base and member destructors in destructor. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@115592 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Analysis/CFG.h | 33 +++++++++++- lib/Analysis/CFG.cpp | 62 ++++++++++++++++++++++ test/Analysis/dtors-in-dtor-cfg-output.cpp | 41 ++++++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 test/Analysis/dtors-in-dtor-cfg-output.cpp diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index f74b58551e..86acb58c50 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -31,8 +31,10 @@ namespace clang { class Decl; class Stmt; class Expr; + class FieldDecl; class VarDecl; class CXXBaseOrMemberInitializer; + class CXXBaseSpecifier; class CFG; class PrinterHelper; class LangOptions; @@ -139,7 +141,7 @@ public: } }; -/// CFGAutomaticObjDtor - Represents C++ object destructor implicit generated +/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated /// for automatic object or temporary bound to const reference at the point /// of leaving its local scope. class CFGAutomaticObjDtor: public CFGImplicitDtor { @@ -162,19 +164,38 @@ public: } }; +/// CFGBaseDtor - Represents C++ object destructor implicitly generated for +/// base object in destructor. class CFGBaseDtor : public CFGImplicitDtor { public: + CFGBaseDtor() {} + CFGBaseDtor(const CXXBaseSpecifier *BS) + : CFGImplicitDtor(BaseDtor, const_cast(BS), NULL) {} + + const CXXBaseSpecifier *getBaseSpecifier() const { + return static_cast(Data1.getPointer()); + } + static bool classof(const CFGElement *E) { return E->getKind() == Dtor && E->getDtorKind() == BaseDtor; } }; +/// CFGMemberDtor - Represents C++ object destructor implicitly generated for +/// member object in destructor. class CFGMemberDtor : public CFGImplicitDtor { public: + CFGMemberDtor() {} + CFGMemberDtor(FieldDecl *FD) + : CFGImplicitDtor(MemberDtor, FD, NULL) {} + + FieldDecl *getFieldDecl() const { + return static_cast(Data1.getPointer()); + } + static bool classof(const CFGElement *E) { return E->getKind() == Dtor && E->getDtorKind() == MemberDtor; } - }; class CFGTemporaryDtor : public CFGImplicitDtor { @@ -437,6 +458,14 @@ public: Elements.push_back(CFGInitializer(I), C); } + void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { + Elements.push_back(CFGBaseDtor(BS), C); + } + + void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { + Elements.push_back(CFGMemberDtor(FD), C); + } + // Destructors must be inserted in reversed order. So insertion is in two // steps. First we prepare space for some number of elements, then we insert // the elements beginning at the last position in prepared space. diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 4eac9ae351..53479bc058 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -307,6 +307,7 @@ private: CFGBlock *addInitializer(CXXBaseOrMemberInitializer *I); void addAutomaticObjDtors(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S); + void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); // Local scopes creation. LocalScope* createOrReuseLocalScope(LocalScope* Scope); @@ -325,6 +326,12 @@ private: void appendInitializer(CFGBlock *B, CXXBaseOrMemberInitializer *I) { B->appendInitializer(I, cfg->getBumpVectorContext()); } + void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) { + B->appendBaseDtor(BS, cfg->getBumpVectorContext()); + } + void appendMemberDtor(CFGBlock *B, FieldDecl *FD) { + B->appendMemberDtor(FD, cfg->getBumpVectorContext()); + } void insertAutomaticObjDtors(CFGBlock* Blk, CFGBlock::iterator I, LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt* S); @@ -407,6 +414,10 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C, assert(Succ == &cfg->getExit()); Block = NULL; // the EXIT block is empty. Create all other blocks lazily. + if (BuildOpts.AddImplicitDtors) + if (const CXXDestructorDecl *DD = dyn_cast_or_null(D)) + addImplicitDtorsForDestructor(DD); + // Visit the statements and create the CFG. CFGBlock *B = addStmt(Statement); @@ -509,6 +520,46 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, appendAutomaticObjDtors(Block, B, E, S); } +/// addImplicitDtorsForDestructor - Add implicit destructors generated for +/// base and member objects in destructor. +void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) { + assert (BuildOpts.AddImplicitDtors + && "Can be called only when dtors should be added"); + const CXXRecordDecl *RD = DD->getParent(); + + // At the end destroy virtual base objects. + for (CXXRecordDecl::base_class_const_iterator VI = RD->vbases_begin(), + VE = RD->vbases_end(); VI != VE; ++VI) { + const CXXRecordDecl *CD = VI->getType()->getAsCXXRecordDecl(); + if (!CD->hasTrivialDestructor()) { + autoCreateBlock(); + appendBaseDtor(Block, VI); + } + } + + // Before virtual bases destroy direct base objects. + for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); BI != BE; ++BI) { + if (!BI->isVirtual()) { + const CXXRecordDecl *CD = BI->getType()->getAsCXXRecordDecl(); + if (!CD->hasTrivialDestructor()) { + autoCreateBlock(); + appendBaseDtor(Block, BI); + } + } + } + + // First destroy member objects. + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); FI != FE; ++FI) { + if (const CXXRecordDecl *CD = FI->getType()->getAsCXXRecordDecl()) + if (!CD->hasTrivialDestructor()) { + autoCreateBlock(); + appendMemberDtor(Block, *FI); + } + } +} + /// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either /// way return valid LocalScope object. LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { @@ -2660,6 +2711,17 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; OS << " (Implicit destructor)\n"; + + } else if (CFGBaseDtor BE = E.getAs()) { + const CXXBaseSpecifier *BS = BE.getBaseSpecifier(); + OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; + OS << " (Base destructor)\n"; + + } else if (CFGMemberDtor ME = E.getAs()) { + FieldDecl *FD = ME.getFieldDecl(); + OS << "this->" << FD->getName(); + OS << ".~" << FD->getType()->getAsCXXRecordDecl()->getName() << "()"; + OS << " (Member destructor)\n"; } } diff --git a/test/Analysis/dtors-in-dtor-cfg-output.cpp b/test/Analysis/dtors-in-dtor-cfg-output.cpp new file mode 100644 index 0000000000..0483cacaff --- /dev/null +++ b/test/Analysis/dtors-in-dtor-cfg-output.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -analyze -cfg-dump -cfg-add-implicit-dtors %s 2>&1 | FileCheck %s +// XPASS: * + +class A { +public: + ~A() {} +}; + +class B : public virtual A { +public: + ~B() {} +}; + +class C : public virtual A { +public: + ~C() {} +}; + +class TestOrder : public C, public B, public virtual A { + A a; + int i; + A *p; +public: + ~TestOrder(); +}; + +TestOrder::~TestOrder() {} + +// CHECK: [ B2 (ENTRY) ] +// CHECK: Predecessors (0): +// CHECK: Successors (1): B1 +// CHECK: [ B1 ] +// CHECK: 1: this->a.~A() (Member object destructor) +// CHECK: 2: ~B() (Base object destructor) +// CHECK: 3: ~C() (Base object destructor) +// CHECK: 4: ~A() (Base object destructor) +// CHECK: Predecessors (1): B2 +// CHECK: Successors (1): B0 +// CHECK: [ B0 (EXIT) ] +// CHECK: Predecessors (1): B1 +// CHECK: Successors (0): -- 2.50.1