[cfe-commits] r115592 - in /cfe/trunk: include/clang/Analysis/CFG.h lib/Analysis/CFG.cpp test/Analysis/dtors-in-dtor-cfg-output.cpp

Marcin Swiderski marcin.sfider at gmail.com
Mon Oct 4 22:37:00 PDT 2010


Author: sfider
Date: Tue Oct  5 00:37:00 2010
New Revision: 115592

URL: http://llvm.org/viewvc/llvm-project?rev=115592&view=rev
Log:
Added support for base and member destructors in destructor.

Added:
    cfe/trunk/test/Analysis/dtors-in-dtor-cfg-output.cpp
Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/lib/Analysis/CFG.cpp

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=115592&r1=115591&r2=115592&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Tue Oct  5 00:37:00 2010
@@ -31,8 +31,10 @@
   class Decl;
   class Stmt;
   class Expr;
+  class FieldDecl;
   class VarDecl;
   class CXXBaseOrMemberInitializer;
+  class CXXBaseSpecifier;
   class CFG;
   class PrinterHelper;
   class LangOptions;
@@ -139,7 +141,7 @@
   }
 };
 
-/// 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 @@
   }
 };
 
+/// 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<CXXBaseSpecifier*>(BS), NULL) {}
+
+  const CXXBaseSpecifier *getBaseSpecifier() const {
+    return static_cast<const CXXBaseSpecifier*>(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<FieldDecl*>(Data1.getPointer());
+  }
+
   static bool classof(const CFGElement *E) {
     return E->getKind() == Dtor && E->getDtorKind() == MemberDtor;
   }
-
 };
 
 class CFGTemporaryDtor : public CFGImplicitDtor {
@@ -437,6 +458,14 @@
     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.

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=115592&r1=115591&r2=115592&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue Oct  5 00:37:00 2010
@@ -307,6 +307,7 @@
   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 @@
   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 @@
   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<CXXDestructorDecl>(D))
+      addImplicitDtorsForDestructor(DD);
+
   // Visit the statements and create the CFG.
   CFGBlock *B = addStmt(Statement);
 
@@ -509,6 +520,46 @@
   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 @@
 
     OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
     OS << " (Implicit destructor)\n";
+
+  } else if (CFGBaseDtor BE = E.getAs<CFGBaseDtor>()) {
+    const CXXBaseSpecifier *BS = BE.getBaseSpecifier();
+    OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
+    OS << " (Base destructor)\n";
+
+  } else if (CFGMemberDtor ME = E.getAs<CFGMemberDtor>()) {
+    FieldDecl *FD = ME.getFieldDecl();
+    OS << "this->" << FD->getName();
+    OS << ".~" << FD->getType()->getAsCXXRecordDecl()->getName() << "()";
+    OS << " (Member destructor)\n";
   }
  }
 

Added: cfe/trunk/test/Analysis/dtors-in-dtor-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dtors-in-dtor-cfg-output.cpp?rev=115592&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/dtors-in-dtor-cfg-output.cpp (added)
+++ cfe/trunk/test/Analysis/dtors-in-dtor-cfg-output.cpp Tue Oct  5 00:37:00 2010
@@ -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):





More information about the cfe-commits mailing list