]>
Commit | Line | Data |
---|---|---|
182da14a JW |
1 | // Nested Exception support header (nested_exception class) for -*- C++ -*- |
2 | ||
83ffe9cd | 3 | // Copyright (C) 2009-2023 Free Software Foundation, Inc. |
182da14a JW |
4 | // |
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) | |
9 | // any later version. | |
10 | ||
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. | |
15 | ||
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. | |
19 | ||
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/>. | |
24 | ||
7c3e9502 | 25 | /** @file bits/nested_exception.h |
f910786b BK |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{exception} | |
182da14a JW |
28 | */ |
29 | ||
30 | #ifndef _GLIBCXX_NESTED_EXCEPTION_H | |
31 | #define _GLIBCXX_NESTED_EXCEPTION_H 1 | |
32 | ||
734f5023 | 33 | #if __cplusplus < 201103L |
2f95713b | 34 | # include <bits/c++0x_warning.h> |
182da14a JW |
35 | #else |
36 | ||
e3fc446b | 37 | #include <bits/move.h> |
c470f3ea | 38 | #include <bits/exception_ptr.h> |
182da14a | 39 | |
182da14a JW |
40 | extern "C++" { |
41 | ||
488d2687 | 42 | namespace std _GLIBCXX_VISIBILITY(default) |
182da14a JW |
43 | { |
44 | /** | |
45 | * @addtogroup exceptions | |
46 | * @{ | |
47 | */ | |
48 | ||
c470f3ea JW |
49 | /** Mixin class that stores the current exception. |
50 | * | |
51 | * This type can be used via `std::throw_with_nested` to store | |
52 | * the current exception nested within another exception. | |
53 | * | |
54 | * @headerfile exception | |
55 | * @since C++11 | |
56 | * @see std::throw_with_nested | |
57 | * @ingroup exceptions | |
58 | */ | |
182da14a JW |
59 | class nested_exception |
60 | { | |
8eead16e BK |
61 | exception_ptr _M_ptr; |
62 | ||
182da14a | 63 | public: |
c470f3ea | 64 | /// The default constructor stores the current exception (if any). |
8535715d | 65 | nested_exception() noexcept : _M_ptr(current_exception()) { } |
182da14a | 66 | |
2ce8cb99 | 67 | nested_exception(const nested_exception&) noexcept = default; |
182da14a | 68 | |
2ce8cb99 | 69 | nested_exception& operator=(const nested_exception&) noexcept = default; |
182da14a | 70 | |
8535715d | 71 | virtual ~nested_exception() noexcept; |
182da14a | 72 | |
c470f3ea | 73 | /// Rethrow the stored exception, or terminate if none was stored. |
2ce8cb99 | 74 | [[noreturn]] |
182da14a | 75 | void |
2ce8cb99 JW |
76 | rethrow_nested() const |
77 | { | |
78 | if (_M_ptr) | |
79 | rethrow_exception(_M_ptr); | |
80 | std::terminate(); | |
81 | } | |
182da14a | 82 | |
c470f3ea | 83 | /// Access the stored exception. |
182da14a | 84 | exception_ptr |
2ce8cb99 | 85 | nested_ptr() const noexcept |
182da14a | 86 | { return _M_ptr; } |
182da14a JW |
87 | }; |
88 | ||
2f7f1aca JW |
89 | /// @cond undocumented |
90 | ||
182da14a JW |
91 | template<typename _Except> |
92 | struct _Nested_exception : public _Except, public nested_exception | |
93 | { | |
2ce8cb99 JW |
94 | explicit _Nested_exception(const _Except& __ex) |
95 | : _Except(__ex) | |
96 | { } | |
97 | ||
8eead16e | 98 | explicit _Nested_exception(_Except&& __ex) |
182da14a JW |
99 | : _Except(static_cast<_Except&&>(__ex)) |
100 | { } | |
101 | }; | |
102 | ||
c470f3ea | 103 | #if __cplusplus < 201703L || ! defined __cpp_if_constexpr |
0470fad0 JW |
104 | // [except.nested]/8 |
105 | // Throw an exception of unspecified type that is publicly derived from | |
106 | // both remove_reference_t<_Tp> and nested_exception. | |
2ce8cb99 | 107 | template<typename _Tp> |
c85d1992 | 108 | [[noreturn]] |
0470fad0 JW |
109 | inline void |
110 | __throw_with_nested_impl(_Tp&& __t, true_type) | |
182da14a | 111 | { |
c470f3ea | 112 | throw _Nested_exception<__remove_cvref_t<_Tp>>{std::forward<_Tp>(__t)}; |
0470fad0 | 113 | } |
2ce8cb99 JW |
114 | |
115 | template<typename _Tp> | |
c85d1992 | 116 | [[noreturn]] |
0470fad0 JW |
117 | inline void |
118 | __throw_with_nested_impl(_Tp&& __t, false_type) | |
119 | { throw std::forward<_Tp>(__t); } | |
c470f3ea | 120 | #endif |
2ce8cb99 | 121 | |
2f7f1aca JW |
122 | /// @endcond |
123 | ||
c470f3ea JW |
124 | /** Throw an exception that also stores the currently active exception. |
125 | * | |
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()`. | |
131 | * | |
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`. | |
138 | * | |
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`, | |
141 | * or vice versa. | |
142 | * | |
143 | * @since C++11 | |
144 | */ | |
2ce8cb99 JW |
145 | template<typename _Tp> |
146 | [[noreturn]] | |
182da14a | 147 | inline void |
2ce8cb99 JW |
148 | throw_with_nested(_Tp&& __t) |
149 | { | |
04c872aa | 150 | using _Up = typename decay<_Tp>::type; |
0470fad0 JW |
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"); | |
c470f3ea JW |
155 | |
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); | |
162 | #else | |
0470fad0 JW |
163 | using __nest = __and_<is_class<_Up>, __bool_constant<!__is_final(_Up)>, |
164 | __not_<is_base_of<nested_exception, _Up>>>; | |
40571365 | 165 | std::__throw_with_nested_impl(std::forward<_Tp>(__t), __nest{}); |
c470f3ea | 166 | #endif |
2ce8cb99 | 167 | } |
182da14a | 168 | |
c470f3ea | 169 | #if __cplusplus < 201703L || ! defined __cpp_if_constexpr |
2f7f1aca JW |
170 | /// @cond undocumented |
171 | ||
0470fad0 JW |
172 | // Attempt dynamic_cast to nested_exception and call rethrow_nested(). |
173 | template<typename _Ex> | |
c470f3ea JW |
174 | inline void |
175 | __rethrow_if_nested_impl(const _Ex* __ptr, true_type) | |
182da14a | 176 | { |
0470fad0 JW |
177 | if (auto __ne_ptr = dynamic_cast<const nested_exception*>(__ptr)) |
178 | __ne_ptr->rethrow_nested(); | |
179 | } | |
180 | ||
181 | // Otherwise, no effects. | |
182 | inline void | |
c470f3ea | 183 | __rethrow_if_nested_impl(const void*, false_type) |
0470fad0 | 184 | { } |
182da14a | 185 | |
2f7f1aca | 186 | /// @endcond |
c470f3ea JW |
187 | #endif |
188 | ||
189 | /** Rethrow a nested exception | |
190 | * | |
191 | * If `__ex` contains a `std::nested_exception` object, call its | |
192 | * `rethrow_nested()` member to rethrow the stored exception. | |
193 | * | |
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. | |
197 | * | |
198 | * @since C++11 | |
199 | */ | |
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 [...] | |
182da14a | 203 | template<typename _Ex> |
c470f3ea JW |
204 | # if ! __cpp_rtti |
205 | [[__gnu__::__always_inline__]] | |
206 | #endif | |
182da14a JW |
207 | inline void |
208 | rethrow_if_nested(const _Ex& __ex) | |
c470f3ea JW |
209 | { |
210 | const _Ex* __ptr = __builtin_addressof(__ex); | |
211 | #if __cplusplus < 201703L || ! defined __cpp_if_constexpr | |
212 | # if __cpp_rtti | |
213 | using __cast = __and_<is_polymorphic<_Ex>, | |
214 | __or_<__not_<is_base_of<nested_exception, _Ex>>, | |
215 | is_convertible<_Ex*, nested_exception*>>>; | |
216 | # else | |
217 | using __cast = __and_<is_polymorphic<_Ex>, | |
218 | is_base_of<nested_exception, _Ex>, | |
219 | is_convertible<_Ex*, nested_exception*>>; | |
220 | # endif | |
221 | std::__rethrow_if_nested_impl(__ptr, __cast{}); | |
222 | #else | |
223 | if constexpr (!is_polymorphic_v<_Ex>) | |
224 | return; | |
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. | |
228 | # if ! __cpp_rtti | |
229 | else if constexpr (!is_base_of_v<nested_exception, _Ex>) | |
230 | return; // Cannot do polymorphic casts without RTTI. | |
231 | # endif | |
232 | else if (auto __ne_ptr = dynamic_cast<const nested_exception*>(__ptr)) | |
233 | __ne_ptr->rethrow_nested(); | |
234 | #endif | |
235 | } | |
182da14a | 236 | |
f0b88346 | 237 | /// @} group exceptions |
182da14a JW |
238 | } // namespace std |
239 | ||
240 | } // extern "C++" | |
241 | ||
734f5023 | 242 | #endif // C++11 |
182da14a | 243 | #endif // _GLIBCXX_NESTED_EXCEPTION_H |