(root)/
gcc-13.2.0/
libstdc++-v3/
libsupc++/
nested_exception.h
       1  // Nested Exception support header (nested_exception class) for -*- C++ -*-
       2  
       3  // Copyright (C) 2009-2023 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     */
      59    class nested_exception
      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
      76      rethrow_nested() const
      77      {
      78        if (_M_ptr)
      79  	rethrow_exception(_M_ptr);
      80        std::terminate();
      81      }
      82  
      83      /// Access the stored exception.
      84      exception_ptr
      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>>,
     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      }
     236  
     237    /// @} group exceptions
     238  } // namespace std
     239  
     240  } // extern "C++"
     241  
     242  #endif // C++11
     243  #endif // _GLIBCXX_NESTED_EXCEPTION_H