diff --git a/libcxx/include/exception b/libcxx/include/exception --- a/libcxx/include/exception +++ b/libcxx/include/exception @@ -306,23 +306,26 @@ (!is_base_of<_To, _From>::value || is_convertible::value)> {}; +template +struct __rethrow_if_nested; + template -inline _LIBCPP_INLINE_VISIBILITY -void -rethrow_if_nested(const _Ep& __e, - __enable_if_t< __can_dynamic_cast<_Ep, nested_exception>::value>* = 0) -{ +struct __rethrow_if_nested<_Ep, true> { + static inline _LIBCPP_INLINE_VISIBILITY void __do_rethrow(const _Ep& __e) { const nested_exception* __nep = dynamic_cast(_VSTD::addressof(__e)); if (__nep) - __nep->rethrow_nested(); -} + __nep->rethrow_nested(); + } +}; template -inline _LIBCPP_INLINE_VISIBILITY -void -rethrow_if_nested(const _Ep&, - __enable_if_t::value>* = 0) -{ +struct __rethrow_if_nested<_Ep, false> { + static inline _LIBCPP_INLINE_VISIBILITY void __do_rethrow(const _Ep&) {} +}; + +template +inline _LIBCPP_INLINE_VISIBILITY void rethrow_if_nested(const _Ep& __e) { + __rethrow_if_nested<_Ep, __can_dynamic_cast<_Ep, nested_exception>::value>::__do_rethrow(__e); } } // namespace std diff --git a/libcxx/test/std/language.support/support.exception/except.nested/call_through_funcptr.pass.cpp b/libcxx/test/std/language.support/support.exception/except.nested/call_through_funcptr.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/support.exception/except.nested/call_through_funcptr.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Check to call std::throw_with_nested or std::rethrow_if_nested +// througn a function pointer. + +// UNSUPPORTED: no-exceptions + +// FIXME: This test fails in MSVC mode due to a stack overflow +// XFAIL: msvc + +#include +#include + +#include "test_macros.h" + +class A { + int data_; + +public: + explicit A(int data) : data_(data) {} + virtual ~A() TEST_NOEXCEPT {} + + friend bool operator==(const A& x, const A& y) { return x.data_ == y.data_; } +}; + +class B : public std::nested_exception, public A { +public: + explicit B(int data) : A(data) {} + B(const B& b) : A(b) {} +}; + +int main(int, char**) { + { + try { + B b(6); + void (*p)(B&) = &std::throw_with_nested; + p(b); + assert(false); + } catch (const std::nested_exception& e) { + assert(e.nested_ptr() == nullptr); + const B& b = dynamic_cast(e); + assert(b == B(6)); + } + } + + { + try { + throw B(5); + } catch (const B& b) { + try { + throw b; + } catch (const A& a) { + try { + void (*p)(const A&) = &std::rethrow_if_nested; + p(a); + assert(false); + } catch (const B& b2) { + assert(b2 == B(5)); + } + } + } + } + return 0; +}