Skip to content

Commit f953761

Browse files
committed
Implement P1831R1: deprecate volatile specializations of tuple and
variant helper methods, and deprecate many volatile atomic methods when that atomic type is not guaranteed to always be lock-free. Closes #100038
1 parent cf79aba commit f953761

File tree

12 files changed

+487
-110
lines changed

12 files changed

+487
-110
lines changed

libcxx/include/__atomic/atomic.h

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct atomic : public __atomic_base<_Tp> {
4747
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {}
4848

4949
_LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile _NOEXCEPT {
50+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
5051
__base::store(__d);
5152
return __d;
5253
}
@@ -72,6 +73,7 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> {
7273
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {}
7374

7475
_LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __d) volatile _NOEXCEPT {
76+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
7577
__base::store(__d);
7678
return __d;
7779
}
@@ -81,6 +83,7 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> {
8183
}
8284

8385
_LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
86+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
8487
// __atomic_fetch_add accepts function pointers, guard against them.
8588
static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
8689
return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
@@ -93,6 +96,7 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> {
9396
}
9497

9598
_LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
99+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
96100
// __atomic_fetch_add accepts function pointers, guard against them.
97101
static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed");
98102
return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
@@ -104,18 +108,41 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> {
104108
return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
105109
}
106110

107-
_LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) volatile _NOEXCEPT { return fetch_add(1); }
108111
_LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) _NOEXCEPT { return fetch_add(1); }
109-
_LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) volatile _NOEXCEPT { return fetch_sub(1); }
112+
_LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) volatile _NOEXCEPT {
113+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
114+
return fetch_add(1);
115+
}
116+
110117
_LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) _NOEXCEPT { return fetch_sub(1); }
111-
_LIBCPP_HIDE_FROM_ABI _Tp* operator++() volatile _NOEXCEPT { return fetch_add(1) + 1; }
118+
_LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) volatile _NOEXCEPT {
119+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
120+
return fetch_sub(1);
121+
}
122+
112123
_LIBCPP_HIDE_FROM_ABI _Tp* operator++() _NOEXCEPT { return fetch_add(1) + 1; }
113-
_LIBCPP_HIDE_FROM_ABI _Tp* operator--() volatile _NOEXCEPT { return fetch_sub(1) - 1; }
124+
_LIBCPP_HIDE_FROM_ABI _Tp* operator++() volatile _NOEXCEPT {
125+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
126+
return fetch_add(1) + 1;
127+
}
128+
114129
_LIBCPP_HIDE_FROM_ABI _Tp* operator--() _NOEXCEPT { return fetch_sub(1) - 1; }
115-
_LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; }
130+
_LIBCPP_HIDE_FROM_ABI _Tp* operator--() volatile _NOEXCEPT {
131+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
132+
return fetch_sub(1) - 1;
133+
}
134+
116135
_LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) _NOEXCEPT { return fetch_add(__op) + __op; }
117-
_LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; }
136+
_LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) volatile _NOEXCEPT {
137+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
138+
return fetch_add(__op) + __op;
139+
}
140+
118141
_LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) _NOEXCEPT { return fetch_sub(__op) - __op; }
142+
_LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT {
143+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free);
144+
return fetch_sub(__op) - __op;
145+
}
119146

