From 881fcaec6be08d821de7df42fdbc99779717f59f Mon Sep 17 00:00:00 2001
From: Andrew Kaylor <andrew.kaylor@intel.com>
Date: Tue, 17 Nov 2015 20:13:04 +0000
Subject: [PATCH] [EH] Keep filter clauses for types that have been caught.

The instruction combiner previously removed types from filter clauses in Landing Pad instructions if the type had previously been seen in a catch clause.  This is incorrect and prevents unexpected exception handlers from rethrowing the caught type.

Differential Revision: http://reviews.llvm.org/D14669



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253370 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../InstCombine/InstructionCombining.cpp      | 22 +++++++++++++++----
 .../InstCombine/LandingPadClauses.ll          | 11 ++++++----
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp
index 3ae7f08238b..dbc963a2b35 100644
--- a/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2486,10 +2486,24 @@ Instruction *InstCombiner::visitLandingPadInst(LandingPadInst &LI) {
             SawCatchAll = true;
             break;
           }
-          if (AlreadyCaught.count(TypeInfo))
-            // Already caught by an earlier clause, so having it in the filter
-            // is pointless.
-            continue;
+
+          // Even if we've seen a type in a catch clause, we don't want to
+          // remove it from the filter.  An unexpected type handler may be
+          // set up for a call site which throws an exception of the same
+          // type caught.  In order for the exception thrown by the unexpected
+          // handler to propogate correctly, the filter must be correctly
+          // described for the call site.
+          //
+          // Example:
+          //
+          // void unexpected() { throw 1;}
+          // void foo() throw (int) {
+          //   std::set_unexpected(unexpected);
+          //   try {
+          //     throw 2.0;
+          //   } catch (int i) {}
+          // }
+
           // There is no point in having multiple copies of the same typeinfo in
           // a filter, so only add it if we didn't already.
           if (SeenInFilter.insert(TypeInfo).second)
diff --git a/test/Transforms/InstCombine/LandingPadClauses.ll b/test/Transforms/InstCombine/LandingPadClauses.ll
index a4d77cbe8ef..75050c91bbb 100644
--- a/test/Transforms/InstCombine/LandingPadClauses.ll
+++ b/test/Transforms/InstCombine/LandingPadClauses.ll
@@ -69,9 +69,11 @@ lpad.c:
           filter [1 x i32*] [i32* @T1]
           catch i32* @T2
   unreachable
+; Caught types should not be removed from filters
 ; CHECK: %c = landingpad
-; CHECK-NEXT: @T1
-; CHECK-NEXT: filter [0 x i32*]
+; CHECK-NEXT: catch i32* @T1
+; CHECK-NEXT: filter [1 x i32*] [i32* @T1]
+; CHECK-NEXT: catch i32* @T2 
 ; CHECK-NEXT: unreachable
 
 lpad.d:
@@ -87,9 +89,10 @@ lpad.e:
           catch i32* @T1
           filter [3 x i32*] [i32* @T1, i32* @T2, i32* @T2]
   unreachable
+; Caught types should not be removed from filters
 ; CHECK: %e = landingpad
-; CHECK-NEXT: @T1
-; CHECK-NEXT: filter [1 x i32*] [i32* @T2]
+; CHECK-NEXT: catch i32* @T1
+; CHECK-NEXT: filter [2 x i32*] [i32* @T1, i32* @T2]
 ; CHECK-NEXT: unreachable
 
 lpad.f:
-- 
2.34.1