r189828 - Add an implicit dtor CFG node just before C++ 'delete' expressions.

Jordan Rose jordan_rose at apple.com
Tue Sep 3 10:00:58 PDT 2013


Author: jrose
Date: Tue Sep  3 12:00:57 2013
New Revision: 189828

URL: http://llvm.org/viewvc/llvm-project?rev=189828&view=rev
Log:
Add an implicit dtor CFG node just before C++ 'delete' expressions.

This paves the way for adding support for modeling the destructor of a
region before it is deleted. The statement "delete <expr>" now generates
this series of CFG elements:

  1. <expr>
  2. [B1.1]->~Foo() (Implicit destructor)
  3. delete [B1.1]

Patch by Karthik Bhat!

Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
    cfe/trunk/test/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=189828&r1=189827&r2=189828&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Tue Sep  3 12:00:57 2013
@@ -43,6 +43,8 @@ namespace clang {
   class PrinterHelper;
   class LangOptions;
   class ASTContext;
+  class CXXRecordDecl;
+  class CXXDeleteExpr;
 
 /// CFGElement - Represents a top-level expression in a basic block.
 class CFGElement {
@@ -53,6 +55,7 @@ public:
     Initializer,
     // dtor kind
     AutomaticObjectDtor,
+    DeleteDtor,
     BaseDtor,
     MemberDtor,
     TemporaryDtor,
@@ -185,6 +188,31 @@ private:
   }
 };
 
+/// CFGDeleteDtor - Represents C++ object destructor generated
+/// from a call to delete.
+class CFGDeleteDtor : public CFGImplicitDtor {
+public:
+  CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE)
+      : CFGImplicitDtor(DeleteDtor, RD, DE) {}
+
+  const CXXRecordDecl *getCXXRecordDecl() const {
+    return static_cast<CXXRecordDecl*>(Data1.getPointer());
+  }
+
+  // Get Delete expression which triggered the destructor call.
+  const CXXDeleteExpr *getDeleteExpr() {
+    return static_cast<CXXDeleteExpr *>(Data2.getPointer());
+  }
+
+
+private:
+  friend class CFGElement;
+  CFGDeleteDtor() {}
+  static bool isKind(const CFGElement &elem) {
+    return elem.getKind() == DeleteDtor;
+  }
+};
+
 /// CFGBaseDtor - Represents C++ object destructor implicitly generated for
 /// base object in destructor.
 class CFGBaseDtor : public CFGImplicitDtor {
@@ -564,6 +592,10 @@ public:
     Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
   }
 
+  void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
+    Elements.push_back(CFGDeleteDtor(RD, DE), 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/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=189828&r1=189827&r2=189828&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Tue Sep  3 12:00:57 2013
@@ -203,6 +203,8 @@ public:
 
   void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, 
                                ExplodedNode *Pred, ExplodedNodeSet &Dst);
+  void ProcessDeleteDtor(const CFGDeleteDtor D,
+                         ExplodedNode *Pred, ExplodedNodeSet &Dst);
   void ProcessBaseDtor(const CFGBaseDtor D,
                        ExplodedNode *Pred, ExplodedNodeSet &Dst);
   void ProcessMemberDtor(const CFGMemberDtor D,

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=189828&r1=189827&r2=189828&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue Sep  3 12:00:57 2013
@@ -363,6 +363,7 @@ private:
                                       AddStmtChoice asc);
   CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
   CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
+  CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
   CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
   CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
                                        AddStmtChoice asc);
@@ -471,6 +472,10 @@ private:
     B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
   }
 
+  void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
+    B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
+  }
+
   void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
       LocalScope::const_iterator B, LocalScope::const_iterator E);
 
@@ -1117,6 +1122,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, Ad
     case Stmt::CXXConstructExprClass:
       return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
 
+    case Stmt::CXXDeleteExprClass:
+      return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
+
     case Stmt::CXXFunctionalCastExprClass:
       return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
 
@@ -3113,6 +3121,22 @@ CFGBlock *CFGBuilder::VisitCXXConstructE
   return VisitChildren(C);
 }
 
