Index: tests/toolchain/eh_throw_tests.cc |
diff --git a/tests/toolchain/eh_throw_tests.cc b/tests/toolchain/eh_throw_tests.cc |
index 0c0baaca0269caf30d09861bec5a6d516ddc5ed9..c86c40fdb609dd51a9f869f51243e208ccbfd762 100644 |
--- a/tests/toolchain/eh_throw_tests.cc |
+++ b/tests/toolchain/eh_throw_tests.cc |
@@ -328,6 +328,56 @@ void test_setjmp_called_via_invoke() { |
} |
+void allowed_exception_spec() throw(MyException) { |
+ throw MyException(600); |
+} |
+ |
+// Test a case in which an exception propagates through an exception |
+// spec which allows the exception type. |
+void test_exception_spec_allowed() { |
+ bool caught = false; |
+ try { |
+ allowed_exception_spec(); |
+ } catch (MyException &exc) { |
+ assert(exc.value == 600); |
+ caught = true; |
+ } |
+ assert(caught); |
+} |
+ |
+ |
+class VirtualBase { |
+ public: |
+ VirtualBase() : value(321) {} |
+ int value; |
+}; |
+ |
+class VirtualDerived : virtual public VirtualBase {}; |
+ |
+void allowed_exception_spec_virtual_base() throw(VirtualBase) { |
+ throw VirtualDerived(); |
+} |
+ |
+// Test that exception types with virtual base classes work when the |
+// base class appears in an exception spec. |
+// |
+// In this case, the C++ runtime library must dereference the |
+// exception's vtable to find the offset of VirtualBase within |
+// VirtualDerived. That is not the case with non-virtual bases, for |
+// which the std::type_info data is enough to adjust the pointer to |
+// the exception without dereferencing it. |
+void test_exception_spec_allowed_with_virtual_base() { |
+ bool caught = false; |
+ try { |
+ allowed_exception_spec_virtual_base(); |
+ } catch (VirtualBase &exc) { |
+ assert(exc.value == 321); |
+ caught = true; |
+ } |
+ assert(caught); |
+} |
+ |
+ |
class RethrowExc {}; |
bool g_dtor_called; |
@@ -359,7 +409,7 @@ void func_with_exception_spec() throw(RethrowExc) { |
// std::set_unexpected() handler is called. The handler is allowed to |
// throw a new exception that matches the exception spec -- we test |
// this case to avoid aborting execution. |
-void test_exception_spec() { |
+void test_exception_spec_calls_handler() { |
g_dtor_called = false; |
std::unexpected_handler old_unexpected_handler = |
std::set_unexpected(rethrow_unexpected_handler); |
@@ -375,6 +425,33 @@ void test_exception_spec() { |
} |
+void unexpected_handler_throwing_virtual_base() { |
+ throw VirtualDerived(); |
+} |
+ |
+void disallowed_exception_spec_virtual_base() throw(VirtualBase) { |
+ throw MyException(0); |
+} |
+ |
+// Test that if a std::set_unexpected() handler throws an exception |
+// with a virtual base class, this new exception is checked against |
+// the original exception spec correctly. |
+void test_exception_spec_handler_throws_virtual_base() { |
+ std::unexpected_handler old_unexpected_handler = |
+ std::set_unexpected(unexpected_handler_throwing_virtual_base); |
+ bool caught = false; |
+ try { |
+ disallowed_exception_spec_virtual_base(); |
+ } catch (VirtualBase &exc) { |
+ assert(exc.value == 321); |
+ caught = true; |
+ } |
+ assert(caught); |
+ // Clean up. |
+ std::set_unexpected(old_unexpected_handler); |
+} |
+ |
+ |
void rethrowing_unexpected_handler() { |
try { |
throw; |
@@ -576,7 +653,10 @@ int main() { |
RUN_TEST(test_multiple_inheritance_exception_ptr()); |
RUN_TEST(test_throw_catch_nested_in_dtor()); |
RUN_TEST(test_setjmp_called_via_invoke()); |
- RUN_TEST(test_exception_spec()); |
+ RUN_TEST(test_exception_spec_allowed()); |
+ RUN_TEST(test_exception_spec_allowed_with_virtual_base()); |
+ RUN_TEST(test_exception_spec_calls_handler()); |
+ RUN_TEST(test_exception_spec_handler_throws_virtual_base()); |
RUN_TEST(test_exception_spec_rethrow_inside_unexpected_handler()); |
RUN_TEST(test_exception_spec_convert_to_bad_exception()); |
#if SUPPORTS_CXX11 |