]> granicus.if.org Git - clang/commitdiff
Implement proper cleanup semantics for condition variables in for
authorDouglas Gregor <dgregor@apple.com>
Wed, 25 Nov 2009 01:51:31 +0000 (01:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 25 Nov 2009 01:51:31 +0000 (01:51 +0000)
statements, e.g.,

  for(; X x = X(); ) { ... }

Daniel or Anders, please review!

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

lib/CodeGen/CGStmt.cpp
test/CodeGenCXX/condition.cpp

index be571fac717bb040dbfca1d36b6a38cdd271e1c6..bbd546261800d942c2ba452620140dd76d02b20f 100644 (file)
@@ -488,27 +488,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
   // Start the loop with a block that tests the condition.
   llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
   llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
+  llvm::BasicBlock *IncBlock = 0;
+  llvm::BasicBlock *CondCleanup = 0;
+  llvm::BasicBlock *EffectiveExitBlock = AfterFor;
   EmitBlock(CondBlock);
 
-  // Create a cleanup scope 
+  // Create a cleanup scope for the condition variable cleanups.
   CleanupScope ConditionScope(*this);
   
-  // Evaluate the condition if present.  If not, treat it as a
-  // non-zero-constant according to 6.8.5.3p2, aka, true.
+  llvm::Value *BoolCondVal = 0;
   if (S.getCond()) {
     // If the for statement has a condition scope, emit the local variable
     // declaration.
-    // FIXME: The cleanup points for this are all wrong.
-    if (S.getConditionVariable())
+    if (S.getConditionVariable()) {
       EmitLocalBlockVarDecl(*S.getConditionVariable());
+      
+      if (ConditionScope.requiresCleanups()) {
+        CondCleanup = createBasicBlock("for.cond.cleanup");
+        EffectiveExitBlock = CondCleanup;
+      }
+    }
     
     // As long as the condition is true, iterate the loop.
     llvm::BasicBlock *ForBody = createBasicBlock("for.body");
 
     // C99 6.8.5p2/p4: The first substatement is executed if the expression
     // compares unequal to 0.  The condition must be a scalar type.
-    EmitBranchOnBoolExpr(S.getCond(), ForBody, AfterFor);
+    BoolCondVal = EvaluateExprAsBool(S.getCond());
+    Builder.CreateCondBr(BoolCondVal, ForBody, EffectiveExitBlock);
 
     EmitBlock(ForBody);
   } else {
@@ -520,7 +527,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
   // condition as the continue block.
   llvm::BasicBlock *ContinueBlock;
   if (S.getInc())
-    ContinueBlock = createBasicBlock("for.inc");
+    ContinueBlock = IncBlock = createBasicBlock("for.inc");
   else
     ContinueBlock = CondBlock;
 
@@ -533,18 +540,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
     DI->setLocation(S.getSourceRange().getBegin());
     DI->EmitRegionStart(CurFn, Builder);
   }
-  EmitStmt(S.getBody());
+
+  {
+    // Create a separate cleanup scope for the body, in case it is not
+    // a compound statement.
+    CleanupScope BodyScope(*this);
+    EmitStmt(S.getBody());
+  }
 
   BreakContinueStack.pop_back();
 
   // If there is an increment, emit it next.
   if (S.getInc()) {
-    EmitBlock(ContinueBlock);
+    EmitBlock(IncBlock);
     EmitStmt(S.getInc());
   }
 
   // Finally, branch back up to the condition for the next iteration.
-  EmitBranch(CondBlock);
+  if (CondCleanup) {
+    // Branch to the cleanup block.
+    EmitBranch(CondCleanup);
+
+    // Emit the cleanup block, which branches back to the loop body or
+    // outside of the for statement once it is done.
+    EmitBlock(CondCleanup);
+    ConditionScope.ForceCleanup();
+    Builder.CreateCondBr(BoolCondVal, CondBlock, AfterFor);
+  } else
+    EmitBranch(CondBlock);
   if (DI) {
     DI->setLocation(S.getSourceRange().getEnd());
     DI->EmitRegionEnd(CurFn, Builder);
index de33668e08735a50ca3c0da65838b5e2627ff201..a6b74efff3892f1188407c62fc144c5e30ea57b6 100644 (file)
@@ -94,11 +94,16 @@ void for_destruct(int z) {
   // CHECK: define void @_Z12for_destruct
   // CHECK: call void @_ZN1YC1Ev
   for(Y y = Y(); X x = X(); ++z)
+    // CHECK: for.cond:
+    // CHECK: call void @_ZN1XC1Ev
     // CHECK: for.body:
     // CHECK: store i32 23
     z = 23;
     // CHECK: for.inc:
-  // CHECK: for.end
+    // CHECK: br label %for.cond.cleanup
+    // CHECK: for.cond.cleanup:
+    // CHECK: call void @_ZN1XD1Ev
+  // CHECK: for.end:
   // CHECK: call void @_ZN1YD1Ev
   // CHECK: store i32 24
   z = 24;