diff options
Diffstat (limited to 'lib/Analysis/CFG.cpp')
-rw-r--r-- | lib/Analysis/CFG.cpp | 500 |
1 files changed, 292 insertions, 208 deletions
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 2f1f1cb..05c5385 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1,4 +1,4 @@ -//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===// + //===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,6 +14,7 @@ #include "llvm/Support/SaveAndRestore.h" #include "clang/Analysis/CFG.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" @@ -312,19 +313,6 @@ private: CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); - CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); - CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, - AddStmtChoice asc); - CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); - CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); - CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S); - CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, - AddStmtChoice asc); - CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc); - CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E, - AddStmtChoice asc); - CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, - AddStmtChoice asc); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); @@ -332,31 +320,47 @@ private: CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *C, AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); + CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, + AddStmtChoice asc); + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); + CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc); + CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S); + CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E, + AddStmtChoice asc); + CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, + AddStmtChoice asc); + CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(DeclStmt *DS); CFGBlock *VisitDefaultStmt(DefaultStmt *D); CFGBlock *VisitDoStmt(DoStmt *D); - CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc); + CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc); CFGBlock *VisitForStmt(ForStmt *F); CFGBlock *VisitGotoStmt(GotoStmt *G); CFGBlock *VisitIfStmt(IfStmt *I); CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc); CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); CFGBlock *VisitLabelStmt(LabelStmt *L); - CFGBlock *VisitLambdaExpr(LambdaExpr *L); + CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc); + CFGBlock *VisitLogicalOperator(BinaryOperator *B); + std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B, + Stmt *Term, + CFGBlock *TrueBlock, + CFGBlock *FalseBlock); CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); - CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); + CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); - CFGBlock *VisitReturnStmt(ReturnStmt *R); CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E); - CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, - AddStmtChoice asc); + CFGBlock *VisitReturnStmt(ReturnStmt *R); CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); CFGBlock *VisitSwitchStmt(SwitchStmt *S); + CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, + AddStmtChoice asc); CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); CFGBlock *VisitWhileStmt(WhileStmt *W); @@ -772,13 +776,12 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, // If this destructor is marked as a no-return destructor, we need to // create a new block for the destructor which does not have as a successor // anything built thus far: control won't flow out of this block. - QualType Ty; - if ((*I)->getType()->isReferenceType()) { + QualType Ty = (*I)->getType(); + if (Ty->isReferenceType()) { Ty = getReferenceInitTemporaryType(*Context, (*I)->getInit()); - } else { - Ty = Context->getBaseElementType((*I)->getType()); } - + Ty = Context->getBaseElementType(Ty); + const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) Block = createNoReturnBlock(); @@ -1070,9 +1073,6 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { case Stmt::LambdaExprClass: return VisitLambdaExpr(cast<LambdaExpr>(S), asc); - case Stmt::AttributedStmtClass: - return Visit(cast<AttributedStmt>(S)->getSubStmt(), asc); - case Stmt::MemberExprClass: return VisitMemberExpr(cast<MemberExpr>(S), asc); @@ -1166,55 +1166,111 @@ CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, return Visit(U->getSubExpr(), AddStmtChoice()); } -CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, - AddStmtChoice asc) { - if (B->isLogicalOp()) { // && or || - CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); - appendStmt(ConfluenceBlock, B); +CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) { + CFGBlock *ConfluenceBlock = Block ? Block : createBlock(); + appendStmt(ConfluenceBlock, B); - if (badCFG) - return 0; + if (badCFG) + return 0; - // create the block evaluating the LHS - CFGBlock *LHSBlock = createBlock(false); - LHSBlock->setTerminator(B); + return VisitLogicalOperator(B, 0, ConfluenceBlock, ConfluenceBlock).first; +} - // create the block evaluating the RHS - Succ = ConfluenceBlock; - Block = NULL; - CFGBlock *RHSBlock = addStmt(B->getRHS()); +std::pair<CFGBlock*, CFGBlock*> +CFGBuilder::VisitLogicalOperator(BinaryOperator *B, + Stmt *Term, + CFGBlock *TrueBlock, + CFGBlock *FalseBlock) { - if (RHSBlock) { - if (badCFG) - return 0; - } else { - // Create an empty block for cases where the RHS doesn't require - // any explicit statements in the CFG. - RHSBlock = createBlock(); + // Introspect the RHS. If it is a nested logical operation, we recursively + // build the CFG using this function. Otherwise, resort to default + // CFG construction behavior. + Expr *RHS = B->getRHS()->IgnoreParens(); + CFGBlock *RHSBlock, *ExitBlock; + + do { + if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS)) + if (B_RHS->isLogicalOp()) { + llvm::tie(RHSBlock, ExitBlock) = + VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock); + break; + } + + // The RHS is not a nested logical operation. Don't push the terminator + // down further, but instead visit RHS and construct the respective + // pieces of the CFG, and link up the RHSBlock with the terminator + // we have been provided. + ExitBlock = RHSBlock = createBlock(false); + + if (!Term) { + assert(TrueBlock == FalseBlock); + addSuccessor(RHSBlock, TrueBlock); + } + else { + RHSBlock->setTerminator(Term); + TryResult KnownVal = tryEvaluateBool(RHS); + addSuccessor(RHSBlock, KnownVal.isFalse() ? NULL : TrueBlock); + addSuccessor(RHSBlock, KnownVal.isTrue() ? NULL : FalseBlock); } - // Generate the blocks for evaluating the LHS. - Block = LHSBlock; - CFGBlock *EntryLHSBlock = addStmt(B->getLHS()); + Block = RHSBlock; + RHSBlock = addStmt(RHS); + } + while (false); - // See if this is a known constant. - TryResult KnownVal = tryEvaluateBool(B->getLHS()); - if (KnownVal.isKnown() && (B->getOpcode() == BO_LOr)) - KnownVal.negate(); + if (badCFG) + return std::make_pair((CFGBlock*)0, (CFGBlock*)0); + + // Generate the blocks for evaluating the LHS. + Expr *LHS = B->getLHS()->IgnoreParens(); + + if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS)) + if (B_LHS->isLogicalOp()) { + if (B->getOpcode() == BO_LOr) + FalseBlock = RHSBlock; + else + TrueBlock = RHSBlock; - // Now link the LHSBlock with RHSBlock. - if (B->getOpcode() == BO_LOr) { - addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); - addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); - } else { - assert(B->getOpcode() == BO_LAnd); - addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); - addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); + // For the LHS, treat 'B' as the terminator that we want to sink + // into the nested branch. The RHS always gets the top-most + // terminator. + return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock); } - return EntryLHSBlock; + // Create the block evaluating the LHS. + // This contains the '&&' or '||' as the terminator. + CFGBlock *LHSBlock = createBlock(false); + LHSBlock->setTerminator(B); + + Block = LHSBlock; + CFGBlock *EntryLHSBlock = addStmt(LHS); + + if (badCFG) + return std::make_pair((CFGBlock*)0, (CFGBlock*)0); + + // See if this is a known constant. + TryResult KnownVal = tryEvaluateBool(LHS); + + // Now link the LHSBlock with RHSBlock. + if (B->getOpcode() == BO_LOr) { + addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : TrueBlock); + addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : RHSBlock); + } else { + assert(B->getOpcode() == BO_LAnd); + addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); + addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : FalseBlock); } + return std::make_pair(EntryLHSBlock, ExitBlock); +} + + +CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, + AddStmtChoice asc) { + // && or || + if (B->isLogicalOp()) + return VisitLogicalOperator(B); + if (B->getOpcode() == BO_Comma) { // , autoCreateBlock(); appendStmt(Block, B); @@ -1284,7 +1340,7 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) { const FunctionType *FT = Ty->getAs<FunctionType>(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - if (Proto->getExceptionSpecType() != EST_Uninstantiated && + if (!isUnresolvedExceptionSpec(Proto->getExceptionSpecType()) && Proto->isNothrow(Ctx)) return false; } @@ -1435,6 +1491,12 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, if (badCFG) return 0; + // If the condition is a logical '&&' or '||', build a more accurate CFG. + if (BinaryOperator *Cond = + dyn_cast<BinaryOperator>(C->getCond()->IgnoreParens())) + if (Cond->isLogicalOp()) + return VisitLogicalOperator(Cond, C, LHSBlock, RHSBlock).first; + // Create the block that will contain the condition. Block = createBlock(false); @@ -1471,11 +1533,10 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { CFGBlock *B = 0; - // FIXME: Add a reverse iterator for DeclStmt to avoid this extra copy. - typedef SmallVector<Decl*,10> BufTy; - BufTy Buf(DS->decl_begin(), DS->decl_end()); - - for (BufTy::reverse_iterator I = Buf.rbegin(), E = Buf.rend(); I != E; ++I) { + // Build an individual DeclStmt for each decl. + for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(), + E = DS->decl_rend(); + I != E; ++I) { // Get the alignment of the new DeclStmt, padding out to >=8 bytes. unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8 ? 8 : llvm::AlignOf<DeclStmt>::Alignment; @@ -1645,6 +1706,19 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { } } + // Specially handle "if (expr1 || ...)" and "if (expr1 && ...)" by + // having these handle the actual control-flow jump. Note that + // if we introduce a condition variable, e.g. "if (int x = exp1 || exp2)" + // we resort to the old control-flow behavior. This special handling + // removes infeasible paths from the control-flow graph by having the + // control-flow transfer of '&&' or '||' go directly into the then/else + // blocks directly. + if (!I->getConditionVariable()) + if (BinaryOperator *Cond = + dyn_cast<BinaryOperator>(I->getCond()->IgnoreParens())) + if (Cond->isLogicalOp()) + return VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first; + // Now create a new block containing the if statement. Block = createBlock(false); @@ -1795,75 +1869,26 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { SaveAndRestore<JumpTarget> save_break(BreakJumpTarget); BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); - // Because of short-circuit evaluation, the condition of the loop can span - // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that - // evaluate the condition. - CFGBlock *ExitConditionBlock = createBlock(false); - CFGBlock *EntryConditionBlock = ExitConditionBlock; - - // Set the terminator for the "exit" condition block. - ExitConditionBlock->setTerminator(F); - - // Now add the actual condition to the condition block. Because the condition - // itself may contain control-flow, new blocks may be created. - if (Stmt *C = F->getCond()) { - Block = ExitConditionBlock; - EntryConditionBlock = addStmt(C); - if (badCFG) - return 0; - assert(Block == EntryConditionBlock || - (Block == 0 && EntryConditionBlock == Succ)); - - // If this block contains a condition variable, add both the condition - // variable and initializer to the CFG. - if (VarDecl *VD = F->getConditionVariable()) { - if (Expr *Init = VD->getInit()) { - autoCreateBlock(); - appendStmt(Block, F->getConditionVariableDeclStmt()); - EntryConditionBlock = addStmt(Init); - assert(Block == EntryConditionBlock); - } - } - - if (Block) { - if (badCFG) - return 0; - } - } - - // The condition block is the implicit successor for the loop body as well as - // any code above the loop. - Succ = EntryConditionBlock; - - // See if this is a known constant. - TryResult KnownVal(true); - - if (F->getCond()) - KnownVal = tryEvaluateBool(F->getCond()); + CFGBlock *BodyBlock = 0, *TransitionBlock = 0; // Now create the loop body. { assert(F->getBody()); - // Save the current values for Block, Succ, and continue targets. - SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); - SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget); + // Save the current values for Block, Succ, continue and break targets. + SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); + SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget); - // Create a new block to contain the (bottom) of the loop body. - Block = NULL; - - // Loop body should end with destructor of Condition variable (if any). - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F); + // Create an empty block to represent the transition block for looping back + // to the head of the loop. If we have increment code, it will + // go in this block as well. + Block = Succ = TransitionBlock = createBlock(false); + TransitionBlock->setLoopTarget(F); if (Stmt *I = F->getInc()) { // Generate increment code in its own basic block. This is the target of // continue statements. Succ = addStmt(I); - } else { - // No increment code. Create a special, empty, block that is used as the - // target block for "looping back" to the start of the loop. - assert(Succ == EntryConditionBlock); - Succ = Block ? Block : createBlock(); } // Finish up the increment (or empty) block if it hasn't been already. @@ -1874,11 +1899,13 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { Block = 0; } - ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos); + // The starting block for the loop increment is the block that should + // represent the 'loop target' for looping back to the start of the loop. + ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos); + ContinueJumpTarget.block->setLoopTarget(F); - // The starting block for the loop increment is the block that should - // represent the 'loop target' for looping back to the start of the loop. - ContinueJumpTarget.block->setLoopTarget(F); + // Loop body should end with destructor of Condition variable (if any). + addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F); // If body is not a compound statement create implicit scope // and add destructors. @@ -1887,20 +1914,79 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { // Now populate the body block, and in the process create new blocks as we // walk the body of the loop. - CFGBlock *BodyBlock = addStmt(F->getBody()); + BodyBlock = addStmt(F->getBody()); - if (!BodyBlock) - BodyBlock = ContinueJumpTarget.block;//can happen for "for (...;...;...);" + if (!BodyBlock) { + // In the case of "for (...;...;...);" we can have a null BodyBlock. + // Use the continue jump target as the proxy for the body. + BodyBlock = ContinueJumpTarget.block; + } else if (badCFG) return 0; + } + + // Because of short-circuit evaluation, the condition of the loop can span + // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that + // evaluate the condition. + CFGBlock *EntryConditionBlock = 0, *ExitConditionBlock = 0; + + do { + Expr *C = F->getCond(); + + // Specially handle logical operators, which have a slightly + // more optimal CFG representation. + if (BinaryOperator *Cond = + dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : 0)) + if (Cond->isLogicalOp()) { + llvm::tie(EntryConditionBlock, ExitConditionBlock) = + VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor); + break; + } - // This new body block is a successor to our "exit" condition block. + // The default case when not handling logical operators. + EntryConditionBlock = ExitConditionBlock = createBlock(false); + ExitConditionBlock->setTerminator(F); + + // See if this is a known constant. + TryResult KnownVal(true); + + if (C) { + // Now add the actual condition to the condition block. + // Because the condition itself may contain control-flow, new blocks may + // be created. Thus we update "Succ" after adding the condition. + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + + // If this block contains a condition variable, add both the condition + // variable and initializer to the CFG. + if (VarDecl *VD = F->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + appendStmt(Block, F->getConditionVariableDeclStmt()); + EntryConditionBlock = addStmt(Init); + assert(Block == EntryConditionBlock); + } + } + + if (Block && badCFG) + return 0; + + KnownVal = tryEvaluateBool(C); + } + + // Add the loop body entry as a successor to the condition. addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock); - } + // Link up the condition block with the code that follows the loop. (the + // false branch). + addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); - // Link up the condition block with the code that follows the loop. (the - // false branch). - addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + } while (false); + + // Link up the loop-back block to the entry condition block. + addSuccessor(TransitionBlock, EntryConditionBlock); + + // The condition block is the implicit successor for any code above the loop. + Succ = EntryConditionBlock; // If the loop contains initialization, create a new block for those // statements. This block can also contain statements that precede the loop. @@ -2108,74 +2194,30 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { return 0; LoopSuccessor = Block; Block = 0; - } else + } else { LoopSuccessor = Succ; - - // Because of short-circuit evaluation, the condition of the loop can span - // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that - // evaluate the condition. - CFGBlock *ExitConditionBlock = createBlock(false); - CFGBlock *EntryConditionBlock = ExitConditionBlock; - - // Set the terminator for the "exit" condition block. - ExitConditionBlock->setTerminator(W); - - // Now add the actual condition to the condition block. Because the condition - // itself may contain control-flow, new blocks may be created. Thus we update - // "Succ" after adding the condition. - if (Stmt *C = W->getCond()) { - Block = ExitConditionBlock; - EntryConditionBlock = addStmt(C); - // The condition might finish the current 'Block'. - Block = EntryConditionBlock; - - // If this block contains a condition variable, add both the condition - // variable and initializer to the CFG. - if (VarDecl *VD = W->getConditionVariable()) { - if (Expr *Init = VD->getInit()) { - autoCreateBlock(); - appendStmt(Block, W->getConditionVariableDeclStmt()); - EntryConditionBlock = addStmt(Init); - assert(Block == EntryConditionBlock); - } - } - - if (Block) { - if (badCFG) - return 0; - } } - // The condition block is the implicit successor for the loop body as well as - // any code above the loop. - Succ = EntryConditionBlock; - - // See if this is a known constant. - const TryResult& KnownVal = tryEvaluateBool(W->getCond()); + CFGBlock *BodyBlock = 0, *TransitionBlock = 0; // Process the loop body. { assert(W->getBody()); - // Save the current values for Block, Succ, and continue and break targets + // Save the current values for Block, Succ, continue and break targets. SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget), - save_break(BreakJumpTarget); + save_break(BreakJumpTarget); // Create an empty block to represent the transition block for looping back // to the head of the loop. - Block = 0; - assert(Succ == EntryConditionBlock); - Succ = createBlock(); - Succ->setLoopTarget(W); + Succ = TransitionBlock = createBlock(false); + TransitionBlock->setLoopTarget(W); ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos); // All breaks should go to the code following the loop. BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); - // NULL out Block to force lazy instantiation of blocks for the body. - Block = NULL; - // Loop body should end with destructor of Condition variable (if any). addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); @@ -2185,22 +2227,69 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { addLocalScopeAndDtors(W->getBody()); // Create the body. The returned block is the entry to the loop body. - CFGBlock *BodyBlock = addStmt(W->getBody()); + BodyBlock = addStmt(W->getBody()); if (!BodyBlock) BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;" - else if (Block) { - if (badCFG) - return 0; + else if (Block && badCFG) + return 0; + } + + // Because of short-circuit evaluation, the condition of the loop can span + // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that + // evaluate the condition. + CFGBlock *EntryConditionBlock = 0, *ExitConditionBlock = 0; + + do { + Expr *C = W->getCond(); + + // Specially handle logical operators, which have a slightly + // more optimal CFG representation. + if (BinaryOperator *Cond = dyn_cast<BinaryOperator>(C->IgnoreParens())) + if (Cond->isLogicalOp()) { + llvm::tie(EntryConditionBlock, ExitConditionBlock) = + VisitLogicalOperator(Cond, W, BodyBlock, + LoopSuccessor); + break; + } + + // The default case when not handling logical operators. + EntryConditionBlock = ExitConditionBlock = createBlock(false); + ExitConditionBlock->setTerminator(W); + + // Now add the actual condition to the condition block. + // Because the condition itself may contain control-flow, new blocks may + // be created. Thus we update "Succ" after adding the condition. + Block = ExitConditionBlock; + Block = EntryConditionBlock = addStmt(C); + + // If this block contains a condition variable, add both the condition + // variable and initializer to the CFG. + if (VarDecl *VD = W->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + appendStmt(Block, W->getConditionVariableDeclStmt()); + EntryConditionBlock = addStmt(Init); + assert(Block == EntryConditionBlock); + } } + if (Block && badCFG) + return 0; + + // See if this is a known constant. + const TryResult& KnownVal = tryEvaluateBool(C); + // Add the loop body entry as a successor to the condition. addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock); - } + // Link up the condition block with the code that follows the loop. (the + // false branch). + addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); - // Link up the condition block with the code that follows the loop. (the - // false branch). - addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor); + } while(false); + + // Link up the loop-back block to the entry condition block. + addSuccessor(TransitionBlock, EntryConditionBlock); // There can be no more statements in the condition block since we loop back // to this block. NULL out Block to force lazy creation of another block. @@ -3203,8 +3292,8 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { } bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const { - if (const CXXDestructorDecl *cdecl = getDestructorDecl(astContext)) { - QualType ty = cdecl->getType(); + if (const CXXDestructorDecl *decl = getDestructorDecl(astContext)) { + QualType ty = decl->getType(); return cast<FunctionType>(ty)->getNoReturnAttr(); } return false; @@ -3631,8 +3720,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper, const Type* T = VD->getType().getTypePtr(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) T = RT->getPointeeType().getTypePtr(); - else if (const Type *ET = T->getArrayElementTypeNoTypeQual()) - T = ET; + T = T->getBaseElementTypeUnsafe(); OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; OS << " (Implicit destructor)\n"; @@ -3644,11 +3732,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper, } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) { const FieldDecl *FD = ME->getFieldDecl(); - - const Type *T = FD->getType().getTypePtr(); - if (const Type *ET = T->getArrayElementTypeNoTypeQual()) - T = ET; - + const Type *T = FD->getType()->getBaseElementTypeUnsafe(); OS << "this->" << FD->getName(); OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; OS << " (Member object destructor)\n"; |