Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2481,9 +2481,31 @@ SawCatchAll = true; break; } - if (AlreadyCaught.count(TypeInfo)) + // Even if we've seen a type in a catch clause, we don't want to + // remove it from the filter if the personality is GNU_CXX or + // GNU_ObjC. In order for __cxa_call_unexpected to work correctly, + // it needs to know about all filtered types. A function that catches + // int and also filters int will go to the unexpected type handler if + // another type of exception is thrown. If the unexpected type handler + // throws an int exception, the libstdc++ library will call terminate + // unless it sees int in the filter list for the call site. + // + // Example: + // + // void unexpected() { throw 1;} + // void foo() throw (int) { + // std::set_unexpected(unexpected); + // try { + // throw 2.0; + // } catch (int i) {} + // } + // + // FIXME: Is this an issue for other personality types? + if (Personality != EHPersonality::GNU_CXX && + Personality != EHPersonality::GNU_ObjC && + AlreadyCaught.count(TypeInfo)) // Already caught by an earlier clause, so having it in the filter - // is pointless. + // is pointless unless the personality is one we excluded above. continue; // There is no point in having multiple copies of the same typeinfo in // a filter, so only add it if we didn't already. Index: test/Transforms/InstCombine/LandingPadClauses.ll =================================================================== --- test/Transforms/InstCombine/LandingPadClauses.ll +++ test/Transforms/InstCombine/LandingPadClauses.ll @@ -145,6 +145,12 @@ invoke void @bar() to label %cont.d unwind label %lpad.d cont.d: + invoke void @bar() + to label %cont.e unwind label %lpad.e +cont.e: + invoke void @bar() + to label %cont.f unwind label %lpad.f +cont.f: ret void lpad.a: @@ -180,6 +186,30 @@ ; CHECK: %d = landingpad ; CHECK-NEXT: null ; CHECK-NEXT: unreachable + +lpad.e: + %e = landingpad { i8*, i32 } + catch i32* @T1 + filter [1 x i32*] [i32* @T1] + catch i32* @T2 + unreachable +; Caught types should not be removed from filters for GNU_CXX +; CHECK: %e = landingpad +; CHECK-NEXT: catch i32* @T1 +; CHECK-NEXT: filter [1 x i32*] [i32* @T1] +; CHECK-NEXT: catch i32* @T2 +; CHECK-NEXT: unreachable + +lpad.f: + %f = landingpad { i8*, i32 } + catch i32* @T1 + filter [3 x i32*] [i32* @T1, i32* @T2, i32* @T2] + unreachable +; Caught types should not be removed from filters for GNU_CXX +; CHECK: %f = landingpad +; CHECK-NEXT: @T1 +; CHECK-NEXT: filter [2 x i32*] [i32* @T1, i32* @T2] +; CHECK-NEXT: unreachable } define void @foo_objc() personality i32 (i32, i64, i8*, i8*)* @__objc_personality_v0 { @@ -196,6 +226,12 @@ invoke void @bar() to label %cont.d unwind label %lpad.d cont.d: + invoke void @bar() + to label %cont.e unwind label %lpad.e +cont.e: + invoke void @bar() + to label %cont.f unwind label %lpad.f +cont.f: ret void lpad.a: @@ -231,6 +267,30 @@ ; CHECK: %d = landingpad ; CHECK-NEXT: null ; CHECK-NEXT: unreachable + +lpad.e: + %e = landingpad { i8*, i32 } + catch i32* @T1 + filter [1 x i32*] [i32* @T1] + catch i32* @T2 + unreachable +; Caught types should not be removed from filters for ObjC +; CHECK: %e = landingpad +; CHECK-NEXT: catch i32* @T1 +; CHECK-NEXT: filter [1 x i32*] [i32* @T1] +; CHECK-NEXT: catch i32* @T2 +; CHECK-NEXT: unreachable + +lpad.f: + %f = landingpad { i8*, i32 } + catch i32* @T1 + filter [3 x i32*] [i32* @T1, i32* @T2, i32* @T2] + unreachable +; Caught types should not be removed from filters for ObjC +; CHECK: %f = landingpad +; CHECK-NEXT: @T1 +; CHECK-NEXT: filter [2 x i32*] [i32* @T1, i32* @T2] +; CHECK-NEXT: unreachable } define void @foo_seh() personality i32 (...)* @__C_specific_handler {