-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libcxx][P1831R1] Deprecating volatile: library #101439
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -27,6 +27,34 @@ | |||||
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD | ||||||
|
||||||
#if _LIBCPP_STD_VER >= 20 | ||||||
template <class _Tp, bool __lock_free> | ||||||
inline constexpr bool __deprecated_if_not_always_lock_free = true; | ||||||
|
||||||
template <class _Tp> | ||||||
[[deprecated("volatile atomic operations are deprecated when std::atomic<T>::is_always_lock_free is false")]] | ||||||
inline constexpr bool __deprecated_if_not_always_lock_free<_Tp, false> = true; | ||||||
|
||||||
// Many volatile overloads of of atomic<T> methods have a requirement to | ||||||
// guarantee atomic<T>::is_always_lock_free is truen in C++20. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// To make this a non-breaking change, this macro is used to emit a warning | ||||||
// when atomic<T>::is_always_lock_free is false without having to duplicate | ||||||
// the method. We could do: | ||||||
// | ||||||
// _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT | ||||||
// requires is_always_lock_free { ... } | ||||||
// | ||||||
// [[deprecated(...)]] _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT | ||||||
// requires !is_always_lock_free { ... } | ||||||
// | ||||||
// But this creates a lot of unecessary duplicate code. | ||||||
# define _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __is_always_lock_free) \ | ||||||
static_assert(__deprecated_if_not_always_lock_free<_Tp, __is_always_lock_free>) | ||||||
#else | ||||||
# define _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __is_always_lock_free) \ | ||||||
{} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be a statement and require a semi-colon.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's definitely not now per P2809R3. However..., shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively, |
||||||
#endif | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not too fond of this entire code, the
Then change the code to
It also needs a comment describing why. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I share your distaste for this use of static assertions, hopefully the issue with attributes on template specializations is eventually fixed (though I'm not 100% sure if its a bug or a feature). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding a comments - do you mean at every single place the macro is used, or do you mean at the definition of the macro? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No just comment for the macro itself. |
||||||
template <class _Tp, bool = is_integral<_Tp>::value && !is_same<_Tp, bool>::value> | ||||||
struct __atomic_base // false | ||||||
{ | ||||||
|
@@ -44,6 +72,7 @@ struct __atomic_base // false | |||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT | ||||||
_LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
std::__cxx_atomic_store(std::addressof(__a_), __d, __m); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT | ||||||
|
@@ -52,15 +81,20 @@ struct __atomic_base // false | |||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT | ||||||
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return std::__cxx_atomic_load(std::addressof(__a_), __m); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT | ||||||
_LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { | ||||||
return std::__cxx_atomic_load(std::addressof(__a_), __m); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT { return load(); } | ||||||
_LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return load(); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI operator _Tp() const _NOEXCEPT { return load(); } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT { | ||||||
|
@@ -69,6 +103,7 @@ struct __atomic_base // false | |||||
_LIBCPP_HIDE_FROM_ABI bool | ||||||
compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT | ||||||
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f); | ||||||
} | ||||||
_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 | |||||
_LIBCPP_HIDE_FROM_ABI bool | ||||||
compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT | ||||||
_LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f); | ||||||
} | ||||||
_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 | |||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI bool | ||||||
compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI bool | ||||||
|
@@ -94,6 +131,7 @@ struct __atomic_base // false | |||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI bool | ||||||
compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, is_always_lock_free); | ||||||
return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m); | ||||||
} | ||||||
_LIBCPP_HIDE_FROM_ABI bool | ||||||
|
@@ -142,54 +180,112 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> { | |||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { | ||||||
return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { | ||||||
return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { | ||||||
return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { | ||||||
return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { | ||||||
return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT { return fetch_add(_Tp(1)); } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator++(int) _NOEXCEPT { return fetch_add(_Tp(1)); } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT { return fetch_sub(_Tp(1)); } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_add(_Tp(1)); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator--(int) _NOEXCEPT { return fetch_sub(_Tp(1)); } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_sub(_Tp(1)); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator++() _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_add(_Tp(1)) + _Tp(1); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator--() _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_sub(_Tp(1)) - _Tp(1); | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) _NOEXCEPT { return fetch_add(__op) + __op; } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_add(__op) + __op; | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) _NOEXCEPT { return fetch_sub(__op) - __op; } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT { return fetch_and(__op) & __op; } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_sub(__op) - __op; | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) _NOEXCEPT { return fetch_and(__op) & __op; } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT { return fetch_or(__op) | __op; } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_and(__op) & __op; | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) _NOEXCEPT { return fetch_or(__op) | __op; } | ||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT { return fetch_xor(__op) ^ __op; } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_or(__op) | __op; | ||||||
} | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; } | ||||||
|
||||||
_LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT { | ||||||
_LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); | ||||||
return fetch_xor(__op) ^ __op; | ||||||
} | ||||||
}; | ||||||
|
||||||
// Here we need _IsIntegral because the default template argument is not enough | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -741,6 +741,21 @@ typedef __char32_t char32_t; | |
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T | ||
# endif | ||
|
||
// P1831R1 deprecated many uses of volatile, but the way attributes work with template specializations require this | ||
// work-around to always raise warnings in cases where templates are specialized for volatile variants of STL types. | ||
# if _LIBCPP_STD_VER >= 20 | ||
template <class _Tp, bool __cxx20 = _LIBCPP_STD_VER >= 20> | ||
_LIBCPP_HIDE_FROM_ABI constexpr bool __volatile_deprecated_since_cxx20_warning = true; | ||
template <class _Tp> | ||
_LIBCPP_DEPRECATED_IN_CXX20 | ||
_LIBCPP_HIDE_FROM_ABI constexpr bool __volatile_deprecated_since_cxx20_warning<_Tp, true> = true; | ||
# define _LIBCPP_VOLATILE_DEPRECATED_WARNING static_assert(__volatile_deprecated_since_cxx20_warning<volatile _Tp>) | ||
# define _LIBCPP_VOLATILE_DEPRECATED_WARNING \ | ||
static_assert(__volatile_deprecated_since_cxx20_warning<volatile _Tp>) | ||
# else | ||
# define _LIBCPP_VOLATILE_DEPRECATED_WARNING static_assert(true) | ||
# endif | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we can do something similar as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm I do think differentiating between I'm not sure what a better name would be since there isn't a specific condition to refer to like |
||
// Macros to enter and leave a state where deprecation warnings are suppressed. | ||
# if defined(_LIBCPP_COMPILER_CLANG_BASED) || defined(_LIBCPP_COMPILER_GCC) | ||
# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH \ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkarns275
This might be because the warning is emitted inside the body of the function. An alternative could be to try emitting the diagnostic in the declaration by doing something like
where
__deprecated_if_not_lock_free
is defined to always expand to its argument as-is, but also trigger the warning if needed.