[libcxx-commits] [libcxx] [libc++] Inline fast path for`exception_ptr` copy constructor & destructor (PR #165909)
Adrian Vogelsgesang via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Oct 31 12:09:12 PDT 2025
https://github.com/vogelsgesang created https://github.com/llvm/llvm-project/pull/165909
This is an early draft for optimizing the `exception_ptr` further. It is based on #164281, I will rebase this PR on `main` after #164281 got merged.
There are two main open questions around ABI stability:
1. How to make sure we still emit the `~exception_ptr` and copy constructor/assignment in the library. The current approach was previously discussed in https://reviews.llvm.org/D122536 (among others by @philnik777). But if there is a better approach, I am happy to adjust this PR
2. If we actually want to introduce the new `__do_{inc,dec}rement` functions or if we want to directly call `__cxa_{inc,dec}rement_refcount` from the headers
Also, there are a couple minor issues (e.g., adjusting the symbol lists) which I will tackle after we have alignment on the high level approach
>From 5527b28f53ee2bab3171f7c32152d52c21b9c960 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 20 Oct 2025 16:07:33 +0000
Subject: [PATCH 01/16] [libc++] Add move constructor & assignment to
`exception_ptr`
This commit adds move constructor and move assignment to
`exception_ptr`. Adding those operators allows us to avoid unnecessary
calls to `__cxa_{inc,dec}rement_refcount`.
Performance results:
```
Benchmark Baseline Candidate Difference % Difference
------------------------------- ---------- ----------- ------------ --------------
bm_nonnull_exception_ptr 52.22 40.92 -11.31 -21.65
bm_null_exception_ptr 31.41 23.29 -8.12 -25.85
bm_optimized_null_exception_ptr 28.69 20.50 -8.19 -28.55
```
This commit does not add a `swap` specialization. Thanks to the added
move-assignment, we already save a couple of increments/decrements also
in the default `swap` implementation. The default `swap` is still not
perfect, as it calls the desctructor on `tmp`. As soon as we also
inlined the `~exception_ptr` destructor fast-path for `__ptr ==
nullptr`, the optimizer should be able to optimize the default `swap`
just as well as a specialized `swap`, though.
---
libcxx/include/__exception/exception_ptr.h | 16 ++++++++++++++++
.../support/runtime/exception_pointer_cxxabi.ipp | 4 ++++
.../runtime/exception_pointer_glibcxx.ipp | 6 ++++++
.../runtime/exception_pointer_unimplemented.ipp | 5 +++++
4 files changed, 31 insertions(+)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index 796fa924be121..38c8036112be4 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -60,6 +60,9 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
void* __ptr_;
+ static void __do_decrement_refcount(void* __ptr) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI static void __decrement_refcount(void* __ptr) _NOEXCEPT { if (__ptr) __do_decrement_refcount(__ptr); }
+
static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
template <class _Ep>
@@ -75,7 +78,9 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
exception_ptr(const exception_ptr&) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&&) _NOEXCEPT;
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&&) _NOEXCEPT;
~exception_ptr() _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; }
@@ -92,6 +97,17 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
};
+_LIBCPP_HIDE_FROM_ABI inline exception_ptr::exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
+ __other.__ptr_ = nullptr;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline exception_ptr& exception_ptr::operator=(exception_ptr&& __other) _NOEXCEPT {
+ __decrement_refcount(__ptr_);
+ __ptr_ = __other.__ptr_;
+ __other.__ptr_ = nullptr;
+ return *this;
+}
+
# if _LIBCPP_HAS_EXCEPTIONS
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
template <class _Ep>
diff --git a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
index 8f5c2060bb06c..a10c06457a998 100644
--- a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
@@ -13,6 +13,10 @@
namespace std {
+void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
+ __cxa_decrement_exception_refcount(__ptr);
+}
+
exception_ptr::~exception_ptr() noexcept { __cxa_decrement_exception_refcount(__ptr_); }
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
diff --git a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
index 174b44ce0e6f7..c10004ead4f7c 100644
--- a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
@@ -27,12 +27,18 @@ struct exception_ptr {
exception_ptr(const exception_ptr&) noexcept;
exception_ptr& operator=(const exception_ptr&) noexcept;
~exception_ptr() noexcept;
+
+ void _M_release() noexcept;
};
} // namespace __exception_ptr
[[noreturn]] void rethrow_exception(__exception_ptr::exception_ptr);
+void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
+ reinterpret_cast<__exception_ptr::exception_ptr*>(this)->_M_release();
+}
+
exception_ptr::~exception_ptr() noexcept { reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr(); }
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
diff --git a/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp b/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
index 05a71ce34e5ac..fdf2076c64386 100644
--- a/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
@@ -11,6 +11,11 @@
namespace std {
+void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
+#warning exception_ptr not yet implemented
+ __libcpp_verbose_abort("exception_ptr not yet implemented\n");
+}
+
exception_ptr::~exception_ptr() noexcept {
#warning exception_ptr not yet implemented
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
>From 36757da3a161148b953ef65ab2fdd635ace5d1f4 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Tue, 21 Oct 2025 11:50:47 +0000
Subject: [PATCH 02/16] Implement using `swap`
---
libcxx/include/__exception/exception_ptr.h | 15 +++++++++------
.../support/runtime/exception_pointer_cxxabi.ipp | 4 ----
.../support/runtime/exception_pointer_glibcxx.ipp | 4 ----
.../runtime/exception_pointer_unimplemented.ipp | 5 -----
4 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index 38c8036112be4..ca02a079642c5 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -16,6 +16,7 @@
#include <__memory/construct_at.h>
#include <__type_traits/decay.h>
#include <__type_traits/is_pointer.h>
+#include <__utility/move.h>
#include <cstdlib>
#include <typeinfo>
@@ -60,9 +61,6 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
void* __ptr_;
- static void __do_decrement_refcount(void* __ptr) _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI static void __decrement_refcount(void* __ptr) _NOEXCEPT { if (__ptr) __do_decrement_refcount(__ptr); }
-
static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
template <class _Ep>
@@ -93,6 +91,12 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
return !(__x == __y);
}
+ friend _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
+ void* __tmp = __x.__ptr_;
+ __x.__ptr_ = __y.__ptr_;
+ __y.__ptr_ = __tmp;
+ }
+
friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
};
@@ -102,9 +106,8 @@ _LIBCPP_HIDE_FROM_ABI inline exception_ptr::exception_ptr(exception_ptr&& __othe
}
_LIBCPP_HIDE_FROM_ABI inline exception_ptr& exception_ptr::operator=(exception_ptr&& __other) _NOEXCEPT {
- __decrement_refcount(__ptr_);
- __ptr_ = __other.__ptr_;
- __other.__ptr_ = nullptr;
+ exception_ptr __tmp(std::move(__other));
+ swap(__tmp, *this);
return *this;
}
diff --git a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
index a10c06457a998..8f5c2060bb06c 100644
--- a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
@@ -13,10 +13,6 @@
namespace std {
-void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
- __cxa_decrement_exception_refcount(__ptr);
-}
-
exception_ptr::~exception_ptr() noexcept { __cxa_decrement_exception_refcount(__ptr_); }
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
diff --git a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
index c10004ead4f7c..a5861dac3469b 100644
--- a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
@@ -35,10 +35,6 @@ struct exception_ptr {
[[noreturn]] void rethrow_exception(__exception_ptr::exception_ptr);
-void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
- reinterpret_cast<__exception_ptr::exception_ptr*>(this)->_M_release();
-}
-
exception_ptr::~exception_ptr() noexcept { reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr(); }
exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
diff --git a/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp b/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
index fdf2076c64386..05a71ce34e5ac 100644
--- a/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
@@ -11,11 +11,6 @@
namespace std {
-void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
-#warning exception_ptr not yet implemented
- __libcpp_verbose_abort("exception_ptr not yet implemented\n");
-}
-
exception_ptr::~exception_ptr() noexcept {
#warning exception_ptr not yet implemented
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
>From 740129e4a94d35d2439b8aef8121329dedfbf042 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Tue, 21 Oct 2025 12:50:38 +0000
Subject: [PATCH 03/16] Define functions inline
---
libcxx/include/__exception/exception_ptr.h | 20 ++++++++-----------
.../runtime/exception_pointer_glibcxx.ipp | 2 --
2 files changed, 8 insertions(+), 14 deletions(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index ca02a079642c5..45da9af66ab4c 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -76,9 +76,15 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
exception_ptr(const exception_ptr&) _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&&) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
+ __other.__ptr_ = nullptr;
+ }
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
- _LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&&) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&& __other) _NOEXCEPT {
+ exception_ptr __tmp(std::move(__other));
+ swap(__tmp, *this);
+ return *this;
+ }
~exception_ptr() _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; }
@@ -101,16 +107,6 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
};
-_LIBCPP_HIDE_FROM_ABI inline exception_ptr::exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
- __other.__ptr_ = nullptr;
-}
-
-_LIBCPP_HIDE_FROM_ABI inline exception_ptr& exception_ptr::operator=(exception_ptr&& __other) _NOEXCEPT {
- exception_ptr __tmp(std::move(__other));
- swap(__tmp, *this);
- return *this;
-}
-
# if _LIBCPP_HAS_EXCEPTIONS
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
template <class _Ep>
diff --git a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
index a5861dac3469b..174b44ce0e6f7 100644
--- a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
@@ -27,8 +27,6 @@ struct exception_ptr {
exception_ptr(const exception_ptr&) noexcept;
exception_ptr& operator=(const exception_ptr&) noexcept;
~exception_ptr() noexcept;
-
- void _M_release() noexcept;
};
} // namespace __exception_ptr
>From 8d90812e90b1a8e7f49f2d15badaf672f740cd1f Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 27 Oct 2025 20:02:21 +0000
Subject: [PATCH 04/16] Undef `move` to fix build
---
libcxx/include/__exception/exception_ptr.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index 45da9af66ab4c..2d86a15f19ead 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -24,6 +24,9 @@
# pragma GCC system_header
#endif
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
#ifndef _LIBCPP_ABI_MICROSOFT
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
@@ -216,4 +219,6 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
#endif // _LIBCPP_ABI_MICROSOFT
_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H
>From b106dc9fcccdad9c8745c7602360e9d40bf04175 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 27 Oct 2025 20:09:31 +0000
Subject: [PATCH 05/16] Make `swap` a non-hidden friend
---
libcxx/include/__exception/exception_ptr.h | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index 2d86a15f19ead..d0da2a688977e 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -100,16 +100,18 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
return !(__x == __y);
}
- friend _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
- void* __tmp = __x.__ptr_;
- __x.__ptr_ = __y.__ptr_;
- __y.__ptr_ = __tmp;
- }
+ friend _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT;
friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
};
+inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
+ void* __tmp = __x.__ptr_;
+ __x.__ptr_ = __y.__ptr_;
+ __y.__ptr_ = __tmp;
+}
+
# if _LIBCPP_HAS_EXCEPTIONS
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
template <class _Ep>
>From 1a26712aa3574024e70aa21af483fb3ad83e3e44 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
Date: Mon, 27 Oct 2025 21:26:25 +0100
Subject: [PATCH 06/16] Update libcxx/include/__exception/exception_ptr.h
Co-authored-by: Nikolas Klauser <nikolasklauser at berlin.de>
---
libcxx/include/__exception/exception_ptr.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index d0da2a688977e..73e5027b33b80 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -107,9 +107,7 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
};
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
- void* __tmp = __x.__ptr_;
- __x.__ptr_ = __y.__ptr_;
- __y.__ptr_ = __tmp;
+ swap(__x.__ptr_, __y.__ptr_);
}
# if _LIBCPP_HAS_EXCEPTIONS
>From baba555a6c4deacd1a5f5f8bba5e2919d185f933 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 13:03:17 +0000
Subject: [PATCH 07/16] Add test cases
---
.../propagation/exception_ptr.pass.cpp | 1 -
.../exception_ptr_move_assignment.cpp | 44 +++++++++++++++++++
.../propagation/exception_ptr_move_ctr.cpp | 42 ++++++++++++++++++
.../propagation/exception_ptr_swap.cpp | 39 ++++++++++++++++
4 files changed, 125 insertions(+), 1 deletion(-)
create mode 100644 libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
create mode 100644 libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
create mode 100644 libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
index 0aded33e660d5..7e25d40dc8a7d 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
@@ -14,7 +14,6 @@
#include <exception>
#include <cassert>
-#include <type_traits>
#include "test_macros.h"
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
new file mode 100644
index 0000000000000..63a4fa0da34f1
--- /dev/null
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <exception>
+
+// typedef unspecified exception_ptr;
+
+// Test the move assignment of exception_ptr
+
+#include <exception>
+#include <utility>
+#include <cassert>
+
+#include "test_macros.h"
+
+int main(int, char**)
+{
+ std::exception_ptr p = std::make_exception_ptr(42);
+ std::exception_ptr p2{p};
+ assert(p2 == p);
+ // Move assignment
+ std::exception_ptr p3
+ p3 = std::move(p2);
+ assert(p3 == p);
+ // `p2` was moved from. In libc++ it will be nullptr, but
+ // this is not guaranteed by the standard.
+ #if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_MICROSOFT)
+ assert(p2 == nullptr);
+ assert(p2 == nullptr);
+ #endif
+
+ try {
+ std::rethrow_exception(p3);
+ } catch (int e) {
+ assert(e == 42);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
new file mode 100644
index 0000000000000..6f6e989bfd707
--- /dev/null
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <exception>
+
+// typedef unspecified exception_ptr;
+
+// Test the move constructor of exception_ptr
+
+#include <exception>
+#include <utility>
+#include <cassert>
+
+#include "test_macros.h"
+
+int main(int, char**)
+{
+ std::exception_ptr p = std::make_exception_ptr(42);
+ std::exception_ptr p2{p};
+ assert(p2 == p);
+ // Move constructor
+ std::exception_ptr p3{std::move(p2)};
+ assert(p3 == p);
+ // `p2` was moved from. In libc++ it will be nullptr, but
+ // this is not guaranteed by the standard.
+ #if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_MICROSOFT)
+ assert(p2 == nullptr);
+ #endif
+
+ try {
+ std::rethrow_exception(p3);
+ } catch (int e) {
+ assert(e == 42);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
new file mode 100644
index 0000000000000..3dd0d34d46200
--- /dev/null
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <exception>
+
+// typedef unspecified exception_ptr;
+
+// Test swapping of exception_ptr
+
+#include <exception>
+#include <utility>
+#include <cassert>
+
+#include "test_macros.h"
+
+int main(int, char**)
+{
+ std::exception_ptr p21 = std::make_exception_ptr(42);
+ std::exception_ptr p42 = std::make_exception_ptr(21);
+ std::swap(p42, p21);
+
+ try {
+ std::rethrow_exception(p21);
+ } catch (int e) {
+ assert(e == 21);
+ }
+ try {
+ std::rethrow_exception(p42);
+ } catch (int e) {
+ assert(e == 42);
+ }
+
+ return 0;
+}
>From 2a22036abbcf9220f21b87e1ee62b3d4f725b65e Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 13:28:46 +0000
Subject: [PATCH 08/16] Formatting, unsupported no-exceptions, directly use
`std::swap`
---
libcxx/include/__exception/exception_ptr.h | 2 +-
.../exception_ptr_move_assignment.cpp | 49 ++++++++++---------
.../propagation/exception_ptr_move_ctr.cpp | 45 ++++++++---------
.../propagation/exception_ptr_swap.cpp | 37 +++++++-------
4 files changed, 68 insertions(+), 65 deletions(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index 73e5027b33b80..e096d8e1dfd49 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -85,7 +85,7 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&& __other) _NOEXCEPT {
exception_ptr __tmp(std::move(__other));
- swap(__tmp, *this);
+ std::swap(__tmp, *this);
return *this;
}
~exception_ptr() _NOEXCEPT;
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
index 63a4fa0da34f1..3f041fc367dfd 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-exceptions
+
// <exception>
// typedef unspecified exception_ptr;
@@ -18,27 +20,26 @@
#include "test_macros.h"
-int main(int, char**)
-{
- std::exception_ptr p = std::make_exception_ptr(42);
- std::exception_ptr p2{p};
- assert(p2 == p);
- // Move assignment
- std::exception_ptr p3
- p3 = std::move(p2);
- assert(p3 == p);
- // `p2` was moved from. In libc++ it will be nullptr, but
- // this is not guaranteed by the standard.
- #if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_MICROSOFT)
- assert(p2 == nullptr);
- assert(p2 == nullptr);
- #endif
-
- try {
- std::rethrow_exception(p3);
- } catch (int e) {
- assert(e == 42);
- }
-
- return 0;
-}
+int main(int, char**) {
+ std::exception_ptr p = std::make_exception_ptr(42);
+ std::exception_ptr p2{p};
+ assert(p2 == p);
+ // Under test: the move assignment
+ std::exception_ptr p3;
+ p3 = std::move(p2);
+ assert(p3 == p);
+// `p2` was moved from. In libc++ it will be nullptr, but
+// this is not guaranteed by the standard.
+#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_MICROSOFT)
+ assert(p2 == nullptr);
+ assert(p2 == nullptr);
+#endif
+
+ try {
+ std::rethrow_exception(p3);
+ } catch (int e) {
+ assert(e == 42);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
index 6f6e989bfd707..37421e86a3d3f 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-exceptions
+
// <exception>
// typedef unspecified exception_ptr;
@@ -18,25 +20,24 @@
#include "test_macros.h"
-int main(int, char**)
-{
- std::exception_ptr p = std::make_exception_ptr(42);
- std::exception_ptr p2{p};
- assert(p2 == p);
- // Move constructor
- std::exception_ptr p3{std::move(p2)};
- assert(p3 == p);
- // `p2` was moved from. In libc++ it will be nullptr, but
- // this is not guaranteed by the standard.
- #if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_MICROSOFT)
- assert(p2 == nullptr);
- #endif
-
- try {
- std::rethrow_exception(p3);
- } catch (int e) {
- assert(e == 42);
- }
-
- return 0;
-}
+int main(int, char**) {
+ std::exception_ptr p = std::make_exception_ptr(42);
+ std::exception_ptr p2{p};
+ assert(p2 == p);
+ // Under test: The move constructor
+ std::exception_ptr p3{std::move(p2)};
+ assert(p3 == p);
+// `p2` was moved from. In libc++ it will be nullptr, but
+// this is not guaranteed by the standard.
+#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_MICROSOFT)
+ assert(p2 == nullptr);
+#endif
+
+ try {
+ std::rethrow_exception(p3);
+ } catch (int e) {
+ assert(e == 42);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
index 3dd0d34d46200..82b4713bed538 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-exceptions
+
// <exception>
// typedef unspecified exception_ptr;
@@ -18,22 +20,21 @@
#include "test_macros.h"
-int main(int, char**)
-{
- std::exception_ptr p21 = std::make_exception_ptr(42);
- std::exception_ptr p42 = std::make_exception_ptr(21);
- std::swap(p42, p21);
-
- try {
- std::rethrow_exception(p21);
- } catch (int e) {
- assert(e == 21);
- }
- try {
- std::rethrow_exception(p42);
- } catch (int e) {
- assert(e == 42);
- }
-
- return 0;
+int main(int, char**) {
+ std::exception_ptr p21 = std::make_exception_ptr(42);
+ std::exception_ptr p42 = std::make_exception_ptr(21);
+ std::swap(p42, p21);
+
+ try {
+ std::rethrow_exception(p21);
+ } catch (int e) {
+ assert(e == 21);
+ }
+ try {
+ std::rethrow_exception(p42);
+ } catch (int e) {
+ assert(e == 42);
+ }
+
+ return 0;
}
>From fb3c6556cc4679078d5bccd0654e4fe7ab6a44a0 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 13:54:45 +0000
Subject: [PATCH 09/16] Apply `std` in front of `swap` in the correct place
---
libcxx/include/__exception/exception_ptr.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index e096d8e1dfd49..dcc926ef666eb 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -17,6 +17,7 @@
#include <__type_traits/decay.h>
#include <__type_traits/is_pointer.h>
#include <__utility/move.h>
+#include <__utility/swap.h>
#include <cstdlib>
#include <typeinfo>
@@ -107,7 +108,7 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
};
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
- swap(__x.__ptr_, __y.__ptr_);
+ std::swap(__x.__ptr_, __y.__ptr_);
}
# if _LIBCPP_HAS_EXCEPTIONS
>From ee4694c780b185314bb9604c845fd7a338751a21 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 14:12:44 +0000
Subject: [PATCH 10/16] Disable tests for C++03
---
.../propagation/exception_ptr_move_assignment.cpp | 2 +-
.../support.exception/propagation/exception_ptr_move_ctr.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
index 3f041fc367dfd..8e2330fe0960d 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: no-exceptions
+// UNSUPPORTED: no-exceptions std-at-least-c++11
// <exception>
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
index 37421e86a3d3f..1be0b0733046e 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: no-exceptions
+// UNSUPPORTED: no-exceptions std-at-least-c++11
// <exception>
>From 3c910b879fb43ebe9e0f6cdf21b08fdde2971403 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 14:36:20 +0000
Subject: [PATCH 11/16] Add missing new lines
---
.../propagation/exception_ptr_move_assignment.cpp | 2 +-
.../support.exception/propagation/exception_ptr_move_ctr.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
index 8e2330fe0960d..a6b475a89ca2d 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
@@ -42,4 +42,4 @@ int main(int, char**) {
}
return 0;
-}
\ No newline at end of file
+}
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
index 1be0b0733046e..cd76995dba826 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
@@ -40,4 +40,4 @@ int main(int, char**) {
}
return 0;
-}
\ No newline at end of file
+}
>From 510786cf1993d5a5a11f08373115ccdc50f1c5ec Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 16:11:49 +0000
Subject: [PATCH 12/16] Forward declare the `swap` overload
---
libcxx/include/__exception/exception_ptr.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index dcc926ef666eb..e78126ea23852 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -62,6 +62,8 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
#ifndef _LIBCPP_ABI_MICROSOFT
+inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT;
+
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
void* __ptr_;
>From 20bcce5e6ba4b1cf9143addf817f707b471c7f3e Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 16:13:32 +0000
Subject: [PATCH 13/16] Fix test case file names
---
...ve_assignment.cpp => exception_ptr_move_assignment.pass.cpp} | 2 +-
...ception_ptr_move_ctr.cpp => exception_ptr_move_ctr.pass.cpp} | 2 +-
.../{exception_ptr_swap.cpp => exception_ptr_swap.pass.cpp} | 0
3 files changed, 2 insertions(+), 2 deletions(-)
rename libcxx/test/std/language.support/support.exception/propagation/{exception_ptr_move_assignment.cpp => exception_ptr_move_assignment.pass.cpp} (95%)
rename libcxx/test/std/language.support/support.exception/propagation/{exception_ptr_move_ctr.cpp => exception_ptr_move_ctr.pass.cpp} (95%)
rename libcxx/test/std/language.support/support.exception/propagation/{exception_ptr_swap.cpp => exception_ptr_swap.pass.cpp} (100%)
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp
similarity index 95%
rename from libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
rename to libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp
index a6b475a89ca2d..e03c336367b93 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: no-exceptions std-at-least-c++11
+// UNSUPPORTED: no-exceptions, std-at-least-c++11
// <exception>
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp
similarity index 95%
rename from libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
rename to libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp
index cd76995dba826..7af49a46a0a28 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: no-exceptions std-at-least-c++11
+// UNSUPPORTED: no-exceptions, std-at-least-c++11
// <exception>
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.pass.cpp
similarity index 100%
rename from libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.cpp
rename to libcxx/test/std/language.support/support.exception/propagation/exception_ptr_swap.pass.cpp
>From 8a1a9cf21eb427c680f1c15f93130f5d8eec70a0 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 16:49:49 +0000
Subject: [PATCH 14/16] Fix `UNSUPPORTED` to exclude C++03 and fix docs
---
libcxx/docs/TestingLibcxx.rst | 2 +-
.../propagation/exception_ptr_move_assignment.pass.cpp | 2 +-
.../propagation/exception_ptr_move_ctr.pass.cpp | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/docs/TestingLibcxx.rst b/libcxx/docs/TestingLibcxx.rst
index dbe69484abedf..e15c5b1a5d32f 100644
--- a/libcxx/docs/TestingLibcxx.rst
+++ b/libcxx/docs/TestingLibcxx.rst
@@ -451,7 +451,7 @@ Instead use:
.. code-block:: cpp
- // UNSUPPORTED: std-at-least-c++26
+ // REQUIRES: std-at-least-c++26
There is no corresponding ``std-at-most-c++23``. This could be useful when
tests are only valid for a small set of standard versions. For example, a
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp
index e03c336367b93..6882bc6548da3 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_assignment.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: no-exceptions, std-at-least-c++11
+// UNSUPPORTED: no-exceptions, c++03
// <exception>
diff --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp
index 7af49a46a0a28..122e229fd6e47 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr_move_ctr.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: no-exceptions, std-at-least-c++11
+// UNSUPPORTED: no-exceptions, c++03
// <exception>
>From 32a85dd3bb8404d775c7fd4a1b0fa4768d5e7935 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 16:53:18 +0000
Subject: [PATCH 15/16] Fix modules build
---
libcxx/modules/std/exception.inc | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/modules/std/exception.inc b/libcxx/modules/std/exception.inc
index 02b0f80190e5b..3dbc0112c15a0 100644
--- a/libcxx/modules/std/exception.inc
+++ b/libcxx/modules/std/exception.inc
@@ -18,6 +18,7 @@ export namespace std {
using std::rethrow_exception;
using std::rethrow_if_nested;
using std::set_terminate;
+ using std::swap;
using std::terminate;
using std::terminate_handler;
using std::throw_with_nested;
>From 38269ec106b6c24b17f6ca89c5a2f77a21722e54 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Fri, 31 Oct 2025 16:06:22 +0000
Subject: [PATCH 16/16] [libc++] Inline copy constructor & destructor for
`std::exception_ptr`
---
libcxx/include/__exception/exception_ptr.h | 59 +++++++++++++++++--
libcxx/src/exception.cpp | 1 +
.../runtime/exception_pointer_cxxabi.ipp | 15 ++---
.../runtime/exception_pointer_glibcxx.ipp | 27 ++++-----
.../exception_pointer_unimplemented.ipp | 9 +--
5 files changed, 71 insertions(+), 40 deletions(-)
diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index e78126ea23852..ce0cdd8350013 100644
--- a/libcxx/include/__exception/exception_ptr.h
+++ b/libcxx/include/__exception/exception_ptr.h
@@ -30,6 +30,28 @@ _LIBCPP_PUSH_MACROS
#ifndef _LIBCPP_ABI_MICROSOFT
+// Previously, parts of exception_ptr were defined out-of-line, which prevented
+// useful compiler optimizations. Changing the out-of-line definitions to inline
+// definitions is an ABI break, however. To prevent this, we have to make sure
+// the symbols remain available in the libc++ library, in addition to being
+// defined inline here in this header.
+// To this end, we use _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE macro:
+// The macro is defined as empty for src/exception.cpp, forcing the definitions of
+// the functions to be emitted and included in the library. When users of libc++
+// compile their code, the __gnu_inline__ attribute will suppress generation of
+// these functions while making their definitions available for inlining.
+#ifdef _LIBCPP_EMIT_CODE_FOR_EXCEPTION_PTR
+# define _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE _LIBCPP_EXPORTED_FROM_ABI
+#else
+# if !__has_cpp_attribute(__gnu__::__gnu_inline__)
+# error "GNU inline attribute is not supported"
+# endif
+# define _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE [[__gnu__::__gnu_inline__]] inline
+#endif
+
+_LIBCPP_DIAGNOSTIC_PUSH
+_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgnu-inline-cpp-without-extern")
+
# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION
namespace __cxxabiv1 {
@@ -67,6 +89,11 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _
class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
void* __ptr_;
+ static void __do_increment_refcount(void* __ptr) _NOEXCEPT;
+ static void __do_decrement_refcount(void* __ptr) _NOEXCEPT;
+ _LIBCPP_HIDE_FROM_ABI static void __increment_refcount(void* __ptr) _NOEXCEPT { if (__ptr) __do_increment_refcount(__ptr); }
+ _LIBCPP_HIDE_FROM_ABI static void __decrement_refcount(void* __ptr) _NOEXCEPT { if (__ptr) __do_decrement_refcount(__ptr); }
+
static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT;
template <class _Ep>
@@ -81,17 +108,18 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
_LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {}
_LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {}
- exception_ptr(const exception_ptr&) _NOEXCEPT;
+ _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr(const exception_ptr&) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) {
__other.__ptr_ = nullptr;
}
- exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
+ _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&& __other) _NOEXCEPT {
- exception_ptr __tmp(std::move(__other));
- std::swap(__tmp, *this);
+ __decrement_refcount(__ptr_);
+ __ptr_ = __other.__ptr_;
+ __other.__ptr_ = nullptr;
return *this;
}
- ~exception_ptr() _NOEXCEPT;
+ _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE ~exception_ptr() _NOEXCEPT;
_LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; }
@@ -109,6 +137,25 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr {
friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
};
+// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
+_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::exception_ptr(const exception_ptr& __other) _NOEXCEPT
+ : __ptr_(__other.__ptr_) {
+ __increment_refcount(__ptr_);
+}
+
+// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
+_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr& exception_ptr::operator=(const exception_ptr& __other) _NOEXCEPT {
+ if (__ptr_ != __other.__ptr_) {
+ __increment_refcount(__other.__ptr_);
+ __decrement_refcount(__ptr_);
+ __ptr_ = __other.__ptr_;
+ }
+ return *this;
+}
+
+// Must be defined outside the class definition due to _LIBCPP_EXPORTED_FROM_LIB_INLINEABLE
+_LIBCPP_EXPORTED_FROM_LIB_INLINEABLE exception_ptr::~exception_ptr() _NOEXCEPT { __decrement_refcount(__ptr_); }
+
inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT {
std::swap(__x.__ptr_, __y.__ptr_);
}
@@ -222,6 +269,8 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT {
#endif // _LIBCPP_ABI_MICROSOFT
_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
+_LIBCPP_DIAGNOSTIC_POP
+
_LIBCPP_POP_MACROS
#endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H
diff --git a/libcxx/src/exception.cpp b/libcxx/src/exception.cpp
index ac6324cd9fe35..9dd9b0c9938fd 100644
--- a/libcxx/src/exception.cpp
+++ b/libcxx/src/exception.cpp
@@ -8,6 +8,7 @@
#define _LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION
#define _LIBCPP_DISABLE_DEPRECATION_WARNINGS
+#define _LIBCPP_EMIT_CODE_FOR_EXCEPTION_PTR
#include <exception>
#include <new>
diff --git a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
index 8f5c2060bb06c..e09bf8981263f 100644
--- a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp
@@ -13,19 +13,12 @@
namespace std {
-exception_ptr::~exception_ptr() noexcept { __cxa_decrement_exception_refcount(__ptr_); }
-
-exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
- __cxa_increment_exception_refcount(__ptr_);
+void exception_ptr::__do_increment_refcount(void* __ptr) noexcept {
+ __cxa_increment_exception_refcount(__ptr);
}
-exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept {
- if (__ptr_ != other.__ptr_) {
- __cxa_increment_exception_refcount(other.__ptr_);
- __cxa_decrement_exception_refcount(__ptr_);
- __ptr_ = other.__ptr_;
- }
- return *this;
+void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
+ __cxa_decrement_exception_refcount(__ptr);
}
exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept {
diff --git a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
index 174b44ce0e6f7..c7b2e343b5f09 100644
--- a/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp
@@ -7,14 +7,14 @@
//
//===----------------------------------------------------------------------===//
+
// libsupc++ does not implement the dependent EH ABI and the functionality
// it uses to implement std::exception_ptr (which it declares as an alias of
// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
// we have little choice but to hijack std::__exception_ptr::exception_ptr's
-// (which fortunately has the same layout as our std::exception_ptr) copy
-// constructor, assignment operator and destructor (which are part of its
-// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
-// function.
+// _M_addref and _M_release and its rethrow_exception function. Fortunately,
+// glibcxx's exception_ptr has the same layout as our exception_ptr and we can
+// reinterpret_cast between the two.
namespace std {
@@ -23,27 +23,20 @@ namespace __exception_ptr {
struct exception_ptr {
void* __ptr_;
- explicit exception_ptr(void*) noexcept;
- exception_ptr(const exception_ptr&) noexcept;
- exception_ptr& operator=(const exception_ptr&) noexcept;
- ~exception_ptr() noexcept;
+ void _M_addref() noexcept;
+ void _M_release() noexcept;
};
} // namespace __exception_ptr
[[noreturn]] void rethrow_exception(__exception_ptr::exception_ptr);
-exception_ptr::~exception_ptr() noexcept { reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr(); }
-
-exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
- new (reinterpret_cast<void*>(this))
- __exception_ptr::exception_ptr(reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
+void exception_ptr::__do_increment_refcount(void* __ptr) noexcept {
+ reinterpret_cast<__exception_ptr::exception_ptr*>(this)->_M_addref();
}
-exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept {
- *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
- reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
- return *this;
+void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
+ reinterpret_cast<__exception_ptr::exception_ptr*>(this)->_M_release();
}
exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept {
diff --git a/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp b/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
index 05a71ce34e5ac..78be16bf95188 100644
--- a/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
+++ b/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp
@@ -11,17 +11,12 @@
namespace std {
-exception_ptr::~exception_ptr() noexcept {
+void exception_ptr::__do_increment_refcount(void* __ptr) noexcept {
#warning exception_ptr not yet implemented
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
}
-exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) {
-#warning exception_ptr not yet implemented
- __libcpp_verbose_abort("exception_ptr not yet implemented\n");
-}
-
-exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept {
+void exception_ptr::__do_decrement_refcount(void* __ptr) noexcept {
#warning exception_ptr not yet implemented
__libcpp_verbose_abort("exception_ptr not yet implemented\n");
}
More information about the libcxx-commits
mailing list