]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libtdc++: Test atomic_ref<volatile T> only if operations are lock-free [PR122584]
authorTomasz Kamiński <tkaminsk@redhat.com>
Wed, 12 Nov 2025 10:16:58 +0000 (11:16 +0100)
committerTomasz Kamiński <tkaminsk@redhat.com>
Thu, 13 Nov 2025 12:23:23 +0000 (13:23 +0100)
For non-templated tests, a volatile_<T> alias is used. This alias expands to
volatile T if std::atomic_ref<T>::is_always_lock_free is true, and to T
otherwise. For templated functions, testing is controlled using if constexpr.

PR libstdc++/115402
PR libstdc++/122584

libstdc++-v3/ChangeLog:

* testsuite/29_atomics/atomic_ref/address.cc: Guard test for
volatile with if constexpr.
* testsuite/29_atomics/atomic_ref/deduction.cc: Likewise.
* testsuite/29_atomics/atomic_ref/op_support.cc: Likewise.
* testsuite/29_atomics/atomic_ref/requirements.cc: Likewise.
* testsuite/29_atomics/atomic_ref/bool.cc: Use volatile_t alias.
* testsuite/29_atomics/atomic_ref/generic.cc: Likewise.
* testsuite/29_atomics/atomic_ref/integral.cc: Likewise.
* testsuite/29_atomics/atomic_ref/pointer.cc: Likewise.
* testsuite/29_atomics/atomic_ref/float.cc: Likewise, and remove
not discarding if constexpr.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/testsuite/29_atomics/atomic_ref/address.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/bool.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/deduction.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/float.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/generic.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/op_support.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/pointer.cc
libstdc++-v3/testsuite/29_atomics/atomic_ref/requirements.cc

index 42a080af55e296c2d28d7ba191b2d6c72a78be4f..e2eda506efa28b691358573019137fc0ed185416 100644 (file)
@@ -24,8 +24,11 @@ void testAtomicRefAddressForCV()
 {
   testAtomicRefAddress<T>();
   testAtomicRefAddress<const T>();
-  testAtomicRefAddress<volatile T>();
-  testAtomicRefAddress<const volatile T>();
+  if constexpr (std::atomic_ref<T>::is_always_lock_free)
+  {
+    testAtomicRefAddress<volatile T>();
+    testAtomicRefAddress<const volatile T>();
+  }
 }
 
 int
