A cleanup can have paths which unwind or end up in unreachable.
If there is an unreachable path *and* a path which unwinds to caller,
we would mistakenly inject an unwind path to a catchswitch on the
unreachable path. This results in a verifier assertion firing because
the cleanup unwinds to two different places: to the caller and to the
catchswitch.
This occured because we used getCleanupRetUnwindDest to determine if the
cleanuppad had no cleanuprets.
This is incorrect, getCleanupRetUnwindDest returns null for cleanuprets
which unwind to caller.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@258651
91177308-0d34-0410-b5e6-
96231b3b80d8
if (!CleanupPad)
continue;
// Skip over any cleanups have unwind targets, they do not need this.
- if (getCleanupRetUnwindDest(CleanupPad) != nullptr)
+ if (any_of(CleanupPad->users(),
+ [](const User *U) { return isa<CleanupReturnInst>(U); }))
continue;
// Walk the blocks within the cleanup which end in 'unreachable'.
// We will replace the unreachable instruction with a cleanupret;
unreachable
}
+; CHECK-LABEL: @test2(
+define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ invoke void @f()
+ to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:
+ unreachable
+
+ehcleanup:
+ %cp = cleanuppad within none []
+ br i1 %B, label %ret, label %if.then
+
+if.then:
+ call void @exit(i32 1) [ "funclet"(token %cp) ]
+ unreachable
+
+ret:
+ cleanupret from %cp unwind to caller
+}
+
+; CHECK: call void @exit(i32 1) [ "funclet"(token %cp) ]
+; CHECK-NEXT: unreachable
+
declare void @f()
declare void @exit(i32) nounwind noreturn