[cfe-commits] r89800 - in /cfe/trunk: include/clang/AST/Stmt.h lib/CodeGen/CGStmt.cpp lib/CodeGen/CodeGenFunction.h lib/Frontend/PCHReaderStmt.cpp lib/Frontend/PCHWriterStmt.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h test/CodeGenCXX/condition.cpp

Douglas Gregor dgregor at apple.com
Tue Nov 24 13:15:45 PST 2009


Author: dgregor
Date: Tue Nov 24 15:15:44 2009
New Revision: 89800

URL: http://llvm.org/viewvc/llvm-project?rev=89800&view=rev
Log:
Clean up the AST for while loops and fix several problems with
cleanups for while loops: 

1) Make sure that we destroy the condition variable of a while statement each time through the loop for, e.g.,

   while (shared_ptr<WorkInt> p = getWorkItem()) {
         // ...
         }

2) Make sure that we always enter a new cleanup scope for the body of the while loop, even when there is no compound expression, e.g.,

   while (blah)
     RAIIObject raii(blah+1);


Modified:
    cfe/trunk/include/clang/AST/Stmt.h
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
    cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/CodeGenCXX/condition.cpp

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Tue Nov 24 15:15:44 2009
@@ -750,10 +750,13 @@
 ///
 class WhileStmt : public Stmt {
   enum { COND, BODY, END_EXPR };
+  VarDecl *Var;
   Stmt* SubExprs[END_EXPR];
   SourceLocation WhileLoc;
 public:
-  WhileStmt(Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) {
+  WhileStmt(VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL)
+    : Stmt(WhileStmtClass), Var(Var) 
+  {
     SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
     SubExprs[BODY] = body;
     WhileLoc = WL;
@@ -762,6 +765,17 @@
   /// \brief Build an empty while statement.
   explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { }
 
+  /// \brief Retrieve the variable declared in this "while" statement, if any.
+  ///
+  /// In the following example, "x" is the condition variable.
+  /// \code
+  /// while (int x = random()) {
+  ///   // ...
+  /// }
+  /// \endcode
+  VarDecl *getConditionVariable() const { return Var; }
+  void setConditionVariable(VarDecl *V) { Var = V; }
+
   Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
   const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
   void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Tue Nov 24 15:15:44 2009
@@ -353,15 +353,37 @@
   // body of the loop.
   llvm::BasicBlock *ExitBlock = createBasicBlock("while.end");
   llvm::BasicBlock *LoopBody  = createBasicBlock("while.body");
+  llvm::BasicBlock *CleanupBlock = 0;
+  llvm::BasicBlock *EffectiveExitBlock = ExitBlock;
 
   // Store the blocks to use for break and continue.
   BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader));
 
+  // C++ [stmt.while]p2:
+  //   When the condition of a while statement is a declaration, the
+  //   scope of the variable that is declared extends from its point
+  //   of declaration (3.3.2) to the end of the while statement.
+  //   [...]
+  //   The object created in a condition is destroyed and created
+  //   with each iteration of the loop.
+  CleanupScope ConditionScope(*this);
+
+  if (S.getConditionVariable()) {
+    EmitLocalBlockVarDecl(*S.getConditionVariable());
+
+    // If this condition variable requires cleanups, create a basic
+    // block to handle those cleanups.
+    if (ConditionScope.requiresCleanups()) {
+      CleanupBlock = createBasicBlock("while.cleanup");
+      EffectiveExitBlock = CleanupBlock;
+    }
+  }
+  
   // Evaluate the conditional in the while header.  C99 6.8.5.1: The
   // evaluation of the controlling expression takes place before each
   // execution of the loop body.
   llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-
+   
   // while(1) is common, avoid extra exit blocks.  Be sure
   // to correctly handle break/continue though.
   bool EmitBoolCondBranch = true;
@@ -371,23 +393,39 @@
 
   // As long as the condition is true, go to the loop body.
   if (EmitBoolCondBranch)
-    Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
-
+    Builder.CreateCondBr(BoolCondVal, LoopBody, EffectiveExitBlock);
+ 
   // Emit the loop body.
-  EmitBlock(LoopBody);
-  EmitStmt(S.getBody());
+  {
+    CleanupScope BodyScope(*this);
+    EmitBlock(LoopBody);
+    EmitStmt(S.getBody());
+  }
 
   BreakContinueStack.pop_back();
 
-  // Cycle to the condition.
-  EmitBranch(LoopHeader);
+  if (CleanupBlock) {
+    // If we have a cleanup block, jump there to perform cleanups
+    // before looping.
+    EmitBranch(CleanupBlock);
+
+    // Emit the cleanup block, performing cleanups for the condition
+    // and then jumping to either the loop header or the exit block.
+    EmitBlock(CleanupBlock);
+    ConditionScope.ForceCleanup();
+    Builder.CreateCondBr(BoolCondVal, LoopHeader, ExitBlock);
+  } else {
+    // Cycle to the condition.
+    EmitBranch(LoopHeader);
+  }
 
   // Emit the exit block.
   EmitBlock(ExitBlock, true);
 
+
   // The LoopHeader typically is just a branch if we skipped emitting
   // a branch, try to erase it.
-  if (!EmitBoolCondBranch)
+  if (!EmitBoolCondBranch && !CleanupBlock)
     SimplifyForwardingBlocks(LoopHeader);
 }
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Nov 24 15:15:44 2009
@@ -171,13 +171,16 @@
     CodeGenFunction& CGF;
     size_t CleanupStackDepth;
     bool OldDidCallStackSave;
