xref: /llvm-project/libcxx/include/__exception/nested_exception.h (revision e99c4906e44ae3f921fa05356909d006cda8d954)
143562287SNikolas Klauser //===----------------------------------------------------------------------===//
243562287SNikolas Klauser //
343562287SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
443562287SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
543562287SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
643562287SNikolas Klauser //
743562287SNikolas Klauser //===----------------------------------------------------------------------===//
843562287SNikolas Klauser 
943562287SNikolas Klauser #ifndef _LIBCPP___EXCEPTION_NESTED_EXCEPTION_H
1043562287SNikolas Klauser #define _LIBCPP___EXCEPTION_NESTED_EXCEPTION_H
1143562287SNikolas Klauser 
1243562287SNikolas Klauser #include <__config>
1343562287SNikolas Klauser #include <__exception/exception_ptr.h>
1443562287SNikolas Klauser #include <__memory/addressof.h>
1543562287SNikolas Klauser #include <__type_traits/decay.h>
16d6832a61SLouis Dionne #include <__type_traits/enable_if.h>
17d6832a61SLouis Dionne #include <__type_traits/integral_constant.h>
1843562287SNikolas Klauser #include <__type_traits/is_base_of.h>
1943562287SNikolas Klauser #include <__type_traits/is_class.h>
20580f6048SNikolas Klauser #include <__type_traits/is_constructible.h>
2143562287SNikolas Klauser #include <__type_traits/is_convertible.h>
2243562287SNikolas Klauser #include <__type_traits/is_final.h>
2343562287SNikolas Klauser #include <__type_traits/is_polymorphic.h>
2443562287SNikolas Klauser #include <__utility/forward.h>
2543562287SNikolas Klauser 
2643562287SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2743562287SNikolas Klauser #  pragma GCC system_header
2843562287SNikolas Klauser #endif
2943562287SNikolas Klauser 
3043562287SNikolas Klauser namespace std { // purposefully not using versioning namespace
3143562287SNikolas Klauser 
32f1ea0b11SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI nested_exception {
3343562287SNikolas Klauser   exception_ptr __ptr_;
3443562287SNikolas Klauser 
3543562287SNikolas Klauser public:
3643562287SNikolas Klauser   nested_exception() _NOEXCEPT;
3770248920SIgor Zhukov   _LIBCPP_HIDE_FROM_ABI nested_exception(const nested_exception&) _NOEXCEPT            = default;
3870248920SIgor Zhukov   _LIBCPP_HIDE_FROM_ABI nested_exception& operator=(const nested_exception&) _NOEXCEPT = default;
3943562287SNikolas Klauser   virtual ~nested_exception() _NOEXCEPT;
4043562287SNikolas Klauser 
4143562287SNikolas Klauser   // access functions
42748023dcSNikolas Klauser   [[__noreturn__]] void rethrow_nested() const;
4343562287SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; }
4443562287SNikolas Klauser };
4543562287SNikolas Klauser 
4643562287SNikolas Klauser template <class _Tp>
4743562287SNikolas Klauser struct __nested : public _Tp, public nested_exception {
4843562287SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI explicit __nested(const _Tp& __t) : _Tp(__t) {}
4943562287SNikolas Klauser };
5043562287SNikolas Klauser 
51*ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS
5243562287SNikolas Klauser template <class _Tp, class _Up, bool>
5343562287SNikolas Klauser struct __throw_with_nested;
5443562287SNikolas Klauser 
5543562287SNikolas Klauser template <class _Tp, class _Up>
5643562287SNikolas Klauser struct __throw_with_nested<_Tp, _Up, true> {
57748023dcSNikolas Klauser   [[__noreturn__]] static inline _LIBCPP_HIDE_FROM_ABI void __do_throw(_Tp&& __t) {
5843562287SNikolas Klauser     throw __nested<_Up>(std::forward<_Tp>(__t));
5943562287SNikolas Klauser   }
6043562287SNikolas Klauser };
6143562287SNikolas Klauser 
6243562287SNikolas Klauser template <class _Tp, class _Up>
6343562287SNikolas Klauser struct __throw_with_nested<_Tp, _Up, false> {
64748023dcSNikolas Klauser   [[__noreturn__]] static inline _LIBCPP_HIDE_FROM_ABI void __do_throw(_Tp&& __t) { throw std::forward<_Tp>(__t); }
6543562287SNikolas Klauser };
6643562287SNikolas Klauser #endif
6743562287SNikolas Klauser 
6843562287SNikolas Klauser template <class _Tp>
69748023dcSNikolas Klauser [[__noreturn__]] _LIBCPP_HIDE_FROM_ABI void throw_with_nested(_Tp&& __t) {
70*ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS
71173476eaSNikolas Klauser   using _Up = __decay_t<_Tp>;
7243562287SNikolas Klauser   static_assert(is_copy_constructible<_Up>::value, "type thrown must be CopyConstructible");
7343562287SNikolas Klauser   __throw_with_nested<_Tp,
7443562287SNikolas Klauser                       _Up,
7543562287SNikolas Klauser                       is_class<_Up>::value && !is_base_of<nested_exception, _Up>::value &&
7643562287SNikolas Klauser                           !__libcpp_is_final<_Up>::value>::__do_throw(std::forward<_Tp>(__t));
7743562287SNikolas Klauser #else
7843562287SNikolas Klauser   ((void)__t);
7943562287SNikolas Klauser   // FIXME: Make this abort
8043562287SNikolas Klauser #endif
8143562287SNikolas Klauser }
8243562287SNikolas Klauser 
8343562287SNikolas Klauser template <class _From, class _To>
8443562287SNikolas Klauser struct __can_dynamic_cast
8543562287SNikolas Klauser     : _BoolConstant< is_polymorphic<_From>::value &&
8643562287SNikolas Klauser                      (!is_base_of<_To, _From>::value || is_convertible<const _From*, const _To*>::value)> {};
8743562287SNikolas Klauser 
880865b782SA. Jiang template <class _Ep, __enable_if_t< __can_dynamic_cast<_Ep, nested_exception>::value, int> = 0>
890865b782SA. Jiang inline _LIBCPP_HIDE_FROM_ABI void rethrow_if_nested(const _Ep& __e) {
9043562287SNikolas Klauser   const nested_exception* __nep = dynamic_cast<const nested_exception*>(std::addressof(__e));
9143562287SNikolas Klauser   if (__nep)
9243562287SNikolas Klauser     __nep->rethrow_nested();
9343562287SNikolas Klauser }
9443562287SNikolas Klauser 
950865b782SA. Jiang template <class _Ep, __enable_if_t<!__can_dynamic_cast<_Ep, nested_exception>::value, int> = 0>
960865b782SA. Jiang inline _LIBCPP_HIDE_FROM_ABI void rethrow_if_nested(const _Ep&) {}
9743562287SNikolas Klauser 
9843562287SNikolas Klauser } // namespace std
9943562287SNikolas Klauser 
10043562287SNikolas Klauser #endif // _LIBCPP___EXCEPTION_NESTED_EXCEPTION_H
101