]> granicus.if.org Git - clang/commitdiff
Introduce cleanup scopes for "if" statements in two places:
authorDouglas Gregor <dgregor@apple.com>
Tue, 24 Nov 2009 16:43:22 +0000 (16:43 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 24 Nov 2009 16:43:22 +0000 (16:43 +0000)
  - 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
lib/CodeGen/CodeGenFunction.h
test/CodeGenCXX/condition.cpp [new file with mode: 0644]

index 1c3f35779471802b1f581c978b483711c6869c1d..51b7cf8a112d3f329cc331f715177a71c724d733 100644 (file)
@@ -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<Expr>(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);
   }
 
index dd26428f8190fdbef0f856eff0aebb4fef1ec3c4..be1a15ed6651a1d32fc45e64535cac3e1fe8593a 100644 (file)
@@ -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 (file)
index 0000000..f8a55d8
--- /dev/null
@@ -0,0 +1,47 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+void *f();
+
+template <typename T> T* g() {
+ if (T* t = f())
+   return t;
+
+ return 0;
+}
+
+void h() {
+ void *a = g<void>();
+}
+
+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
+}