+    bool PerformCleanup;
 
     CleanupScope(const CleanupScope &); // DO NOT IMPLEMENT
     CleanupScope &operator=(const CleanupScope &); // DO NOT IMPLEMENT
 
   public:
     /// \brief Enter a new cleanup scope.
-    explicit CleanupScope(CodeGenFunction &CGF) : CGF(CGF) {
+    explicit CleanupScope(CodeGenFunction &CGF) 
+      : CGF(CGF), PerformCleanup(true) 
+    {
       CleanupStackDepth = CGF.CleanupEntries.size();
       OldDidCallStackSave = CGF.DidCallStackSave;
     }
@@ -185,8 +188,24 @@
     /// \brief Exit this cleanup scope, emitting any accumulated
     /// cleanups.
     ~CleanupScope() {
+      if (PerformCleanup) {
+        CGF.DidCallStackSave = OldDidCallStackSave;
+        CGF.EmitCleanupBlocks(CleanupStackDepth);
+      }
+    }
+
+    /// \brief Determine whether this scope requires any cleanups.
+    bool requiresCleanups() const {
+      return CGF.CleanupEntries.size() > CleanupStackDepth;
+    }
+
+    /// \brief Force the emission of cleanups now, instead of waiting
+    /// until this object is destroyed.
+    void ForceCleanup() {
+      assert(PerformCleanup && "Already forced cleanup");
       CGF.DidCallStackSave = OldDidCallStackSave;
       CGF.EmitCleanupBlocks(CleanupStackDepth);
+      PerformCleanup = false;
     }
   };
 

Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Tue Nov 24 15:15:44 2009
@@ -210,6 +210,7 @@
 
 unsigned PCHStmtReader::VisitWhileStmt(WhileStmt *S) {
   VisitStmt(S);
+  S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
   S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2]));
   S->setBody(StmtStack.back());
   S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));

Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Tue Nov 24 15:15:44 2009
@@ -193,6 +193,7 @@
 
 void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) {
   VisitStmt(S);
+  Writer.AddDeclRef(S->getConditionVariable(), Record);
   Writer.WriteSubStmt(S->getCond());
   Writer.WriteSubStmt(S->getBody());
   Writer.AddSourceLocation(S->getWhileLoc(), Record);

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Nov 24 15:15:44 2009
@@ -720,6 +720,15 @@
   Expr *condExpr = CondArg.takeAs<Expr>();
   assert(condExpr && "ActOnWhileStmt(): missing expression");
 
+  VarDecl *ConditionVar = 0;
+  if (CXXConditionDeclExpr *Cond = dyn_cast<CXXConditionDeclExpr>(condExpr)) {
+    ConditionVar = Cond->getVarDecl();
+    condExpr = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar,
+                                   ConditionVar->getLocation(), 
+                                 ConditionVar->getType().getNonReferenceType());
+    // FIXME: Leaks the old condExpr
+  }
+
   if (CheckBooleanCondition(condExpr, WhileLoc)) {
     CondArg = condExpr;
     return StmtError();
@@ -729,7 +738,8 @@
   DiagnoseUnusedExprResult(bodyStmt);
 
   CondArg.release();
-  return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc));
+  return Owned(new (Context) WhileStmt(ConditionVar, condExpr, bodyStmt, 
+                                       WhileLoc));
 }
 
 Action::OwningStmtResult

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Nov 24 15:15:44 2009
@@ -3139,7 +3139,18 @@
 Sema::OwningStmtResult
 TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
   // Transform the condition
-  OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+  OwningExprResult Cond(SemaRef);
+  VarDecl *ConditionVar = 0;
+  if (S->getConditionVariable()) {
+    ConditionVar 
+      = cast_or_null<VarDecl>(
+                   getDerived().TransformDefinition(S->getConditionVariable()));
+    if (!ConditionVar)
+      return SemaRef.StmtError();
+    
+    Cond = getSema().CheckConditionVariable(ConditionVar);
+  } else
+    Cond = getDerived().TransformExpr(S->getCond());
   if (Cond.isInvalid())
     return SemaRef.StmtError();
 

Modified: cfe/trunk/test/CodeGenCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/condition.cpp?rev=89800&r1=89799&r2=89800&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/condition.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/condition.cpp Tue Nov 24 15:15:44 2009
@@ -69,3 +69,23 @@
   // CHECK: store i32 20
   z = 20;
 }
+
+int foo();
+
+void while_destruct(int z) {
+  // CHECK: define void @_Z14while_destructi
+  // CHECK: while.cond: 
+  while (X x = X()) {
+    // CHECK: call void @_ZN1XC1Ev
+
+    // CHECK: while.body:
+    // CHECK: store i32 21
+    z = 21;
+
+    // CHECK: while.cleanup:
+    // CHECK: call void @_ZN1XD1Ev
+  }
+  // CHECK: while.end
+  // CHECK: store i32 22
+  z = 22;
+}





More information about the cfe-commits mailing list