diff --git a/include/exception b/include/exception index 82fdbb1a..600b5483 100644 --- a/include/exception +++ b/include/exception @@ -76,6 +76,7 @@ template void rethrow_if_nested(const E& e); #include <__config> #include +#include #pragma GCC system_header @@ -150,6 +151,83 @@ make_exception_ptr(_E __e) } } +// nested_exception + +class _LIBCPP_EXCEPTION_ABI nested_exception +{ + exception_ptr __ptr_; +public: + nested_exception(); +// nested_exception(const nested_exception&) throw() = default; +// nested_exception& operator=(const nested_exception&) throw() = default; + virtual ~nested_exception(); + + // access functions + void rethrow_nested /*[[noreturn]]*/ () const; + exception_ptr nested_ptr() const {return __ptr_;} +}; + +template +struct __nested + : public _Tp, + public nested_exception +{ + explicit __nested(const _Tp& __t) : _Tp(__t) {} +}; + +template +void +#ifdef _LIBCPP_MOVE +throw_with_nested /*[[noreturn]]*/ (_Tp&& __t, typename enable_if< + is_class::type>::value && + !is_base_of::type>::value + >::type* = 0) +#else +throw_with_nested (_Tp& __t, typename enable_if< + is_class<_Tp>::value && !is_base_of::value + >::type* = 0) +#endif +{ + throw __nested::type>(_STD::forward<_Tp>(__t)); +} + +template +void +#ifdef _LIBCPP_MOVE +throw_with_nested /*[[noreturn]]*/ (_Tp&& __t, typename enable_if< + !is_class::type>::value || + is_base_of::type>::value + >::type* = 0) +#else +throw_with_nested (_Tp& __t, typename enable_if< + !is_class<_Tp>::value || is_base_of::value + >::type* = 0) +#endif +{ + throw _STD::forward<_Tp>(__t); +} + +template +inline +void +rethrow_if_nested(const _E& __e, typename enable_if< + !is_same<_E, nested_exception>::value && + is_convertible<_E*, nested_exception*>::value + >::type* = 0) +{ + static_cast(__e).rethrow_nested(); +} + +template +inline +void +rethrow_if_nested(const _E& __e, typename enable_if< + is_same<_E, nested_exception>::value || + !is_convertible<_E*, nested_exception*>::value + >::type* = 0) +{ +} + } // std #endif // _LIBCPP_EXCEPTION diff --git a/src/exception.cpp b/src/exception.cpp index e48e9c49..9bed6f49 100644 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -142,6 +142,23 @@ exception_ptr& exception_ptr::operator=(const exception_ptr& other) #endif } +nested_exception::nested_exception() + : __ptr_(current_exception()) +{ +} + +nested_exception::~nested_exception() +{ +} + +void +nested_exception::rethrow_nested /*[[noreturn]]*/ () const +{ + if (__ptr_ == nullptr) + terminate(); + rethrow_exception(__ptr_); +} + } // std diff --git a/test/language.support/support.exception/except.nested/assign.pass.cpp b/test/language.support/support.exception/except.nested/assign.pass.cpp new file mode 100644 index 00000000..e4355488 --- /dev/null +++ b/test/language.support/support.exception/except.nested/assign.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class nested_exception; + +// nested_exception& operator=(const nested_exception&) throw() = default; + +#include +#include + +class A +{ + int data_; +public: + explicit A(int data) : data_(data) {} + + friend bool operator==(const A& x, const A& y) {return x.data_ == y.data_;} +}; + +int main() +{ + { + std::nested_exception e0; + std::nested_exception e; + e = e0; + assert(e.nested_ptr() == nullptr); + } + { + try + { + throw A(2); + assert(false); + } + catch (const A&) + { + std::nested_exception e0; + std::nested_exception e; + e = e0; + assert(e.nested_ptr() != nullptr); + try + { + rethrow_exception(e.nested_ptr()); + assert(false); + } + catch (const A& a) + { + assert(a == A(2)); + } + } + } +} diff --git a/test/language.support/support.exception/except.nested/ctor_copy.pass.cpp b/test/language.support/support.exception/except.nested/ctor_copy.pass.cpp new file mode 100644 index 00000000..e8105b23 --- /dev/null +++ b/test/language.support/support.exception/except.nested/ctor_copy.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class nested_exception; + +// nested_exception(const nested_exception&) throw() = default; + +#include +#include + +class A +{ + int data_; +public: + explicit A(int data) : data_(data) {} + + friend bool operator==(const A& x, const A& y) {return x.data_ == y.data_;} +}; + +int main() +{ + { + std::nested_exception e0; + std::nested_exception e = e0; + assert(e.nested_ptr() == nullptr); + } + { + try + { + throw A(2); + assert(false); + } + catch (const A&) + { + std::nested_exception e0; + std::nested_exception e = e0; + assert(e.nested_ptr() != nullptr); + try + { + rethrow_exception(e.nested_ptr()); + assert(false); + } + catch (const A& a) + { + assert(a == A(2)); + } + } + } +} diff --git a/test/language.support/support.exception/except.nested/ctor_default.pass.cpp b/test/language.support/support.exception/except.nested/ctor_default.pass.cpp new file mode 100644 index 00000000..26b45087 --- /dev/null +++ b/test/language.support/support.exception/except.nested/ctor_default.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class nested_exception; + +// nested_exception() throw(); + +#include +#include + +class A +{ + int data_; +public: + explicit A(int data) : data_(data) {} + + friend bool operator==(const A& x, const A& y) {return x.data_ == y.data_;} +}; + +int main() +{ + { + std::nested_exception e; + assert(e.nested_ptr() == nullptr); + } + { + try + { + throw A(2); + assert(false); + } + catch (const A&) + { + std::nested_exception e; + assert(e.nested_ptr() != nullptr); + try + { + rethrow_exception(e.nested_ptr()); + assert(false); + } + catch (const A& a) + { + assert(a == A(2)); + } + } + } +} diff --git a/test/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp b/test/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp new file mode 100644 index 00000000..c3f0222e --- /dev/null +++ b/test/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class nested_exception; + +// template void rethrow_if_nested(const E& e); + +#include +#include +#include + +class A +{ + int data_; +public: + explicit A(int data) : data_(data) {} + + friend bool operator==(const A& x, const A& y) {return x.data_ == y.data_;} +}; + +class B + : public std::nested_exception +{ + int data_; +public: + explicit B(int data) : data_(data) {} + B(const B& b) : data_(b.data_) {} + + friend bool operator==(const B& x, const B& y) {return x.data_ == y.data_;} +}; + +int main() +{ + { + try + { + A a(3); + std::rethrow_if_nested(a); + assert(true); + } + catch (...) + { + assert(false); + } + } + { + try + { + throw B(5); + } + catch (const B& b0) + { + try + { + B b = b0; + std::rethrow_if_nested(b); + assert(false); + } + catch (const B& b) + { + assert(b == B(5)); + } + } + } +} diff --git a/test/language.support/support.exception/except.nested/rethrow_nested.pass.cpp b/test/language.support/support.exception/except.nested/rethrow_nested.pass.cpp new file mode 100644 index 00000000..ff55d11c --- /dev/null +++ b/test/language.support/support.exception/except.nested/rethrow_nested.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class nested_exception; + +// void rethrow_nested [[noreturn]] () const; + +#include +#include +#include + +class A +{ + int data_; +public: + explicit A(int data) : data_(data) {} + + friend bool operator==(const A& x, const A& y) {return x.data_ == y.data_;} +}; + +void go_quietly() +{ + std::exit(0); +} + +int main() +{ + { + try + { + throw A(2); + assert(false); + } + catch (const A&) + { + const std::nested_exception e; + assert(e.nested_ptr() != nullptr); + try + { + e.rethrow_nested(); + assert(false); + } + catch (const A& a) + { + assert(a == A(2)); + } + } + } + { + try + { + std::set_terminate(go_quietly); + const std::nested_exception e; + e.rethrow_nested(); + assert(false); + } + catch (...) + { + assert(false); + } + } +} diff --git a/test/language.support/support.exception/except.nested/throw_with_nested.pass.cpp b/test/language.support/support.exception/except.nested/throw_with_nested.pass.cpp new file mode 100644 index 00000000..35d19162 --- /dev/null +++ b/test/language.support/support.exception/except.nested/throw_with_nested.pass.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class nested_exception; + +// template void throw_with_nested [[noreturn]] (T&& t); + +#include +#include +#include + +class A +{ + int data_; +public: + explicit A(int data) : data_(data) {} + + friend bool operator==(const A& x, const A& y) {return x.data_ == y.data_;} +}; + +class B + : public std::nested_exception +{ + int data_; +public: + explicit B(int data) : data_(data) {} + + friend bool operator==(const B& x, const B& y) {return x.data_ == y.data_;} +}; + +int main() +{ + { + try + { + A a(3); + std::throw_with_nested(a); + assert(false); + } + catch (const A& a) + { + assert(a == A(3)); + } + } + { + try + { + A a(4); + std::throw_with_nested(a); + assert(false); + } + catch (const std::nested_exception& e) + { + assert(e.nested_ptr() == nullptr); + } + } + { + try + { + B b(5); + std::throw_with_nested(b); + assert(false); + } + catch (const B& b) + { + assert(b == B(5)); + } + } + { + try + { + B b(6); + std::throw_with_nested(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 + { + int i = 7; + std::throw_with_nested(i); + assert(false); + } + catch (int i) + { + assert(i == 7); + } + } +}