]> granicus.if.org Git - clang/commitdiff
Added support for comma expressions and DeclStmts which may have
authorTed Kremenek <kremenek@apple.com>
Tue, 28 Aug 2007 18:14:37 +0000 (18:14 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 28 Aug 2007 18:14:37 +0000 (18:14 +0000)
arbitrarily complex control-flow in their subexpressions.

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

AST/CFG.cpp

index 64a75b20084d81b39597d0ce57b4e2ede4820ad2..68471ac955ae69e5c4d379e9c644040d631e6763 100644 (file)
@@ -101,6 +101,7 @@ private:
   CFGBlock* addStmt(Stmt* S);
   CFGBlock* WalkAST(Stmt* S, bool AlwaysAddStmt);
   CFGBlock* WalkAST_VisitChildren(Stmt* S);
+  CFGBlock* WalkAST_VisitVarDecl(VarDecl* D);
   void FinishBlock(CFGBlock* B);
   
 };
@@ -185,7 +186,8 @@ CFGBlock* CFGBuilder::addStmt(Stmt* S) {
 }
 
 /// WalkAST - Used by addStmt to walk the subtree of a statement and
-///   add extra blocks for ternary operators, &&, and ||.
+///   add extra blocks for ternary operators, &&, and ||.  We also
+///   process "," and DeclStmts (which may contain nested control-flow).
 CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) {    
   switch (S->getStmtClass()) {
     case Stmt::ConditionalOperatorClass: {
@@ -210,6 +212,13 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) {
       return addStmt(C->getCond());
     }
 
+    case Stmt::DeclStmtClass:      
+      if (VarDecl* V = dyn_cast<VarDecl>(cast<DeclStmt>(S)->getDecl())) {      
+        Block->appendStmt(S);
+        return WalkAST_VisitVarDecl(V);
+      }
+      else return Block;
+
     case Stmt::BinaryOperatorClass: {
       BinaryOperator* B = cast<BinaryOperator>(S);
 
@@ -232,6 +241,11 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) {
         // Generate the blocks for evaluating the LHS.
         Block = LHSBlock;
         return addStmt(B->getLHS());                                    
+      }
+      else if (B->getOpcode() == BinaryOperator::Comma) { // ,
+        Block->appendStmt(B);
+        addStmt(B->getRHS());
+        return addStmt(B->getLHS());
       }    
 
       // Fall through to the default case.
@@ -243,6 +257,25 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) {
   };
 }
 
+/// WalkAST_VisitVarDecl - Utility method to handle VarDecls contained in
+///  DeclStmts.  Because the initialization code for declarations can
+///  contain arbitrary expressions, we must linearize declarations
+///  to handle arbitrary control-flow induced by those expressions.
+CFGBlock* CFGBuilder::WalkAST_VisitVarDecl(VarDecl* V) {
+  // We actually must parse the LAST declaration in a chain of
+  // declarations first, because we are building the CFG in reverse
+  // order.
+  if (Decl* D = V->getNextDeclarator())
+    if (VarDecl* Next = cast<VarDecl>(D))
+      Block = WalkAST_VisitVarDecl(Next);
+    
+  if (Expr* E = V->getInit())
+    return addStmt(E);
+
+  assert (Block);
+  return Block;
+}
+
 /// WalkAST_VisitChildren - Utility method to call WalkAST on the
 ///  children of a Stmt.
 CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* S) {
@@ -365,9 +398,6 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
   
   // The Exit block is the only successor.
   Block->addSuccessor(&cfg->getExit());
-
-  // Also add the return statement as the terminator.
-  Block->setTerminator(R);
     
   // Add the return statement to the block.  This may create new blocks
   // if R contains control-flow (short-circuit operations).