2424#include " test_helper.h"
2525#include " test_macros.h"
2626
27- template <typename T>
27+ template <typename T, typename U>
28+ concept has_compare_exchange_strong_1 =
29+ requires { std::declval<T>().compare_exchange_strong (std::declval<U&>(), std::declval<U>()); };
30+ template <typename T, typename U>
31+ concept has_compare_exchange_strong_2 = requires {
32+ std::declval<T>().compare_exchange_strong (std::declval<U&>(), std::declval<U>(), std::declval<std::memory_order>());
33+ };
34+ template <typename T, typename U>
35+ concept has_compare_exchange_strong_3 = requires {
36+ std::declval<T>().compare_exchange_strong (
37+ std::declval<U&>(), std::declval<U>(), std::declval<std::memory_order>(), std::declval<std::memory_order>());
38+ };
39+
40+ template <typename T, typename U>
41+ concept has_compare_exchange_strong =
42+ has_compare_exchange_strong_1<T, U> && has_compare_exchange_strong_2<T, U> && has_compare_exchange_strong_3<T, U>;
43+
44+ template <typename T, typename U>
45+ concept does_not_have_compare_exchange_strong =
46+ !has_compare_exchange_strong_1<T, U> && !has_compare_exchange_strong_2<T, U> &&
47+ !has_compare_exchange_strong_3<T, U>;
48+
49+ template <typename U>
2850struct TestCompareExchangeStrong {
2951 void operator ()() const {
52+ static_assert (has_compare_exchange_strong<std::atomic_ref<U>, U>);
53+ do_test<U>();
54+ do_test_atomic<U>();
55+ static_assert (does_not_have_compare_exchange_strong<std::atomic_ref<U const >, U>);
56+ if constexpr (std::atomic_ref<U>::is_always_lock_free) {
57+ static_assert (has_compare_exchange_strong<std::atomic_ref<U volatile >, U>);
58+ do_test<U volatile >();
59+ do_test_atomic<U volatile >();
60+ static_assert (does_not_have_compare_exchange_strong<std::atomic_ref<U const volatile >, U>);
61+ }
62+ }
63+
64+ template <typename T>
65+ void do_test () const {
3066 {
3167 T x (T (1 ));
3268 std::atomic_ref<T> const a (x);
3369
34- T t (T (1 ));
70+ std:: remove_cv_t <T> t (T (1 ));
3571 std::same_as<bool > decltype (auto ) y = a.compare_exchange_strong (t, T (2 ));
3672 assert (y == true );
37- assert (a == T (2 ));
38- assert (t == T (1 ));
73+ assert (a == std:: remove_cv_t <T> (2 ));
74+ assert (t == std:: remove_cv_t <T> (1 ));
3975 y = a.compare_exchange_strong (t, T (3 ));
4076 assert (y == false );
41- assert (a == T (2 ));
42- assert (t == T (2 ));
77+ assert (a == std:: remove_cv_t <T> (2 ));
78+ assert (t == std:: remove_cv_t <T> (2 ));
4379
4480 ASSERT_NOEXCEPT (a.compare_exchange_strong (t, T (2 )));
4581 }
4682 {
4783 T x (T (1 ));
4884 std::atomic_ref<T> const a (x);
4985
50- T t (T (1 ));
86+ std:: remove_cv_t <T> t (T (1 ));
5187 std::same_as<bool > decltype (auto ) y = a.compare_exchange_strong (t, T (2 ), std::memory_order_seq_cst);
5288 assert (y == true );
53- assert (a == T (2 ));
54- assert (t == T (1 ));
89+ assert (a == std:: remove_cv_t <T> (2 ));
90+ assert (t == std:: remove_cv_t <T> (1 ));
5591 y = a.compare_exchange_strong (t, T (3 ), std::memory_order_seq_cst);
5692 assert (y == false );
57- assert (a == T (2 ));
58- assert (t == T (2 ));
93+ assert (a == std:: remove_cv_t <T> (2 ));
94+ assert (t == std:: remove_cv_t <T> (2 ));
5995
6096 ASSERT_NOEXCEPT (a.compare_exchange_strong (t, T (2 ), std::memory_order_seq_cst));
6197 }
6298 {
6399 T x (T (1 ));
64100 std::atomic_ref<T> const a (x);
65101
66- T t (T (1 ));
102+ std:: remove_cv_t <T> t (T (1 ));
67103 std::same_as<bool > decltype (auto ) y =
68104 a.compare_exchange_strong (t, T (2 ), std::memory_order_release, std::memory_order_relaxed);
69105 assert (y == true );
70- assert (a == T (2 ));
71- assert (t == T (1 ));
106+ assert (a == std:: remove_cv_t <T> (2 ));
107+ assert (t == std:: remove_cv_t <T> (1 ));
72108 y = a.compare_exchange_strong (t, T (3 ), std::memory_order_release, std::memory_order_relaxed);
73109 assert (y == false );
74- assert (a == T (2 ));
75- assert (t == T (2 ));
110+ assert (a == std:: remove_cv_t <T> (2 ));
111+ assert (t == std:: remove_cv_t <T> (2 ));
76112
77113 ASSERT_NOEXCEPT (a.compare_exchange_strong (t, T (2 ), std::memory_order_release, std::memory_order_relaxed));
78114 }
115+ }
79116
117+ template <typename T>
118+ void do_test_atomic () const {
80119 // success memory_order::release
81120 {
82- auto store = [](std::atomic_ref<T> const & x, T old_val, T new_val) {
83- auto r = x.compare_exchange_strong (old_val, new_val, std::memory_order::release, std::memory_order::relaxed);
121+ auto store = [](std::atomic_ref<T> const & x, T const & old_val, T const & new_val) {
122+ auto r = x.compare_exchange_strong (
123+ const_cast <std::remove_cv_t <T>&>(old_val),
124+ const_cast <std::remove_cv_t <T> const &>(new_val),
125+ std::memory_order::release,
126+ std::memory_order::relaxed);
84127 assert (r);
85128 };
86129
87130 auto load = [](std::atomic_ref<T> const & x) { return x.load (std::memory_order::acquire); };
88131 test_acquire_release<T>(store, load);
89-
90- auto store_one_arg = [](std::atomic_ref<T> const & x, T old_val, T new_val) {
91- auto r = x.compare_exchange_strong (old_val, new_val, std::memory_order::release);
132+ auto store_one_arg = [](std::atomic_ref<T> const & x, T const & old_val, T const & new_val) {
133+ auto r = x.compare_exchange_strong (
134+ const_cast <std::remove_cv_t <T>&>(old_val),
135+ const_cast <std::remove_cv_t <T> const &>(new_val),
136+ std::memory_order::release);
92137 assert (r);
93138 };
94139 test_acquire_release<T>(store_one_arg, load);
95140 }
96141
97142 // success memory_order::acquire
98143 {
99- auto store = [](std::atomic_ref<T> const & x, T, T new_val) { x.store (new_val, std::memory_order::release); };
144+ auto store = [](std::atomic_ref<T> const & x, T const &, T const & new_val) {
145+ x.store (const_cast <std::remove_cv_t <T> const &>(new_val), std::memory_order::release);
146+ };
100147
101148 auto load = [](std::atomic_ref<T> const & x) {
102149 auto val = x.load (std::memory_order::relaxed);
@@ -117,8 +164,12 @@ struct TestCompareExchangeStrong {
117164
118165 // success memory_order::acq_rel
119166 {
120- auto store = [](std::atomic_ref<T> const & x, T old_val, T new_val) {
121- auto r = x.compare_exchange_strong (old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed);
167+ auto store = [](std::atomic_ref<T> const & x, T const & old_val, T const & new_val) {
168+ auto r = x.compare_exchange_strong (
169+ const_cast <std::remove_cv_t <T>&>(old_val),
170+ const_cast <std::remove_cv_t <T> const &>(new_val),
171+ std::memory_order::acq_rel,
172+ std::memory_order::relaxed);
122173 assert (r);
123174 };
124175 auto load = [](std::atomic_ref<T> const & x) {
@@ -129,8 +180,11 @@ struct TestCompareExchangeStrong {
129180 };
130181 test_acquire_release<T>(store, load);
131182
132- auto store_one_arg = [](std::atomic_ref<T> const & x, T old_val, T new_val) {
133- auto r = x.compare_exchange_strong (old_val, new_val, std::memory_order::acq_rel);
183+ auto store_one_arg = [](std::atomic_ref<T> const & x, T const & old_val, T const & new_val) {
184+ auto r = x.compare_exchange_strong (
185+ const_cast <std::remove_cv_t <T>&>(old_val),
186+ const_cast <std::remove_cv_t <T> const &>(new_val),
187+ std::memory_order::acq_rel);
134188 assert (r);
135189 };
136190 auto load_one_arg = [](std::atomic_ref<T> const & x) {
@@ -144,8 +198,12 @@ struct TestCompareExchangeStrong {
144198
145199 // success memory_order::seq_cst
146200 {
147- auto store = [](std::atomic_ref<T> const & x, T old_val, T new_val) {
148- auto r = x.compare_exchange_strong (old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed);
201+ auto store = [](std::atomic_ref<T> const & x, T const & old_val, T const & new_val) {
202+ auto r = x.compare_exchange_strong (
203+ const_cast <std::remove_cv_t <T>&>(old_val),
204+ const_cast <std::remove_cv_t <T> const &>(new_val),
205+ std::memory_order::seq_cst,
206+ std::memory_order::relaxed);
149207 assert (r);
150208 };
151209 auto load = [](std::atomic_ref<T> const & x) {
@@ -156,8 +214,11 @@ struct TestCompareExchangeStrong {
156214 };
157215 test_seq_cst<T>(store, load);
158216
159- auto store_one_arg = [](std::atomic_ref<T> const & x, T old_val, T new_val) {
160- auto r = x.compare_exchange_strong (old_val, new_val, std::memory_order::seq_cst);
217+ auto store_one_arg = [](std::atomic_ref<T> const & x, T const & old_val, T const & new_val) {
218+ auto r = x.compare_exchange_strong (
219+ const_cast <std::remove_cv_t <T>&>(old_val),
220+ const_cast <std::remove_cv_t <T> const &>(new_val),
221+ std::memory_order::seq_cst);
161222 assert (r);
162223 };
163224 auto load_one_arg = [](std::atomic_ref<T> const & x) {
@@ -171,10 +232,12 @@ struct TestCompareExchangeStrong {
171232
172233 // failure memory_order::acquire
173234 {
174- auto store = [](std::atomic_ref<T> const & x, T, T new_val) { x.store (new_val, std::memory_order::release); };
175- auto load = [](std::atomic_ref<T> const & x) {
235+ auto store = [](std::atomic_ref<T> const & x, T const &, T const & new_val) {
236+ x.store (const_cast <std::remove_cv_t <T> const &>(new_val), std::memory_order::release);
237+ };
238+ auto load = [](std::atomic_ref<T> const & x) {
176239 auto result = x.load (std::memory_order::relaxed);
177- T unexpected (T (255 ));
240+ std:: remove_cv_t <T> unexpected (std:: remove_cv_t <T> (255 ));
178241 bool r =
179242 x.compare_exchange_strong (unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire);
180243 assert (!r);
@@ -184,7 +247,7 @@ struct TestCompareExchangeStrong {
184247
185248 auto load_one_arg = [](std::atomic_ref<T> const & x) {
186249 auto result = x.load (std::memory_order::relaxed);
187- T unexpected (T (255 ));
250+ std:: remove_cv_t <T> unexpected (std:: remove_cv_t <T> (255 ));
188251 bool r = x.compare_exchange_strong (unexpected, unexpected, std::memory_order::acquire);
189252 assert (!r);
190253 return result;
@@ -194,7 +257,7 @@ struct TestCompareExchangeStrong {
194257 // acq_rel replaced by acquire
195258 auto load_one_arg_acq_rel = [](std::atomic_ref<T> const & x) {
196259 auto result = x.load (std::memory_order::relaxed);
197- T unexpected (T (255 ));
260+ std:: remove_cv_t <T> unexpected (std:: remove_cv_t <T> (255 ));
198261 bool r = x.compare_exchange_strong (unexpected, unexpected, std::memory_order::acq_rel);
199262 assert (!r);
200263 return result;
@@ -204,10 +267,12 @@ struct TestCompareExchangeStrong {
204267
205268 // failure memory_order::seq_cst
206269 {
207- auto store = [](std::atomic_ref<T> const & x, T, T new_val) { x.store (new_val, std::memory_order::seq_cst); };
208- auto load = [](std::atomic_ref<T> const & x) {
270+ auto store = [](std::atomic_ref<T> const & x, T const &, T const & new_val) {
271+ x.store (const_cast <std::remove_cv_t <T> const &>(new_val), std::memory_order::seq_cst);
272+ };
273+ auto load = [](std::atomic_ref<T> const & x) {
209274 auto result = x.load (std::memory_order::relaxed);
210- T unexpected (T (255 ));
275+ std:: remove_cv_t <T> unexpected (std:: remove_cv_t <T> (255 ));
211276 bool r =
212277 x.compare_exchange_strong (unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst);
213278 assert (!r);
0 commit comments