diff options
8 files changed, 512 insertions, 0 deletions
diff --git a/libcxx/include/exception b/libcxx/include/exception index 82fdbb1a37c..600b54838b2 100644 --- a/libcxx/include/exception +++ b/libcxx/include/exception @@ -76,6 +76,7 @@ template <class E> void rethrow_if_nested(const E& e); #include <__config> #include <cstddef> +#include <type_traits> #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 <class _Tp> +struct __nested + : public _Tp, + public nested_exception +{ + explicit __nested(const _Tp& __t) : _Tp(__t) {} +}; + +template <class _Tp> +void +#ifdef _LIBCPP_MOVE +throw_with_nested /*[[noreturn]]*/ (_Tp&& __t, typename enable_if< + is_class<typename remove_reference<_Tp>::type>::value && + !is_base_of<nested_exception, typename remove_reference<_Tp>::type>::value + >::type* = 0) +#else +throw_with_nested (_Tp& __t, typename enable_if< + is_class<_Tp>::value && !is_base_of<nested_exception, _Tp>::value + >::type* = 0) +#endif +{ + throw __nested<typename remove_reference<_Tp>::type>(_STD::forward<_Tp>(__t)); +} + +template <class _Tp> +void +#ifdef _LIBCPP_MOVE +throw_with_nested /*[[noreturn]]*/ (_Tp&& __t, typename enable_if< + !is_class<typename remove_reference<_Tp>::type>::value || + is_base_of<nested_exception, typename remove_reference<_Tp>::type>::value + >::type* = 0) +#else +throw_with_nested (_Tp& __t, typename enable_if< + !is_class<_Tp>::value || is_base_of<nested_exception, _Tp>::value + >::type* = 0) +#endif +{ + throw _STD::forward<_Tp>(__t); +} + +template <class _E> +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<const nested_exception&>(__e).rethrow_nested(); +} + +template <class _E> +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/libcxx/src/exception.cpp b/libcxx/src/exception.cpp index e48e9c4901e..9bed6f49bf2 100644 --- a/libcxx/src/exception.cpp +++ b/libcxx/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/libcxx/test/language.support/support.exception/except.nested/assign.pass.cpp b/libcxx/test/language.support/support.exception/except.nested/assign.pass.cpp new file mode 100644 index 00000000000..e4355488201 --- /dev/null +++ b/libcxx/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. +// +//===----------------------------------------------------------------------===// + +// <exception> + +// class nested_exception; + +// nested_exception& operator=(const nested_exception&) throw() = default; + +#include <exception> +#include <cassert> + +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/libcxx/test/language.support/support.exception/except.nested/ctor_copy.pass.cpp b/libcxx/test/language.support/support.exception/except.nested/ctor_copy.pass.cpp new file mode 100644 index 00000000000..e8105b2335c --- /dev/null +++ b/libcxx/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. +// +//===----------------------------------------------------------------------===// + +// <exception> + +// class nested_exception; + +// nested_exception(const nested_exception&) throw() = default; + +#include <exception> +#include <cassert> + +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/libcxx/test/language.support/support.exception/except.nested/ctor_default.pass.cpp b/libcxx/test/language.support/support.exception/except.nested/ctor_default.pass.cpp new file mode 100644 index 00000000000..26b45087683 --- /dev/null +++ b/libcxx/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. +// +//===----------------------------------------------------------------------===// + +// <exception> + +// class nested_exception; + +// nested_exception() throw(); + +#include <exception> +#include <cassert> + +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/libcxx/test/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp b/libcxx/test/language.support/support.exception/except.nested/rethrow_if_nested.pass.cpp new file mode 100644 index 00000000000..c3f0222e0a5 --- /dev/null +++ b/libcxx/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. +// +//===----------------------------------------------------------------------===// + +// <exception> + +// class nested_exception; + +// template <class E> void rethrow_if_nested(const E& e); + +#include <exception> +#include <cstdlib> +#include <cassert> + +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/libcxx/test/language.support/support.exception/except.nested/rethrow_nested.pass.cpp b/libcxx/test/language.support/support.exception/except.nested/rethrow_nested.pass.cpp new file mode 100644 index 00000000000..ff55d11c983 --- /dev/null +++ b/libcxx/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. +// +//===----------------------------------------------------------------------===// + +// <exception> + +// class nested_exception; + +// void rethrow_nested [[noreturn]] () const; + +#include <exception> +#include <cstdlib> +#include <cassert> + +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/libcxx/test/language.support/support.exception/except.nested/throw_with_nested.pass.cpp b/libcxx/test/language.support/support.exception/except.nested/throw_with_nested.pass.cpp new file mode 100644 index 00000000000..35d1916223a --- /dev/null +++ b/libcxx/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. +// +//===----------------------------------------------------------------------===// + +// <exception> + +// class nested_exception; + +// template<class T> void throw_with_nested [[noreturn]] (T&& t); + +#include <exception> +#include <cstdlib> +#include <cassert> + +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<const B&>(e); + assert(b == B(6)); + } + } + { + try + { + int i = 7; + std::throw_with_nested(i); + assert(false); + } + catch (int i) + { + assert(i == 7); + } + } +} |