+
+CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
+                                         AddStmtChoice asc) {
+  autoCreateBlock();
+  appendStmt(Block, DE);
+  QualType DTy = DE->getDestroyedType();
+  DTy = DTy.getNonReferenceType();
+  CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl();
+  if (RD) {
+    if (!RD->hasTrivialDestructor())
+      appendDeleteDtor(Block, RD, DE);
+  }
+
+  return VisitChildren(DE);
+}
+
 CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
                                                  AddStmtChoice asc) {
   if (asc.alwaysAdd(*this, E)) {
@@ -3413,6 +3437,14 @@ CFGImplicitDtor::getDestructorDecl(ASTCo
       cast<CXXRecordDecl>(recordType->getDecl());
       return classDecl->getDestructor();      
     }
+    case CFGElement::DeleteDtor: {
+      const CXXDeleteExpr *DE = castAs<CFGDeleteDtor>().getDeleteExpr();
+      QualType DTy = DE->getDestroyedType();
+      DTy = DTy.getNonReferenceType();
+      const CXXRecordDecl *classDecl =
+          astContext.getBaseElementType(DTy)->getAsCXXRecordDecl();
+      return classDecl->getDestructor();
+    }
     case CFGElement::TemporaryDtor: {
       const CXXBindTemporaryExpr *bindExpr =
         castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
@@ -3751,6 +3783,15 @@ static void print_elem(raw_ostream &OS,
     OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
     OS << " (Implicit destructor)\n";
 
+  } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
+    const CXXRecordDecl *RD = DE->getCXXRecordDecl();
+    if (!RD)
+      return;
+    CXXDeleteExpr *DelExpr =
+        const_cast<CXXDeleteExpr*>(DE->getDeleteExpr());
+    Helper->handledStmt(cast<Stmt>(DelExpr->getArgument()), OS);
+    OS << "->~" << RD->getName().str() << "()";
+    OS << " (Implicit destructor)\n";
   } else if (Optional<CFGBaseDtor> BE = E.getAs<CFGBaseDtor>()) {
     const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
     OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=189828&r1=189827&r2=189828&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Sep  3 12:00:57 2013
@@ -287,6 +287,7 @@ void ExprEngine::processCFGElement(const
       ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
       return;
     case CFGElement::AutomaticObjectDtor:
+    case CFGElement::DeleteDtor:
     case CFGElement::BaseDtor:
     case CFGElement::MemberDtor:
     case CFGElement::TemporaryDtor:
@@ -535,6 +536,9 @@ void ExprEngine::ProcessImplicitDtor(con
   case CFGElement::TemporaryDtor:
     ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst);
     break;
+  case CFGElement::DeleteDtor:
+    ProcessDeleteDtor(D.castAs<CFGDeleteDtor>(), Pred, Dst);
+    break;
   default:
     llvm_unreachable("Unexpected dtor kind.");
   }
@@ -562,6 +566,12 @@ void ExprEngine::ProcessAutomaticObjDtor
                      Pred, Dst);
 }
 
+void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
+                                   ExplodedNode *Pred,
+                                   ExplodedNodeSet &Dst) {
+  //TODO: Handle DeleteDtor
+}
+
 void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
                                  ExplodedNode *Pred, ExplodedNodeSet &Dst) {
   const LocationContext *LCtx = Pred->getLocationContext();

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=189828&r1=189827&r2=189828&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Tue Sep  3 12:00:57 2013
@@ -559,6 +559,9 @@ getLocationForCaller(const StackFrameCon
     return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
                                              SM, CallerCtx);
   }
+  case CFGElement::DeleteDtor: {
+    llvm_unreachable("not yet implemented!");
+  }
   case CFGElement::BaseDtor:
   case CFGElement::MemberDtor: {
     const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();

Modified: cfe/trunk/test/Analysis/cfg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg.cpp?rev=189828&r1=189827&r2=189828&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg.cpp (original)
+++ cfe/trunk/test/Analysis/cfg.cpp Tue Sep  3 12:00:57 2013
@@ -98,3 +98,49 @@ void testBuiltinSize() {
   extern int *dummy();
   (void)__builtin_object_size(dummy(), 0);
 }
+
+
+class A {
+public:
+  A() {}
+  ~A() {}
+};
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT:   1:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   2: new A([B1.1])
+// CHECK-NEXT:   3: A *a = new A();
+// CHECK-NEXT:   4: a
+// CHECK-NEXT:   5: [B1.4] (ImplicitCastExpr, LValueToRValue, class A *)
+// CHECK-NEXT:   6: [B1.5]->~A() (Implicit destructor)
+// CHECK-NEXT:   7: delete [B1.5]
+// CHECK-NEXT:   Preds (1): B2
+// CHECK-NEXT:   Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void test_deletedtor() {
+  A *a = new A();
+  delete a;
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT:   1: 5
+// CHECK-NEXT:   2:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   3: new A {{\[\[}}B1.1]]
+// CHECK-NEXT:   4: A *a = new A [5];
+// CHECK-NEXT:   5: a
+// CHECK-NEXT:   6: [B1.5] (ImplicitCastExpr, LValueToRValue, class A *)
+// CHECK-NEXT:   7: [B1.6]->~A() (Implicit destructor)
+// CHECK-NEXT:   8: delete [] [B1.6]
+// CHECK-NEXT:   Preds (1): B2
+// CHECK-NEXT:   Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void test_deleteArraydtor() {
+  A *a = new A[5];
+  delete[] a;
+}





More information about the cfe-commits mailing list