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