120147
atomic& operator=(const atomic&) = delete;
121148
atomic& operator=(const atomic&) volatile = delete;
@@ -201,9 +228,8 @@ struct atomic<_Tp> : __atomic_base<_Tp> {
201228
atomic& operator=(const atomic&) = delete;
202229
atomic& operator=(const atomic&) volatile = delete;
203230

204-
_LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept
205-
requires __base::is_always_lock_free
206-
{
231+
_LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept {
232+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
207233
__base::store(__d);
208234
return __d;
209235
}
@@ -212,37 +238,33 @@ struct atomic<_Tp> : __atomic_base<_Tp> {
212238
return __d;
213239
}
214240

215-
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
216-
requires __base::is_always_lock_free
217-
{
241+
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept {
242+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
218243
return __fetch_add(*this, __op, __m);
219244
}
220245

221246
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
222247
return __fetch_add(*this, __op, __m);
223248
}
224249

225-
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
226-
requires __base::is_always_lock_free
227-
{
250+
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept {
251+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
228252
return __fetch_sub(*this, __op, __m);
229253
}
230254

231255
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
232256
return __fetch_sub(*this, __op, __m);
233257
}
234258

235-
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept
236-
requires __base::is_always_lock_free
237-
{
259+
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept {
260+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
238261
return fetch_add(__op) + __op;
239262
}
240263

241264
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) noexcept { return fetch_add(__op) + __op; }
242265

243-
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept
244-
requires __base::is_always_lock_free
245-
{
266+
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept {
267+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
246268
return fetch_sub(__op) - __op;
247269
}
248270

@@ -272,8 +294,7 @@ atomic_init(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NO
272294
}
273295

274296
template <class _Tp>
275-
_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void
276-
atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
297+
_LIBCPP_HIDE_FROM_ABI void atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT {
277298
std::__cxx_atomic_init(std::addressof(__o->__a_), __d);
278299
}
279300

libcxx/include/__atomic/atomic_base.h

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,34 @@
2727

2828
_LIBCPP_BEGIN_NAMESPACE_STD
2929

30+
#if _LIBCPP_STD_VER >= 20
31+
template <class _Tp, bool __lock_free>
32+
inline constexpr bool __deprecated_if_not_always_lock_free = true;
33+
34+
template <class _Tp>
35+
[[deprecated("volatile atomic operations are deprecated when std::atomic<T>::is_always_lock_free is false")]]
36+
inline constexpr bool __deprecated_if_not_always_lock_free<_Tp, false> = true;
37+
38+
// Many volatile overloads of of atomic<T> methods have a requirement to
39+
// guarantee atomic<T>::is_always_lock_free is truen in C++20.
40+
// To make this a non-breaking change, this macro is used to emit a warning
41+
// when atomic<T>::is_always_lock_free is false without having to duplicate
42+
// the method. We could do:
43+
//
44+
// _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
45+
// requires is_always_lock_free { ... }
46+
//
47+
// [[deprecated(...)]] _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
48+
// requires !is_always_lock_free { ... }
49+
//
50+
// But this creates a lot of unecessary duplicate code.
51+
# define _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __is_always_lock_free) \
52+
static_assert(__deprecated_if_not_always_lock_free<_Tp, __is_always_lock_free>)
53+
#else
54+
# define _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __is_always_lock_free) \
55+
{}
56+
#endif
57+
3058
template <class _Tp, bool = is_integral<_Tp>::value && !is_same<_Tp, bool>::value>
3159
struct __atomic_base // false
3260
{
@@ -44,6 +72,7 @@ struct __atomic_base // false
4472
}
4573
_LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
4674
_LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
75+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
4776
std::__cxx_atomic_store(std::addressof(__a_), __d, __m);
4877
}
4978
_LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT
@@ -52,15 +81,20 @@ struct __atomic_base // false
5281
}
5382
_LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
5483
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
84+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
5585
return std::__cxx_atomic_load(std::addressof(__a_), __m);
5686
}
5787
_LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
5888
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
5989
return std::__cxx_atomic_load(std::addressof(__a_), __m);
6090
}
61-
_LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT { return load(); }
91+
_LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT {
92+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
93+
return load();
94+
}
6295
_LIBCPP_HIDE_FROM_ABI operator _Tp() const _NOEXCEPT { return load(); }
6396
_LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
97+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
6498
return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m);
6599
}
66100
_LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
@@ -69,6 +103,7 @@ struct __atomic_base // false
69103
_LIBCPP_HIDE_FROM_ABI bool
70104
compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT
71105
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
106+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
72107
return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
73108
}
74109
_LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT
@@ -78,6 +113,7 @@ struct __atomic_base // false
78113
_LIBCPP_HIDE_FROM_ABI bool
79114
compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT
80115
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
116+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
81117
return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
82118
}
83119
_LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT
@@ -86,6 +122,7 @@ struct __atomic_base // false
86122
}
87123
_LIBCPP_HIDE_FROM_ABI bool
88124
compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
125+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
89126
return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
90127
}
91128
_LIBCPP_HIDE_FROM_ABI bool
@@ -94,6 +131,7 @@ struct __atomic_base // false
94131
}
95132
_LIBCPP_HIDE_FROM_ABI bool
96133
compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
134+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free);
97135
return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
98136
}
99137
_LIBCPP_HIDE_FROM_ABI bool
@@ -142,54 +180,112 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
142180
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
143181

