@@ -93,51 +93,61 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
9393};
9494
9595template <class _Ep >
96- _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr (_Ep __e) _NOEXCEPT {
97- # if _LIBCPP_HAS_EXCEPTIONS
98- # if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201103L
99- // Clang treats throwing ObjC types differently, and we have to preserve original throw-ing behavior
100- // to not break some ObjC invariants. ObjC types are thrown by a pointer, hence the condition;
101- // although it does also trigger for some valid c++ usages, this should be a case rare enough to
102- // not complicate the condition any further
103- if constexpr (is_pointer<_Ep>::value) {
104- try {
105- throw __e;
106- } catch (...) {
107- return current_exception ();
108- }
109- } else {
110- using _Ep2 = __decay_t <_Ep>;
111-
112- void * __ex = __cxxabiv1::__cxa_allocate_exception (sizeof (_Ep));
113- # ifdef __wasm__
114- // In Wasm, a destructor returns its argument
115- (void )__cxxabiv1::__cxa_init_primary_exception (
116- __ex, const_cast <std::type_info*>(&typeid (_Ep)), [](void * __p) -> void * {
117- # else
118- (void )__cxxabiv1::__cxa_init_primary_exception (__ex, const_cast <std::type_info*>(&typeid (_Ep)), [](void * __p) {
119- # endif
120- std::__destroy_at (static_cast <_Ep2*>(__p));
121- # ifdef __wasm__
122- return __p;
123- # endif
124- });
125-
126- try {
127- ::new (__ex) _Ep2 (__e);
128- return exception_ptr::__from_native_exception_pointer (__ex);
129- } catch (...) {
130- __cxxabiv1::__cxa_free_exception (__ex);
131- return current_exception ();
132- }
96+ _LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_explicit (_Ep& __e) _NOEXCEPT {
97+ using _Ep2 = __decay_t <_Ep>;
98+ void * __ex = __cxxabiv1::__cxa_allocate_exception (sizeof (_Ep));
99+ # ifdef __wasm__
100+ auto __cleanup = [](void * __p) -> void * {
101+ std::__destroy_at (static_cast <_Ep2*>(__p));
102+ return __p;
103+ };
104+ # else
105+ auto __cleanup = [](void * __p) { std::__destroy_at (static_cast <_Ep2*>(__p)); };
106+ # endif
107+ (void )__cxxabiv1::__cxa_init_primary_exception (__ex, const_cast <std::type_info*>(&typeid (_Ep)), __cleanup);
108+
109+ try {
110+ ::new (__ex) _Ep2 (__e);
111+ return exception_ptr::__from_native_exception_pointer (__ex);
112+ } catch (...) {
113+ __cxxabiv1::__cxa_free_exception (__ex);
114+ return current_exception ();
133115 }
134- # else // !(_LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201103L)
116+ }
117+
118+ template <class _Ep >
119+ _LIBCPP_HIDE_FROM_ABI exception_ptr __make_exception_ptr_via_throw (_Ep& __e) _NOEXCEPT {
135120 try {
136121 throw __e;
137122 } catch (...) {
138123 return current_exception ();
139124 }
125+ }
126+
127+ template <class _Ep >
128+ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr (_Ep __e) _NOEXCEPT {
129+ # if _LIBCPP_HAS_EXCEPTIONS
130+ // Objective-C exceptions are thrown via pointer. When throwing an Objective-C exception,
131+ // Clang generates a call to `objc_exception_throw` instead of the usual `__cxa_throw`.
132+ // That function creates an exception with a special Objective-C typeinfo instead of
133+ // the usual C++ typeinfo, since that is needed to implement the behavior documented
134+ // at [1]).
135+ //
136+ // Because of this special behavior, we can't create an exception via `__cxa_init_primary_exception`
137+ // for Objective-C exceptions, otherwise we'd bypass `objc_exception_throw`. See https://llvm.org/PR135089.
138+ //
139+ // [1]:
140+ // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Articles/Exceptions64Bit.html
141+ if constexpr (is_pointer<_Ep>::value) {
142+ return std::__make_exception_ptr_via_throw (__e);
143+ }
144+
145+ # if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201103L
146+ return std::__make_exception_ptr_explicit (__e);
147+ # else
148+ return std::__make_exception_ptr_via_throw (__e);
140149# endif
150+
141151# else // !LIBCPP_HAS_EXCEPTIONS
142152 ((void )__e);
143153 std::abort ();
0 commit comments