1 // Nested Exception support header (nested_exception class) for -*- C++ -*-
3 // Copyright (C) 2009-2023 Free Software Foundation, Inc.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file bits/nested_exception.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{exception}
30 #ifndef _GLIBCXX_NESTED_EXCEPTION_H
31 #define _GLIBCXX_NESTED_EXCEPTION_H 1
33 #if __cplusplus < 201103L
34 # include <bits/c++0x_warning.h>
37 #include <bits/move.h>
38 #include <bits/exception_ptr.h>
42 namespace std
_GLIBCXX_VISIBILITY(default)
45 * @addtogroup exceptions
49 /** Mixin class that stores the current exception.
51 * This type can be used via `std::throw_with_nested` to store
52 * the current exception nested within another exception.
54 * @headerfile exception
56 * @see std::throw_with_nested
59 class nested_exception
64 /// The default constructor stores the current exception (if any).
65 nested_exception() noexcept
: _M_ptr(current_exception()) { }
67 nested_exception(const nested_exception
&) noexcept
= default;
69 nested_exception
& operator=(const nested_exception
&) noexcept
= default;
71 virtual ~nested_exception() noexcept
;
73 /// Rethrow the stored exception, or terminate if none was stored.
76 rethrow_nested() const
79 rethrow_exception(_M_ptr
);
83 /// Access the stored exception.
85 nested_ptr() const noexcept
89 /// @cond undocumented
91 template<typename _Except
>
92 struct _Nested_exception
: public _Except
, public nested_exception
94 explicit _Nested_exception(const _Except
& __ex
)
98 explicit _Nested_exception(_Except
&& __ex
)
99 : _Except(static_cast<_Except
&&>(__ex
))
103 #if __cplusplus < 201703L || ! defined __cpp_if_constexpr
105 // Throw an exception of unspecified type that is publicly derived from
106 // both remove_reference_t<_Tp> and nested_exception.
107 template<typename _Tp
>
110 __throw_with_nested_impl(_Tp
&& __t
, true_type
)
112 throw _Nested_exception
<__remove_cvref_t
<_Tp
>>{std::forward
<_Tp
>(__t
)};
115 template<typename _Tp
>
118 __throw_with_nested_impl(_Tp
&& __t
, false_type
)
119 { throw std::forward
<_Tp
>(__t
); }
124 /** Throw an exception that also stores the currently active exception.
126 * If `_Tp` is derived from `std::nested_exception` or is not usable
127 * as a base-class, throws a copy of `__t`.
128 * Otherwise, throws an object of an implementation-defined type derived
129 * from both `_Tp` and `std::nested_exception`, containing a copy of `__t`
130 * and the result of `std::current_exception()`.
132 * In other words, throws the argument as a new exception that contains
133 * the currently active exception nested within it. This is intended for
134 * use in a catch handler to replace the caught exception with a different
135 * type, while still preserving the original exception. When the new
136 * exception is caught, the nested exception can be rethrown by using
137 * `std::rethrow_if_nested`.
139 * This can be used at API boundaries, for example to catch a library's
140 * internal exception type and rethrow it nested with a `std::runtime_error`,
145 template<typename _Tp
>
148 throw_with_nested(_Tp
&& __t
)
150 using _Up
= typename decay
<_Tp
>::type
;
151 using _CopyConstructible
152 = __and_
<is_copy_constructible
<_Up
>, is_move_constructible
<_Up
>>;
153 static_assert(_CopyConstructible::value
,
154 "throw_with_nested argument must be CopyConstructible");
156 #if __cplusplus >= 201703L && __cpp_if_constexpr
157 if constexpr (is_class_v
<_Up
>)
158 if constexpr (!is_final_v
<_Up
>)
159 if constexpr (!is_base_of_v
<nested_exception
, _Up
>)
160 throw _Nested_exception
<_Up
>{std::forward
<_Tp
>(__t
)};
161 throw std::forward
<_Tp
>(__t
);
163 using __nest
= __and_
<is_class
<_Up
>, __bool_constant
<!__is_final(_Up
)>,
164 __not_
<is_base_of
<nested_exception
, _Up
>>>;
165 std::__throw_with_nested_impl(std::forward
<_Tp
>(__t
), __nest
{});
169 #if __cplusplus < 201703L || ! defined __cpp_if_constexpr
170 /// @cond undocumented
172 // Attempt dynamic_cast to nested_exception and call rethrow_nested().
173 template<typename _Ex
>
175 __rethrow_if_nested_impl(const _Ex
* __ptr
, true_type
)
177 if (auto __ne_ptr
= dynamic_cast<const nested_exception
*>(__ptr
))
178 __ne_ptr
->rethrow_nested();
181 // Otherwise, no effects.
183 __rethrow_if_nested_impl(const void*, false_type
)
189 /** Rethrow a nested exception
191 * If `__ex` contains a `std::nested_exception` object, call its
192 * `rethrow_nested()` member to rethrow the stored exception.
194 * After catching an exception thrown by a call to `std::throw_with_nested`
195 * this function can be used to rethrow the exception that was active when
196 * `std::throw_with_nested` was called.
200 // _GLIBCXX_RESOLVE_LIB_DEFECTS
201 // 2484. rethrow_if_nested() is doubly unimplementable
202 // 2784. Resolution to LWG 2484 is missing "otherwise, no effects" and [...]
203 template<typename _Ex
>
205 [[__gnu__::__always_inline__
]]
208 rethrow_if_nested(const _Ex
& __ex
)
210 const _Ex
* __ptr
= __builtin_addressof(__ex
);
211 #if __cplusplus < 201703L || ! defined __cpp_if_constexpr
213 using __cast
= __and_
<is_polymorphic
<_Ex
>,
214 __or_
<__not_
<is_base_of
<nested_exception
, _Ex
>>,
215 is_convertible
<_Ex
*, nested_exception
*>>>;
217 using __cast
= __and_
<is_polymorphic
<_Ex
>,
218 is_base_of
<nested_exception
, _Ex
>,
219 is_convertible
<_Ex
*, nested_exception
*>>;
221 std::__rethrow_if_nested_impl(__ptr
, __cast
{});
223 if constexpr (!is_polymorphic_v
<_Ex
>)
225 else if constexpr (is_base_of_v
<nested_exception
, _Ex
>
226 && !is_convertible_v
<_Ex
*, nested_exception
*>)
227 return; // nested_exception base class is inaccessible or ambiguous.
229 else if constexpr (!is_base_of_v
<nested_exception
, _Ex
>)
230 return; // Cannot do polymorphic casts without RTTI.
232 else if (auto __ne_ptr
= dynamic_cast<const nested_exception
*>(__ptr
))
233 __ne_ptr
->rethrow_nested();
237 /// @} group exceptions
243 #endif // _GLIBCXX_NESTED_EXCEPTION_H