libstdc++
nested_exception.h
Go to the documentation of this file.
1 // Nested Exception support header (nested_exception class) for -*- C++ -*-
2 
3 // Copyright (C) 2009-2024 Free Software Foundation, Inc.
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 
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}
28  */
29 
30 #ifndef _GLIBCXX_NESTED_EXCEPTION_H
31 #define _GLIBCXX_NESTED_EXCEPTION_H 1
32 
33 #if __cplusplus < 201103L
34 # include <bits/c++0x_warning.h>
35 #else
36 
37 #include <bits/move.h>
38 #include <bits/exception_ptr.h>
39 
40 extern "C++" {
41 
42 namespace std _GLIBCXX_VISIBILITY(default)
43 {
44  /**
45  * @addtogroup exceptions
46  * @{
47  */
48 
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  */
60  {
61  exception_ptr _M_ptr;
62 
63  public:
64  /// The default constructor stores the current exception (if any).
65  nested_exception() noexcept : _M_ptr(current_exception()) { }
66 
67  nested_exception(const nested_exception&) noexcept = default;
68 
69  nested_exception& operator=(const nested_exception&) noexcept = default;
70 
71  virtual ~nested_exception() noexcept;
72 
73  /// Rethrow the stored exception, or terminate if none was stored.
74  [[noreturn]]
75  void
77  {
78  if (_M_ptr)
79  rethrow_exception(_M_ptr);
81  }
82 
83  /// Access the stored exception.
85  nested_ptr() const noexcept
86  { return _M_ptr; }
87  };
88 
89  /// @cond undocumented
90 
91  template<typename _Except>
92  struct _Nested_exception : public _Except, public nested_exception
93  {
94  explicit _Nested_exception(const _Except& __ex)
95  : _Except(__ex)
96  { }
97 
98  explicit _Nested_exception(_Except&& __ex)
99  : _Except(static_cast<_Except&&>(__ex))
100  { }
101  };
102 
103 #if __cplusplus < 201703L || ! defined __cpp_if_constexpr
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.
107  template<typename _Tp>
108  [[noreturn]]
109  inline void
110  __throw_with_nested_impl(_Tp&& __t, true_type)
111  {
112  throw _Nested_exception<__remove_cvref_t<_Tp>>{std::forward<_Tp>(__t)};
113  }
114 
115  template<typename _Tp>
116  [[noreturn]]
117  inline void
118  __throw_with_nested_impl(_Tp&& __t, false_type)
119  { throw std::forward<_Tp>(__t); }
120 #endif
121 
122  /// @endcond
123 
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  */
145  template<typename _Tp>
146  [[noreturn]]
147  inline void
148  throw_with_nested(_Tp&& __t)
149  {
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");
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
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{});
166 #endif
167  }
168 
169 #if __cplusplus < 201703L || ! defined __cpp_if_constexpr
170  /// @cond undocumented
171 
172  // Attempt dynamic_cast to nested_exception and call rethrow_nested().
173  template<typename _Ex>
174  inline void
175  __rethrow_if_nested_impl(const _Ex* __ptr, true_type)
176  {
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
183  __rethrow_if_nested_impl(const void*, false_type)
184  { }
185 
186  /// @endcond
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 [...]
203  template<typename _Ex>
204 # if ! __cpp_rtti
205  [[__gnu__::__always_inline__]]
206 #endif
207  inline void
208  rethrow_if_nested(const _Ex& __ex)
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>>,
216 # else
217  using __cast = __and_<is_polymorphic<_Ex>,
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  }
236 
237  /// @} group exceptions
238 } // namespace std
239 
240 } // extern "C++"
241 
242 #endif // C++11
243 #endif // _GLIBCXX_NESTED_EXCEPTION_H
__bool_constant< true > true_type
The type used as a compile-time boolean with true value.
Definition: type_traits:111
__bool_constant< false > false_type
The type used as a compile-time boolean with false value.
Definition: type_traits:114
exception_ptr current_exception() noexcept
void rethrow_exception(exception_ptr)
Throw the object pointed to by the exception_ptr.
void terminate() noexcept
void rethrow_if_nested(const _Ex &__ex)
void throw_with_nested(_Tp &&__t)
ISO C++ entities toplevel namespace is std.
is_move_constructible
Definition: type_traits:1170
is_base_of
Definition: type_traits:1494
is_convertible
Definition: type_traits:1536
An opaque pointer to an arbitrary exception.
Definition: exception_ptr.h:98
void rethrow_nested() const
Rethrow the stored exception, or terminate if none was stored.
exception_ptr nested_ptr() const noexcept
Access the stored exception.
nested_exception() noexcept
The default constructor stores the current exception (if any).