[libcxx-commits] [libcxx] [libc++][atomics] P3936R1: Safer ``atomic_ref::address`` (PR #189761)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Tue Mar 31 22:44:47 PDT 2026


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/189761

>From 65495a97ff6272c0a581bd9905b8d0992ad1daec Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 Apr 2026 00:57:07 +0300
Subject: [PATCH 1/5] [libc++][atomics] P3936R1: Safer ``atomic_ref::address``

Implements  P3936R1

Closes #

References:

- https://llvm.org/PR162236
- https://wg21.link/p3936r1
---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +-
 libcxx/docs/ReleaseNotes/23.rst               |   1 +
 libcxx/include/__atomic/atomic_ref.h          |   6 +-
 libcxx/include/version                        |   4 +-
 .../std/atomics/atomics.ref/address.pass.cpp  | 132 +++++++++++++++++-
 .../atomic.version.compile.pass.cpp           |   4 +-
 .../version.version.compile.pass.cpp          |   4 +-
 .../generate_feature_test_macro_components.py |   3 +-
 8 files changed, 143 insertions(+), 13 deletions(-)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 0f65770a4fa14..1447261645a7b 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -420,7 +420,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_atomic_min_max``                               *unimplemented*
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_atomic_ref``                                   ``202411L``
+    ``__cpp_lib_atomic_ref``                                   ``202603L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_bind_front``                                   ``202306L``
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index aeabfeedfbc5e..f64491eca98d0 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -39,6 +39,7 @@ Implemented Papers
 ------------------
 
 - P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github <https://llvm.org/PR105184>`__)
+- P3936R1: Safer ``atomic_ref::address``
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h
index a5bc0aba38bd2..30910d81c976a 100644
--- a/libcxx/include/__atomic/atomic_ref.h
+++ b/libcxx/include/__atomic/atomic_ref.h
@@ -31,6 +31,7 @@
 #include <__cstddef/ptrdiff_t.h>
 #include <__memory/addressof.h>
 #include <__memory/is_sufficiently_aligned.h>
+#include <__type_traits/copy_cv.h>
 #include <__type_traits/has_unique_object_representation.h>
 #include <__type_traits/is_trivially_copyable.h>
 #include <cstring>
@@ -113,6 +114,9 @@ struct __atomic_ref_base {
 
 public:
   using value_type = _Tp;
+#  if _LIBCPP_STD_VER >= 26
+  using __address_return_t = __copy_cv_t<_Tp, void>*;
+#  endif
 
   static constexpr size_t required_alignment = alignof(_Tp) > __min_alignment ? alignof(_Tp) : __min_alignment;
 
@@ -224,7 +228,7 @@ struct __atomic_ref_base {
   _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__atomic_notify_one(*this); }
   _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__atomic_notify_all(*this); }
 #  if _LIBCPP_STD_VER >= 26
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* address() const noexcept { return __ptr_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __address_return_t address() const noexcept { return __ptr_; }
 #  endif
 
 protected:
diff --git a/libcxx/include/version b/libcxx/include/version
index c43d36e569efb..105a04545da0e 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -37,7 +37,7 @@ __cpp_lib_atomic_float                                  201711L <atomic>
 __cpp_lib_atomic_is_always_lock_free                    201603L <atomic>
 __cpp_lib_atomic_lock_free_type_aliases                 201907L <atomic>
 __cpp_lib_atomic_min_max                                202403L <atomic>
-__cpp_lib_atomic_ref                                    202411L <atomic>
+__cpp_lib_atomic_ref                                    202603L <atomic>
                                                         201806L // C++20
 __cpp_lib_atomic_shared_ptr                             201711L <atomic>
 __cpp_lib_atomic_value_initialization                   201911L <atomic> <memory>
@@ -551,7 +551,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # define __cpp_lib_associative_heterogeneous_insertion  202306L
 // # define __cpp_lib_atomic_min_max                       202403L
 # undef  __cpp_lib_atomic_ref
-# define __cpp_lib_atomic_ref                           202411L
+# define __cpp_lib_atomic_ref                           202603L
 # undef  __cpp_lib_bind_front
 # define __cpp_lib_bind_front                           202306L
 # define __cpp_lib_bitset                               202306L
diff --git a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
index 27f0c198e89ef..299bcd6e75f7b 100644
--- a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
@@ -8,7 +8,7 @@
 
 // REQUIRES: std-at-least-c++26
 
-// constexpr T* address() const noexcept;
+// constexpr address-return-type address() const noexcept;
 
 #include <atomic>
 #include <cassert>
@@ -18,21 +18,145 @@
 #include "atomic_helpers.h"
 #include "test_macros.h"
 
+// Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's
+// top-level cv-qualifiers.
+template <class _From>
+struct copy_cv {
+  template <class _To>
+  using apply _LIBCPP_NODEBUG = _To;
+};
+
+template <class _From>
+struct copy_cv<const _From> {
+  template <class _To>
+  using apply _LIBCPP_NODEBUG = const _To;
+};
+
+template <class _From>
+struct copy_cv<volatile _From> {
+  template <class _To>
+  using apply _LIBCPP_NODEBUG = volatile _To;
+};
+
+template <class _From>
+struct copy_cv<const volatile _From> {
+  template <class _To>
+  using apply _LIBCPP_NODEBUG = const volatile _To;
+};
+
+template <class _From, class _To>
+using copy_cv_t _LIBCPP_NODEBUG = typename copy_cv<_From>::template apply<_To>;
+
+template <template <class TestArg> class TestFunctor>
+struct TestEachCVAtomicType {
+  void operator()() const {
+    // integral types
+
+    TestFunctor<char>()();
+    TestFunctor<signed char>()();
+    TestFunctor<unsigned char>()();
+    TestFunctor<short>()();
+    TestFunctor<unsigned short>()();
+    TestFunctor<int>()();
+    TestFunctor<unsigned int>()();
+    TestFunctor<long>()();
+    TestFunctor<unsigned long>()();
+    TestFunctor<long long>()();
+    TestFunctor<unsigned long long>()();
+    TestFunctor<wchar_t>()();
+#if TEST_STD_VER >= 20 && defined(__cpp_char8_t)
+    TestFunctor<char8_t>()();
+#endif
+    TestFunctor<char16_t>()();
+    TestFunctor<char32_t>()();
+    TestFunctor<std::int8_t>()();
+    TestFunctor<std::uint8_t>()();
+    TestFunctor<std::int16_t>()();
+    TestFunctor<std::uint16_t>()();
+    TestFunctor<std::int32_t>()();
+    TestFunctor<std::uint32_t>()();
+    TestFunctor<std::int64_t>()();
+    TestFunctor<std::uint64_t>()();
+
+    TestFunctor<const char>()();
+    TestFunctor<const signed char>()();
+    TestFunctor<const unsigned char>()();
+    TestFunctor<const short>()();
+    TestFunctor<const unsigned short>()();
+    TestFunctor<const int>()();
+    TestFunctor<const unsigned int>()();
+    TestFunctor<const long>()();
+    TestFunctor<const unsigned long>()();
+    TestFunctor<const long long>()();
+    TestFunctor<const unsigned long long>()();
+    TestFunctor<const wchar_t>()();
+#if TEST_STD_VER >= 20 && defined(__cpp_char8_t)
+    TestFunctor<const char8_t>()();
+#endif
+    TestFunctor<const char16_t>()();
+    TestFunctor<const char32_t>()();
+    TestFunctor<const std::int8_t>()();
+    TestFunctor<const std::uint8_t>()();
+    TestFunctor<const std::int16_t>()();
+    TestFunctor<const std::uint16_t>()();
+    TestFunctor<const std::int32_t>()();
+    TestFunctor<const std::uint32_t>()();
+    TestFunctor<const std::int64_t>()();
+    TestFunctor<const std::uint64_t>()();
+
+    TestFunctor<char>()();
+    TestFunctor<signed char>()();
+    TestFunctor<unsigned char>()();
+    TestFunctor<short>()();
+    TestFunctor<unsigned short>()();
+    TestFunctor<int>()();
+    TestFunctor<unsigned int>()();
+    TestFunctor<long>()();
+    TestFunctor<unsigned long>()();
+    TestFunctor<long long>()();
+    TestFunctor<unsigned long long>()();
+    TestFunctor<wchar_t>()();
+#if TEST_STD_VER >= 20 && defined(__cpp_char8_t)
+    TestFunctor<char8_t>()();
+#endif
+    TestFunctor<char16_t>()();
+    TestFunctor<char32_t>()();
+    TestFunctor<std::int8_t>()();
+    TestFunctor<std::uint8_t>()();
+    TestFunctor<std::int16_t>()();
+    TestFunctor<std::uint16_t>()();
+    TestFunctor<std::int32_t>()();
+    TestFunctor<std::uint32_t>()();
+    TestFunctor<std::int64_t>()();
+    TestFunctor<std::uint64_t>()();
+
+    // floating-point types
+
+    TestFunctor<float>()();
+    TestFunctor<double>()();
+
+    TestFunctor<const float>()();
+    TestFunctor<const double>()();
+  }
+};
+
 template <typename T>
 struct TestAddress {
   void operator()() const {
     alignas(std::atomic_ref<T>::required_alignment) T x(T(1));
     const std::atomic_ref<T> a(x);
 
-    std::same_as<T*> decltype(auto) p = a.address();
+    using AddressReturnT = copy_cv_t<T, void>*;
+
+    std::same_as<AddressReturnT> decltype(auto) p = a.address();
     assert(std::addressof(x) == p);
 
-    static_assert(noexcept((a.address())));
+    static_assert(noexcept(a.address()));
   }
 };
 
 int main(int, char**) {
-  TestEachAtomicType<TestAddress>()();
+  TestEachCVAtomicType<TestAddress>()();
 
   return 0;
 }
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp
index 8bd027445c85b..e62416257a696 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp
@@ -355,8 +355,8 @@
 #  ifndef __cpp_lib_atomic_ref
 #    error "__cpp_lib_atomic_ref should be defined in c++26"
 #  endif
-#  if __cpp_lib_atomic_ref != 202411L
-#    error "__cpp_lib_atomic_ref should have the value 202411L in c++26"
+#  if __cpp_lib_atomic_ref != 202603L
+#    error "__cpp_lib_atomic_ref should have the value 202603L in c++26"
 #  endif
 
 #  if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index a1c8755af4ad9..71b9d573a1778 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -6341,8 +6341,8 @@
 #  ifndef __cpp_lib_atomic_ref
 #    error "__cpp_lib_atomic_ref should be defined in c++26"
 #  endif
-#  if __cpp_lib_atomic_ref != 202411L
-#    error "__cpp_lib_atomic_ref should have the value 202411L in c++26"
+#  if __cpp_lib_atomic_ref != 202603L
+#    error "__cpp_lib_atomic_ref should have the value 202603L in c++26"
 #  endif
 
 #  if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index c5f81ca172f5a..55748bde39fb5 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -197,7 +197,8 @@ def add_version_header(tc):
             "name": "__cpp_lib_atomic_ref",
             "values": {
                 "c++20": 201806,
-                "c++26": 202411,  # P2835R7: Expose std::atomic_ref 's object address
+                # "c++26": 202411,  # P2835R7: Expose std::atomic_ref 's object address
+                "c++26": 202603,  # P3936R1: Safer atomic_ref::address
             },
             "headers": ["atomic"],
         },

>From bb7ea3a7b86fcd00fc8543137a5c727b880d7174 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 Apr 2026 01:17:00 +0300
Subject: [PATCH 2/5] Full coverage

---
 .../std/atomics/atomics.ref/address.pass.cpp  | 115 +++++-------------
 1 file changed, 28 insertions(+), 87 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
index 299bcd6e75f7b..c90c740eb819a 100644
--- a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 // REQUIRES: std-at-least-c++26
+// ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-deprecated-volatile
+// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated-volatile
 
 // constexpr address-return-type address() const noexcept;
 
@@ -47,96 +49,35 @@ struct copy_cv<const volatile _From> {
 template <class _From, class _To>
 using copy_cv_t _LIBCPP_NODEBUG = typename copy_cv<_From>::template apply<_To>;
 
+template <class T>
+using identity_t = T;
+
+template <class T>
+using add_const_t = const T;
+
+template <class T>
+using add_volatile_t = volatile T;
+
+template <class T>
+using add_const_volatile_t = const volatile T;
+
+template <template <class TestArg> class TestFunctor, template <class> class AddQualifier>
+struct TestEachAtomicTypeWithCV {
+  template <class T>
+  struct Qualified {
+    void operator()() const { TestFunctor<AddQualifier<T>>()(); }
+  };
+
+  void operator()() const { TestEachAtomicType<Qualified>()(); }
+};
+
 template <template <class TestArg> class TestFunctor>
 struct TestEachCVAtomicType {
   void operator()() const {
-    // integral types
-
-    TestFunctor<char>()();
-    TestFunctor<signed char>()();
-    TestFunctor<unsigned char>()();
-    TestFunctor<short>()();
-    TestFunctor<unsigned short>()();
-    TestFunctor<int>()();
-    TestFunctor<unsigned int>()();
-    TestFunctor<long>()();
-    TestFunctor<unsigned long>()();
-    TestFunctor<long long>()();
-    TestFunctor<unsigned long long>()();
-    TestFunctor<wchar_t>()();
-#if TEST_STD_VER >= 20 && defined(__cpp_char8_t)
-    TestFunctor<char8_t>()();
-#endif
-    TestFunctor<char16_t>()();
-    TestFunctor<char32_t>()();
-    TestFunctor<std::int8_t>()();
-    TestFunctor<std::uint8_t>()();
-    TestFunctor<std::int16_t>()();
-    TestFunctor<std::uint16_t>()();
-    TestFunctor<std::int32_t>()();
-    TestFunctor<std::uint32_t>()();
-    TestFunctor<std::int64_t>()();
-    TestFunctor<std::uint64_t>()();
-
-    TestFunctor<const char>()();
-    TestFunctor<const signed char>()();
-    TestFunctor<const unsigned char>()();
-    TestFunctor<const short>()();
-    TestFunctor<const unsigned short>()();
-    TestFunctor<const int>()();
-    TestFunctor<const unsigned int>()();
-    TestFunctor<const long>()();
-    TestFunctor<const unsigned long>()();
-    TestFunctor<const long long>()();
-    TestFunctor<const unsigned long long>()();
-    TestFunctor<const wchar_t>()();
-#if TEST_STD_VER >= 20 && defined(__cpp_char8_t)
-    TestFunctor<const char8_t>()();
-#endif
-    TestFunctor<const char16_t>()();
-    TestFunctor<const char32_t>()();
-    TestFunctor<const std::int8_t>()();
-    TestFunctor<const std::uint8_t>()();
-    TestFunctor<const std::int16_t>()();
-    TestFunctor<const std::uint16_t>()();
-    TestFunctor<const std::int32_t>()();
-    TestFunctor<const std::uint32_t>()();
-    TestFunctor<const std::int64_t>()();
-    TestFunctor<const std::uint64_t>()();
-
-    TestFunctor<char>()();
-    TestFunctor<signed char>()();
-    TestFunctor<unsigned char>()();
-    TestFunctor<short>()();
-    TestFunctor<unsigned short>()();
-    TestFunctor<int>()();
-    TestFunctor<unsigned int>()();
-    TestFunctor<long>()();
-    TestFunctor<unsigned long>()();
-    TestFunctor<long long>()();
-    TestFunctor<unsigned long long>()();
-    TestFunctor<wchar_t>()();
-#if TEST_STD_VER >= 20 && defined(__cpp_char8_t)
-    TestFunctor<char8_t>()();
-#endif
-    TestFunctor<char16_t>()();
-    TestFunctor<char32_t>()();
-    TestFunctor<std::int8_t>()();
-    TestFunctor<std::uint8_t>()();
-    TestFunctor<std::int16_t>()();
-    TestFunctor<std::uint16_t>()();
-    TestFunctor<std::int32_t>()();
-    TestFunctor<std::uint32_t>()();
-    TestFunctor<std::int64_t>()();
-    TestFunctor<std::uint64_t>()();
-
-    // floating-point types
-
-    TestFunctor<float>()();
-    TestFunctor<double>()();
-
-    TestFunctor<const float>()();
-    TestFunctor<const double>()();
+    TestEachAtomicTypeWithCV<TestFunctor, identity_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, add_const_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, add_volatile_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, add_const_volatile_t>()();
   }
 };
 

>From de1406ab257bbf682ce2bfaaef1312601d5e6808 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hristo.goshev.hristov at gmail.com>
Date: Wed, 1 Apr 2026 08:23:35 +0300
Subject: [PATCH 3/5] Apply suggestions from code review

Co-authored-by: A. Jiang <de34 at live.cn>
---
 libcxx/docs/ReleaseNotes/23.rst                        | 2 +-
 libcxx/include/__atomic/atomic_ref.h                   | 2 +-
 libcxx/test/std/atomics/atomics.ref/address.pass.cpp   | 8 ++++----
 libcxx/utils/generate_feature_test_macro_components.py | 3 +--
 4 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index f64491eca98d0..462c90ded8701 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -39,7 +39,7 @@ Implemented Papers
 ------------------
 
 - P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github <https://llvm.org/PR105184>`__)
-- P3936R1: Safer ``atomic_ref::address``
+- P3936R1: Safer ``atomic_ref::address`` (`Github <https://llvm.org/PR189594>`__)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h
index 30910d81c976a..ec1b24e730ac8 100644
--- a/libcxx/include/__atomic/atomic_ref.h
+++ b/libcxx/include/__atomic/atomic_ref.h
@@ -228,7 +228,7 @@ struct __atomic_ref_base {
   _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__atomic_notify_one(*this); }
   _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__atomic_notify_all(*this); }
 #  if _LIBCPP_STD_VER >= 26
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __address_return_t address() const noexcept { return __ptr_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __copy_cv_t<_Tp, void>* address() const noexcept { return __ptr_; }
 #  endif
 
 protected:
diff --git a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
index c90c740eb819a..c7d9c8c6152e0 100644
--- a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
@@ -74,10 +74,10 @@ struct TestEachAtomicTypeWithCV {
 template <template <class TestArg> class TestFunctor>
 struct TestEachCVAtomicType {
   void operator()() const {
-    TestEachAtomicTypeWithCV<TestFunctor, identity_t>()();
-    TestEachAtomicTypeWithCV<TestFunctor, add_const_t>()();
-    TestEachAtomicTypeWithCV<TestFunctor, add_volatile_t>()();
-    TestEachAtomicTypeWithCV<TestFunctor, add_const_volatile_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::type_identity_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::add_const_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::add_volatile_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::add_cv_t>()();
   }
 };
 
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 55748bde39fb5..a1d5aca1d3442 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -197,8 +197,7 @@ def add_version_header(tc):
             "name": "__cpp_lib_atomic_ref",
             "values": {
                 "c++20": 201806,
-                # "c++26": 202411,  # P2835R7: Expose std::atomic_ref 's object address
-                "c++26": 202603,  # P3936R1: Safer atomic_ref::address
+                "c++26": 202603,
             },
             "headers": ["atomic"],
         },

>From b29afd811adc04349d579810c19967a20f6710f5 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 Apr 2026 08:27:19 +0300
Subject: [PATCH 4/5] Cleanup

---
 libcxx/include/__atomic/atomic_ref.h                 |  3 ---
 libcxx/test/std/atomics/atomics.ref/address.pass.cpp | 11 ++++++-----
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h
index ec1b24e730ac8..c551f99024931 100644
--- a/libcxx/include/__atomic/atomic_ref.h
+++ b/libcxx/include/__atomic/atomic_ref.h
@@ -114,9 +114,6 @@ struct __atomic_ref_base {
 
 public:
   using value_type = _Tp;
-#  if _LIBCPP_STD_VER >= 26
-  using __address_return_t = __copy_cv_t<_Tp, void>*;
-#  endif
 
   static constexpr size_t required_alignment = alignof(_Tp) > __min_alignment ? alignof(_Tp) : __min_alignment;
 
diff --git a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
index c7d9c8c6152e0..db56be9080a25 100644
--- a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // REQUIRES: std-at-least-c++26
+
 // ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-deprecated-volatile
 // ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated-volatile
 
@@ -25,29 +26,29 @@
 template <class _From>
 struct copy_cv {
   template <class _To>
-  using apply _LIBCPP_NODEBUG = _To;
+  using apply = _To;
 };
 
 template <class _From>
 struct copy_cv<const _From> {
   template <class _To>
-  using apply _LIBCPP_NODEBUG = const _To;
+  using apply = const _To;
 };
 
 template <class _From>
 struct copy_cv<volatile _From> {
   template <class _To>
-  using apply _LIBCPP_NODEBUG = volatile _To;
+  using apply = volatile _To;
 };
 
 template <class _From>
 struct copy_cv<const volatile _From> {
   template <class _To>
-  using apply _LIBCPP_NODEBUG = const volatile _To;
+  using apply = const volatile _To;
 };
 
 template <class _From, class _To>
-using copy_cv_t _LIBCPP_NODEBUG = typename copy_cv<_From>::template apply<_To>;
+using copy_cv_t = typename copy_cv<_From>::template apply<_To>;
 
 template <class T>
 using identity_t = T;

>From 12cf1d7f1499aa46ccece5eb6807cfb9dedceaf2 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 1 Apr 2026 08:44:29 +0300
Subject: [PATCH 5/5] Applied suggestion

---
 .../std/atomics/atomics.ref/address.pass.cpp  | 49 +++----------------
 1 file changed, 7 insertions(+), 42 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
index db56be9080a25..ec94e639b9598 100644
--- a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
@@ -17,51 +17,11 @@
 #include <cassert>
 #include <concepts>
 #include <memory>
+#include <type_traits>
 
 #include "atomic_helpers.h"
 #include "test_macros.h"
 
-// Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's
-// top-level cv-qualifiers.
-template <class _From>
-struct copy_cv {
-  template <class _To>
-  using apply = _To;
-};
-
-template <class _From>
-struct copy_cv<const _From> {
-  template <class _To>
-  using apply = const _To;
-};
-
-template <class _From>
-struct copy_cv<volatile _From> {
-  template <class _To>
-  using apply = volatile _To;
-};
-
-template <class _From>
-struct copy_cv<const volatile _From> {
-  template <class _To>
-  using apply = const volatile _To;
-};
-
-template <class _From, class _To>
-using copy_cv_t = typename copy_cv<_From>::template apply<_To>;
-
-template <class T>
-using identity_t = T;
-
-template <class T>
-using add_const_t = const T;
-
-template <class T>
-using add_volatile_t = volatile T;
-
-template <class T>
-using add_const_volatile_t = const volatile T;
-
 template <template <class TestArg> class TestFunctor, template <class> class AddQualifier>
 struct TestEachAtomicTypeWithCV {
   template <class T>
@@ -88,7 +48,12 @@ struct TestAddress {
     alignas(std::atomic_ref<T>::required_alignment) T x(T(1));
     const std::atomic_ref<T> a(x);
 
-    using AddressReturnT = copy_cv_t<T, void>*;
+    using AddressReturnT =
+        std::conditional_t<std::is_const_v<T> && std::is_volatile_v<T>,
+                           const volatile void,
+                           std::conditional_t<std::is_volatile_v<T>,
+                                              volatile void,
+                                              std::conditional_t<std::is_const_v<T>, const void, void>>>*;
 
     std::same_as<AddressReturnT> decltype(auto) p = a.address();
     assert(std::addressof(x) == p);



More information about the libcxx-commits mailing list