master
  1//===----------------------------------------------------------------------===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#ifndef _LIBCPP___EXCEPTION_EXCEPTION_PTR_H
 10#define _LIBCPP___EXCEPTION_EXCEPTION_PTR_H
 11
 12#include <__config>
 13#include <__cstddef/nullptr_t.h>
 14#include <__exception/operations.h>
 15#include <__memory/addressof.h>
 16#include <__memory/construct_at.h>
 17#include <__type_traits/decay.h>
 18#include <__type_traits/is_pointer.h>
 19#include <cstdlib>
 20#include <typeinfo>
 21
 22#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 23#  pragma GCC system_header
 24#endif
 25
 26#ifndef _LIBCPP_ABI_MICROSOFT
 27
 28#  if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
 29
 30namespace __cxxabiv1 {
 31
 32extern "C" {
 33_LIBCPP_OVERRIDABLE_FUNC_VIS void* __cxa_allocate_exception(size_t) throw();
 34_LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_free_exception(void*) throw();
 35
 36struct __cxa_exception;
 37_LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* __cxa_init_primary_exception(
 38    void*,
 39    std::type_info*,
 40#    if defined(_WIN32)
 41    void(__thiscall*)(void*)) throw();
 42#    elif defined(__wasm__)
 43    // In Wasm, a destructor returns its argument
 44    void* (*)(void*)) throw();
 45#    else
 46    void (*)(void*)) throw();
 47#    endif
 48}
 49
 50} // namespace __cxxabiv1
 51
 52#  endif
 53
 54#endif
 55
 56_LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
 57
 58#ifndef _LIBCPP_ABI_MICROSOFT
 59
 60class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
 61  void* __ptr_;
 62
 63  static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
 64
 65  template <class _Ep>
 66  friend _LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_explicit(_Ep&) _NOEXCEPT;
 67
 68public:
 69  // exception_ptr is basically a COW string so it is trivially relocatable.
 70  // It is also replaceable because assignment has normal value semantics.
 71  using __trivially_relocatable _LIBCPP_NODEBUG = exception_ptr;
 72  using __replaceable _LIBCPP_NODEBUG           = exception_ptr;
 73
 74  _LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
 75  _LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
 76
 77  exception_ptr(const exception_ptr&) _NOEXCEPT;
 78  exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
 79  ~exception_ptr() _NOEXCEPT;
 80
 81  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; }
 82
 83  friend _LIBCPP_HIDE_FROM_ABI bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
 84    return __x.__ptr_ == __y.__ptr_;
 85  }
 86
 87  friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
 88    return !(__x == __y);
 89  }
 90
 91  friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
 92  friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
 93};
 94
 95#  if _LIBCPP_HAS_EXCEPTIONS
 96#    if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
 97template <class _Ep>
 98_LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_explicit(_Ep& __e) _NOEXCEPT {
 99  using _Ep2 = __decay_t<_Ep>;
100  void* __ex = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ep));
101#      ifdef __wasm__
102  auto __cleanup = [](void* __p) -> void* {
103    std::__destroy_at(static_cast<_Ep2*>(__p));
104    return __p;
105  };
106#      else
107  auto __cleanup = [](void* __p) { std::__destroy_at(static_cast<_Ep2*>(__p)); };
108#      endif
109  (void)__cxxabiv1::__cxa_init_primary_exception(__ex, const_cast<std::type_info*>(&typeid(_Ep)), __cleanup);
110
111  try {
112    ::new (__ex) _Ep2(__e);
113    return exception_ptr::__from_native_exception_pointer(__ex);
114  } catch (...) {
115    __cxxabiv1::__cxa_free_exception(__ex);
116    return current_exception();
117  }
118}
119#    endif
120
121template <class _Ep>
122_LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_via_throw(_Ep& __e) _NOEXCEPT {
123  try {
124    throw __e;
125  } catch (...) {
126    return current_exception();
127  }
128}
129
130template <class _Ep>
131_LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
132  // Objective-C exceptions are thrown via pointer. When throwing an Objective-C exception,
133  // Clang generates a call to `objc_exception_throw` instead of the usual `__cxa_throw`.
134  // That function creates an exception with a special Objective-C typeinfo instead of
135  // the usual C++ typeinfo, since that is needed to implement the behavior documented
136  // at [1]).
137  //
138  // Because of this special behavior, we can't create an exception via `__cxa_init_primary_exception`
139  // for Objective-C exceptions, otherwise we'd bypass `objc_exception_throw`. See https://llvm.org/PR135089.
140  //
141  // [1]:
142  // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Articles/Exceptions64Bit.html
143  if _LIBCPP_CONSTEXPR (is_pointer<_Ep>::value) {
144    return std::__make_exception_ptr_via_throw(__e);
145  }
146
147#    if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && !defined(_LIBCPP_CXX03_LANG)
148  return std::__make_exception_ptr_explicit(__e);
149#    else
150  return std::__make_exception_ptr_via_throw(__e);
151#    endif
152}
153#  else  // !_LIBCPP_HAS_EXCEPTIONS
154template <class _Ep>
155_LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT {
156  std::abort();
157}
158#  endif // _LIBCPP_HAS_EXCEPTIONS
159
160#else // _LIBCPP_ABI_MICROSOFT
161
162class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
163  _LIBCPP_DIAGNOSTIC_PUSH
164  _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-private-field")
165  void* __ptr1_;
166  void* __ptr2_;
167  _LIBCPP_DIAGNOSTIC_POP
168
169public:
170  exception_ptr() _NOEXCEPT;
171  exception_ptr(nullptr_t) _NOEXCEPT;
172  exception_ptr(const exception_ptr& __other) _NOEXCEPT;
173  exception_ptr& operator=(const exception_ptr& __other) _NOEXCEPT;
174  exception_ptr& operator=(nullptr_t) _NOEXCEPT;
175  ~exception_ptr() _NOEXCEPT;
176  explicit operator bool() const _NOEXCEPT;
177};
178
179_LIBCPP_EXPORTED_FROM_ABI bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT;
180
181inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT {
182  return !(__x == __y);
183}
184
185_LIBCPP_EXPORTED_FROM_ABI void swap(exception_ptr&, exception_ptr&) _NOEXCEPT;
186
187_LIBCPP_EXPORTED_FROM_ABI exception_ptr __copy_exception_ptr(void* __except, const void* __ptr);
188_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
189[[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
190
191// This is a built-in template function which automagically extracts the required
192// information.
193template <class _E>
194void* __GetExceptionInfo(_E);
195
196template <class _Ep>
197_LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
198  return __copy_exception_ptr(std::addressof(__e), __GetExceptionInfo(__e));
199}
200
201#endif // _LIBCPP_ABI_MICROSOFT
202_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
203
204#endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H