144182
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
183+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
145184
return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
146185
}
186+
147187
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
148188
return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
149189
}
190+
150191
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
192+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
151193
return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
152194
}
195+
153196
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
154197
return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
155198
}
199+
156200
_LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
201+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
157202
return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m);
158203
}
204+
159205
_LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
160206
return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m);
161207
}
208+
162209
_LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
210+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
163211
return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m);
164212
}
213+
165214
_LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
166215
return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m);
167216
}
217+
168218
_LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
219+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
169220
return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m);
170221
}
222+
171223
_LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
172224
return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m);
173225
}
174226

175-
_LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT { return fetch_add(_Tp(1)); }
176227
_LIBCPP_HIDE_FROM_ABI _Tp operator++(int) _NOEXCEPT { return fetch_add(_Tp(1)); }
177-
_LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT { return fetch_sub(_Tp(1)); }
228+
229+
_LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT {
230+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
231+
return fetch_add(_Tp(1));
232+
}
233+
178234
_LIBCPP_HIDE_FROM_ABI _Tp operator--(int) _NOEXCEPT { return fetch_sub(_Tp(1)); }
179-
_LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); }
235+
236+
_LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT {
237+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
238+
return fetch_sub(_Tp(1));
239+
}
240+
180241
_LIBCPP_HIDE_FROM_ABI _Tp operator++() _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); }
181-
_LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); }
242+
243+
_LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT {
244+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
245+
return fetch_add(_Tp(1)) + _Tp(1);
246+
}
247+
182248
_LIBCPP_HIDE_FROM_ABI _Tp operator--() _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); }
183-
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; }
249+
250+
_LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT {
251+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
252+
return fetch_sub(_Tp(1)) - _Tp(1);
253+
}
254+
184255
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) _NOEXCEPT { return fetch_add(__op) + __op; }
185-
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; }
256+
257+
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT {
258+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
259+
return fetch_add(__op) + __op;
260+
}
261+
186262
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) _NOEXCEPT { return fetch_sub(__op) - __op; }
187-
_LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT { return fetch_and(__op) & __op; }
263+
264+
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT {
265+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
266+
return fetch_sub(__op) - __op;
267+
}
268+
188269
_LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) _NOEXCEPT { return fetch_and(__op) & __op; }
189-
_LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT { return fetch_or(__op) | __op; }
270+
271+
_LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT {
272+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
273+
return fetch_and(__op) & __op;
274+
}
275+
190276
_LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) _NOEXCEPT { return fetch_or(__op) | __op; }
191-
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT { return fetch_xor(__op) ^ __op; }
277+
278+
_LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT {
279+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
280+
return fetch_or(__op) | __op;
281+
}
282+
192283
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; }
284+
285+
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT {
286+
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free);
287+
return fetch_xor(__op) ^ __op;
288+
}
193289
};
194290

195291
// Here we need _IsIntegral because the default template argument is not enough

libcxx/include/__config

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,21 @@ typedef __char32_t char32_t;
741741
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T
742742
# endif
743743

744+
// P1831R1 deprecated many uses of volatile, but the way attributes work with template specializations require this
745+
// work-around to always raise warnings in cases where templates are specialized for volatile variants of STL types.
746+
# if _LIBCPP_STD_VER >= 20
747+
template <class _Tp, bool __cxx20 = _LIBCPP_STD_VER >= 20>
748+
_LIBCPP_HIDE_FROM_ABI constexpr bool __volatile_deprecated_since_cxx20_warning = true;
749+
template <class _Tp>
750+
_LIBCPP_DEPRECATED_IN_CXX20
751+
_LIBCPP_HIDE_FROM_ABI constexpr bool __volatile_deprecated_since_cxx20_warning<_Tp, true> = true;
752+
# define _LIBCPP_VOLATILE_DEPRECATED_WARNING static_assert(__volatile_deprecated_since_cxx20_warning<volatile _Tp>)
753+
# define _LIBCPP_VOLATILE_DEPRECATED_WARNING \
754+
static_assert(__volatile_deprecated_since_cxx20_warning<volatile _Tp>)
755+
# endif
756+
# define _LIBCPP_VOLATILE_DEPRECATED_WARNING do { } while (0)
757+
# endif
758+
744759
// Macros to enter and leave a state where deprecation warnings are suppressed.
745760
# if defined(_LIBCPP_COMPILER_CLANG_BASED) || defined(_LIBCPP_COMPILER_GCC)
746761
# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH \

0 commit comments

Comments
 (0)