index c73319010ee8ef76f2f2046ec11fca20fa671419..76ba9fdbc632643f2382f001a7a5041b0f3b44ca 100644 (file)
 
 #include <atomic>
 #include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
 
 void
 test01()
 {
   bool value;
-
   {
     const auto mo = std::memory_order_relaxed;
     std::atomic_ref<bool> a(value);
@@ -66,8 +70,8 @@ test02()
   std::atomic_ref<bool> a0(b);
   std::atomic_ref<bool> a1(b);
   std::atomic_ref<const bool> a1c(b);
-  std::atomic_ref<volatile bool> a1v(b);
-  std::atomic_ref<const volatile bool> a1cv(b);
+  std::atomic_ref<volatile_<bool>> a1v(b);
+  std::atomic_ref<volatile_<const bool>> a1cv(b);
   std::atomic_ref<bool> a2(a0);
   b = true;
   VERIFY( a1.load() );
index 01dbfce2375180f716ad0c276cf58316a0b0ce21..bfc2080e566a2c79ee5673dd2795b154ad6fd3c5 100644 (file)
@@ -33,8 +33,11 @@ test(T v)
 {
   test_impl<T>(v);
   test_impl<const T>(v);
-  test_impl<volatile T>(v);
-  test_impl<const volatile T>(v);
+  if constexpr (std::atomic_ref<T>::is_always_lock_free)
+  {
+    test_impl<volatile T>(v);
+    test_impl<const volatile T>(v);
+  }
 }
 
 int main()
index c69f3a711d3483974ff64e0b21412994b3993a54..5736668aeee1c6f796f3a58fc0eca6077b3b8244 100644 (file)
 
 #include <atomic>
 #include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
 
 void
 test01()
@@ -297,22 +302,19 @@ test03()
 void
 test04()
 {
-  if constexpr (std::atomic_ref<float>::is_always_lock_free)
-  {
-    float i = 0.0f;
-    std::atomic_ref<float> a0(i);
-    std::atomic_ref<float> a1(i);
-    std::atomic_ref<const float> a1c(i);
-    std::atomic_ref<volatile float> a1v(i);
-    std::atomic_ref<const volatile float> a1cv(i);
-    std::atomic_ref<float> a2(a0);
-    a0 = 1.0f;
-    VERIFY( a1 == 1.0f );
-    VERIFY( a1c == 1.0f );
-    VERIFY( a1v == 1.0f );
-    VERIFY( a1cv == 1.0f );
-    VERIFY( a2 == 1.0f );
-  }
+  float i = 0.0f;
+  std::atomic_ref<float> a0(i);
+  std::atomic_ref<float> a1(i);
+  std::atomic_ref<const float> a1c(i);
+  std::atomic_ref<volatile_<float>> a1v(i);
+  std::atomic_ref<volatile_<const float>> a1cv(i);
+  std::atomic_ref<float> a2(a0);
+  a0 = 1.0f;
+  VERIFY( a1 == 1.0f );
+  VERIFY( a1c == 1.0f );
+  VERIFY( a1v == 1.0f );
+  VERIFY( a1cv == 1.0f );
+  VERIFY( a2 == 1.0f );
 }
 
 int
index 079ec1b1a785a90eba2133184efc131c3c25d6d2..7bdecdd9be8df210546e490c7e3cbcc83bd8e2cd 100644 (file)
 #include <atomic>
 #include <limits.h>
 #include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
 
 struct X
 {
@@ -109,8 +114,8 @@ test02()
   std::atomic_ref<X> a0(i);
   std::atomic_ref<X> a1(i);
   std::atomic_ref<const X> a1c(i);
-  std::atomic_ref<volatile X> a1v(i);
-  std::atomic_ref<const volatile X> a1cv(i);
+  std::atomic_ref<volatile_<X>> a1v(i);
+  std::atomic_ref<volatile_<const X>> a1cv(i);
   std::atomic_ref<X> a2(a0);
   a0 = 42;
   VERIFY( a1.load() == 42 );
index 310434cefb54a667704cc6a2917918400f3d120f..010b40b62a0da6c6d318f497e624912c5b6f1010 100644 (file)
 #include <atomic>
 #include <limits.h>
 #include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
 
 void
 test01()
@@ -303,8 +308,8 @@ test03()
   std::atomic_ref<int> a0(i);
   std::atomic_ref<int> a1(i);
   std::atomic_ref<const int> a1c(i);
-  std::atomic_ref<volatile int> a1v(i);
-  std::atomic_ref<const volatile int> a1cv(i);
+  std::atomic_ref<volatile_<int>> a1v(i);
+  std::atomic_ref<volatile_<const int>> a1cv(i);
   std::atomic_ref<int> a2(a0);
   a0 = 42;
   VERIFY( a1 == 42 );
index 93c65dce2636640f592bc644f8c9855e5e38869f..3afa0bb6a8d20f1518c0708f79c0347b1319c16c 100644 (file)
@@ -2,6 +2,11 @@
 
 #include <atomic>
 
+template<typename T>
+concept is_supported
+  = !std::is_volatile_v<T>
+  || std::atomic_ref<std::remove_cv_t<T>>::is_always_lock_free;
+
 template<class T> concept has_and = requires (T& a) { a &= false; };
 template<class T> concept has_or = requires (T& a) { a |= false; };
 template<class T> concept has_xor = requires (T& a) { a ^= false; };
@@ -16,53 +21,62 @@ template<typename T>
 void
 no_stores()
 {
-  static_assert( !HAS(a = t) );
-  static_assert( !HAS(a.store(t)) );
-  static_assert( !HAS(a.store(t, mo)) );
-  static_assert( !HAS(a.exchange(t)) );
-  static_assert( !HAS(a.exchange(t, mo)) );
-
-  static_assert( !HAS(a.compare_exchange_weak(t, t)) );
-  static_assert( !HAS(a.compare_exchange_weak(t, t, mo)) );
-  static_assert( !HAS(a.compare_exchange_weak(t, t, mo, mo)) );
-
-  static_assert( !HAS(a.compare_exchange_strong(t, t)) );
-  static_assert( !HAS(a.compare_exchange_strong(t, t, mo)) );
-  static_assert( !HAS(a.compare_exchange_strong(t, t, mo, mo)) );
+  if constexpr (is_supported<T>)
+  {
+    static_assert( !HAS(a = t) );
+    static_assert( !HAS(a.store(t)) );
+    static_assert( !HAS(a.store(t, mo)) );
+    static_assert( !HAS(a.exchange(t)) );
+    static_assert( !HAS(a.exchange(t, mo)) );
+
+    static_assert( !HAS(a.compare_exchange_weak(t, t)) );
+    static_assert( !HAS(a.compare_exchange_weak(t, t, mo)) );
+    static_assert( !HAS(a.compare_exchange_weak(t, t, mo, mo)) );
+
+    static_assert( !HAS(a.compare_exchange_strong(t, t)) );
+    static_assert( !HAS(a.compare_exchange_strong(t, t, mo)) );
+    static_assert( !HAS(a.compare_exchange_strong(t, t, mo, mo)) );
+  }
 }
 
 template<typename T>
 void
 no_additions()
 {
-  static_assert( !HAS(a++) );
-  static_assert( !HAS(++a) );
-  static_assert( !HAS(a += t) );
-  static_assert( !HAS(a.fetch_add(t)) );
-  static_assert( !HAS(a.fetch_add(t, mo)) );
-
-  static_assert( !HAS(a--) );
-  static_assert( !HAS(--a) );
-  static_assert( !HAS(a -= t) );
-  static_assert( !HAS(a.fetch_sub(t)) );
-  static_assert( !HAS(a.fetch_sub(t, mo)) );
+  if constexpr (is_supported<T>)
+  {
+    static_assert( !HAS(a++) );
+    static_assert( !HAS(++a) );
+    static_assert( !HAS(a += t) );
+    static_assert( !HAS(a.fetch_add(t)) );
+    static_assert( !HAS(a.fetch_add(t, mo)) );
+
+    static_assert( !HAS(a--) );
+    static_assert( !HAS(--a) );
+    static_assert( !HAS(a -= t) );
+    static_assert( !HAS(a.fetch_sub(t)) );
+    static_assert( !HAS(a.fetch_sub(t, mo)) );
+  }
 }
 
 template<typename T>
 void
 no_bitops()
 {
-  static_assert( !HAS(a &= t) );
-  static_assert( !HAS(a.fetch_and(t)) );
-  static_assert( !HAS(a.fetch_and(t, mo)) );
-
-  static_assert( !HAS(a |= t) );
-  static_assert( !HAS(a.fetch_or(t)) );
-  static_assert( !HAS(a.fetch_or(t, mo)) );
-
-  static_assert( !HAS(a ^= t) );
-  static_assert( !HAS(a.fetch_xor(t)) );
-  static_assert( !HAS(a.fetch_xor(t, mo)) );
+  if constexpr (is_supported<T>)
+  {
+    static_assert( !HAS(a &= t) );
+    static_assert( !HAS(a.fetch_and(t)) );
+    static_assert( !HAS(a.fetch_and(t, mo)) );
+
+    static_assert( !HAS(a |= t) );
+    static_assert( !HAS(a.fetch_or(t)) );
+    static_assert( !HAS(a.fetch_or(t, mo)) );
+
+    static_assert( !HAS(a ^= t) );
+    static_assert( !HAS(a.fetch_xor(t)) );
+    static_assert( !HAS(a.fetch_xor(t, mo)) );
+  }
 }
 
 template<typename T>
index 8db45c797c8d2635381d8ba40102912a5538195b..c503b330f9d67faf1fded5617c066b76b8b2e4e4 100644 (file)
 
 #include <atomic>
 #include <testsuite_hooks.h>
+#include <type_traits>
+
+template<typename T>
+using volatile_
+ = std::conditional_t<std::atomic_ref<T>::is_always_lock_free, volatile T, T>;
 
 void
 test01()
@@ -211,8 +216,8 @@ test03()
   std::atomic_ref<int*> a0(ptr);
   std::atomic_ref<int*> a1(ptr);
   std::atomic_ref<int* const> a1c(ptr);
-  std::atomic_ref<int* volatile> a1v(ptr);
-  std::atomic_ref<int* const volatile> a1cv(ptr);
+  std::atomic_ref<volatile_<int*>> a1v(ptr);
+  std::atomic_ref<volatile_<int* const>> a1cv(ptr);
   std::atomic_ref<int*> a2(a0);
   a0 = &i;
   VERIFY( a1 == &i );
index 8617661f8e139002bd931ebe962c60ca1a845977..5d67c77daa8d0c9ce427eeecd0c9db56c7751699 100644 (file)
 #include <atomic>
 #include <type_traits>
 
+template<typename T>
+concept is_supported
+  = !std::is_volatile_v<T>
+  || std::atomic_ref<std::remove_cv_t<T>>::is_always_lock_free;
+
 template <class T>
 void
 test_generic()
 {
-  using A = std::atomic_ref<T>;
-  static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_nothrow_copy_constructible_v<A> );
-  static_assert( std::is_trivially_destructible_v<A> );
-  static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
-  static_assert( !requires { typename A::difference_type; } );
-  static_assert( !std::is_copy_assignable_v<A> );
-  static_assert( !std::is_move_assignable_v<A> );
+  if constexpr (is_supported<T>)
+  {
+    using A = std::atomic_ref<T>;
+    static_assert( std::is_standard_layout_v<A> );
+    static_assert( std::is_nothrow_copy_constructible_v<A> );
+    static_assert( std::is_trivially_destructible_v<A> );
+    static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+    static_assert( !requires { typename A::difference_type; } );
+    static_assert( !std::is_copy_assignable_v<A> );
+    static_assert( !std::is_move_assignable_v<A> );
+  }
 }
 
 template <class T>
 void
 test_integral()
 {
-  using A = std::atomic_ref<T>;
-  static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_nothrow_copy_constructible_v<A> );
-  static_assert( std::is_trivially_destructible_v<A> );
-  static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
-  static_assert( std::is_same_v<typename A::difference_type, typename A::value_type> );
-  static_assert( !std::is_copy_assignable_v<A> );
-  static_assert( !std::is_move_assignable_v<A> );
+  if constexpr (is_supported<T>)
+  {
+    using A = std::atomic_ref<T>;
+    static_assert( std::is_standard_layout_v<A> );
+    static_assert( std::is_nothrow_copy_constructible_v<A> );
+    static_assert( std::is_trivially_destructible_v<A> );
+    static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+    static_assert( std::is_same_v<typename A::difference_type, typename A::value_type> );
+    static_assert( !std::is_copy_assignable_v<A> );
+    static_assert( !std::is_move_assignable_v<A> );
+  }
 }
 
 template <class T>
 void
 test_floating_point()
 {
-  using A = std::atomic_ref<T>;
-  static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_nothrow_copy_constructible_v<A> );
-  static_assert( std::is_trivially_destructible_v<A> );
-  static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
-  static_assert( std::is_same_v<typename A::difference_type, typename A::value_type> );
-  static_assert( !std::is_copy_assignable_v<A> );
-  static_assert( !std::is_move_assignable_v<A> );
+  if constexpr (is_supported<T>)
+  {
+    using A = std::atomic_ref<T>;
+    static_assert( std::is_standard_layout_v<A> );
+    static_assert( std::is_nothrow_copy_constructible_v<A> );
+    static_assert( std::is_trivially_destructible_v<A> );
+    static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+    static_assert( std::is_same_v<typename A::difference_type, typename A::value_type> );
+    static_assert( !std::is_copy_assignable_v<A> );
+    static_assert( !std::is_move_assignable_v<A> );
+  }
 }
 
 template <class T>
 void
 test_pointer()
 {
-  using A = std::atomic_ref<T>;
-  static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_nothrow_copy_constructible_v<A> );
-  static_assert( std::is_trivially_destructible_v<A> );
-  static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
-  static_assert( std::is_same_v<typename A::difference_type, std::ptrdiff_t> );
-  static_assert( std::is_nothrow_copy_constructible_v<A> );
-  static_assert( !std::is_copy_assignable_v<A> );
-  static_assert( !std::is_move_assignable_v<A> );
+  if constexpr (is_supported<T>)
+  {
+    using A = std::atomic_ref<T>;
+    static_assert( std::is_standard_layout_v<A> );
+    static_assert( std::is_nothrow_copy_constructible_v<A> );
+    static_assert( std::is_trivially_destructible_v<A> );
+    static_assert( std::is_same_v<typename A::value_type, std::remove_cv_t<T>> );
+    static_assert( std::is_same_v<typename A::difference_type, std::ptrdiff_t> );
+    static_assert( std::is_nothrow_copy_constructible_v<A> );
+    static_assert( !std::is_copy_assignable_v<A> );
+    static_assert( !std::is_move_assignable_v<A> );
+  }
 }
 
 int