Index: lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- lib/Transforms/Utils/InlineFunction.cpp +++ lib/Transforms/Utils/InlineFunction.cpp @@ -552,7 +552,8 @@ /// block of the inlined code (the last block is the end of the function), /// and InlineCodeInfo is information about the code that got inlined. static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock, - ClonedCodeInfo &InlinedCodeInfo) { + ClonedCodeInfo &InlinedCodeInfo, + UnwindDestMemoTy &FuncletUnwindMap) { BasicBlock *UnwindDest = II->getUnwindDest(); Function *Caller = FirstNewBlock->getParent(); @@ -584,7 +585,6 @@ // This connects all the instructions which 'unwind to caller' to the invoke // destination. - UnwindDestMemoTy FuncletUnwindMap; for (Function::iterator BB = FirstNewBlock->getIterator(), E = Caller->end(); BB != E; ++BB) { if (auto *CRI = dyn_cast(BB->getTerminator())) { @@ -1712,13 +1712,15 @@ // any call instructions into invoke instructions. This is sensitive to which // funclet pads were top-level in the inlinee, so must be done before // rewriting the "parent pad" links. + UnwindDestMemoTy FuncletUnwindMap; if (auto *II = dyn_cast(TheCall)) { BasicBlock *UnwindDest = II->getUnwindDest(); Instruction *FirstNonPHI = UnwindDest->getFirstNonPHI(); if (isa(FirstNonPHI)) { HandleInlinedLandingPad(II, &*FirstNewBlock, InlinedFunctionInfo); } else { - HandleInlinedEHPad(II, &*FirstNewBlock, InlinedFunctionInfo); + HandleInlinedEHPad(II, &*FirstNewBlock, InlinedFunctionInfo, + FuncletUnwindMap); } } @@ -1727,6 +1729,11 @@ // EHPad. if (CallSiteEHPad) { + Value *CallSiteUnwindDestToken = + getUnwindDestToken(CallSiteEHPad, FuncletUnwindMap); + bool CallSiteEHPadUnwindsToCaller = + !CallSiteUnwindDestToken || + isa(CallSiteUnwindDestToken); for (Function::iterator BB = FirstNewBlock->getIterator(), E = Caller->end(); BB != E; ++BB) { @@ -1763,6 +1770,15 @@ OpBundles.clear(); } + // It is problematic if the inlinee has a cleanupret which unwinds to + // caller and we inline it into a call site which doesn't unwind but into + // an EH pad that does. Such an edge must be dynamically unreachable. + // As such, we replace the cleanupret with unreachable. + if (auto *CleanupRet = dyn_cast(BB->getTerminator())) + if (CleanupRet->unwindsToCaller() && !CallSiteEHPadUnwindsToCaller && + isa(TheCall)) + changeToUnreachable(CleanupRet, /*UseLLVMTrap=*/false); + Instruction *I = BB->getFirstNonPHI(); if (!I->isEHPad()) continue; Index: test/Transforms/Inline/pr26698.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/pr26698.ll @@ -0,0 +1,65 @@ +; RUN: opt -S -inline < %s | FileCheck %s +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc18.0.0" + +declare void @g(i32) + +define void @f() personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @g(i32 0) + to label %invoke.cont unwind label %cs.bb + +invoke.cont: + ret void + +cs.bb: + %cs = catchswitch within none [label %cp.bb] unwind label %cleanup.bb + +cp.bb: + %cpouter1 = catchpad within %cs [i8* null, i32 0, i8* null] + call void @dtor() #1 [ "funclet"(token %cpouter1) ] + catchret from %cpouter1 to label %invoke.cont + +cleanup.bb: + %cpouter2 = cleanuppad within none [] + call void @g(i32 1) [ "funclet"(token %cpouter2) ] + cleanupret from %cpouter2 unwind to caller +} + +declare i32 @__CxxFrameHandler3(...) + +; Function Attrs: nounwind +define internal void @dtor() #1 personality i32 (...)* @__CxxFrameHandler3 { +entry: + invoke void @g(i32 2) + to label %invoke.cont unwind label %ehcleanup1 + +invoke.cont: + ret void + +ehcleanup1: + %cpinner1 = cleanuppad within none [] + invoke void @g(i32 3) [ "funclet" (token %cpinner1) ] + to label %done unwind label %ehcleanup2 +done: + unreachable + +ehcleanup2: + %cpinner2 = cleanuppad within %cpinner1 [] + call void @g(i32 4) [ "funclet" (token %cpinner2) ] + cleanupret from %cpinner2 unwind to caller +} + +; CHECK-LABEL: define void @f( + +; CHECK: %[[cs:.*]] = catchswitch within none + +; CHECK: %[[cpouter1:.*]] = catchpad within %[[cs]] + +; CHECK: %[[cpinner1:.*]] = cleanuppad within %[[cpouter1]] + +; CHECK: %[[cpinner2:.*]] = cleanuppad within %[[cpinner1]] +; CHECK-NEXT: call void @g(i32 4) #0 [ "funclet"(token %[[cpinner2]]) ] +; CHECK-NEXT: unreachable + +attributes #1 = { nounwind }