xref: /llvm-project/libcxx/include/__cxx03/__exception/nested_exception.h (revision ce7771902dc50d900de639d499a60486b83f70e0)
1e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
2e78f53d1SNikolas Klauser //
3e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e78f53d1SNikolas Klauser //
7e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
8e78f53d1SNikolas Klauser 
9*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___EXCEPTION_NESTED_EXCEPTION_H
10*ce777190SNikolas Klauser #define _LIBCPP___CXX03___EXCEPTION_NESTED_EXCEPTION_H
11e78f53d1SNikolas Klauser 
1273fbae83SNikolas Klauser #include <__cxx03/__config>
1373fbae83SNikolas Klauser #include <__cxx03/__exception/exception_ptr.h>
1473fbae83SNikolas Klauser #include <__cxx03/__memory/addressof.h>
1573fbae83SNikolas Klauser #include <__cxx03/__type_traits/decay.h>
1673fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_base_of.h>
1773fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_class.h>
1873fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_constructible.h>
1973fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_convertible.h>
2073fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_final.h>
2173fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_polymorphic.h>
2273fbae83SNikolas Klauser #include <__cxx03/__utility/forward.h>
2373fbae83SNikolas Klauser #include <__cxx03/cstddef>
24e78f53d1SNikolas Klauser 
25e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26e78f53d1SNikolas Klauser #  pragma GCC system_header
27e78f53d1SNikolas Klauser #endif
28e78f53d1SNikolas Klauser 
29e78f53d1SNikolas Klauser namespace std { // purposefully not using versioning namespace
30e78f53d1SNikolas Klauser 
31e78f53d1SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI nested_exception {
32e78f53d1SNikolas Klauser   exception_ptr __ptr_;
33e78f53d1SNikolas Klauser 
34e78f53d1SNikolas Klauser public:
35e78f53d1SNikolas Klauser   nested_exception() _NOEXCEPT;
36e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI nested_exception(const nested_exception&) _NOEXCEPT            = default;
37e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI nested_exception& operator=(const nested_exception&) _NOEXCEPT = default;
38e78f53d1SNikolas Klauser   virtual ~nested_exception() _NOEXCEPT;
39e78f53d1SNikolas Klauser 
40e78f53d1SNikolas Klauser   // access functions
41e78f53d1SNikolas Klauser   _LIBCPP_NORETURN void rethrow_nested() const;
42e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; }
43e78f53d1SNikolas Klauser };
44e78f53d1SNikolas Klauser 
45e78f53d1SNikolas Klauser template <class _Tp>
46e78f53d1SNikolas Klauser struct __nested : public _Tp, public nested_exception {
47e78f53d1SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __nested(const _Tp& __t) : _Tp(__t) {}
48e78f53d1SNikolas Klauser };
49e78f53d1SNikolas Klauser 
50e78f53d1SNikolas Klauser #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
51e78f53d1SNikolas Klauser template <class _Tp, class _Up, bool>
52e78f53d1SNikolas Klauser struct __throw_with_nested;
53e78f53d1SNikolas Klauser 
54e78f53d1SNikolas Klauser template <class _Tp, class _Up>
55e78f53d1SNikolas Klauser struct __throw_with_nested<_Tp, _Up, true> {
56e78f53d1SNikolas Klauser   _LIBCPP_NORETURN static inline _LIBCPP_HIDE_FROM_ABI void __do_throw(_Tp&& __t) {
57e78f53d1SNikolas Klauser     throw __nested<_Up>(std::forward<_Tp>(__t));
58e78f53d1SNikolas Klauser   }
59e78f53d1SNikolas Klauser };
60e78f53d1SNikolas Klauser 
61e78f53d1SNikolas Klauser template <class _Tp, class _Up>
62e78f53d1SNikolas Klauser struct __throw_with_nested<_Tp, _Up, false> {
63e78f53d1SNikolas Klauser   _LIBCPP_NORETURN static inline _LIBCPP_HIDE_FROM_ABI void __do_throw(_Tp&& __t) { throw std::forward<_Tp>(__t); }
64e78f53d1SNikolas Klauser };
65e78f53d1SNikolas Klauser #endif
66e78f53d1SNikolas Klauser 
67e78f53d1SNikolas Klauser template <class _Tp>
68e78f53d1SNikolas Klauser _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void throw_with_nested(_Tp&& __t) {
69e78f53d1SNikolas Klauser #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
70e78f53d1SNikolas Klauser   using _Up = __decay_t<_Tp>;
71e78f53d1SNikolas Klauser   static_assert(is_copy_constructible<_Up>::value, "type thrown must be CopyConstructible");
72e78f53d1SNikolas Klauser   __throw_with_nested<_Tp,
73e78f53d1SNikolas Klauser                       _Up,
74e78f53d1SNikolas Klauser                       is_class<_Up>::value && !is_base_of<nested_exception, _Up>::value &&
75e78f53d1SNikolas Klauser                           !__libcpp_is_final<_Up>::value>::__do_throw(std::forward<_Tp>(__t));
76e78f53d1SNikolas Klauser #else
77e78f53d1SNikolas Klauser   ((void)__t);
78e78f53d1SNikolas Klauser   // FIXME: Make this abort
79e78f53d1SNikolas Klauser #endif
80e78f53d1SNikolas Klauser }
81e78f53d1SNikolas Klauser 
82e78f53d1SNikolas Klauser template <class _From, class _To>
83e78f53d1SNikolas Klauser struct __can_dynamic_cast
84e78f53d1SNikolas Klauser     : _BoolConstant< is_polymorphic<_From>::value &&
85e78f53d1SNikolas Klauser                      (!is_base_of<_To, _From>::value || is_convertible<const _From*, const _To*>::value)> {};
86e78f53d1SNikolas Klauser 
87e78f53d1SNikolas Klauser template <class _Ep, __enable_if_t< __can_dynamic_cast<_Ep, nested_exception>::value, int> = 0>
88e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI void rethrow_if_nested(const _Ep& __e) {
89e78f53d1SNikolas Klauser   const nested_exception* __nep = dynamic_cast<const nested_exception*>(std::addressof(__e));
90e78f53d1SNikolas Klauser   if (__nep)
91e78f53d1SNikolas Klauser     __nep->rethrow_nested();
92e78f53d1SNikolas Klauser }
93e78f53d1SNikolas Klauser 
94e78f53d1SNikolas Klauser template <class _Ep, __enable_if_t<!__can_dynamic_cast<_Ep, nested_exception>::value, int> = 0>
95e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI void rethrow_if_nested(const _Ep&) {}
96e78f53d1SNikolas Klauser 
97e78f53d1SNikolas Klauser } // namespace std
98e78f53d1SNikolas Klauser 
99*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___EXCEPTION_NESTED_EXCEPTION_H
100