[libcxx-commits] [libcxx] [libc++] Add move constructor & assignment to `exception_ptr` (PR #164281)
Adrian Vogelsgesang via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 21 05:18:45 PDT 2025
https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/164281
>From 47823b92f0e160893e34b339c92e1c455d69cbea Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 20 Oct 2025 13:47:44 +0000
Subject: [PATCH 1/7] [libc++] Add benchmark for `std::exception_ptr`
This commit adds benchmarks for `std::exception_ptr` to set a baseline
in preparation for follow-up optimizations.
---
.../test/benchmarks/exception_ptr.bench.cpp | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/libcxx/test/benchmarks/exception_ptr.bench.cpp b/libcxx/test/benchmarks/exception_ptr.bench.cpp
index 7791c510b1eb6..1ff1d8b10d2b0 100644
--- a/libcxx/test/benchmarks/exception_ptr.bench.cpp
+++ b/libcxx/test/benchmarks/exception_ptr.bench.cpp
@@ -18,4 +18,49 @@ void bm_make_exception_ptr(benchmark::State& state) {
}
BENCHMARK(bm_make_exception_ptr)->ThreadRange(1, 8);
+static bool exception_ptr_moves_copies_swap(std::exception_ptr p1) {
+ // Taken from https://github.com/llvm/llvm-project/issues/44892
+ std::exception_ptr p2(p1); // Copy constructor
+ std::exception_ptr p3(std::move(p2)); // Move constructor
+ p2 = std::move(p1); // Move assignment
+ p1 = p2; // Copy assignment
+ swap(p1, p2); // Swap
+ // Comparisons against nullptr. The overhead from creating temporary `exception_ptr`
+ // instances should be optimized out.
+ bool is_null = p1 == nullptr && nullptr == p2;
+ bool is_equal = p1 == p2; // Comparison
+ return is_null && is_equal;
+}
+
+void bm_nonnull_exception_ptr(benchmark::State& state) {
+ std::exception_ptr excptr = std::make_exception_ptr(42);
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(excptr));
+ }
+}
+BENCHMARK(bm_nonnull_exception_ptr);
+
+void bm_null_exception_ptr(benchmark::State& state) {
+ std::exception_ptr excptr;
+ for (auto _ : state) {
+ // All of the `exception_ptr_noops` are no-ops but the optimizer
+ // cannot optimize them away, because the `DoNotOptimize` calls
+ // prevent the optimizer from doing so.
+ benchmark::DoNotOptimize(excptr);
+ benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(excptr));
+ }
+}
+BENCHMARK(bm_null_exception_ptr);
+
+void bm_optimized_null_exception_ptr(benchmark::State& state) {
+ for (auto _ : state) {
+ // All of the `exception_ptr_noops` are no-ops because
+ // the exception_ptr is empty. Hence, the compiler should
+ // be able to optimize them very aggressively.
+ benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(std::exception_ptr{nullptr}));
+ }
+}
+BENCHMARK(bm_optimized_null_exception_ptr);
+
BENCHMARK_MAIN();
>From 2da884557c493cdc10ea5c34cce92bffad78b9f1 Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Mon, 20 Oct 2025 21:11:04 +0000
Subject: [PATCH 2/7] Update comments
---
libcxx/test/benchmarks/exception_ptr.bench.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/benchmarks/exception_ptr.bench.cpp b/libcxx/test/benchmarks/exception_ptr.bench.cpp
index 1ff1d8b10d2b0..467deeb3fd96d 100644
--- a/libcxx/test/benchmarks/exception_ptr.bench.cpp
+++ b/libcxx/test/benchmarks/exception_ptr.bench.cpp
@@ -32,6 +32,7 @@ static bool exception_ptr_moves_copies_swap(std::exception_ptr p1) {
return is_null && is_equal;
}
+// Benchmark copies, moves and comparisons of a non-null exception_ptr.
void bm_nonnull_exception_ptr(benchmark::State& state) {
std::exception_ptr excptr = std::make_exception_ptr(42);
for (auto _ : state) {
@@ -41,23 +42,22 @@ void bm_nonnull_exception_ptr(benchmark::State& state) {
}
BENCHMARK(bm_nonnull_exception_ptr);
+// Benchmark copies, moves and comparisons of a nullptr exception_ptr
+// where the compiler cannot prove that the exception_ptr is always
+// a nullptr and needs to emit runtime checks.
void bm_null_exception_ptr(benchmark::State& state) {
std::exception_ptr excptr;
for (auto _ : state) {
- // All of the `exception_ptr_noops` are no-ops but the optimizer
- // cannot optimize them away, because the `DoNotOptimize` calls
- // prevent the optimizer from doing so.
benchmark::DoNotOptimize(excptr);
benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(excptr));
}
}
BENCHMARK(bm_null_exception_ptr);
+// Benchmark copies, moves and comparisons of a nullptr exception_ptr
+// where the compiler can proof that the exception_ptr is always a nullptr.
void bm_optimized_null_exception_ptr(benchmark::State& state) {
for (auto _ : state) {
- // All of the `exception_ptr_noops` are no-ops because
- // the exception_ptr is empty. Hence, the compiler should
- // be able to optimize them very aggressively.
benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(std::exception_ptr{nullptr}));
}
}
>From bb6480e8de53232fee727053b5f9955df67af3fd Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
Date: Tue, 21 Oct 2025 11:59:33 +0200
Subject: [PATCH 3/7] update link in comment
Co-authored-by: Nikolas Klauser <nikolasklauser at berlin.de>
---
libcxx/test/benchmarks/exception_ptr.bench.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/benchmarks/exception_ptr.bench.cpp b/libcxx/test/benchmarks/exception_ptr.bench.cpp
index 467deeb3fd96d..fe754898f0c96 100644
--- a/libcxx/test/benchmarks/exception_ptr.bench.cpp
+++ b/libcxx/test/benchmarks/exception_ptr.bench.cpp
@@ -19,7 +19,7 @@ void bm_make_exception_ptr(benchmark::State& state) {
BENCHMARK(bm_make_exception_ptr)->ThreadRange(1, 8);
static bool exception_ptr_moves_copies_swap(std::exception_ptr p1) {
- // Taken from https://github.com/llvm/llvm-project/issues/44892
+ // Taken from https://llvm.org/PR45547
std::exception_ptr p2(p1); // Copy constructor
std::exception_ptr p3(std::move(p2)); // Move constructor
p2 = std::move(p1); // Move assignment
>From a799f0e92534d254ce1bca431c43acf2bfb4f23c Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Tue, 21 Oct 2025 10:52:47 +0000
Subject: [PATCH 4/7] Remove some comments
---
libcxx/test/benchmarks/exception_ptr.bench.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/benchmarks/exception_ptr.bench.cpp b/libcxx/test/benchmarks/exception_ptr.bench.cpp
index fe754898f0c96..c3a3aa3e044c9 100644
--- a/libcxx/test/benchmarks/exception_ptr.bench.cpp
+++ b/libcxx/test/benchmarks/exception_ptr.bench.cpp
@@ -20,15 +20,15 @@ BENCHMARK(bm_make_exception_ptr)->ThreadRange(1, 8);
static bool exception_ptr_moves_copies_swap(std::exception_ptr p1) {
// Taken from https://llvm.org/PR45547
- std::exception_ptr p2(p1); // Copy constructor
- std::exception_ptr p3(std::move(p2)); // Move constructor
- p2 = std::move(p1); // Move assignment
- p1 = p2; // Copy assignment
- swap(p1, p2); // Swap
+ std::exception_ptr p2(p1);
+ std::exception_ptr p3(std::move(p2));
+ p2 = std::move(p1);
+ p1 = p2;
+ swap(p1, p2);
// Comparisons against nullptr. The overhead from creating temporary `exception_ptr`
// instances should be optimized out.
bool is_null = p1 == nullptr && nullptr == p2;
- bool is_equal = p1 == p2; // Comparison
+ bool is_equal = p1 == p2;
return is_null && is_equal;
}
>From b81d32bb4ad124b2861e00b9e43f44499d12a84f Mon Sep 17 00:00:00 2001
From: Adrian Vogelsgesang <avogelsgesang at salesforce.com>
Date: Tue, 21 Oct 2025 11:29:51 +0000
Subject: [PATCH 5/7] Add benchmarks for individual operations
---
.../test/benchmarks/exception_ptr.bench.cpp | 135 ++++++++++++++++--
1 file changed, 125 insertions(+), 10 deletions(-)
diff --git a/libcxx/test/benchmarks/exception_ptr.bench.cpp b/libcxx/test/benchmarks/exception_ptr.bench.cpp
index c3a3aa3e044c9..5eee9f70cd665 100644
--- a/libcxx/test/benchmarks/exception_ptr.bench.cpp
+++ b/libcxx/test/benchmarks/exception_ptr.bench.cpp
@@ -18,7 +18,122 @@ void bm_make_exception_ptr(benchmark::State& state) {
}
BENCHMARK(bm_make_exception_ptr)->ThreadRange(1, 8);
-static bool exception_ptr_moves_copies_swap(std::exception_ptr p1) {
+void bm_exception_ptr_copy_ctor_nonnull(benchmark::State& state) {
+ std::exception_ptr excptr = std::make_exception_ptr(42);
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ benchmark::DoNotOptimize(std::exception_ptr(excptr));
+ }
+}
+BENCHMARK(bm_exception_ptr_copy_ctor_nonnull);
+
+void bm_exception_ptr_copy_ctor_null(benchmark::State& state) {
+ std::exception_ptr excptr = nullptr;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ benchmark::DoNotOptimize(std::exception_ptr(excptr));
+ }
+}
+BENCHMARK(bm_exception_ptr_copy_ctor_null);
+
+
+void bm_exception_ptr_move_ctor_nonnull(benchmark::State& state) {
+ std::exception_ptr excptr = std::make_exception_ptr(42);
+ for (auto _ : state) {
+ // Need to copy, such that the `excptr` is not moved from and
+ // empty after the first loop iteration.
+ std::exception_ptr excptr_copy(excptr);
+ benchmark::DoNotOptimize(excptr_copy);
+ benchmark::DoNotOptimize(std::exception_ptr(std::move(excptr_copy)));
+ }
+}
+BENCHMARK(bm_exception_ptr_move_ctor_nonnull);
+
+void bm_exception_ptr_move_ctor_null(benchmark::State& state) {
+ std::exception_ptr excptr = nullptr;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ benchmark::DoNotOptimize(std::exception_ptr(std::move(excptr)));
+ }
+}
+BENCHMARK(bm_exception_ptr_move_ctor_null);
+
+void bm_exception_ptr_copy_assign_nonnull(benchmark::State& state) {
+ std::exception_ptr excptr = std::make_exception_ptr(42);
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ std::exception_ptr new_excptr;
+ new_excptr = excptr;
+ benchmark::DoNotOptimize(new_excptr);
+ }
+}
+BENCHMARK(bm_exception_ptr_copy_assign_nonnull);
+
+void bm_exception_ptr_copy_assign_null(benchmark::State& state) {
+ std::exception_ptr excptr = nullptr;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ std::exception_ptr new_excptr;
+ new_excptr = excptr;
+ benchmark::DoNotOptimize(new_excptr);
+ }
+}
+BENCHMARK(bm_exception_ptr_copy_assign_null);
+
+
+void bm_exception_ptr_move_assign_nonnull(benchmark::State& state) {
+ std::exception_ptr excptr = std::make_exception_ptr(42);
+ for (auto _ : state) {
+ // Need to copy, such that the `excptr` is not moved from and
+ // empty after the first loop iteration.
+ std::exception_ptr excptr_copy(excptr);
+ benchmark::DoNotOptimize(excptr_copy);
+ std::exception_ptr new_excptr;
+ new_excptr = std::move(excptr_copy);
+ benchmark::DoNotOptimize(new_excptr);
+ }
+}
+BENCHMARK(bm_exception_ptr_move_assign_nonnull);
+
+void bm_exception_ptr_move_assign_null(benchmark::State& state) {
+ std::exception_ptr excptr = nullptr;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ std::exception_ptr new_excptr;
+ new_excptr = std::move(excptr);
+ benchmark::DoNotOptimize(new_excptr);
+ }
+}
+BENCHMARK(bm_exception_ptr_move_assign_null);
+
+void bm_exception_ptr_swap_nonnull(benchmark::State& state) {
+ std::exception_ptr excptr = std::make_exception_ptr(41);
+ std::exception_ptr excptr2 = std::make_exception_ptr(42);
+ for (auto _ : state) {
+ swap(excptr, excptr2);
+ benchmark::DoNotOptimize(excptr);
+ benchmark::DoNotOptimize(excptr2);
+ }
+}
+BENCHMARK(bm_exception_ptr_swap_nonnull);
+
+void bm_exception_ptr_swap_null(benchmark::State& state) {
+ std::exception_ptr excptr = nullptr;
+ std::exception_ptr excptr2 = nullptr;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(excptr);
+ swap(excptr, excptr2);
+ benchmark::DoNotOptimize(excptr2);
+ }
+}
+BENCHMARK(bm_exception_ptr_swap_null);
+
+// A chain of moves, copies and swaps.
+// In contrast to the previous benchmarks of individual operations,
+// this benchmark performs a chain of operations. It thereby
+// specifically stresses the information available to the compiler
+// for optimizations from the header itself.
+static bool exception_ptr_move_copy_swap(std::exception_ptr p1) {
// Taken from https://llvm.org/PR45547
std::exception_ptr p2(p1);
std::exception_ptr p3(std::move(p2));
@@ -33,34 +148,34 @@ static bool exception_ptr_moves_copies_swap(std::exception_ptr p1) {
}
// Benchmark copies, moves and comparisons of a non-null exception_ptr.
-void bm_nonnull_exception_ptr(benchmark::State& state) {
+void bm_exception_ptr_move_copy_swap_nonnull(benchmark::State& state) {
std::exception_ptr excptr = std::make_exception_ptr(42);
for (auto _ : state) {
benchmark::DoNotOptimize(excptr);
- benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(excptr));
+ benchmark::DoNotOptimize(exception_ptr_move_copy_swap(excptr));
}
}
-BENCHMARK(bm_nonnull_exception_ptr);
+BENCHMARK(bm_exception_ptr_move_copy_swap_nonnull);
// Benchmark copies, moves and comparisons of a nullptr exception_ptr
// where the compiler cannot prove that the exception_ptr is always
// a nullptr and needs to emit runtime checks.
-void bm_null_exception_ptr(benchmark::State& state) {
+void bm_exception_ptr_move_copy_swap_null(benchmark::State& state) {
std::exception_ptr excptr;
for (auto _ : state) {
benchmark::DoNotOptimize(excptr);
- benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(excptr));
+ benchmark::DoNotOptimize(exception_ptr_move_copy_swap(excptr));
}
}
-BENCHMARK(bm_null_exception_ptr);
+BENCHMARK(bm_exception_ptr_move_copy_swap_null);
// Benchmark copies, moves and comparisons of a nullptr exception_ptr
// where the compiler can proof that the exception_ptr is always a nullptr.
-void bm_optimized_null_exception_ptr(benchmark::State& state) {
+void bm_exception_ptr_move_copy_swap_null_optimized(benchmark::State& state) {
for (auto _ : state) {
- benchmark::DoNotOptimize(exception_ptr_moves_copies_swap(std::exception_ptr{nullptr}));
+ benchmark::DoNotOptimize(exception_ptr_move_copy_swap(std::exception_ptr{nullptr}));
}
}
-BENCHMARK(bm_optimized_null_exception_ptr);
+BENCHMARK(bm_exception_ptr_move_copy_swap_null_optimized);
BENCHMARK_MAIN();
>From ec3d5b37df67fb950fe1e73c6812242f8cc17f7e 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 6/7] [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 154c286681e040a2e927e16344c491d085613943 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 7/7] 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");
More information about the libcxx-commits
mailing list