Index: llvm/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -1376,10 +1376,38 @@ !SCCNodes.contains(CB->getCalledFunction()); } +static bool canUnwindPastLandingPad(const LandingPadInst *LP) { + // Because phase one unwinding skips cleanup landingpads, we effectively + // unwind past this frame, and callers need to have valid unwind info. + if (LP->isCleanup()) + return true; + + for (unsigned I = 0; I < LP->getNumClauses(); ++I) { + Constant *Clause = LP->getClause(I); + // catch ptr null catches all exceptions. + if (LP->isCatch(I) && isa(Clause)) + return false; + // filter [0 x ptr] catches all exceptions. + if (LP->isFilter(I) && Clause->getType()->getArrayNumElements() == 0) + return false; + } + + // May catch only some subset of exceptions, in which case other exceptions + // will continue unwinding. + return true; +} + /// Helper for NoUnwind inference predicate InstrBreaksAttribute. static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes) { - if (!I.mayThrow()) + if (!I.mayThrow()) { + if (auto *LP = dyn_cast(&I)) + return canUnwindPastLandingPad(LP); + // Treat cleanuppad as unwinding, for the same reasons as cleanup + // landingpad. + if (isa(&I)) + return true; return false; + } if (const auto *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { // I is a may-throw call to a function inside our SCC. This doesn't Index: llvm/test/Transforms/FunctionAttrs/nounwind.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/nounwind.ll +++ llvm/test/Transforms/FunctionAttrs/nounwind.ll @@ -130,7 +130,7 @@ @catch_ty = external global ptr define void @catch_specific_landingpad() personality ptr @__gxx_personality_v0 { -; CHECK: Function Attrs: noreturn nounwind +; CHECK: Function Attrs: noreturn ; CHECK-LABEL: define {{[^@]+}}@catch_specific_landingpad ; CHECK-SAME: () #[[ATTR3:[0-9]+]] personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: invoke void @do_throw() @@ -159,7 +159,7 @@ define void @catch_all_landingpad() personality ptr @__gxx_personality_v0 { ; CHECK: Function Attrs: noreturn nounwind ; CHECK-LABEL: define {{[^@]+}}@catch_all_landingpad -; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 { +; CHECK-SAME: () #[[ATTR4:[0-9]+]] personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: invoke void @do_throw() ; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]] ; CHECK: lpad: @@ -184,7 +184,7 @@ } define void @filter_specific_landingpad() personality ptr @__gxx_personality_v0 { -; CHECK: Function Attrs: noreturn nounwind +; CHECK: Function Attrs: noreturn ; CHECK-LABEL: define {{[^@]+}}@filter_specific_landingpad ; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: invoke void @do_throw() @@ -213,7 +213,7 @@ define void @filter_none_landingpad() personality ptr @__gxx_personality_v0 { ; CHECK: Function Attrs: noreturn nounwind ; CHECK-LABEL: define {{[^@]+}}@filter_none_landingpad -; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 { +; CHECK-SAME: () #[[ATTR4]] personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: invoke void @do_throw() ; CHECK-NEXT: to label [[UNREACHABLE:%.*]] unwind label [[LPAD:%.*]] ; CHECK: lpad: @@ -238,7 +238,7 @@ } define void @cleanup_landingpad() personality ptr @__gxx_personality_v0 { -; CHECK: Function Attrs: noreturn nounwind +; CHECK: Function Attrs: noreturn ; CHECK-LABEL: define {{[^@]+}}@cleanup_landingpad ; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: invoke void @do_throw() @@ -265,7 +265,7 @@ } define void @cleanuppad() personality ptr @__gxx_personality_v0 { -; CHECK: Function Attrs: noreturn nounwind +; CHECK: Function Attrs: noreturn ; CHECK-LABEL: define {{[^@]+}}@cleanuppad ; CHECK-SAME: () #[[ATTR3]] personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: invoke void @do_throw()