]> granicus.if.org Git - clang/commitdiff
Add CFG logic to create a conditional branch for modeling static initializers.
authorTed Kremenek <kremenek@apple.com>
Thu, 28 Mar 2013 18:43:15 +0000 (18:43 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 28 Mar 2013 18:43:15 +0000 (18:43 +0000)
This is an optional variant of the CFG.  This allows analyses to model whether
or not a static initializer has run, e.g.:

  static Foo x = bar();

For basic dataflow analysis in Sema we will just assume that the initializer
always runs.  For the static analyzer we can use this branch to accurately
track whether or not initializers are on.

This patch just adds the (opt-in) functionality to the CFG.  The
static analyzer still needs to be modified to adopt this feature.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178263 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/CFG.h
lib/Analysis/CFG.cpp

index 57f980ef4c72480332fddd293c19f5be42e88747..ee0be736dd5ed2d9f3d828892073849fa1eef506 100644 (file)
@@ -601,6 +601,7 @@ public:
     bool AddInitializers;
     bool AddImplicitDtors;
     bool AddTemporaryDtors;
+    bool AddStaticInitBranches;
 
     bool alwaysAdd(const Stmt *stmt) const {
       return alwaysAddMask[stmt->getStmtClass()];
@@ -621,7 +622,8 @@ public:
       ,AddEHEdges(false)
       ,AddInitializers(false)
       ,AddImplicitDtors(false)
-      ,AddTemporaryDtors(false) {}
+      ,AddTemporaryDtors(false)
+      ,AddStaticInitBranches(false) {}
   };
 
   /// \brief Provides a custom implementation of the iterator class to have the
index f20f84c5c0fdf096903d2a57ca9f19fbb55aac1c..f436ef3f6a33d7e8cbd6c04e60fcc1120b1bfc0d 100644 (file)
@@ -1653,10 +1653,24 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
   bool IsReference = false;
   bool HasTemporaries = false;
 
+  // Guard static initializers under a branch.
+  CFGBlock *blockBeforeInit = 0;
+
   // Destructors of temporaries in initialization expression should be called
   // after initialization finishes.
   Expr *Init = VD->getInit();
   if (Init) {
+    if (BuildOpts.AddStaticInitBranches && VD->isStaticLocal()) {
+      // For static variables, we need to create a branch to track
+      // whether or not they are initialized.
+      if (Block) {
+        Succ = Block;
+        if (badCFG)
+          return 0;
+      }
+      blockBeforeInit = Succ;
+    }
+
     IsReference = VD->getType()->isReferenceType();
     HasTemporaries = isa<ExprWithCleanups>(Init);
 
@@ -1700,7 +1714,18 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
   if (ScopePos && VD == *ScopePos)
     ++ScopePos;
 
-  return Block ? Block : LastBlock;
+  CFGBlock *B = Block ? Block : LastBlock;
+  if (blockBeforeInit) {
+    Succ = B;
+    Block = 0;
+    CFGBlock *branchBlock = createBlock(false);
+    branchBlock->setTerminator(DS);
+    addSuccessor(branchBlock, blockBeforeInit);
+    addSuccessor(branchBlock, B);
+    B = branchBlock;
+  }
+
+  return B;
 }
 
 CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
@@ -3642,6 +3667,11 @@ public:
     Terminator->printPretty(OS, Helper, Policy);
   }
 
+  void VisitDeclStmt(DeclStmt *DS) {
+    VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+    OS << "static init " << VD->getName();
+  }
+
   void VisitForStmt(ForStmt *F) {
     OS << "for (" ;
     if (F->getInit())