[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