]> granicus.if.org Git - clang/commitdiff
Fix CFG construction for ObjCForCollectionStmt: 'element' expression can be anything...
authorTed Kremenek <kremenek@apple.com>
Fri, 14 Nov 2008 01:57:41 +0000 (01:57 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 14 Nov 2008 01:57:41 +0000 (01:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59289 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/CFG.cpp

index 0a349131c2fcd10bfa4b8d60ed7170b8857ddee8..f8c3c26bb110a599711ce17fe9a632b2462e618f 100644 (file)
@@ -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());
 }