Fix a subtle bug where the cleanup scope entries had a dangling block reference
authorDaniel Dunbar <daniel@zuster.org>
Wed, 1 Apr 2009 04:37:47 +0000 (04:37 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Wed, 1 Apr 2009 04:37:47 +0000 (04:37 +0000)
 - <rdar://problem/6732143> Crash when generating @synchronize for
   zero-cost exception

 - Thanks to Anders for helping track down the problem.

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

lib/CodeGen/CGStmt.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGen/rdr-6732143-dangling-block-reference.m [new file with mode: 0644]

index 91aa88569e389447a75e3e5e4a2c3e219bcf02fb..ff9021012611b781c58bda3eef44536659cd7a57 100644 (file)
@@ -175,6 +175,24 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
   return RV;
 }
 
+void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
+  llvm::BranchInst *BI = dyn_cast<llvm::BranchInst>(BB->getTerminator());
+  
+  // If there is a cleanup stack, then we it isn't worth trying to
+  // simplify this block (we would need to remove it from the scope map
+  // and cleanup entry).
+  if (!CleanupEntries.empty())
+    return;
+
+  // Can only simplify direct branches.
+  if (!BI || !BI->isUnconditional())
+    return;
+
+  BB->replaceAllUsesWith(BI->getSuccessor(0));
+  BI->eraseFromParent();
+  BB->eraseFromParent();
+}
+
 void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
   // Fall out of the current block (if necessary).
   EmitBranch(BB);
@@ -339,13 +357,10 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
   // Emit the exit block.
   EmitBlock(ExitBlock, true);
 
-  // If LoopHeader is a simple forwarding block then eliminate it.
-  if (!EmitBoolCondBranch 
-      && &LoopHeader->front() == LoopHeader->getTerminator()) {
-    LoopHeader->replaceAllUsesWith(LoopBody);
-    LoopHeader->getTerminator()->eraseFromParent();
-    LoopHeader->eraseFromParent();
-  }
+  // The LoopHeader typically is just a branch if we skipped emitting
+  // a branch, try to erase it.
+  if (!EmitBoolCondBranch)
+    SimplifyForwardingBlocks(LoopHeader);
 }
 
 void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
@@ -387,14 +402,12 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
     Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo);
   
   // Emit the exit block.
-  EmitBlock(AfterDo, true);
+  EmitBlock(AfterDo);
 
-  // If DoCond is a simple forwarding block then eliminate it.
-  if (!EmitBoolCondBranch && &DoCond->front() == DoCond->getTerminator()) {
-    DoCond->replaceAllUsesWith(AfterDo);
-    DoCond->getTerminator()->eraseFromParent();
-    DoCond->eraseFromParent();
-  }
+  // The DoCond block typically is just a branch if we skipped
+  // emitting a branch, try to erase it.
+  if (!EmitBoolCondBranch)
+    SimplifyForwardingBlocks(DoCond);
 }
 
 void CodeGenFunction::EmitForStmt(const ForStmt &S) {
index 9dbbb25b220036938281b76ee4c7859e794b5860..61b266542898c20ab0ab7bf213e922013fae7b68 100644 (file)
@@ -339,6 +339,11 @@ public:
   /// label maps to.
   llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S);
 
+  /// SimplifyForwardingBlocks - If the given basic block is only a
+  /// branch to another basic block, simplify it. This assumes that no
+  /// other code could potentially reference the basic block.
+  void SimplifyForwardingBlocks(llvm::BasicBlock *BB);
+
   /// EmitBlock - Emit the given block \arg BB and set it as the insert point,
   /// adding a fall-through branch from the current insert block if
   /// necessary. It is legal to call this function even if there is no current
diff --git a/test/CodeGen/rdr-6732143-dangling-block-reference.m b/test/CodeGen/rdr-6732143-dangling-block-reference.m
new file mode 100644 (file)
index 0000000..2d1baa6
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm %s -o -
+
+void f0(id x) {
+  @synchronized (x) {      
+    do { ; } while(0);
+    @try {
+    } @finally {
+    }
+  }
+}