aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/CFG.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-11-14 01:57:41 +0000
committerTed Kremenek <kremenek@apple.com>2008-11-14 01:57:41 +0000
commit4cb3a855df3b3f8d551565cae9f43939a301ea89 (patch)
treef63037a8f0a90e2c86399924c91f8be087b4767d /lib/AST/CFG.cpp
parent8c9988251cc45bbb2791a0a35d41c31657e68c57 (diff)
Fix CFG construction for ObjCForCollectionStmt: 'element' expression can be anything that evaluates to an lvalue
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59289 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/CFG.cpp')
-rw-r--r--lib/AST/CFG.cpp64
1 files changed, 44 insertions, 20 deletions
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
index 0a349131c2..f8c3c26bb1 100644
--- a/lib/AST/CFG.cpp
+++ b/lib/AST/CFG.cpp
@@ -802,6 +802,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// 1. collection_expression
// T. jump to loop_entry
// loop_entry:
+ // 1. side-effects of element expression
// 1. ObjCForCollectionStmt [performs binding to newVariable]
// T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil]
// TB:
@@ -831,32 +832,55 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
}
else LoopSuccessor = Succ;
- // Build the condition block. The condition has no short-circuit evaluation,
- // so we don't need multiple blocks like other control-flow structures with
- // conditions.
- CFGBlock* ConditionBlock = createBlock(false);
- ConditionBlock->appendStmt(S);
- ConditionBlock->setTerminator(S); // No need to call FinishBlock; 1 stmt
+ // Build the condition blocks.
+ CFGBlock* ExitConditionBlock = createBlock(false);
+ CFGBlock* EntryConditionBlock = ExitConditionBlock;
- // Now create the true branch.
- // Save the current values for the continue and break targets
- SaveAndRestore<CFGBlock*> save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
+ // Set the terminator for the "exit" condition block.
+ ExitConditionBlock->setTerminator(S);
+
+ // The last statement in the block should be the ObjCForCollectionStmt,
+ // which performs the actual binding to 'element' and determines if there
+ // are any more items in the collection.
+ ExitConditionBlock->appendStmt(S);
+ Block = ExitConditionBlock;
- BreakTargetBlock = LoopSuccessor;
- ContinueTargetBlock = ConditionBlock;
- Succ = ConditionBlock;
+ // Walk the 'element' expression to see if there are any side-effects. We
+ // generate new blocks as necesary. We DON'T add the statement by default
+ // to the CFG unless it contains control-flow.
+ EntryConditionBlock = WalkAST(S->getElement(), false);
+ if (Block) { FinishBlock(EntryConditionBlock); Block = 0; }
- CFGBlock* BodyBlock = Visit(S->getBody());
- FinishBlock(BodyBlock);
+ // The condition block is the implicit successor for the loop body as
+ // well as any code above the loop.
+ Succ = EntryConditionBlock;
- // Connect up the condition block
- ConditionBlock->addSuccessor(BodyBlock);
- ConditionBlock->addSuccessor(LoopSuccessor);
+ // Now create the true branch.
+ {
+ // Save the current values for Succ, continue and break targets.
+ SaveAndRestore<CFGBlock*> save_Succ(Succ),
+ save_continue(ContinueTargetBlock), save_break(BreakTargetBlock);
+
+ BreakTargetBlock = LoopSuccessor;
+ ContinueTargetBlock = EntryConditionBlock;
+
+ CFGBlock* BodyBlock = Visit(S->getBody());
+
+ if (!BodyBlock)
+ BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
+ else if (Block)
+ FinishBlock(BodyBlock);
+
+ // This new body block is a successor to our "exit" condition block.
+ ExitConditionBlock->addSuccessor(BodyBlock);
+ }
+ // Link up the condition block with the code that follows the loop.
+ // (the false branch).
+ ExitConditionBlock->addSuccessor(LoopSuccessor);
+
// Now create a prologue block to contain the collection expression.
- Block = 0;
- Succ = ConditionBlock;
+ Block = createBlock();
return addStmt(S->getCollection());
}