From 01234bbc1cb94946df8046ad95e17537082b4f71 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 24 Nov 2009 16:43:22 +0000 Subject: [PATCH] Introduce cleanup scopes for "if" statements in two places: - Outside the "if", to ensure that we destroy the condition variable at the end of the "if" statement rather than at the end of the block containing the "if" statement. - Inside the "then" and "else" branches, so that we emit then- or else-local cleanups at the end of the corresponding block when the block is not a compound statement. To make adding these new cleanup scopes easier (and since switch/do/while will all need the same treatment), added the CleanupScope RAII object to introduce a new cleanup scope and make sure it gets cleaned up. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89773 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGStmt.cpp | 28 ++++++++++++--------- lib/CodeGen/CodeGenFunction.h | 25 +++++++++++++++++++ test/CodeGenCXX/condition.cpp | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 test/CodeGenCXX/condition.cpp diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 1c3f357794..51b7cf8a11 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -153,9 +153,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, } // Keep track of the current cleanup stack depth. - size_t CleanupStackDepth = CleanupEntries.size(); - bool OldDidCallStackSave = DidCallStackSave; - DidCallStackSave = false; + CleanupScope Scope(*this); for (CompoundStmt::const_body_iterator I = S.body_begin(), E = S.body_end()-GetLast; I != E; ++I) @@ -185,10 +183,6 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, RV = EmitAnyExpr(cast(LastStmt), AggLoc); } - DidCallStackSave = OldDidCallStackSave; - - EmitCleanupBlocks(CleanupStackDepth); - return RV; } @@ -294,8 +288,10 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // C99 6.8.4.1: The first substatement is executed if the expression compares // unequal to 0. The condition must be a scalar type. + CleanupScope ConditionScope(*this); + if (S.getConditionVariable()) - EmitDecl(*S.getConditionVariable()); + EmitLocalBlockVarDecl(*S.getConditionVariable()); // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. @@ -308,8 +304,10 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // If the skipped block has no labels in it, just emit the executed block. // This avoids emitting dead code and simplifies the CFG substantially. if (!ContainsLabel(Skipped)) { - if (Executed) + if (Executed) { + CleanupScope ExecutedScope(*this); EmitStmt(Executed); + } return; } } @@ -324,14 +322,20 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock); // Emit the 'then' code. - EmitBlock(ThenBlock); - EmitStmt(S.getThen()); + EmitBlock(ThenBlock); + { + CleanupScope ThenScope(*this); + EmitStmt(S.getThen()); + } EmitBranch(ContBlock); // Emit the 'else' code if present. if (const Stmt *Else = S.getElse()) { EmitBlock(ElseBlock); - EmitStmt(Else); + { + CleanupScope ElseScope(*this); + EmitStmt(Else); + } EmitBranch(ContBlock); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index dd26428f81..be1a15ed66 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -165,6 +165,31 @@ public: } }; + /// \brief Enters a new scope for capturing cleanups, all of which will be + /// executed once the scope is exited. + class CleanupScope { + CodeGenFunction& CGF; + size_t CleanupStackDepth; + bool OldDidCallStackSave; + + 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) { + CleanupStackDepth = CGF.CleanupEntries.size(); + OldDidCallStackSave = CGF.DidCallStackSave; + } + + /// \brief Exit this cleanup scope, emitting any accumulated + /// cleanups. + ~CleanupScope() { + CGF.DidCallStackSave = OldDidCallStackSave; + CGF.EmitCleanupBlocks(CleanupStackDepth); + } + }; + /// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup /// blocks that have been added. void EmitCleanupBlocks(size_t OldCleanupStackSize); diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp new file mode 100644 index 0000000000..f8a55d8716 --- /dev/null +++ b/test/CodeGenCXX/condition.cpp @@ -0,0 +1,47 @@ +// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +void *f(); + +template T* g() { + if (T* t = f()) + return t; + + return 0; +} + +void h() { + void *a = g(); +} + +struct X { + X(); + ~X(); + operator bool(); +}; + +struct Y { + Y(); + ~Y(); +}; + +void if_destruct(int z) { + // Verify that the condition variable is destroyed at the end of the + // "if" statement. + // CHECK: call void @_ZN1XC1Ev + // CHECK: call zeroext i1 @_ZN1XcvbEv + if (X x = X()) { + // CHECK: store i32 18 + z = 18; + } + // CHECK: call void @_ZN1XD1Ev + // CHECK: store i32 17 + z = 17; + + // CHECK: call void @_ZN1XC1Ev + if (X x = X()) + Y y; + // CHECK: if.then + // CHECK: call void @_ZN1YC1Ev + // CHECK: call void @_ZN1YD1Ev + // CHECK: if.end + // CHECK: call void @_ZN1XD1Ev +} -- 2.40.0