From d01eb982ba5016e7e5245ad6962326c56c8253b4 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 24 Mar 2020 19:46:01 +0100 Subject: [PATCH 1/7] [tuple] Deprecate volatile specializations --- stl/inc/utility | 11 +++++++---- stl/inc/yvals_core.h | 13 ++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 69db55c5f6b..8a8d541e79e 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -436,11 +436,12 @@ struct tuple_size : _Tuple_size_sfinae<_Tuple> { // size of const }; template -struct tuple_size : _Tuple_size_sfinae<_Tuple> { // size of volatile tuple +_CXX20_DEPRECATE_VOLATILE struct tuple_size : _Tuple_size_sfinae<_Tuple> { // size of volatile tuple }; template -struct tuple_size : _Tuple_size_sfinae<_Tuple> { // size of const volatile tuple +_CXX20_DEPRECATE_VOLATILE struct tuple_size + : _Tuple_size_sfinae<_Tuple> { // size of const volatile tuple }; template @@ -456,13 +457,15 @@ struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const _Tuple> : tuple_element }; template -struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, volatile _Tuple> : tuple_element<_Index, _Tuple> { +_CXX20_DEPRECATE_VOLATILE struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, volatile _Tuple> + : tuple_element<_Index, _Tuple> { using _Mybase = tuple_element<_Index, _Tuple>; using type = add_volatile_t; }; template -struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const volatile _Tuple> : tuple_element<_Index, _Tuple> { +_CXX20_DEPRECATE_VOLATILE struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const volatile _Tuple> + : tuple_element<_Index, _Tuple> { using _Mybase = tuple_element<_Index, _Tuple>; using type = add_cv_t; }; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 534a8aa71b1..60edae4b7f3 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -949,7 +949,18 @@ #define _CXX20_DEPRECATE_OLD_SHARED_PTR_ATOMIC_SUPPORT #endif // ^^^ warning disabled ^^^ -// next warning number: STL4030 +#if _HAS_CXX20 && !defined(_SILENCE_CXX20_VOLATILE_DEPRECATION_WARNING) \ + && !defined(_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS) +#define _CXX20_DEPRECATE_VOLATILE \ + [[deprecated("warning STL4030: " \ + "The volatile keyword has been partially deprecated in C++20. " \ + "You can define _SILENCE_CXX20_VOLATILE_DEPRECATION_WARNING " \ + "or _SILENCE_ALL_CXX20_DEPRECATION_WARNINGS to acknowledge that you have received this warning.")]] +#else // ^^^ warning enabled / warning disabled vvv +#define _CXX20_DEPRECATE_VOLATILE +#endif // ^^^ warning disabled ^^^ + +// next warning number: STL4031 // P0619R4 Removing C++17-Deprecated Features #ifndef _HAS_FEATURES_REMOVED_IN_CXX20 From c6f48e41c8a8799faccbf284ac0839b25564d9bb Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 24 Mar 2020 19:46:31 +0100 Subject: [PATCH 2/7] [variant] Deprecate volatile specializations --- stl/inc/variant | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/variant b/stl/inc/variant index fb1211ed3cf..e480b22f334 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -381,9 +381,9 @@ struct variant_size; // undefined template struct variant_size : variant_size<_Ty>::type {}; template -struct variant_size : variant_size<_Ty>::type {}; +_CXX20_DEPRECATE_VOLATILE struct variant_size : variant_size<_Ty>::type {}; template -struct variant_size : variant_size<_Ty>::type {}; +_CXX20_DEPRECATE_VOLATILE struct variant_size : variant_size<_Ty>::type {}; template inline constexpr size_t variant_size_v = variant_size<_Ty>::value; @@ -399,11 +399,11 @@ struct variant_alternative<_Idx, const _Ty> { using type = add_const_t>; }; template -struct variant_alternative<_Idx, volatile _Ty> { +_CXX20_DEPRECATE_VOLATILE struct variant_alternative<_Idx, volatile _Ty> { using type = add_volatile_t>; }; template -struct variant_alternative<_Idx, const volatile _Ty> { +_CXX20_DEPRECATE_VOLATILE struct variant_alternative<_Idx, const volatile _Ty> { using type = add_cv_t>; }; template From b2286507672d622b56ced343f13dd8e905cbabfd Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Sun, 12 Apr 2020 21:37:13 +0200 Subject: [PATCH 3/7] [atomic] Restric volatile atomic operations Fixes #558 Co-Authored-By: Casey Carter --- stl/inc/atomic | 99 +++++++++++++++++-- stl/inc/yvals_core.h | 9 +- .../test.cpp | 9 +- 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 1ce5172cabd..1fd4d759bab 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1158,6 +1158,24 @@ struct _Atomic_integral<_Ty, 8> : _Atomic_storage<_Ty> { // atomic integral oper #endif // _M_IX86 }; +#if 1 // TRANSITION, ABI +template +_INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= 8 && (_TypeSize & (_TypeSize - 1)) == 0; +#else // ^^^ don't break ABI / break ABI vvv +#if _ATOMIC_HAS_DCAS +template +_INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= 2 * sizeof(void*); +#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv +template +_INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= sizeof(void*); +#endif // _ATOMIC_HAS_DCAS +#endif // break ABI + +template +_INLINE_VAR constexpr bool _Deprecate_non_lock_free_volatile = true; + +template <> +_CXX20_DEPRECATE_VOLATILE _INLINE_VAR constexpr bool _Deprecate_non_lock_free_volatile = true; // STRUCT TEMPLATE _Atomic_integral_facade template @@ -1178,10 +1196,12 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { // are far more common than volatile ones. using _Base::fetch_add; _Ty fetch_add(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand); } _Ty fetch_add(const _Ty _Operand, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand, _Order); } @@ -1194,6 +1214,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty fetch_sub(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(_Negate(_Operand)); } @@ -1202,51 +1223,62 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty fetch_sub(const _Ty _Operand, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(_Negate(_Operand), _Order); } using _Base::fetch_and; _Ty fetch_and(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand); } _Ty fetch_and(const _Ty _Operand, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand, _Order); } using _Base::fetch_or; _Ty fetch_or(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand); } _Ty fetch_or(const _Ty _Operand, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand, _Order); } using _Base::fetch_xor; _Ty fetch_xor(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand); } _Ty fetch_xor(const _Ty _Operand, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand, _Order); } using _Base::operator++; _Ty operator++(int) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(0); } _Ty operator++() volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(); } using _Base::operator--; _Ty operator--(int) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(0); } _Ty operator--() volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(); } @@ -1255,6 +1287,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator+=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand) + _Operand); } @@ -1263,6 +1296,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator-=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->fetch_sub(_Operand) - _Operand); } @@ -1271,6 +1305,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator&=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand) & _Operand); } @@ -1279,6 +1314,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator|=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand) | _Operand); } @@ -1287,6 +1323,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator^=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand) ^ _Operand); } }; @@ -1317,6 +1354,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { // We make the primary functions non-volatile for better debug codegen, as non-volatile atomics // are far more common than volatile ones. _Ty fetch_add(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_add(_Operand, _Order); } @@ -1329,6 +1367,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty fetch_sub(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_sub(_Operand, _Order); } @@ -1337,6 +1376,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty operator+=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_add(_Operand) + _Operand; } @@ -1345,6 +1385,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty operator-=(const _Ty _Operand) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_sub(_Operand) - _Operand; } }; @@ -1378,14 +1419,17 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty fetch_add(const ptrdiff_t _Diff) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_pointer*>(this)->fetch_add(_Diff); } _Ty fetch_add(const ptrdiff_t _Diff, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast<_Atomic_pointer*>(this)->fetch_add(_Diff, _Order); } _Ty fetch_sub(const ptrdiff_t _Diff) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff))); } @@ -1394,6 +1438,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty fetch_sub(const ptrdiff_t _Diff, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff)), _Order); } @@ -1402,6 +1447,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator++(int) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(1); } @@ -1410,6 +1456,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator++() volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(1) + 1; } @@ -1418,6 +1465,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator--(int) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(-1); } @@ -1426,6 +1474,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator--() volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(-1) - 1; } @@ -1434,6 +1483,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator+=(const ptrdiff_t _Diff) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(_Diff) + _Diff; } @@ -1442,6 +1492,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator-=(const ptrdiff_t _Diff) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff))) - _Diff; } @@ -1495,11 +1546,12 @@ public: atomic(const atomic&) = delete; atomic& operator=(const atomic&) = delete; -#if 1 // TRANSITION, ABI #if _HAS_CXX17 - static constexpr bool is_always_lock_free = sizeof(_Ty) <= 8 && (sizeof(_Ty) & sizeof(_Ty) - 1) == 0; + static constexpr bool is_always_lock_free = _Is_always_lock_free; #endif // _HAS_CXX17 +#if 1 // TRANSITION, ABI + _NODISCARD bool is_lock_free() const volatile noexcept { constexpr bool _Result = sizeof(_Ty) <= 8 && (sizeof(_Ty) & sizeof(_Ty) - 1) == 0; return _Result; @@ -1517,14 +1569,6 @@ public: #else // ^^^ don't break ABI / break ABI vvv -#if _HAS_CXX17 -#if _ATOMIC_HAS_DCAS - static constexpr bool is_always_lock_free = sizeof(_Ty) <= 2 * sizeof(void*); -#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv - static constexpr bool is_always_lock_free = sizeof(_Ty) <= sizeof(void*); -#endif // _ATOMIC_HAS_DCAS -#endif // _HAS_CXX17 - _NODISCARD bool is_lock_free() const volatile noexcept { #if _ATOMIC_HAS_DCAS return sizeof(_Ty) <= 2 * sizeof(void*); @@ -1539,6 +1583,7 @@ public: } _Ty operator=(const _Ty _Value) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); this->store(_Value); return _Value; } @@ -1555,42 +1600,51 @@ public: // non-volatile should result in better debug codegen. using _Base::store; void store(const _Ty _Value) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); const_cast(this)->_Base::store(_Value); } void store(const _Ty _Value, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); const_cast(this)->_Base::store(_Value, _Order); } using _Base::load; _NODISCARD _Ty load() const volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast(this)->_Base::load(); } _NODISCARD _Ty load(const memory_order _Order) const volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast(this)->_Base::load(_Order); } using _Base::exchange; _Ty exchange(const _Ty _Value) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast(this)->_Base::exchange(_Value); } _Ty exchange(const _Ty _Value, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast(this)->_Base::exchange(_Value, _Order); } using _Base::compare_exchange_strong; bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast(this)->_Base::compare_exchange_strong(_Expected, _Desired); } bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return const_cast(this)->_Base::compare_exchange_strong(_Expected, _Desired, _Order); } bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired, const memory_order _Success, const memory_order _Failure) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1601,6 +1655,7 @@ public: bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired) volatile noexcept { // we have no weak CAS intrinsics, even on ARM32/ARM64, so fall back to strong + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired); } @@ -1609,6 +1664,7 @@ public: } bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired, const memory_order _Order) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired, _Order); } @@ -1618,6 +1674,7 @@ public: bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired, const memory_order _Success, const memory_order _Failure) volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1627,6 +1684,7 @@ public: } operator _Ty() const volatile noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return this->load(); } @@ -1666,11 +1724,13 @@ template _CXX20_DEPRECATE_ATOMIC_INIT void atomic_init( volatile atomic<_Ty>* const _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { // NB: respecting volatility here appears unimplementable + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); _STD atomic_init(const_cast*>(_Mem), _Value); } template void atomic_store(volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); _Mem->store(_Value); } @@ -1682,6 +1742,7 @@ void atomic_store(atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noexce template void atomic_store_explicit( volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); _Mem->store(_Value, _Order); } @@ -1692,6 +1753,7 @@ void atomic_store_explicit(atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Valu template _NODISCARD _Ty atomic_load(const volatile atomic<_Ty>* const _Mem) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->load(); } @@ -1702,6 +1764,7 @@ _NODISCARD _Ty atomic_load(const atomic<_Ty>* const _Mem) noexcept { template _NODISCARD _Ty atomic_load_explicit(const volatile atomic<_Ty>* const _Mem, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->load(_Order); } @@ -1712,6 +1775,7 @@ _NODISCARD _Ty atomic_load_explicit(const atomic<_Ty>* const _Mem, const memory_ template _Ty atomic_exchange(volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->exchange(_Value); } @@ -1723,6 +1787,7 @@ _Ty atomic_exchange(atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noex template _Ty atomic_exchange_explicit( volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->exchange(_Value, _Order); } @@ -1735,6 +1800,7 @@ _Ty atomic_exchange_explicit( template bool atomic_compare_exchange_strong( volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired); } @@ -1747,6 +1813,7 @@ bool atomic_compare_exchange_strong( template bool atomic_compare_exchange_strong_explicit(volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired, const memory_order _Success, const memory_order _Failure) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1759,6 +1826,7 @@ bool atomic_compare_exchange_strong_explicit(atomic<_Ty>* const _Mem, _Identity_ template bool atomic_compare_exchange_weak( volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired); } @@ -1771,6 +1839,7 @@ bool atomic_compare_exchange_weak( template bool atomic_compare_exchange_weak_explicit(volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired, const memory_order _Success, const memory_order _Failure) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1782,6 +1851,7 @@ bool atomic_compare_exchange_weak_explicit(atomic<_Ty>* const _Mem, _Identity_t< template _Ty atomic_fetch_add(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_add(_Value); } @@ -1793,6 +1863,7 @@ _Ty atomic_fetch_add(atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_t template _Ty atomic_fetch_add_explicit(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_add(_Value, _Order); } @@ -1804,6 +1875,7 @@ _Ty atomic_fetch_add_explicit( template _Ty atomic_fetch_sub(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_sub(_Value); } @@ -1815,6 +1887,7 @@ _Ty atomic_fetch_sub(atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_t template _Ty atomic_fetch_sub_explicit(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_sub(_Value, _Order); } @@ -1826,6 +1899,7 @@ _Ty atomic_fetch_sub_explicit( template _Ty atomic_fetch_and(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_and(_Value); } @@ -1837,6 +1911,7 @@ _Ty atomic_fetch_and(atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _ template _Ty atomic_fetch_and_explicit( volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_and(_Value, _Order); } @@ -1848,6 +1923,7 @@ _Ty atomic_fetch_and_explicit( template _Ty atomic_fetch_or(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_or(_Value); } @@ -1859,6 +1935,7 @@ _Ty atomic_fetch_or(atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _V template _Ty atomic_fetch_or_explicit( volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_or(_Value, _Order); } @@ -1870,6 +1947,7 @@ _Ty atomic_fetch_or_explicit( template _Ty atomic_fetch_xor(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_xor(_Value); } @@ -1881,6 +1959,7 @@ _Ty atomic_fetch_xor(atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _ template _Ty atomic_fetch_xor_explicit( volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value, const memory_order _Order) noexcept { + static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); return _Mem->fetch_xor(_Value, _Order); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 60edae4b7f3..f164ab891d5 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -211,6 +211,7 @@ // _HAS_CXX20 and _SILENCE_ALL_CXX20_DEPRECATION_WARNINGS control: // P0767R1 Deprecating is_pod +// P1831R1 Deprecating volatile In The Standard Library // Other C++20 deprecation warnings // Parallel Algorithms Notes @@ -951,10 +952,10 @@ #if _HAS_CXX20 && !defined(_SILENCE_CXX20_VOLATILE_DEPRECATION_WARNING) \ && !defined(_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS) -#define _CXX20_DEPRECATE_VOLATILE \ - [[deprecated("warning STL4030: " \ - "The volatile keyword has been partially deprecated in C++20. " \ - "You can define _SILENCE_CXX20_VOLATILE_DEPRECATION_WARNING " \ +#define _CXX20_DEPRECATE_VOLATILE \ + [[deprecated("warning STL4030: " \ + "Some operations on volatile-qualified types in the STL are deprecated in C++20. " \ + "You can define _SILENCE_CXX20_VOLATILE_DEPRECATION_WARNING " \ "or _SILENCE_ALL_CXX20_DEPRECATION_WARNINGS to acknowledge that you have received this warning.")]] #else // ^^^ warning enabled / warning disabled vvv #define _CXX20_DEPRECATE_VOLATILE diff --git a/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp b/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp index 9142751b376..b089aa49d9e 100644 --- a/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp +++ b/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp @@ -188,7 +188,14 @@ void helper2() { template void helper1() { helper2>(); - helper2>(); + +#if _HAS_CXX20 + if constexpr (atomic::is_always_lock_free) { +#endif // _HAS_CXX20 + helper2>(); +#if _HAS_CXX20 + } +#endif // _HAS_CXX20 } template From b0bc8c79efdb9495598395d5b4086c1c45a85bb4 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 13 Apr 2020 08:10:21 +0200 Subject: [PATCH 4/7] Move attribute to the "right" position --- stl/inc/utility | 8 ++++---- stl/inc/variant | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 8a8d541e79e..1c9d6299ae1 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -436,11 +436,11 @@ struct tuple_size : _Tuple_size_sfinae<_Tuple> { // size of const }; template -_CXX20_DEPRECATE_VOLATILE struct tuple_size : _Tuple_size_sfinae<_Tuple> { // size of volatile tuple +struct _CXX20_DEPRECATE_VOLATILE tuple_size : _Tuple_size_sfinae<_Tuple> { // size of volatile tuple }; template -_CXX20_DEPRECATE_VOLATILE struct tuple_size +struct _CXX20_DEPRECATE_VOLATILE tuple_size : _Tuple_size_sfinae<_Tuple> { // size of const volatile tuple }; @@ -457,14 +457,14 @@ struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const _Tuple> : tuple_element }; template -_CXX20_DEPRECATE_VOLATILE struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, volatile _Tuple> +struct _CXX20_DEPRECATE_VOLATILE _MSVC_KNOWN_SEMANTICS tuple_element<_Index, volatile _Tuple> : tuple_element<_Index, _Tuple> { using _Mybase = tuple_element<_Index, _Tuple>; using type = add_volatile_t; }; template -_CXX20_DEPRECATE_VOLATILE struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const volatile _Tuple> +struct _CXX20_DEPRECATE_VOLATILE _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const volatile _Tuple> : tuple_element<_Index, _Tuple> { using _Mybase = tuple_element<_Index, _Tuple>; using type = add_cv_t; diff --git a/stl/inc/variant b/stl/inc/variant index e480b22f334..b7e9a34c8c2 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -381,9 +381,9 @@ struct variant_size; // undefined template struct variant_size : variant_size<_Ty>::type {}; template -_CXX20_DEPRECATE_VOLATILE struct variant_size : variant_size<_Ty>::type {}; +struct _CXX20_DEPRECATE_VOLATILE variant_size : variant_size<_Ty>::type {}; template -_CXX20_DEPRECATE_VOLATILE struct variant_size : variant_size<_Ty>::type {}; +struct _CXX20_DEPRECATE_VOLATILE variant_size : variant_size<_Ty>::type {}; template inline constexpr size_t variant_size_v = variant_size<_Ty>::value; @@ -399,11 +399,11 @@ struct variant_alternative<_Idx, const _Ty> { using type = add_const_t>; }; template -_CXX20_DEPRECATE_VOLATILE struct variant_alternative<_Idx, volatile _Ty> { +struct _CXX20_DEPRECATE_VOLATILE variant_alternative<_Idx, volatile _Ty> { using type = add_volatile_t>; }; template -_CXX20_DEPRECATE_VOLATILE struct variant_alternative<_Idx, const volatile _Ty> { +struct _CXX20_DEPRECATE_VOLATILE variant_alternative<_Idx, const volatile _Ty> { using type = add_cv_t>; }; template From e543bcad0a5d5e196963a35a2faf92d141c1deed Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 13 Apr 2020 08:12:22 +0200 Subject: [PATCH 5/7] No newline Co-Authored-By: Casey Carter --- stl/inc/atomic | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 1fd4d759bab..37bdd80bd2c 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1551,7 +1551,6 @@ public: #endif // _HAS_CXX17 #if 1 // TRANSITION, ABI - _NODISCARD bool is_lock_free() const volatile noexcept { constexpr bool _Result = sizeof(_Ty) <= 8 && (sizeof(_Ty) & sizeof(_Ty) - 1) == 0; return _Result; From eee21ba23c6b0d221faeb5635679f88aa5625f13 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 21 Apr 2020 17:09:17 -0700 Subject: [PATCH 6/7] Partially specialize the variable template. --- stl/inc/atomic | 142 ++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 37bdd80bd2c..1b51d79868e 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1171,11 +1171,11 @@ _INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= sizeof(void*); #endif // _ATOMIC_HAS_DCAS #endif // break ABI -template +template > _INLINE_VAR constexpr bool _Deprecate_non_lock_free_volatile = true; -template <> -_CXX20_DEPRECATE_VOLATILE _INLINE_VAR constexpr bool _Deprecate_non_lock_free_volatile = true; +template +_CXX20_DEPRECATE_VOLATILE _INLINE_VAR constexpr bool _Deprecate_non_lock_free_volatile<_Ty, false> = true; // STRUCT TEMPLATE _Atomic_integral_facade template @@ -1196,12 +1196,12 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { // are far more common than volatile ones. using _Base::fetch_add; _Ty fetch_add(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand); } _Ty fetch_add(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand, _Order); } @@ -1214,7 +1214,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty fetch_sub(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(_Negate(_Operand)); } @@ -1223,62 +1223,62 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty fetch_sub(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(_Negate(_Operand), _Order); } using _Base::fetch_and; _Ty fetch_and(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand); } _Ty fetch_and(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand, _Order); } using _Base::fetch_or; _Ty fetch_or(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand); } _Ty fetch_or(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand, _Order); } using _Base::fetch_xor; _Ty fetch_xor(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand); } _Ty fetch_xor(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand, _Order); } using _Base::operator++; _Ty operator++(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(0); } _Ty operator++() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(); } using _Base::operator--; _Ty operator--(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(0); } _Ty operator--() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(); } @@ -1287,7 +1287,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator+=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand) + _Operand); } @@ -1296,7 +1296,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator-=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->fetch_sub(_Operand) - _Operand); } @@ -1305,7 +1305,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator&=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand) & _Operand); } @@ -1314,7 +1314,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator|=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand) | _Operand); } @@ -1323,7 +1323,7 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator^=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand) ^ _Operand); } }; @@ -1354,7 +1354,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { // We make the primary functions non-volatile for better debug codegen, as non-volatile atomics // are far more common than volatile ones. _Ty fetch_add(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_add(_Operand, _Order); } @@ -1367,7 +1367,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty fetch_sub(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_sub(_Operand, _Order); } @@ -1376,7 +1376,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty operator+=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_add(_Operand) + _Operand; } @@ -1385,7 +1385,7 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty operator-=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_sub(_Operand) - _Operand; } }; @@ -1419,17 +1419,17 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty fetch_add(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_pointer*>(this)->fetch_add(_Diff); } _Ty fetch_add(const ptrdiff_t _Diff, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_pointer*>(this)->fetch_add(_Diff, _Order); } _Ty fetch_sub(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff))); } @@ -1438,7 +1438,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty fetch_sub(const ptrdiff_t _Diff, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff)), _Order); } @@ -1447,7 +1447,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator++(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(1); } @@ -1456,7 +1456,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator++() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(1) + 1; } @@ -1465,7 +1465,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator--(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(-1); } @@ -1474,7 +1474,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator--() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(-1) - 1; } @@ -1483,7 +1483,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator+=(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(_Diff) + _Diff; } @@ -1492,7 +1492,7 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator-=(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff))) - _Diff; } @@ -1582,7 +1582,7 @@ public: } _Ty operator=(const _Ty _Value) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); this->store(_Value); return _Value; } @@ -1599,51 +1599,51 @@ public: // non-volatile should result in better debug codegen. using _Base::store; void store(const _Ty _Value) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); const_cast(this)->_Base::store(_Value); } void store(const _Ty _Value, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); const_cast(this)->_Base::store(_Value, _Order); } using _Base::load; _NODISCARD _Ty load() const volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast(this)->_Base::load(); } _NODISCARD _Ty load(const memory_order _Order) const volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast(this)->_Base::load(_Order); } using _Base::exchange; _Ty exchange(const _Ty _Value) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast(this)->_Base::exchange(_Value); } _Ty exchange(const _Ty _Value, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast(this)->_Base::exchange(_Value, _Order); } using _Base::compare_exchange_strong; bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast(this)->_Base::compare_exchange_strong(_Expected, _Desired); } bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast(this)->_Base::compare_exchange_strong(_Expected, _Desired, _Order); } bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired, const memory_order _Success, const memory_order _Failure) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1654,7 +1654,7 @@ public: bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired) volatile noexcept { // we have no weak CAS intrinsics, even on ARM32/ARM64, so fall back to strong - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired); } @@ -1663,7 +1663,7 @@ public: } bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired, _Order); } @@ -1673,7 +1673,7 @@ public: bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired, const memory_order _Success, const memory_order _Failure) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return this->compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1683,7 +1683,7 @@ public: } operator _Ty() const volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return this->load(); } @@ -1723,13 +1723,13 @@ template _CXX20_DEPRECATE_ATOMIC_INIT void atomic_init( volatile atomic<_Ty>* const _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { // NB: respecting volatility here appears unimplementable - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); _STD atomic_init(const_cast*>(_Mem), _Value); } template void atomic_store(volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); _Mem->store(_Value); } @@ -1741,7 +1741,7 @@ void atomic_store(atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noexce template void atomic_store_explicit( volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); _Mem->store(_Value, _Order); } @@ -1752,7 +1752,7 @@ void atomic_store_explicit(atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Valu template _NODISCARD _Ty atomic_load(const volatile atomic<_Ty>* const _Mem) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->load(); } @@ -1763,7 +1763,7 @@ _NODISCARD _Ty atomic_load(const atomic<_Ty>* const _Mem) noexcept { template _NODISCARD _Ty atomic_load_explicit(const volatile atomic<_Ty>* const _Mem, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->load(_Order); } @@ -1774,7 +1774,7 @@ _NODISCARD _Ty atomic_load_explicit(const atomic<_Ty>* const _Mem, const memory_ template _Ty atomic_exchange(volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->exchange(_Value); } @@ -1786,7 +1786,7 @@ _Ty atomic_exchange(atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value) noex template _Ty atomic_exchange_explicit( volatile atomic<_Ty>* const _Mem, const _Identity_t<_Ty> _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->exchange(_Value, _Order); } @@ -1799,7 +1799,7 @@ _Ty atomic_exchange_explicit( template bool atomic_compare_exchange_strong( volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired); } @@ -1812,7 +1812,7 @@ bool atomic_compare_exchange_strong( template bool atomic_compare_exchange_strong_explicit(volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired, const memory_order _Success, const memory_order _Failure) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1825,7 +1825,7 @@ bool atomic_compare_exchange_strong_explicit(atomic<_Ty>* const _Mem, _Identity_ template bool atomic_compare_exchange_weak( volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired); } @@ -1838,7 +1838,7 @@ bool atomic_compare_exchange_weak( template bool atomic_compare_exchange_weak_explicit(volatile atomic<_Ty>* const _Mem, _Identity_t<_Ty>* const _Expected, const _Identity_t<_Ty> _Desired, const memory_order _Success, const memory_order _Failure) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->compare_exchange_strong(*_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } @@ -1850,7 +1850,7 @@ bool atomic_compare_exchange_weak_explicit(atomic<_Ty>* const _Mem, _Identity_t< template _Ty atomic_fetch_add(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_add(_Value); } @@ -1862,7 +1862,7 @@ _Ty atomic_fetch_add(atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_t template _Ty atomic_fetch_add_explicit(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_add(_Value, _Order); } @@ -1874,7 +1874,7 @@ _Ty atomic_fetch_add_explicit( template _Ty atomic_fetch_sub(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_sub(_Value); } @@ -1886,7 +1886,7 @@ _Ty atomic_fetch_sub(atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_t template _Ty atomic_fetch_sub_explicit(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::difference_type _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_sub(_Value, _Order); } @@ -1898,7 +1898,7 @@ _Ty atomic_fetch_sub_explicit( template _Ty atomic_fetch_and(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_and(_Value); } @@ -1910,7 +1910,7 @@ _Ty atomic_fetch_and(atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _ template _Ty atomic_fetch_and_explicit( volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_and(_Value, _Order); } @@ -1922,7 +1922,7 @@ _Ty atomic_fetch_and_explicit( template _Ty atomic_fetch_or(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_or(_Value); } @@ -1934,7 +1934,7 @@ _Ty atomic_fetch_or(atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _V template _Ty atomic_fetch_or_explicit( volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_or(_Value, _Order); } @@ -1946,7 +1946,7 @@ _Ty atomic_fetch_or_explicit( template _Ty atomic_fetch_xor(volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_xor(_Value); } @@ -1958,7 +1958,7 @@ _Ty atomic_fetch_xor(atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _ template _Ty atomic_fetch_xor_explicit( volatile atomic<_Ty>* _Mem, const typename atomic<_Ty>::value_type _Value, const memory_order _Order) noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Is_always_lock_free>, "Never fails"); + static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return _Mem->fetch_xor(_Value, _Order); } From e56a0314c343b40a08197796821c4fa591cc0e7c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 21 Apr 2020 17:33:58 -0700 Subject: [PATCH 7/7] Integral, floating, pointer are always lock-free. --- stl/inc/atomic | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 1b51d79868e..b52d5f3ecf8 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1191,17 +1191,17 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { using _Base::_Base; #endif // ^^^ no workaround ^^^ + // _Deprecate_non_lock_free_volatile is unnecessary here. + // note: const_cast-ing away volatile is safe because all our intrinsics add volatile back on. // We make the primary functions non-volatile for better debug codegen, as non-volatile atomics // are far more common than volatile ones. using _Base::fetch_add; _Ty fetch_add(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand); } _Ty fetch_add(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand, _Order); } @@ -1214,7 +1214,6 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty fetch_sub(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(_Negate(_Operand)); } @@ -1223,62 +1222,51 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty fetch_sub(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(_Negate(_Operand), _Order); } using _Base::fetch_and; _Ty fetch_and(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand); } _Ty fetch_and(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand, _Order); } using _Base::fetch_or; _Ty fetch_or(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand); } _Ty fetch_or(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand, _Order); } using _Base::fetch_xor; _Ty fetch_xor(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand); } _Ty fetch_xor(const _Ty _Operand, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand, _Order); } using _Base::operator++; _Ty operator++(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(0); } _Ty operator++() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(); } using _Base::operator--; _Ty operator--(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(0); } _Ty operator--() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(); } @@ -1287,7 +1275,6 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator+=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand) + _Operand); } @@ -1296,7 +1283,6 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator-=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->fetch_sub(_Operand) - _Operand); } @@ -1305,7 +1291,6 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator&=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand) & _Operand); } @@ -1314,7 +1299,6 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator|=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand) | _Operand); } @@ -1323,7 +1307,6 @@ struct _Atomic_integral_facade : _Atomic_integral<_Ty> { } _Ty operator^=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return static_cast<_Ty>(const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand) ^ _Operand); } }; @@ -1350,11 +1333,12 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { return _Temp; } + // _Deprecate_non_lock_free_volatile is unnecessary here. + // note: const_cast-ing away volatile is safe because all our intrinsics add volatile back on. // We make the primary functions non-volatile for better debug codegen, as non-volatile atomics // are far more common than volatile ones. _Ty fetch_add(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_add(_Operand, _Order); } @@ -1367,7 +1351,6 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty fetch_sub(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_sub(_Operand, _Order); } @@ -1376,7 +1359,6 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty operator+=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_add(_Operand) + _Operand; } @@ -1385,7 +1367,6 @@ struct _Atomic_floating : _Atomic_storage<_Ty> { } _Ty operator-=(const _Ty _Operand) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_floating*>(this)->fetch_sub(_Operand) - _Operand; } }; @@ -1418,18 +1399,17 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { return reinterpret_cast<_Ty>(_Result); } + // _Deprecate_non_lock_free_volatile is unnecessary here. + _Ty fetch_add(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_pointer*>(this)->fetch_add(_Diff); } _Ty fetch_add(const ptrdiff_t _Diff, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return const_cast<_Atomic_pointer*>(this)->fetch_add(_Diff, _Order); } _Ty fetch_sub(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff))); } @@ -1438,7 +1418,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty fetch_sub(const ptrdiff_t _Diff, const memory_order _Order) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff)), _Order); } @@ -1447,7 +1426,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator++(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(1); } @@ -1456,7 +1434,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator++() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(1) + 1; } @@ -1465,7 +1442,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator--(int) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(-1); } @@ -1474,7 +1450,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator--() volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(-1) - 1; } @@ -1483,7 +1458,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator+=(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(_Diff) + _Diff; } @@ -1492,7 +1466,6 @@ struct _Atomic_pointer : _Atomic_storage<_Ty> { } _Ty operator-=(const ptrdiff_t _Diff) volatile noexcept { - static_assert(_Deprecate_non_lock_free_volatile<_Ty>, "Never fails"); return fetch_add(static_cast(0 - static_cast(_Diff))) - _Diff; }