[libcxx-commits] [libcxx] [libc++] Add move constructor & assignment to `exception_ptr` (PR #164281)

Adrian Vogelsgesang via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 31 06:55:55 PDT 2025


https://github.com/vogelsgesang updated https://github.com/llvm/llvm-project/pull/164281

>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 1/9] [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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 08b0a141a1fdd5a3143fb821f12714f91d562fd9 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 9/9] Apply `std` in front of `swap` in the correct place

---
 libcxx/include/__exception/exception_ptr.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h
index e096d8e1dfd49..5178cf9dbfcc5 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));
-    std::swap(__tmp, *this);
+    swap(__tmp, *this);
     return *this;
   }
   ~exception_ptr() _NOEXCEPT;
@@ -107,7 +107,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



More information about the libcxx-commits mailing list