Fix a subtle bug where the cleanup scope entries had a dangling block reference
- <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
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 91aa885..ff90210 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -175,6 +175,24 @@
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 @@
// 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 @@
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) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 9dbbb25..61b2665 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -339,6 +339,11 @@
/// 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
index 0000000..2d1baa6
--- /dev/null
+++ b/test/CodeGen/rdr-6732143-dangling-block-reference.m
@@ -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 {
+ }
+ }
+}