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

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 2 03:51:27 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

<details>
<summary>Changes</summary>

Implements  P3936R1

Closes #<!-- -->189594

# References:

- https://llvm.org/PR162236
- https://wg21.link/p3936r1

---
Full diff: https://github.com/llvm/llvm-project/pull/189761.diff


8 Files Affected:

- (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1) 
- (modified) libcxx/docs/ReleaseNotes/23.rst (+1) 
- (modified) libcxx/include/__atomic/atomic_ref.h (+2-1) 
- (modified) libcxx/include/version (+2-2) 
- (modified) libcxx/test/std/atomics/atomics.ref/address.pass.cpp (+35-4) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+2-2) 
- (modified) libcxx/utils/generate_feature_test_macro_components.py (+1-1) 


``````````diff
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..462c90ded8701 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`` (`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 a5bc0aba38bd2..c551f99024931 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>
@@ -224,7 +225,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 __copy_cv_t<_Tp, void>* 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..ec94e639b9598 100644
--- a/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.ref/address.pass.cpp
@@ -8,31 +8,62 @@
 
 // REQUIRES: std-at-least-c++26
 
-// constexpr T* address() const noexcept;
+// ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-deprecated-volatile
+// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated-volatile
+
+// constexpr address-return-type address() const noexcept;
 
 #include <atomic>
 #include <cassert>
 #include <concepts>
 #include <memory>
+#include <type_traits>
 
 #include "atomic_helpers.h"
 #include "test_macros.h"
 
+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 {
+    TestEachAtomicTypeWithCV<TestFunctor, std::type_identity_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::add_const_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::add_volatile_t>()();
+    TestEachAtomicTypeWithCV<TestFunctor, std::add_cv_t>()();
+  }
+};
+
 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 =
+        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);
 
-    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..a1d5aca1d3442 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -197,7 +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,
             },
             "headers": ["atomic"],
         },

``````````

</details>


https://github.com/llvm/llvm-project/pull/189761


More information about the libcxx-commits mailing list