From b49e1aa3ef2ec0d84dfc36e85c41e5f8fd145100 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 28 Aug 2007 18:14:37 +0000 Subject: [PATCH] Added support for comma expressions and DeclStmts which may have 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 | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/AST/CFG.cpp b/AST/CFG.cpp index 64a75b2008..68471ac955 100644 --- a/AST/CFG.cpp +++ b/AST/CFG.cpp @@ -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(cast(S)->getDecl())) { + Block->appendStmt(S); + return WalkAST_VisitVarDecl(V); + } + else return Block; + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(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(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). -- 2.40.0