diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h index bcea21f5ce2e1..bd1a22ecdbc98 100644 --- a/libcxx/include/__atomic/atomic.h +++ b/libcxx/include/__atomic/atomic.h @@ -47,6 +47,7 @@ struct atomic : public __atomic_base<_Tp> { _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {} _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile _NOEXCEPT { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); __base::store(__d); return __d; } @@ -72,6 +73,7 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> { _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {} _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __d) volatile _NOEXCEPT { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free); __base::store(__d); return __d; } @@ -81,6 +83,7 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> { } _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free); // __atomic_fetch_add accepts function pointers, guard against them. static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed"); return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); @@ -93,6 +96,7 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> { } _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free); // __atomic_fetch_add accepts function pointers, guard against them. static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed"); return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); @@ -104,18 +108,41 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> { return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); } - _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) volatile _NOEXCEPT { return fetch_add(1); } _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) _NOEXCEPT { return fetch_add(1); } - _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) volatile _NOEXCEPT { return fetch_sub(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(1); + } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) _NOEXCEPT { return fetch_sub(1); } - _LIBCPP_HIDE_FROM_ABI _Tp* operator++() volatile _NOEXCEPT { return fetch_add(1) + 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(1); + } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++() _NOEXCEPT { return fetch_add(1) + 1; } - _LIBCPP_HIDE_FROM_ABI _Tp* operator--() volatile _NOEXCEPT { return fetch_sub(1) - 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++() volatile _NOEXCEPT { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free); + return fetch_add(1) + 1; + } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--() _NOEXCEPT { return fetch_sub(1) - 1; } - _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __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(1) - 1; + } + _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) _NOEXCEPT { return fetch_add(__op) + __op; } - _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __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-=(ptrdiff_t __op) _NOEXCEPT { return fetch_sub(__op) - __op; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp*, __base::is_always_lock_free); + return fetch_sub(__op) - __op; + } atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; @@ -201,9 +228,8 @@ struct atomic<_Tp> : __atomic_base<_Tp> { atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; - _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept - requires __base::is_always_lock_free - { + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept { + _LIBCPP_DEPRECATED_NOT_ALWAYS_LOCK_FREE(_Tp, __base::is_always_lock_free); __base::store(__d); return __d; } @@ -212,9 +238,8 @@ struct atomic<_Tp> : __atomic_base<_Tp> { return __d; } - _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept - requires __base::is_always_lock_free - { + _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 __fetch_add(*this, __op, __m); } @@ -222,9 +247,8 @@ struct atomic<_Tp> : __atomic_base<_Tp> { return __fetch_add(*this, __op, __m); } - _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept - requires __base::is_always_lock_free - { + _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 __fetch_sub(*this, __op, __m); } @@ -232,17 +256,15 @@ struct atomic<_Tp> : __atomic_base<_Tp> { return __fetch_sub(*this, __op, __m); } - _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept - requires __base::is_always_lock_free - { + _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_add(__op) + __op; } - _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept - requires __base::is_always_lock_free - { + _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; } @@ -272,8 +294,7 @@ atomic_init(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NO } template -_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void -atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI void atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { std::__cxx_atomic_init(std::addressof(__o->__a_), __d); } diff --git a/libcxx/include/__atomic/atomic_base.h b/libcxx/include/__atomic/atomic_base.h index 93f5c4cff0d1b..57f3b8b574f2b 100644 --- a/libcxx/include/__atomic/atomic_base.h +++ b/libcxx/include/__atomic/atomic_base.h @@ -27,6 +27,34 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#if _LIBCPP_STD_VER >= 20 +template +inline constexpr bool __deprecated_if_not_always_lock_free = true; + +template +[[deprecated("volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false")]] +inline constexpr bool __deprecated_if_not_always_lock_free<_Tp, false> = true; + +// Many volatile overloads of of atomic methods have a requirement to +// guarantee atomic::is_always_lock_free is truen in C++20. +// To make this a non-breaking change, this macro is used to emit a warning +// when atomic::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) \ + {} +#endif + template ::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 diff --git a/libcxx/include/__config b/libcxx/include/__config index 392053a64a8dc..eeb6ea66a6481 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -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 = 20> + _LIBCPP_HIDE_FROM_ABI constexpr bool __volatile_deprecated_since_cxx20_warning = true; + template + _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) +# define _LIBCPP_VOLATILE_DEPRECATED_WARNING \ + static_assert(__volatile_deprecated_since_cxx20_warning) +# else +# define _LIBCPP_VOLATILE_DEPRECATED_WARNING static_assert(true) +# endif + // 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 \ diff --git a/libcxx/include/__tuple/tuple_element.h b/libcxx/include/__tuple/tuple_element.h index 9127c47dc8f1a..54434ea2edcb7 100644 --- a/libcxx/include/__tuple/tuple_element.h +++ b/libcxx/include/__tuple/tuple_element.h @@ -30,11 +30,13 @@ struct _LIBCPP_TEMPLATE_VIS tuple_element<_Ip, const _Tp> { template struct _LIBCPP_TEMPLATE_VIS tuple_element<_Ip, volatile _Tp> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; typedef _LIBCPP_NODEBUG volatile typename tuple_element<_Ip, _Tp>::type type; }; template struct _LIBCPP_TEMPLATE_VIS tuple_element<_Ip, const volatile _Tp> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; typedef _LIBCPP_NODEBUG const volatile typename tuple_element<_Ip, _Tp>::type type; }; diff --git a/libcxx/include/__tuple/tuple_size.h b/libcxx/include/__tuple/tuple_size.h index 18a17fd4d5878..949aed1e42e29 100644 --- a/libcxx/include/__tuple/tuple_size.h +++ b/libcxx/include/__tuple/tuple_size.h @@ -39,12 +39,16 @@ template struct _LIBCPP_TEMPLATE_VIS tuple_size<__enable_if_tuple_size_imp< volatile _Tp, __enable_if_t::value>, integral_constant)>>> - : public integral_constant::value> {}; + : public integral_constant::value> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; +}; template struct _LIBCPP_TEMPLATE_VIS tuple_size<__enable_if_tuple_size_imp)>>> - : public integral_constant::value> {}; + : public integral_constant::value> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; +}; #else template diff --git a/libcxx/include/atomic b/libcxx/include/atomic index 772ac998615a9..8c9e21273fd20 100644 --- a/libcxx/include/atomic +++ b/libcxx/include/atomic @@ -74,30 +74,39 @@ struct atomic atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; - T load(memory_order m = memory_order_seq_cst) const volatile noexcept; + T load(memory_order m = memory_order_seq_cst) const volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T load(memory_order m = memory_order_seq_cst) const noexcept; - operator T() const volatile noexcept; + operator T() const volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 operator T() const noexcept; - void store(T desr, memory_order m = memory_order_seq_cst) volatile noexcept; + void store(T desr, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 void store(T desr, memory_order m = memory_order_seq_cst) noexcept; - T operator=(T) volatile noexcept; + T operator=(T) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T operator=(T) noexcept; - T exchange(T desr, memory_order m = memory_order_seq_cst) volatile noexcept; + T exchange(T desr, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T exchange(T desr, memory_order m = memory_order_seq_cst) noexcept; bool compare_exchange_weak(T& expc, T desr, - memory_order s, memory_order f) volatile noexcept; + memory_order s, memory_order f) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(T& expc, T desr, memory_order s, memory_order f) noexcept; bool compare_exchange_strong(T& expc, T desr, - memory_order s, memory_order f) volatile noexcept; + memory_order s, memory_order f) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(T& expc, T desr, - memory_order s, memory_order f) noexcept; + memory_order s, memory_order f) noexcept bool compare_exchange_weak(T& expc, T desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(T& expc, T desr, memory_order m = memory_order_seq_cst) noexcept; bool compare_exchange_strong(T& expc, T desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(T& expc, T desr, memory_order m = memory_order_seq_cst) noexcept; @@ -125,63 +134,85 @@ struct atomic atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; - integral load(memory_order m = memory_order_seq_cst) const volatile noexcept; + integral load(memory_order m = memory_order_seq_cst) const volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral load(memory_order m = memory_order_seq_cst) const noexcept; operator integral() const volatile noexcept; operator integral() const noexcept; - void store(integral desr, memory_order m = memory_order_seq_cst) volatile noexcept; + void store(integral desr, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 void store(integral desr, memory_order m = memory_order_seq_cst) noexcept; - integral operator=(integral desr) volatile noexcept; + integral operator=(integral desr) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator=(integral desr) noexcept; integral exchange(integral desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral exchange(integral desr, memory_order m = memory_order_seq_cst) noexcept; bool compare_exchange_weak(integral& expc, integral desr, - memory_order s, memory_order f) volatile noexcept; + memory_order s, memory_order f) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(integral& expc, integral desr, memory_order s, memory_order f) noexcept; bool compare_exchange_strong(integral& expc, integral desr, - memory_order s, memory_order f) volatile noexcept; + memory_order s, memory_order f) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(integral& expc, integral desr, memory_order s, memory_order f) noexcept; bool compare_exchange_weak(integral& expc, integral desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(integral& expc, integral desr, memory_order m = memory_order_seq_cst) noexcept; bool compare_exchange_strong(integral& expc, integral desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(integral& expc, integral desr, memory_order m = memory_order_seq_cst) noexcept; - integral fetch_add(integral op, memory_order m = memory_order_seq_cst) volatile noexcept; + integral fetch_add(integral op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral fetch_add(integral op, memory_order m = memory_order_seq_cst) noexcept; - integral fetch_sub(integral op, memory_order m = memory_order_seq_cst) volatile noexcept; + integral fetch_sub(integral op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral fetch_sub(integral op, memory_order m = memory_order_seq_cst) noexcept; - integral fetch_and(integral op, memory_order m = memory_order_seq_cst) volatile noexcept; + integral fetch_and(integral op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral fetch_and(integral op, memory_order m = memory_order_seq_cst) noexcept; - integral fetch_or(integral op, memory_order m = memory_order_seq_cst) volatile noexcept; + integral fetch_or(integral op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral fetch_or(integral op, memory_order m = memory_order_seq_cst) noexcept; - integral fetch_xor(integral op, memory_order m = memory_order_seq_cst) volatile noexcept; + integral fetch_xor(integral op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral fetch_xor(integral op, memory_order m = memory_order_seq_cst) noexcept; - integral operator++(int) volatile noexcept; + integral operator++(int) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator++(int) noexcept; - integral operator--(int) volatile noexcept; + integral operator--(int) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator--(int) noexcept; - integral operator++() volatile noexcept; + integral operator++() volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator++() noexcept; - integral operator--() volatile noexcept; + integral operator--() volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator--() noexcept; - integral operator+=(integral op) volatile noexcept; + integral operator+=(integral op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator+=(integral op) noexcept; - integral operator-=(integral op) volatile noexcept; + integral operator-=(integral op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator-=(integral op) noexcept; - integral operator&=(integral op) volatile noexcept; + integral operator&=(integral op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator&=(integral op) noexcept; - integral operator|=(integral op) volatile noexcept; + integral operator|=(integral op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator|=(integral op) noexcept; - integral operator^=(integral op) volatile noexcept; + integral operator^=(integral op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 integral operator^=(integral op) noexcept; void wait(integral, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20 @@ -209,49 +240,66 @@ struct atomic atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; - T* load(memory_order m = memory_order_seq_cst) const volatile noexcept; + T* load(memory_order m = memory_order_seq_cst) const volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* load(memory_order m = memory_order_seq_cst) const noexcept; - operator T*() const volatile noexcept; + operator T*() const volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 operator T*() const noexcept; - void store(T* desr, memory_order m = memory_order_seq_cst) volatile noexcept; + void store(T* desr, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 void store(T* desr, memory_order m = memory_order_seq_cst) noexcept; - T* operator=(T*) volatile noexcept; + T* operator=(T*) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator=(T*) noexcept; - T* exchange(T* desr, memory_order m = memory_order_seq_cst) volatile noexcept; + T* exchange(T* desr, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* exchange(T* desr, memory_order m = memory_order_seq_cst) noexcept; bool compare_exchange_weak(T*& expc, T* desr, - memory_order s, memory_order f) volatile noexcept; + memory_order s, memory_order f) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(T*& expc, T* desr, memory_order s, memory_order f) noexcept; bool compare_exchange_strong(T*& expc, T* desr, - memory_order s, memory_order f) volatile noexcept; + memory_order s, memory_order f) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(T*& expc, T* desr, memory_order s, memory_order f) noexcept; bool compare_exchange_weak(T*& expc, T* desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(T*& expc, T* desr, memory_order m = memory_order_seq_cst) noexcept; bool compare_exchange_strong(T*& expc, T* desr, - memory_order m = memory_order_seq_cst) volatile noexcept; + memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(T*& expc, T* desr, memory_order m = memory_order_seq_cst) noexcept; - T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile noexcept; + T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept; - T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile noexcept; + T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept; - T* operator++(int) volatile noexcept; + T* operator++(int) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator++(int) noexcept; - T* operator--(int) volatile noexcept; + T* operator--(int) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator--(int) noexcept; - T* operator++() volatile noexcept; + T* operator++() volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator++() noexcept; - T* operator--() volatile noexcept; + T* operator--() volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator--() noexcept; - T* operator+=(ptrdiff_t op) volatile noexcept; + T* operator+=(ptrdiff_t op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator+=(ptrdiff_t op) noexcept; - T* operator-=(ptrdiff_t op) volatile noexcept; + T* operator-=(ptrdiff_t op) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 T* operator-=(ptrdiff_t op) noexcept; void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20 @@ -277,48 +325,61 @@ struct atomic { // since C++20 atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) volatile = delete; - void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept; + void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept; - floating-point-type operator=(floating-point-type) volatile noexcept; + floating-point-type operator=(floating-point-type) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type operator=(floating-point-type) noexcept; - floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept; + floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type load(memory_order = memory_order::seq_cst) noexcept; - operator floating-point-type() volatile noexcept; + operator floating-point-type() volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 operator floating-point-type() noexcept; floating-point-type exchange(floating-point-type, - memory_order = memory_order::seq_cst) volatile noexcept; + memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type exchange(floating-point-type, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_weak(floating-point-type&, floating-point-type, - memory_order, memory_order) volatile noexcept; + memory_order, memory_order) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(floating-point-type&, floating-point-type, memory_order, memory_order) noexcept; bool compare_exchange_strong(floating-point-type&, floating-point-type, - memory_order, memory_order) volatile noexcept; + memory_order, memory_order) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(floating-point-type&, floating-point-type, memory_order, memory_order) noexcept; bool compare_exchange_weak(floating-point-type&, floating-point-type, - memory_order = memory_order::seq_cst) volatile noexcept; + memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_weak(floating-point-type&, floating-point-type, memory_order = memory_order::seq_cst) noexcept; bool compare_exchange_strong(floating-point-type&, floating-point-type, - memory_order = memory_order::seq_cst) volatile noexcept; + memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 bool compare_exchange_strong(floating-point-type&, floating-point-type, memory_order = memory_order::seq_cst) noexcept; floating-point-type fetch_add(floating-point-type, - memory_order = memory_order::seq_cst) volatile noexcept; + memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type fetch_add(floating-point-type, memory_order = memory_order::seq_cst) noexcept; floating-point-type fetch_sub(floating-point-type, - memory_order = memory_order::seq_cst) volatile noexcept; + memory_order = memory_order::seq_cst) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type fetch_sub(floating-point-type, memory_order = memory_order::seq_cst) noexcept; - floating-point-type operator+=(floating-point-type) volatile noexcept; + floating-point-type operator+=(floating-point-type) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type operator+=(floating-point-type) noexcept; - floating-point-type operator-=(floating-point-type) volatile noexcept; + floating-point-type operator-=(floating-point-type) volatile noexcept + requires atomic::is_always_lock_free; // constraint since C++20 floating-point-type operator-=(floating-point-type) noexcept; void wait(floating-point-type, memory_order = memory_order::seq_cst) const volatile noexcept; // since C++20 @@ -574,7 +635,8 @@ void atomic_signal_fence(memory_order m) noexcept; // deprecated template - void atomic_init(volatile atomic* obj, atomic::value_type desr) noexcept; + void atomic_init(volatile atomic* obj, atomic::value_type desr) noexcept + requires atomic::is_always_lock_free; // constraint since C++20 template void atomic_init(atomic* obj, atomic::value_type desr) noexcept; diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 081b90c7bbec5..46b7b70bf6b13 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -132,7 +132,7 @@ tuple(allocator_arg_t, Alloc, pair) -> tuple; // since C++ template tuple(allocator_arg_t, Alloc, tuple) -> tuple; // since C++17 -struct ignore-type { // exposition only // Since C++26 +struct ignore-type { // exposition only // since C++26 constexpr const ignore-type& operator=(const auto &) const noexcept { return *this; } @@ -154,12 +154,21 @@ template template struct tuple_size; // undefined template struct tuple_size>; template - inline constexpr size_t tuple_size_v = tuple_size::value; // C++17 + inline constexpr size_t tuple_size_v = tuple_size::value; // C++17 + +template struct tuple_size; +template struct tuple_size; // deprecated in C++20 +template struct tuple_size; // deprecated in C++20 + template struct tuple_element; // undefined template struct tuple_element>; template using tuple_element_t = typename tuple_element ::type; // C++14 +template struct tuple_element; +template struct tuple_element; // deprecated in C++20 +template struct tuple_element; // deprecated in C++20 + // 20.4.1.5, element access: template typename tuple_element>::type& diff --git a/libcxx/include/variant b/libcxx/include/variant index 5f2d03b7227b8..cbcd7d9ebbc6d 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -74,9 +74,9 @@ namespace std { // [variant.visit], visitation template - constexpr decltype(auto) visit(this Self&&, Visitor&&); // Since C++26 + constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 template - constexpr R visit(this Self&&, Visitor&&); // Since C++26 + constexpr R visit(this Self&&, Visitor&&); // since C++26 }; // 20.7.3, variant helper classes @@ -86,8 +86,8 @@ namespace std { inline constexpr size_t variant_size_v = variant_size::value; template struct variant_size; - template struct variant_size; - template struct variant_size; + template struct variant_size; // deprecated in C++20 + template struct variant_size; // deprecated in C++20 template struct variant_size>; @@ -98,8 +98,8 @@ namespace std { using variant_alternative_t = typename variant_alternative::type; template struct variant_alternative; - template struct variant_alternative; - template struct variant_alternative; + template struct variant_alternative; // deprecated in C++20 + template struct variant_alternative; // deprecated in C++20 template struct variant_alternative>; @@ -318,10 +318,14 @@ template struct _LIBCPP_TEMPLATE_VIS variant_size : variant_size<_Tp> {}; template -struct _LIBCPP_TEMPLATE_VIS variant_size : variant_size<_Tp> {}; +struct _LIBCPP_TEMPLATE_VIS variant_size : variant_size<_Tp> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; +}; template -struct _LIBCPP_TEMPLATE_VIS variant_size : variant_size<_Tp> {}; +struct _LIBCPP_TEMPLATE_VIS variant_size : variant_size<_Tp> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; +}; template struct _LIBCPP_TEMPLATE_VIS variant_size> : integral_constant {}; @@ -336,10 +340,14 @@ template struct _LIBCPP_TEMPLATE_VIS variant_alternative<_Ip, const _Tp> : add_const> {}; template -struct _LIBCPP_TEMPLATE_VIS variant_alternative<_Ip, volatile _Tp> : add_volatile> {}; +struct _LIBCPP_TEMPLATE_VIS variant_alternative<_Ip, volatile _Tp> : add_volatile> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; +}; template -struct _LIBCPP_TEMPLATE_VIS variant_alternative<_Ip, const volatile _Tp> : add_cv> {}; +struct _LIBCPP_TEMPLATE_VIS variant_alternative<_Ip, const volatile _Tp> : add_cv> { + _LIBCPP_VOLATILE_DEPRECATED_WARNING; +}; template struct _LIBCPP_TEMPLATE_VIS variant_alternative<_Ip, variant<_Types...>> { diff --git a/libcxx/test/libcxx/atomics/atomics.types.operations/atomic_volatile_require_lock_free_in_cxx20.verify.cpp b/libcxx/test/libcxx/atomics/atomics.types.operations/atomic_volatile_require_lock_free_in_cxx20.verify.cpp new file mode 100644 index 0000000000000..d835422f2c05b --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.types.operations/atomic_volatile_require_lock_free_in_cxx20.verify.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++17 + +#include + +struct arr { + int x[32]; +}; + +struct arr2 { + int x[32]; +}; + +void f() { + std::memory_order ord = std::memory_order_relaxed; + + int expected = 0, desired = 0; + std::atomic i{}; + i.operator=(0); + i.store(0, ord); + i.load(ord); + i.operator int(); + i.exchange(0, ord); + i.compare_exchange_weak(expected, desired, ord); + i.compare_exchange_weak(expected, desired, ord, ord); + i.compare_exchange_strong(expected, desired, ord); + i.compare_exchange_strong(expected, desired, ord, ord); + + volatile std::atomic vi{}; + vi.operator=(0); + vi.store(0, ord); + vi.load(ord); + vi.operator int(); + vi.exchange(0, ord); + vi.compare_exchange_weak(expected, desired, ord); + vi.compare_exchange_weak(expected, desired, ord, ord); + vi.compare_exchange_strong(expected, desired, ord); + vi.compare_exchange_strong(expected, desired, ord, ord); + + arr test_value; + + volatile std::atomic va{}; + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.operator=(test_value); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.store(test_value, ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.load(ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.operator arr(); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.exchange(test_value, ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.compare_exchange_weak(test_value, test_value, ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.compare_exchange_weak(test_value, test_value, ord, ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.compare_exchange_strong(test_value, test_value, ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + va.compare_exchange_strong(test_value, test_value, ord, ord); + + const volatile std::atomic cva{}; + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + cva.load(ord); + + // expected-warning@*:* {{'__deprecated_if_not_always_lock_free' is deprecated: volatile atomic operations are deprecated when std::atomic::is_always_lock_free is false}} + cva.operator arr2(); +} diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.helper/volatile_tuple_element_deprecated_in_cxx20.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.helper/volatile_tuple_element_deprecated_in_cxx20.verify.cpp new file mode 100644 index 0000000000000..2282e4a2c4620 --- /dev/null +++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.helper/volatile_tuple_element_deprecated_in_cxx20.verify.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++17 + +#include +#include + +[[maybe_unused]] std::tuple_element<0, std::tuple> test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::tuple_element<0, volatile std::tuple> vol_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::tuple_element<0, const volatile std::tuple> const_vol_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::tuple_element<0, volatile std::array> vol_arr_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::tuple_element<0, const volatile std::array> const_vol_arr_test; + diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.helper/volatile_tuple_size_deprecated_in_cxx20.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.helper/volatile_tuple_size_deprecated_in_cxx20.verify.cpp new file mode 100644 index 0000000000000..3005d639763fd --- /dev/null +++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.helper/volatile_tuple_size_deprecated_in_cxx20.verify.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++17 + +#include + +[[maybe_unused]] std::tuple_size> test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::tuple_size> vol_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::tuple_size> const_vol_test; diff --git a/libcxx/test/libcxx/utilities/variant/variant.variant/variant.helper/volatile_deprecated.verify.cpp b/libcxx/test/libcxx/utilities/variant/variant.variant/variant.helper/volatile_deprecated.verify.cpp new file mode 100644 index 0000000000000..8694476dbca36 --- /dev/null +++ b/libcxx/test/libcxx/utilities/variant/variant.variant/variant.helper/volatile_deprecated.verify.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++17 + +#include + +typedef std::variant vars; + +[[maybe_unused]] std::variant_alternative<0, vars> alt_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::variant_alternative<0, volatile vars> vol_alt_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::variant_alternative<0, volatile vars> const_vol_alt_test; + +[[maybe_unused]] std::variant_size size_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::variant_size vol_size_test; + +// expected-warning@*:* {{'__volatile_deprecated_since_cxx20_warning>' is deprecated}} +[[maybe_unused]] std::variant_size const_vol_size_test; diff --git a/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.pass.cpp b/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.pass.cpp index fb7aa7cf02ca5..a79db20a6ce30 100644 --- a/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.pass.cpp @@ -32,20 +32,6 @@ void test() static_assert((std::is_same::type, Exp>::value), ""); static_assert((std::is_same::type, Exp>::value), ""); } - { - typedef T volatile Exp; - typedef std::array volatile C; - static_assert((std::is_same::type, Exp>::value), ""); - static_assert((std::is_same::type, Exp>::value), ""); - static_assert((std::is_same::type, Exp>::value), ""); - } - { - typedef T const volatile Exp; - typedef std::array const volatile C; - static_assert((std::is_same::type, Exp>::value), ""); - static_assert((std::is_same::type, Exp>::value), ""); - static_assert((std::is_same::type, Exp>::value), ""); - } } int main(int, char**)