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