From f1734703770c3da4e93422e4c8d4a695a7c06eee Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sat, 30 Dec 2023 21:40:37 -0500 Subject: [PATCH 01/91] [libc++][atomic_ref] Refactor atomic_base_impl class and friends so it can be reused to implement atomic_ref. Salvaged/adapted from https://reviews.llvm.org/D72240 Co-Authored-By: Benjamin Trapani --- libcxx/include/__atomic/cxx_atomic_impl.h | 409 ++++------------------ libcxx/include/__config | 4 +- 2 files changed, 66 insertions(+), 347 deletions(-) diff --git a/libcxx/include/__atomic/cxx_atomic_impl.h b/libcxx/include/__atomic/cxx_atomic_impl.h index 1a0b808a0cb1c..18c85aec4eef2 100644 --- a/libcxx/include/__atomic/cxx_atomic_impl.h +++ b/libcxx/include/__atomic/cxx_atomic_impl.h @@ -15,8 +15,12 @@ #include <__memory/addressof.h> #include <__type_traits/conditional.h> #include <__type_traits/is_assignable.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_reference.h> #include <__type_traits/is_trivially_copyable.h> +#include <__type_traits/is_volatile.h> #include <__type_traits/remove_const.h> +#include <__type_traits/remove_reference.h> #include #include @@ -58,9 +62,27 @@ struct __cxx_atomic_base_impl { } # endif // _LIBCPP_CXX03_LANG _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {} + using __contained_t = _Tp; _Tp __a_value; }; +template class _TemplateTp> +struct __is_instantiation_of : false_type {}; + +template class _TemplateTp> +struct __is_instantiation_of<_TemplateTp<_Tp>, _TemplateTp> : true_type {}; + +template ::type, + __cxx_atomic_base_impl>::value, + bool>::type> +struct __cxx_atomic_base_impl_traits { + static constexpr bool __is_value_volatile = is_volatile<_Tp>::value; + static constexpr bool __is_value_ref = is_reference::value; + using __underlying_t = typename remove_volatile::type>::type; + static constexpr bool __is_value_pointer = is_pointer<__underlying_t>::value; +}; + _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_order(memory_order __order) { // Avoid switch statement to make this a constexpr. return __order == memory_order_relaxed @@ -87,13 +109,15 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_failure_order(memory : (__order == memory_order_acq_rel ? __ATOMIC_ACQUIRE : __ATOMIC_CONSUME)))); } -template -_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { +template ::__is_value_volatile, bool>::type = 0> +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_init(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val) { __cxx_atomic_assign_volatile(__a->__a_value, __val); } -template -_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { +template ::__is_value_volatile, bool>::type = 0> +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_init(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val) { __a->__a_value = __val; } @@ -107,53 +131,28 @@ _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order template _LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) { +__cxx_atomic_store(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val, memory_order __order) { __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) { - __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const volatile __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) { - _Tp __ret; +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t +__cxx_atomic_load(const _Tp* __a, memory_order __order) { + typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __ret; __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); return __ret; } template -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_load_inplace(const volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_load_inplace( + const _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t* __dst, memory_order __order) { __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_load_inplace(const __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) { - __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) { - _Tp __ret; - __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); - return __ret; -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) { - _Tp __ret; - __atomic_exchange( - std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); - return __ret; -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) { - _Tp __ret; +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_exchange( + _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, memory_order __order) { + typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __ret; __atomic_exchange( std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); return __ret; @@ -161,9 +160,9 @@ _LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a template _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( - volatile __cxx_atomic_base_impl<_Tp>* __a, - _Tp* __expected, - _Tp __value, + _Tp* __a, + typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t* __expected, + typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, memory_order __success, memory_order __failure) { return __atomic_compare_exchange( @@ -175,23 +174,11 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( __to_gcc_failure_order(__failure)); } -template -_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( - __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) { - return __atomic_compare_exchange( - std::addressof(__a->__a_value), - __expected, - std::addressof(__value), - false, - __to_gcc_order(__success), - __to_gcc_failure_order(__failure)); -} - template _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( - volatile __cxx_atomic_base_impl<_Tp>* __a, - _Tp* __expected, - _Tp __value, + _Tp* __a, + typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t* __expected, + typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, memory_order __success, memory_order __failure) { return __atomic_compare_exchange( @@ -203,18 +190,6 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( __to_gcc_failure_order(__failure)); } -template -_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( - __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) { - return __atomic_compare_exchange( - std::addressof(__a->__a_value), - __expected, - std::addressof(__value), - true, - __to_gcc_order(__success), - __to_gcc_failure_order(__failure)); -} - template struct __skip_amt { enum { value = 1 }; @@ -233,302 +208,44 @@ template struct __skip_amt<_Tp[n]> {}; template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_add(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { - return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { - return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_sub(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { - return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t +__cxx_atomic_fetch_add(_Tp* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_add( + std::addressof(__a->__a_value), + __delta * __skip_amt::__underlying_t>::value, + __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { - return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_and(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { - return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t +__cxx_atomic_fetch_sub(_Tp* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_sub( + std::addressof(__a->__a_value), + __delta * __skip_amt::__underlying_t>::value, + __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_fetch_and( + _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __pattern, memory_order __order) { return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_or(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_fetch_or( + _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __pattern, memory_order __order) { return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { - return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_xor(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { - return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_fetch_xor( + _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __pattern, memory_order __order) { return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); } # define __cxx_atomic_is_lock_free(__s) __atomic_is_lock_free(__s, 0) -#elif defined(_LIBCPP_HAS_C_ATOMIC_IMP) - -template -struct __cxx_atomic_base_impl { - _LIBCPP_HIDE_FROM_ABI -# ifndef _LIBCPP_CXX03_LANG - __cxx_atomic_base_impl() _NOEXCEPT = default; -# else - __cxx_atomic_base_impl() _NOEXCEPT : __a_value() { - } -# endif // _LIBCPP_CXX03_LANG - _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {} - _LIBCPP_DISABLE_EXTENSION_WARNING _Atomic(_Tp) __a_value; -}; - -# define __cxx_atomic_is_lock_free(__s) __c11_atomic_is_lock_free(__s) - -_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_thread_fence(memory_order __order) _NOEXCEPT { - __c11_atomic_thread_fence(static_cast<__memory_order_underlying_t>(__order)); -} - -_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order) _NOEXCEPT { - __c11_atomic_signal_fence(static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val) _NOEXCEPT { - __c11_atomic_init(std::addressof(__a->__a_value), __val); -} -template -_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) _NOEXCEPT { - __c11_atomic_init(std::addressof(__a->__a_value), __val); -} - -template -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_store(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val, memory_order __order) _NOEXCEPT { - __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) _NOEXCEPT { - __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const volatile* __a, memory_order __order) _NOEXCEPT { - using __ptr_type = __remove_const_t__a_value)>*; - return __c11_atomic_load( - const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const* __a, memory_order __order) _NOEXCEPT { - using __ptr_type = __remove_const_t__a_value)>*; - return __c11_atomic_load( - const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const volatile* __a, _Tp* __dst, memory_order __order) _NOEXCEPT { - using __ptr_type = __remove_const_t__a_value)>*; - *__dst = __c11_atomic_load( - const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const* __a, _Tp* __dst, memory_order __order) _NOEXCEPT { - using __ptr_type = __remove_const_t__a_value)>*; - *__dst = __c11_atomic_load( - const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __value, memory_order __order) _NOEXCEPT { - return __c11_atomic_exchange( - std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) _NOEXCEPT { - return __c11_atomic_exchange( - std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order)); -} - -_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR memory_order __to_failure_order(memory_order __order) { - // Avoid switch statement to make this a constexpr. - return __order == memory_order_release - ? memory_order_relaxed - : (__order == memory_order_acq_rel ? memory_order_acquire : __order); -} - -template -_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( - __cxx_atomic_base_impl<_Tp> volatile* __a, - _Tp* __expected, - _Tp __value, - memory_order __success, - memory_order __failure) _NOEXCEPT { - return __c11_atomic_compare_exchange_strong( - std::addressof(__a->__a_value), - __expected, - __value, - static_cast<__memory_order_underlying_t>(__success), - static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); -} -template -_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( - __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) - _NOEXCEPT { - return __c11_atomic_compare_exchange_strong( - std::addressof(__a->__a_value), - __expected, - __value, - static_cast<__memory_order_underlying_t>(__success), - static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); -} - -template -_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( - __cxx_atomic_base_impl<_Tp> volatile* __a, - _Tp* __expected, - _Tp __value, - memory_order __success, - memory_order __failure) _NOEXCEPT { - return __c11_atomic_compare_exchange_weak( - std::addressof(__a->__a_value), - __expected, - __value, - static_cast<__memory_order_underlying_t>(__success), - static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); -} -template -_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( - __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) - _NOEXCEPT { - return __c11_atomic_compare_exchange_weak( - std::addressof(__a->__a_value), - __expected, - __value, - static_cast<__memory_order_underlying_t>(__success), - static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_add( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Tp __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_add( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp* -__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_add( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp* -__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*>* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_add( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_sub( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Tp __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_sub( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp* -__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_sub( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp* -__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*>* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_sub( - std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_and( - std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_and( - std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_or( - std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_or( - std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_xor( - std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} -template -_LIBCPP_HIDE_FROM_ABI _Tp -__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_xor( - std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} - -#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP, _LIBCPP_HAS_C_ATOMIC_IMP - +#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP #ifdef _LIBCPP_ATOMIC_ONLY_USE_BUILTINS template @@ -813,7 +530,7 @@ template > #endif //_LIBCPP_ATOMIC_ONLY_USE_BUILTINS struct __cxx_atomic_impl : public _Base { - static_assert(is_trivially_copyable<_Tp>::value, "std::atomic requires that 'T' be a trivially copyable type"); + using __base = _Base; _LIBCPP_HIDE_FROM_ABI __cxx_atomic_impl() _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_impl(_Tp __value) _NOEXCEPT : _Base(__value) {} diff --git a/libcxx/include/__config b/libcxx/include/__config index d356960e9e62b..e7d6551c867de 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1183,7 +1183,9 @@ __sanitizer_verify_double_ended_contiguous_container(const void*, const void*, c # if __has_feature(cxx_atomic) || __has_extension(c_atomic) || __has_keyword(_Atomic) # define _LIBCPP_HAS_C_ATOMIC_IMP -# elif defined(_LIBCPP_COMPILER_GCC) +# endif + +# if defined(_LIBCPP_COMPILER_GCC) || (__has_builtin(__atomic_load) && __has_builtin(__atomic_store) && __has_builtin(__atomic_exchange) && __has_builtin(__atomic_compare_exchange)) # define _LIBCPP_HAS_GCC_ATOMIC_IMP # endif From 3d8d9db866d483759ac2f1d7da8cf448459fb1cc Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sat, 30 Dec 2023 21:47:43 -0500 Subject: [PATCH 02/91] [libc++][atomic_ref] Enable atomic load/exchange for non-default constructible types --- libcxx/include/__atomic/cxx_atomic_impl.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libcxx/include/__atomic/cxx_atomic_impl.h b/libcxx/include/__atomic/cxx_atomic_impl.h index 18c85aec4eef2..56cd703c25894 100644 --- a/libcxx/include/__atomic/cxx_atomic_impl.h +++ b/libcxx/include/__atomic/cxx_atomic_impl.h @@ -138,9 +138,11 @@ __cxx_atomic_store(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__unde template _LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_load(const _Tp* __a, memory_order __order) { - typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __ret; - __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); - return __ret; + using _Ret = typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t; + alignas(alignof(_Ret)) unsigned char __mem[sizeof(_Ret)]; + __atomic_load( + std::addressof(__a->__a_value), std::addressof(*reinterpret_cast<_Ret*>(__mem)), __to_gcc_order(__order)); + return *reinterpret_cast<_Ret*>(__mem); } template @@ -152,10 +154,14 @@ _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_load_inplace( template _LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_exchange( _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, memory_order __order) { - typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __ret; + using _Ret = typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t; + alignas(alignof(_Ret)) unsigned char __mem[sizeof(_Ret)]; __atomic_exchange( - std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); - return __ret; + std::addressof(__a->__a_value), + std::addressof(__value), + std::addressof(*reinterpret_cast<_Ret*>(__mem)), + __to_gcc_order(__order)); + return *reinterpret_cast<_Ret*>(__mem); } template From f05a599cbb48e680f22d97e8d19b23399a3ba288 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sat, 30 Dec 2023 21:50:09 -0500 Subject: [PATCH 03/91] [libc++][atomic_ref] Add _LIBCPP_CHECK_WAIT_MEMORY_ORDER macro --- libcxx/include/__atomic/check_memory_order.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libcxx/include/__atomic/check_memory_order.h b/libcxx/include/__atomic/check_memory_order.h index 3012aec0521b3..536f764a61902 100644 --- a/libcxx/include/__atomic/check_memory_order.h +++ b/libcxx/include/__atomic/check_memory_order.h @@ -27,4 +27,8 @@ _LIBCPP_DIAGNOSE_WARNING(__f == memory_order_release || __f == memory_order_acq_rel, \ "memory order argument to atomic operation is invalid") +#define _LIBCPP_CHECK_WAIT_MEMORY_ORDER(__m) \ + _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_release || __m == memory_order_acq_rel, \ + "memory order argument to atomic operation is invalid") + #endif // _LIBCPP___ATOMIC_CHECK_MEMORY_ORDER_H From 6e01477cdeb41ba2cb62f922fd95dff91401016b Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sat, 30 Dec 2023 21:51:40 -0500 Subject: [PATCH 04/91] [libc++][atomic_ref] Implement C++20 atomic_ref --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__atomic/atomic_ref.h | 238 +++++++++++++++++++++++++++ libcxx/include/atomic | 1 + 3 files changed, 240 insertions(+) create mode 100644 libcxx/include/__atomic/atomic_ref.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 6ded426640f0d..1da9cfbd3adf7 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -236,6 +236,7 @@ set(files __atomic/atomic_flag.h __atomic/atomic_init.h __atomic/atomic_lock_free.h + __atomic/atomic_ref.h __atomic/atomic_sync.h __atomic/check_memory_order.h __atomic/contention_t.h diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h new file mode 100644 index 0000000000000..b4299804eccc3 --- /dev/null +++ b/libcxx/include/__atomic/atomic_ref.h @@ -0,0 +1,238 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_REF_H +#define _LIBCPP___ATOMIC_ATOMIC_REF_H + +#include <__assert> +#include <__atomic/check_memory_order.h> +#include <__atomic/cxx_atomic_impl.h> +#include <__atomic/is_always_lock_free.h> +#include <__config> +#include <__memory/addressof.h> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template && !is_same_v<_Tp, bool>, bool = is_floating_point_v<_Tp>> +struct __atomic_ref_base { + mutable __cxx_atomic_impl<_Tp&> __a_; + + using value_type = _Tp; + + static constexpr size_t required_alignment = alignof(_Tp); + + static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<_Tp>::__value; + + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __cxx_atomic_is_lock_free(sizeof(_Tp)); } + + _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept + _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, + "memory order argument to atomic store operation is invalid"); + __cxx_atomic_store(&__a_, __desired, __order); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { + store(__desired); + return __desired; + } + + _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__order) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || + __order == memory_order::seq_cst, + "memory order argument to atomic load operation is invalid"); + return __cxx_atomic_load(&__a_, __order); + } + + _LIBCPP_HIDE_FROM_ABI operator _Tp() const noexcept { return load(); } + + _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { + return __cxx_atomic_exchange(&__a_, __desired, __order); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __failure == memory_order::relaxed || __failure == memory_order::consume || + __failure == memory_order::acquire || __failure == memory_order::seq_cst, + "failure memory order argument to weak atomic compare-and-exchange operation is invalid"); + return __cxx_atomic_compare_exchange_weak(&__a_, &__expected, __desired, __success, __failure); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __failure == memory_order::relaxed || __failure == memory_order::consume || + __failure == memory_order::acquire || __failure == memory_order::seq_cst, + "failure memory order argument to strong atomic compare-and-exchange operation is invalid"); + return __cxx_atomic_compare_exchange_strong(&__a_, &__expected, __desired, __success, __failure); + } + + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { + return __cxx_atomic_compare_exchange_weak(&__a_, &__expected, __desired, __order, __order); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { + return __cxx_atomic_compare_exchange_strong(&__a_, &__expected, __desired, __order, __order); + } + + _LIBCPP_HIDE_FROM_ABI void wait(_Tp __old, memory_order __order = memory_order::seq_cst) const noexcept + _LIBCPP_CHECK_WAIT_MEMORY_ORDER(__order) { + _LIBCPP_ASSERT_UNCATEGORIZED( + __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || + __order == memory_order::seq_cst, + "memory order argument to atomic wait operation is invalid"); + __cxx_atomic_wait(addressof(__a_), __old, __order); + } + _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { __cxx_atomic_notify_one(addressof(__a_)); } + _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { __cxx_atomic_notify_all(addressof(__a_)); } + + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __a_(__obj) {} +}; + +template +struct __atomic_ref_base<_Tp, /*_IsIntegral=*/true, /*_IsFloatingPoint=*/false> + : public __atomic_ref_base<_Tp, false, false> { + using __base = __atomic_ref_base<_Tp, false, false>; + + using difference_type = __base::value_type; + + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __base(__obj) {} + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_add(&this->__a_, __arg, __order); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_sub(&this->__a_, __arg, __order); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_and(&this->__a_, __arg, __order); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_or(&this->__a_, __arg, __order); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_xor(&this->__a_, __arg, __order); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) const noexcept { return fetch_add(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) const noexcept { return fetch_sub(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator++() const noexcept { return fetch_add(_Tp(1)) + _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--() const noexcept { return fetch_sub(_Tp(1)) - _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __arg) const noexcept { return fetch_sub(__arg) - __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __arg) const noexcept { return fetch_and(__arg) & __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __arg) const noexcept { return fetch_or(__arg) | __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __arg) const noexcept { return fetch_xor(__arg) ^ __arg; } +}; + +template +struct __atomic_ref_base<_Tp, /*_IsIntegral=*/false, /*_IsFloatingPoint=*/true> + : public __atomic_ref_base<_Tp, false, false> { + using __base = __atomic_ref_base<_Tp, false, false>; + + using difference_type = __base::value_type; + + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __base(__obj) {} + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_add(&this->__a_, __arg, __order); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_sub(&this->__a_, __arg, __order); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __arg) const noexcept { return fetch_sub(__arg) - __arg; } +}; + +template +struct atomic_ref : public __atomic_ref_base<_Tp> { + static_assert(is_trivially_copyable<_Tp>::value, "std::atomic_ref requires that 'T' be a trivially copyable type"); + + using __base = __atomic_ref_base<_Tp>; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } + + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; +}; + +template +struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { + using __base = __atomic_ref_base<_Tp*>; + + using difference_type = ptrdiff_t; + + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_add(&this->__a_, __arg, __order); + } + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __cxx_atomic_fetch_sub(&this->__a_, __arg, __order); + } + + _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) const noexcept { return fetch_add(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) const noexcept { return fetch_sub(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++() const noexcept { return fetch_add(1) + 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--() const noexcept { return fetch_sub(1) - 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __arg) const noexcept { return fetch_add(__arg) + __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __arg) const noexcept { return fetch_sub(__arg) - __arg; } + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp*& __ptr) : __base(__ptr) {} + + _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP__ATOMIC_ATOMIC_REF_H diff --git a/libcxx/include/atomic b/libcxx/include/atomic index 2e8f5b521a55e..b71033b8a43f3 100644 --- a/libcxx/include/atomic +++ b/libcxx/include/atomic @@ -594,6 +594,7 @@ template #include <__atomic/atomic_flag.h> #include <__atomic/atomic_init.h> #include <__atomic/atomic_lock_free.h> +#include <__atomic/atomic_ref.h> #include <__atomic/atomic_sync.h> #include <__atomic/check_memory_order.h> #include <__atomic/contention_t.h> From 1575d41fed20826be90b6b2ed0f0dd4ef3ca6e7f Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sat, 30 Dec 2023 21:54:12 -0500 Subject: [PATCH 05/91] [libc++][atomic_ref] Add tests for atomic_ref --- .../assert.compare_exchange_strong.pass.cpp | 63 +++++++++ .../assert.compare_exchange_weak.pass.cpp | 63 +++++++++ .../atomics/atomics.ref/assert.ctor.pass.cpp | 38 +++++ .../atomics/atomics.ref/assert.load.pass.cpp | 60 ++++++++ .../atomics/atomics.ref/assert.store.pass.cpp | 68 +++++++++ .../atomics/atomics.ref/assert.wait.pass.cpp | 60 ++++++++ .../std/atomics/atomics.ref/assign.pass.cpp | 50 +++++++ .../atomics.ref/bitwise_and_assign.pass.cpp | 47 +++++++ .../atomics.ref/bitwise_or_assign.pass.cpp | 47 +++++++ .../atomics.ref/bitwise_xor_assign.pass.cpp | 47 +++++++ .../compare_exchange_strong.pass.cpp | 83 +++++++++++ .../compare_exchange_weak.pass.cpp | 84 +++++++++++ .../std/atomics/atomics.ref/convert.pass.cpp | 47 +++++++ .../atomics.ref/ctor.explicit.verify.cpp | 34 +++++ .../std/atomics/atomics.ref/ctor.pass.cpp | 46 ++++++ .../atomics/atomics.ref/deduction.pass.cpp | 39 ++++++ .../std/atomics/atomics.ref/exchange.pass.cpp | 48 +++++++ .../atomics/atomics.ref/fetch_add.pass.cpp | 75 ++++++++++ .../atomics/atomics.ref/fetch_and.pass.cpp | 56 ++++++++ .../std/atomics/atomics.ref/fetch_or.pass.cpp | 54 +++++++ .../atomics/atomics.ref/fetch_sub.pass.cpp | 75 ++++++++++ .../atomics/atomics.ref/fetch_xor.pass.cpp | 54 +++++++ .../atomics.ref/increment_decrement.pass.cpp | 77 ++++++++++ .../atomics.ref/is_always_lock_free.pass.cpp | 47 +++++++ .../std/atomics/atomics.ref/load.pass.cpp | 48 +++++++ .../atomics/atomics.ref/member_types.pass.cpp | 132 ++++++++++++++++++ .../atomics/atomics.ref/notify_all.pass.cpp | 86 ++++++++++++ .../atomics/atomics.ref/notify_one.pass.cpp | 54 +++++++ .../operator_minus_equals.pass.cpp | 64 +++++++++ .../atomics.ref/operator_plus_equals.pass.cpp | 64 +++++++++ .../atomics.ref/required_alignment.pass.cpp | 34 +++++ .../std/atomics/atomics.ref/store.pass.cpp | 50 +++++++ .../std/atomics/atomics.ref/type.verify.cpp | 26 ++++ .../std/atomics/atomics.ref/wait.pass.cpp | 65 +++++++++ 34 files changed, 1985 insertions(+) create mode 100644 libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp create mode 100644 libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp create mode 100644 libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp create mode 100644 libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp create mode 100644 libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp create mode 100644 libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/assign.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/convert.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/load.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/member_types.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/store.pass.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/type.verify.cpp create mode 100644 libcxx/test/std/atomics/atomics.ref/wait.pass.cpp diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp new file mode 100644 index 0000000000000..3a991c9351cd8 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -0,0 +1,63 @@ +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings + +// + +// bool compare_exchange_strong(T& expected, T desired, memory_order success, memory_order failure) const noexcept; +// +// Preconditions: failure is memory_order::relaxed, memory_order::consume, memory_order::acquire, or memory_order::seq_cst. + +#include + +#include "check_assertion.h" + +template +void test_compare_exchange_strong_invalid_memory_order() { + { + T x(T(1)); + std::atomic_ref a(x); + T t(T(2)); + a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + T t(T(2)); + a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_release); + }()), + "memory order argument to strong atomic compare-and-exchange operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + T t(T(2)); + a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); + }()), + "memory order argument to strong atomic compare-and-exchange operation is invalid"); +} + +int main(int, char**) { + test_compare_exchange_strong_invalid_memory_order(); + test_compare_exchange_strong_invalid_memory_order(); + test_compare_exchange_strong_invalid_memory_order(); + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_compare_exchange_strong_invalid_memory_order(); + + return 0; +} diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp new file mode 100644 index 0000000000000..c9506f556129e --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -0,0 +1,63 @@ +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings + +// + +// bool compare_exchange_weak(T& expected, T desired, memory_order success, memory_order failure) const noexcept; +// +// Preconditions: failure is memory_order::relaxed, memory_order::consume, memory_order::acquire, or memory_order::seq_cst. + +#include + +#include "check_assertion.h" + +template +void test_compare_exchange_weak_invalid_memory_order() { + { + T x(T(1)); + std::atomic_ref a(x); + T t(T(2)); + a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + T t(T(2)); + a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_release); + }()), + "memory order argument to weak atomic compare-and-exchange operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + T t(T(2)); + a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); + }()), + "memory order argument to weak atomic compare-and-exchange operation is invalid"); +} + +int main(int, char**) { + test_compare_exchange_weak_invalid_memory_order(); + test_compare_exchange_weak_invalid_memory_order(); + test_compare_exchange_weak_invalid_memory_order(); + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_compare_exchange_weak_invalid_memory_order(); + + return 0; +} diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp new file mode 100644 index 0000000000000..3705167181519 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -0,0 +1,38 @@ +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: availability-verbose_abort-missing + +// + +// atomic_ref(T& obj); +// +// Preconditions: The referenced object is aligned to required_alignment. + +#include + +#include "check_assertion.h" + +int main(int, char**) { + { + char c[8]; + float* f = new (c) float(3.14f); + [[maybe_unused]] std::atomic_ref r(*f); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + char c[8]; + float* f = new (c + 1) float(3.14f); + [[maybe_unused]] std::atomic_ref r(*f); + }()), + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + + return 0; +} diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp new file mode 100644 index 0000000000000..4181b1c12c7db --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -0,0 +1,60 @@ +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings + +// + +// T load(memory_order order = memory_order::seq_cst) const noexcept; +// +// Preconditions: order is memory_order::relaxed, memory_order::consume, memory_order::acquire, or memory_order::seq_cst. + +#include + +#include "check_assertion.h" + +template +void test_load_invalid_memory_order() { + { + T x(T(1)); + std::atomic_ref a(x); + (void)a.load(std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + (void)a.load(std::memory_order_release); + }()), + "memory order argument to atomic load operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + (void)a.load(std::memory_order_acq_rel); + }()), + "memory order argument to atomic load operation is invalid"); +} + +int main(int, char**) { + test_load_invalid_memory_order(); + test_load_invalid_memory_order(); + test_load_invalid_memory_order(); + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_load_invalid_memory_order(); + + return 0; +} diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp new file mode 100644 index 0000000000000..f543bcc35295f --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -0,0 +1,68 @@ +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings + +// + +// void store(T desired, memory_order order = memory_order::seq_cst) const noexcept; +// +// Preconditions: order is memory_order::relaxed, memory_order::release, or memory_order::seq_cst. + +#include + +#include "check_assertion.h" + +template +void test_store_invalid_memory_order() { + { + T x(T(1)); + std::atomic_ref a(x); + a.store(T(2), std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + a.store(T(2), std::memory_order_consume); + }()), + "memory order argument to atomic store operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + a.store(T(2), std::memory_order_acquire); + }()), + "memory order argument to atomic store operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + a.store(T(2), std::memory_order_acq_rel); + }()), + "memory order argument to atomic store operation is invalid"); +} + +int main(int, char**) { + test_store_invalid_memory_order(); + test_store_invalid_memory_order(); + test_store_invalid_memory_order(); + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_store_invalid_memory_order(); + + return 0; +} diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp new file mode 100644 index 0000000000000..2b1c920852747 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -0,0 +1,60 @@ +// +// 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 +// +//===----------------------------------------------------------------------===// +// REQUIRES: has-unix-headers +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: availability-verbose_abort-missing +// ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings + +// + +// void wait(T old, memory_order order = memory_order::seq_cst) const noexcept; +// +// Preconditions: order is memory_order::relaxed, memory_order::consume, memory_order::acquire, or memory_order::seq_cst. + +#include + +#include "check_assertion.h" + +template +void test_wait_invalid_memory_order() { + { + T x(T(1)); + std::atomic_ref a(x); + a.wait(T(2), std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + a.wait(T(2), std::memory_order_release); + }()), + "memory order argument to atomic wait operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref a(x); + a.wait(T(2), std::memory_order_acq_rel); + }()), + "memory order argument to atomic wait operation is invalid"); +} + +int main(int, char**) { + test_wait_invalid_memory_order(); + test_wait_invalid_memory_order(); + test_wait_invalid_memory_order(); + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_wait_invalid_memory_order(); + + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp new file mode 100644 index 0000000000000..95d29df70fe16 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -0,0 +1,50 @@ +// +// 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++14, c++17 + +// T operator=(T) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_assign() { + T x(T(1)); + std::atomic_ref a(x); + + a = T(2); + assert(x == T(2)); + + ASSERT_NOEXCEPT(a = T(0)); + static_assert(std::is_nothrow_assignable_v, T>); + + static_assert(!std::is_copy_assignable_v>); +} + +void test() { + test_assign(); + + test_assign(); + + test_assign(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_assign(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp new file mode 100644 index 0000000000000..68c64b9ab3458 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -0,0 +1,47 @@ +// +// 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++14, c++17 + +// integral-type operator&=(integral-type) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_bitwise_and_assign = requires { std::declval() &= std::declval(); }; + +static_assert(!has_bitwise_and_assign>); +static_assert(!has_bitwise_and_assign>); +static_assert(!has_bitwise_and_assign>); +static_assert(!has_bitwise_and_assign>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_bitwise_and_assign>); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert((a &= T(2)) == T(0)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a &= T(0)); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp new file mode 100644 index 0000000000000..20ec80697c70e --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -0,0 +1,47 @@ +// +// 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++14, c++17 + +// integral-type operator|=(integral-type) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_bitwise_or_assign = requires { std::declval() |= std::declval(); }; + +static_assert(!has_bitwise_or_assign>); +static_assert(!has_bitwise_or_assign>); +static_assert(!has_bitwise_or_assign>); +static_assert(!has_bitwise_or_assign>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_bitwise_or_assign>); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert((a |= T(2)) == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a &= T(0)); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp new file mode 100644 index 0000000000000..2d41bf01f9562 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -0,0 +1,47 @@ +// +// 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++14, c++17 + +// integral-type operator|=(integral-type) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_bitwise_xor_assign = requires { std::declval() ^= std::declval(); }; + +static_assert(!has_bitwise_xor_assign>); +static_assert(!has_bitwise_xor_assign>); +static_assert(!has_bitwise_xor_assign>); +static_assert(!has_bitwise_xor_assign>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_bitwise_xor_assign>); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert((a ^= T(2)) == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a ^= T(0)); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp new file mode 100644 index 0000000000000..b9dc84c04f766 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -0,0 +1,83 @@ +// +// 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++14, c++17 + +// bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept; +// bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_compare_exchange_strong() { + { + T x(T(1)); + std::atomic_ref a(x); + + T t(T(1)); + assert(a.compare_exchange_strong(t, T(2)) == true); + assert(a == T(2)); + assert(t == T(1)); + assert(a.compare_exchange_strong(t, T(3)) == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2))); + } + { + T x(T(1)); + std::atomic_ref a(x); + + T t(T(1)); + assert(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst) == true); + assert(a == T(2)); + assert(t == T(1)); + assert(a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst) == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst)); + } + { + T x(T(1)); + std::atomic_ref a(x); + + T t(T(1)); + assert(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed) == true); + assert(a == T(2)); + assert(t == T(1)); + assert(a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed) == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed)); + } +} + +void test() { + test_compare_exchange_strong(); + + test_compare_exchange_strong(); + + test_compare_exchange_strong(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_compare_exchange_strong(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp new file mode 100644 index 0000000000000..3d16be5e3a149 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -0,0 +1,84 @@ +// +// 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++14, c++17 + +// bool compare_exchange_weak(T&, T, memory_order, memory_order) const noexcept; +// bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_compare_exchange_weak() { + { + T x(T(1)); + std::atomic_ref a(x); + + T t(T(1)); + assert(a.compare_exchange_weak(t, T(2)) == true); + assert(a == T(2)); + assert(t == T(1)); + assert(a.compare_exchange_weak(t, T(3)) == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2))); + } + { + T x(T(1)); + std::atomic_ref a(x); + + T t(T(1)); + assert(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst) == true); + assert(a == T(2)); + assert(t == T(1)); + assert(a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst) == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst)); + } + { + T x(T(1)); + std::atomic_ref a(x); + + T t(T(1)); + assert(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed) == true); + assert(a == T(2)); + assert(t == T(1)); + assert(a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed) == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed)); + } +} + +void test() { + test_compare_exchange_weak(); + + test_compare_exchange_weak(); + + test_compare_exchange_weak(); + + struct X { + int i; + //X() = default; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_compare_exchange_weak(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp new file mode 100644 index 0000000000000..cdfd3442eac80 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -0,0 +1,47 @@ +// +// 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++14, c++17 + +// operator T() const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_convert() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a == T(1)); + + ASSERT_NOEXCEPT(T(a)); + static_assert(std::is_nothrow_convertible_v, T>); +} + +void test() { + test_convert(); + + test_convert(); + + test_convert(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_convert(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp new file mode 100644 index 0000000000000..3f1c133c643d6 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp @@ -0,0 +1,34 @@ +// +// 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++14, c++17 + +// explicit atomic_ref(T&); + +#include + +template +void test(std::atomic_ref) {} + +void explicit_ctor() { + int i = 0; + // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} + test(i); + + float f = 0.f; + // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} + test(f); + + int* p = &i; + // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} + test(p); + + struct X { + } x; + // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} + test(x); +} diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp new file mode 100644 index 0000000000000..42890f4a537fc --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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++14, c++17 + +// + +// explicit atomic_ref(T&); + +#include +#include + +#include "test_macros.h" + +template +auto makeAtomicRef(T& obj) { + // check that the constructor is explicit + static_assert(!std::is_convertible_v>); + static_assert(std::is_constructible_v, T&>); + return std::atomic_ref(obj); +} + +void test() { + int i = 0; + (void)makeAtomicRef(i); + + float f = 0.f; + (void)makeAtomicRef(f); + + int* p = &i; + (void)makeAtomicRef(p); + + struct X { + } x; + (void)makeAtomicRef(x); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp new file mode 100644 index 0000000000000..62cfcc08aa042 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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++14, c++17 +// ADDITIONAL_COMPILE_FLAGS: -Wno-ctad-maybe-unsupported + +// + +#include +#include + +void test() { + int i = 0; + std::atomic_ref a0(i); + static_assert(std::is_same_v>); + + float f = 0.f; + std::atomic_ref a1(f); + static_assert(std::is_same_v>); + + int* p = &i; + std::atomic_ref a2(p); + static_assert(std::is_same_v>); + + struct X { + } x; + std::atomic_ref a3(x); + static_assert(std::is_same_v>); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp new file mode 100644 index 0000000000000..75055bd8679bc --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -0,0 +1,48 @@ +// +// 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++14, c++17 + +// T exchange(T, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_exchange() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.exchange(T(2)) == T(1)); + ASSERT_NOEXCEPT(a.exchange(T(2))); + + assert(a.exchange(T(3), std::memory_order_seq_cst) == T(2)); + ASSERT_NOEXCEPT(a.exchange(T(3), std::memory_order_seq_cst)); +} + +void test() { + test_exchange(); + + test_exchange(); + + test_exchange(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_exchange(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp new file mode 100644 index 0000000000000..439d5a305dd6b --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -0,0 +1,75 @@ +// +// 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++14, c++17 + +// integral-type fetch_add(integral-type, memory_order = memory_order::seq_cst) const noexcept; +// floating-point-type fetch_add(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; +// T* fetch_add(difference_type, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_fetch_add = requires { + std::declval().fetch_add(std::declval()); + std::declval().fetch_add(std::declval(), std::declval()); +}; + +static_assert(!has_fetch_add>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_fetch_add>); + +template +void test_arithmetic() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.fetch_add(T(2)) == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_add(T(0))); + + assert(a.fetch_add(T(4), std::memory_order_relaxed) == T(3)); + assert(x == T(7)); + ASSERT_NOEXCEPT(a.fetch_add(T(0), std::memory_order_relaxed)); +} + +template +void test_pointer() { + using X = std::remove_pointer_t; + X t[9] = {}; + T p{&t[1]}; + std::atomic_ref a(p); + + assert(a.fetch_add(2) == &t[1]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a.fetch_add(0)); + + assert(a.fetch_add(4, std::memory_order_relaxed) == &t[3]); + assert(a == &t[7]); + ASSERT_NOEXCEPT(a.fetch_add(0, std::memory_order_relaxed)); +} + +void test() { + test_arithmetic(); + test_arithmetic(); + + test_pointer(); + test_pointer(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp new file mode 100644 index 0000000000000..d837bc8f423c9 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -0,0 +1,56 @@ +// +// 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++14, c++17 + +// integral-type fetch_and(integral-type, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_fetch_and = requires { + std::declval().fetch_and(std::declval()); + std::declval().fetch_and(std::declval(), std::declval()); +}; + +static_assert(!has_fetch_and>); +static_assert(!has_fetch_and>); +static_assert(!has_fetch_and>); +static_assert(!has_fetch_and>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_fetch_and>); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.fetch_and(T(2)) == T(1)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a.fetch_and(T(0))); + + x = T(1); + + assert(a.fetch_and(T(2), std::memory_order_relaxed) == T(1)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a.fetch_and(T(0), std::memory_order_relaxed)); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp new file mode 100644 index 0000000000000..88a836810b002 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -0,0 +1,54 @@ +// +// 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++14, c++17 + +// integral-type fetch_or(integral-type, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_fetch_or = requires { + std::declval().fetch_or(std::declval()); + std::declval().fetch_or(std::declval(), std::declval()); +}; + +static_assert(!has_fetch_or>); +static_assert(!has_fetch_or>); +static_assert(!has_fetch_or>); +static_assert(!has_fetch_or>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_fetch_or>); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.fetch_or(T(2)) == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_or(T(0))); + + assert(a.fetch_or(T(2), std::memory_order_relaxed) == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_or(T(0), std::memory_order_relaxed)); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp new file mode 100644 index 0000000000000..e9fc7ea7cb5ff --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -0,0 +1,75 @@ +// +// 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++14, c++17 + +// integral-type fetch_sub(integral-type, memory_order = memory_order::seq_cst) const noexcept; +// floating-point-type fetch_sub(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; +// T* fetch_sub(difference_type, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_fetch_sub = requires { + std::declval().fetch_sub(std::declval()); + std::declval().fetch_sub(std::declval(), std::declval()); +}; + +static_assert(!has_fetch_sub>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_fetch_sub>); + +template +void test_arithmetic() { + T x(T(7)); + std::atomic_ref a(x); + + assert(a.fetch_sub(T(4)) == T(7)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_sub(T(0))); + + assert(a.fetch_sub(T(2), std::memory_order_relaxed) == T(3)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a.fetch_sub(T(0), std::memory_order_relaxed)); +} + +template +void test_pointer() { + using X = std::remove_pointer_t; + X t[9] = {}; + T p{&t[7]}; + std::atomic_ref a(p); + + assert(a.fetch_sub(4) == &t[7]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a.fetch_sub(0)); + + assert(a.fetch_sub(2, std::memory_order_relaxed) == &t[3]); + assert(a == &t[1]); + ASSERT_NOEXCEPT(a.fetch_sub(0, std::memory_order_relaxed)); +} + +void test() { + test_arithmetic(); + test_arithmetic(); + + test_pointer(); + test_pointer(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp new file mode 100644 index 0000000000000..2e2f913e9e242 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -0,0 +1,54 @@ +// +// 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++14, c++17 + +// integral-type fetch_xor(integral-type, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_fetch_xor = requires { + std::declval().fetch_xor(std::declval()); + std::declval().fetch_xor(std::declval(), std::declval()); +}; + +static_assert(!has_fetch_xor>); +static_assert(!has_fetch_xor>); +static_assert(!has_fetch_xor>); +static_assert(!has_fetch_xor>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_fetch_xor>); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.fetch_xor(T(2)) == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_xor(T(0))); + + assert(a.fetch_xor(T(2), std::memory_order_relaxed) == T(3)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a.fetch_xor(T(0), std::memory_order_relaxed)); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp new file mode 100644 index 0000000000000..dd1bcaa6f554f --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -0,0 +1,77 @@ +// +// 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++14, c++17 + +// integral-type operator++(int) const noexcept; +// integral-type operator--(int) const noexcept; +// integral-type operator++() const noexcept; +// integral-type operator--() const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_pre_increment_operator = requires { ++std::declval(); }; + +template +concept has_post_increment_operator = requires { std::declval()++; }; + +template +concept has_pre_decrement_operator = requires { --std::declval(); }; + +template +concept has_post_decrement_operator = requires { std::declval()--; }; + +template +constexpr bool does_not_have_increment_nor_decrement_operators() { + return !has_pre_increment_operator && !has_pre_decrement_operator && !has_post_increment_operator && + !has_post_decrement_operator; +} + +static_assert(does_not_have_increment_nor_decrement_operators()); +static_assert(does_not_have_increment_nor_decrement_operators()); +static_assert(does_not_have_increment_nor_decrement_operators()); +static_assert(does_not_have_increment_nor_decrement_operators()); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(does_not_have_increment_nor_decrement_operators()); + +template +void test_integral() { + T x(T(1)); + std::atomic_ref a(x); + + assert(++a == T(2)); + assert(x == T(2)); + ASSERT_NOEXCEPT(++a); + + assert(--a == T(1)); + assert(x == T(1)); + ASSERT_NOEXCEPT(--a); + + assert(a++ == T(1)); + assert(x == T(2)); + ASSERT_NOEXCEPT(++a); + + assert(a-- == T(2)); + assert(x == T(1)); + ASSERT_NOEXCEPT(--a); +} + +void test() { test_integral(); } + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp new file mode 100644 index 0000000000000..7f0548d251248 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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++14, c++17 + +// + +// static constexpr bool is_always_lock_free; +// bool is_lock_free() const noexcept; + +#include +#include + +#include "test_macros.h" + +template +void checkAlwaysLockFree(std::atomic_ref a) { + if (std::atomic_ref::is_always_lock_free) { + assert(a.is_lock_free()); + } + ASSERT_NOEXCEPT(a.is_lock_free()); +} + +void test() { + int i = 0; + checkAlwaysLockFree(std::atomic_ref(i)); + + float f = 0.f; + checkAlwaysLockFree(std::atomic_ref(f)); + + int* p = &i; + checkAlwaysLockFree(std::atomic_ref(p)); + + struct X { + } x; + checkAlwaysLockFree(std::atomic_ref(x)); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp new file mode 100644 index 0000000000000..fe3aaaf1edcf8 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -0,0 +1,48 @@ +// +// 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++14, c++17 + +// T load(memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_load() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.load() == T(1)); + ASSERT_NOEXCEPT(a.load()); + + assert(a.load(std::memory_order_seq_cst) == T(1)); + ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); +} + +void test() { + test_load(); + + test_load(); + + test_load(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_load(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/member_types.pass.cpp b/libcxx/test/std/atomics/atomics.ref/member_types.pass.cpp new file mode 100644 index 0000000000000..d4e2f0126d621 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/member_types.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// 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++14, c++17, c++20 + +// + +// template +// struct atomic_ref +// { +// using value_type = T; +// using difference_type = value_type; // only for atomic_ref and +// // atomic_ref specializations +// using difference_type = std::ptrdiff_t; // only for atomic_ref specializations +// +// explicit atomic_ref(T&); +// atomic_ref(const atomic_ref&) noexcept; +// atomic_ref& operator=(const atomic_ref&) = delete; +// }; + +#include +#include + +#include "test_macros.h" + +template +concept has_difference_type = requires { typename T::difference_type; }; + +template +void check_member_types() { + if constexpr ((std::is_integral_v && !std::is_same_v) || std::is_floating_point_v) { + ASSERT_SAME_TYPE(typename std::atomic_ref::value_type, T); + ASSERT_SAME_TYPE(typename std::atomic_ref::difference_type, T); + } else if constexpr (std::is_pointer_v) { + ASSERT_SAME_TYPE(typename std::atomic_ref::value_type, T); + ASSERT_SAME_TYPE(typename std::atomic_ref::difference_type, std::ptrdiff_t); + } else { + ASSERT_SAME_TYPE(typename std::atomic_ref::value_type, T); + static_assert(!has_difference_type>); + } +} + +template +void test() { + // value_type and difference_type (except for primary template) + check_member_types(); + + static_assert(std::is_nothrow_copy_constructible_v>); + + static_assert(!std::is_copy_assignable_v>); + + // explicit constructor + static_assert(!std::is_convertible_v>); + static_assert(std::is_constructible_v, T&>); +} + +void testall() { + // Primary template + struct Empty {}; + test(); + struct Trivial { + int a; + float b; + }; + test(); + test(); + + // Partial specialization for pointer types + test(); + + // Specialization for integral types + // + character types + test(); + test(); + test(); + test(); + test(); + // + standard signed integer types + test(); + test(); + test(); + test(); + test(); + // + standard unsigned integer types + test(); + test(); + test(); + test(); + test(); + // + any other types needed by the typedefs in the header + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + // Specialization for floating-point types + // + floating-point types + test(); + test(); + test(); + // + TODO extended floating-point types +} + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp new file mode 100644 index 0000000000000..3ea9de240a192 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -0,0 +1,86 @@ +// +// 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++14, c++17 + +// void notify_all() const noexcept; + +#include +#include +#include +#include +#include + +#include "make_test_thread.h" +#include "test_macros.h" + +template +void test_notify_all() { + T x(T(1)); + std::atomic_ref a(x); + + bool done = false; + std::atomic started_num = 0; + std::atomic wait_done_num = 0; + + constexpr auto number_of_threads = 8; + std::vector threads; + threads.reserve(number_of_threads); + + for (auto j = 0; j < number_of_threads; ++j) { + threads.push_back(support::make_test_thread([&a, &started_num, &done, &wait_done_num] { + started_num.fetch_add(1, std::memory_order::relaxed); + + a.wait(T(1)); + wait_done_num.fetch_add(1, std::memory_order::relaxed); + + // likely to fail if wait did not block + assert(done); + })); + } + + while (started_num.load(std::memory_order::relaxed) != number_of_threads) { + std::this_thread::yield(); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + done = true; + a.store(T(3)); + a.notify_all(); + + // notify_all should unblock all the threads so that the loop below won't stuck + while (wait_done_num.load(std::memory_order::relaxed) != number_of_threads) { + std::this_thread::yield(); + } + + for (auto& thread : threads) { + thread.join(); + } + + ASSERT_NOEXCEPT(a.notify_all()); +} + +void test() { + test_notify_all(); + + test_notify_all(); + + test_notify_all(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_notify_all(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp new file mode 100644 index 0000000000000..a3ae251ab770c --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -0,0 +1,54 @@ +// +// 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++14, c++17 + +// void notify_one() const noexcept; + +#include +#include +#include +#include +#include + +#include "make_test_thread.h" +#include "test_macros.h" + +template +void test_notify_one() { + T x(T(1)); + std::atomic_ref a(x); + + std::thread t = support::make_test_thread([&]() { + a.store(T(3)); + a.notify_one(); + }); + a.wait(T(1)); + assert(a.load() == T(3)); + t.join(); + ASSERT_NOEXCEPT(a.notify_one()); +} + +void test() { + test_notify_one(); + + test_notify_one(); + + test_notify_one(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_notify_one(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp new file mode 100644 index 0000000000000..2570d07da0f58 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -0,0 +1,64 @@ +// +// 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++14, c++17 + +// integral-type operator-=(integral-type) const noexcept; +// floating-point-type operator-=(floating-point-type) const noexcept; +// T* operator-=(difference_type) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_operator_minus_equals = requires { std::declval() -= std::declval(); }; + +static_assert(!has_operator_minus_equals>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_operator_minus_equals>); + +template +void test_arithmetic() { + T x(T(3)); + std::atomic_ref a(x); + + assert((a -= T(2)) == T(1)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a -= T(0)); +} + +template +void test_pointer() { + using X = std::remove_pointer_t; + X t[9] = {}; + T p{&t[3]}; + std::atomic_ref a(p); + + assert((a -= 2) == &t[1]); + assert(a == &t[1]); + ASSERT_NOEXCEPT(a -= 0); +} + +void test() { + test_arithmetic(); + test_arithmetic(); + + test_pointer(); + test_pointer(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp new file mode 100644 index 0000000000000..7c097e568349c --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -0,0 +1,64 @@ +// +// 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++14, c++17 + +// integral-type operator+=(integral-type) const noexcept; +// floating-point-type operator+=(floating-point-type) const noexcept; +// T* operator+=(difference_type) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +concept has_operator_plus_equals = requires { std::declval() += std::declval(); }; + +static_assert(!has_operator_plus_equals>); +struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } +}; +static_assert(!has_operator_plus_equals>); + +template +void test_arithmetic() { + T x(T(1)); + std::atomic_ref a(x); + + assert((a += T(2)) == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a += T(0)); +} + +template +void test_pointer() { + using X = std::remove_pointer_t; + X t[9] = {}; + T p{&t[1]}; + std::atomic_ref a(p); + + assert((a += 2) == &t[3]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a += 0); +} + +void test() { + test_arithmetic(); + test_arithmetic(); + + test_pointer(); + test_pointer(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp new file mode 100644 index 0000000000000..341c6d18707cd --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp @@ -0,0 +1,34 @@ +// +// 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++14, c++17 + +// static constexpr size_t required_alignment; + +#include + +template +void checkRequiredAlignment() { + static_assert(std::atomic_ref::required_alignment >= alignof(T)); +} + +void test() { + checkRequiredAlignment(); + checkRequiredAlignment(); + checkRequiredAlignment(); + struct Empty {}; + checkRequiredAlignment(); + struct Trivial { + int a; + }; + checkRequiredAlignment(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp new file mode 100644 index 0000000000000..102311bb43b23 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -0,0 +1,50 @@ +// +// 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++14, c++17 + +// void store(T, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "test_macros.h" + +template +void test_store() { + T x(T(1)); + std::atomic_ref a(x); + + a.store(T(2)); + assert(x == T(2)); + ASSERT_NOEXCEPT(a.store(T(1))); + + a.store(T(3), std::memory_order_seq_cst); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.store(T(0), std::memory_order_seq_cst)); +} + +void test() { + test_store(); + + test_store(); + + test_store(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_store(); +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/atomics/atomics.ref/type.verify.cpp b/libcxx/test/std/atomics/atomics.ref/type.verify.cpp new file mode 100644 index 0000000000000..9a8b036ffd1f8 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/type.verify.cpp @@ -0,0 +1,26 @@ +// +// 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++14, c++17 + +// + +// template +// class atomic_ref; + +// The program is ill-formed if is_trivially_copyable_v is false. + +#include + +void trivially_copyable() { + struct X { + X() = default; + X(X const&) {} // -> not trivially copyable + } x; + // expected-error-re@*:* {{static assertion failed {{.*}}atomic_ref requires that 'T' be a trivially copyable type}} + std::atomic_ref r(x); +} diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp new file mode 100644 index 0000000000000..51d3a79dd59a5 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -0,0 +1,65 @@ +// +// 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++14, c++17 + +// void wait(T, memory_order = memory_order::seq_cst) const noexcept; + +#include +#include +#include + +#include "make_test_thread.h" +#include "test_macros.h" + +template +void test_wait() { + T x(T(1)); + std::atomic_ref a(x); + + assert(a.load() == T(1)); + a.wait(T(0)); + std::thread t1 = support::make_test_thread([&]() { + a.store(T(3)); + a.notify_one(); + }); + a.wait(T(1)); + assert(a.load() == T(3)); + t1.join(); + ASSERT_NOEXCEPT(a.wait(T(0))); + + assert(a.load() == T(3)); + a.wait(T(0), std::memory_order_seq_cst); + std::thread t2 = support::make_test_thread([&]() { + a.store(T(5)); + a.notify_one(); + }); + a.wait(T(3), std::memory_order_seq_cst); + assert(a.load() == T(5)); + t2.join(); + ASSERT_NOEXCEPT(a.wait(T(0), std::memory_order_seq_cst)); +} + +void test() { + test_wait(); + + test_wait(); + + test_wait(); + + struct X { + int i; + X(int ii) noexcept : i(ii) {} + bool operator==(X o) const { return i == o.i; } + }; + test_wait(); +} + +int main(int, char**) { + test(); + return 0; +} From 2767cf0ff06858db923a748afacd1469fe89b5d0 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sun, 31 Dec 2023 08:41:09 -0500 Subject: [PATCH 06/91] [libc++][atomic_ref] Fix shadow warning --- libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp | 4 ++-- .../std/atomics/atomics.ref/operator_minus_equals.pass.cpp | 4 ++-- .../std/atomics/atomics.ref/operator_plus_equals.pass.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index 439d5a305dd6b..84ad4f54a6b5c 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -47,8 +47,8 @@ void test_arithmetic() { template void test_pointer() { - using X = std::remove_pointer_t; - X t[9] = {}; + using U = std::remove_pointer_t; + U t[9] = {}; T p{&t[1]}; std::atomic_ref a(p); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index e9fc7ea7cb5ff..031f6f78a37c0 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -47,8 +47,8 @@ void test_arithmetic() { template void test_pointer() { - using X = std::remove_pointer_t; - X t[9] = {}; + using U = std::remove_pointer_t; + U t[9] = {}; T p{&t[7]}; std::atomic_ref a(p); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index 2570d07da0f58..e7e25efb7acd2 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -40,8 +40,8 @@ void test_arithmetic() { template void test_pointer() { - using X = std::remove_pointer_t; - X t[9] = {}; + using U = std::remove_pointer_t; + U t[9] = {}; T p{&t[3]}; std::atomic_ref a(p); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index 7c097e568349c..1aeadffafaef8 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -40,8 +40,8 @@ void test_arithmetic() { template void test_pointer() { - using X = std::remove_pointer_t; - X t[9] = {}; + using U = std::remove_pointer_t; + U t[9] = {}; T p{&t[1]}; std::atomic_ref a(p); From d79c4275c7b896e3ed4dc94c972047a520fb9b25 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sun, 31 Dec 2023 21:53:56 -0500 Subject: [PATCH 07/91] [libc++][atomic_ref] Revert all changes to __atomic/cxx_atomic_impl.h --- libcxx/include/__atomic/cxx_atomic_impl.h | 423 ++++++++++++++++++---- libcxx/include/__config | 4 +- 2 files changed, 351 insertions(+), 76 deletions(-) diff --git a/libcxx/include/__atomic/cxx_atomic_impl.h b/libcxx/include/__atomic/cxx_atomic_impl.h index 56cd703c25894..1a0b808a0cb1c 100644 --- a/libcxx/include/__atomic/cxx_atomic_impl.h +++ b/libcxx/include/__atomic/cxx_atomic_impl.h @@ -15,12 +15,8 @@ #include <__memory/addressof.h> #include <__type_traits/conditional.h> #include <__type_traits/is_assignable.h> -#include <__type_traits/is_pointer.h> -#include <__type_traits/is_reference.h> #include <__type_traits/is_trivially_copyable.h> -#include <__type_traits/is_volatile.h> #include <__type_traits/remove_const.h> -#include <__type_traits/remove_reference.h> #include #include @@ -62,27 +58,9 @@ struct __cxx_atomic_base_impl { } # endif // _LIBCPP_CXX03_LANG _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {} - using __contained_t = _Tp; _Tp __a_value; }; -template class _TemplateTp> -struct __is_instantiation_of : false_type {}; - -template class _TemplateTp> -struct __is_instantiation_of<_TemplateTp<_Tp>, _TemplateTp> : true_type {}; - -template ::type, - __cxx_atomic_base_impl>::value, - bool>::type> -struct __cxx_atomic_base_impl_traits { - static constexpr bool __is_value_volatile = is_volatile<_Tp>::value; - static constexpr bool __is_value_ref = is_reference::value; - using __underlying_t = typename remove_volatile::type>::type; - static constexpr bool __is_value_pointer = is_pointer<__underlying_t>::value; -}; - _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_order(memory_order __order) { // Avoid switch statement to make this a constexpr. return __order == memory_order_relaxed @@ -109,15 +87,13 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_failure_order(memory : (__order == memory_order_acq_rel ? __ATOMIC_ACQUIRE : __ATOMIC_CONSUME)))); } -template ::__is_value_volatile, bool>::type = 0> -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_init(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val) { +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { __cxx_atomic_assign_volatile(__a->__a_value, __val); } -template ::__is_value_volatile, bool>::type = 0> -_LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_init(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val) { +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { __a->__a_value = __val; } @@ -131,44 +107,63 @@ _LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order template _LIBCPP_HIDE_FROM_ABI void -__cxx_atomic_store(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val, memory_order __order) { +__cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) { __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_load(const _Tp* __a, memory_order __order) { - using _Ret = typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t; - alignas(alignof(_Ret)) unsigned char __mem[sizeof(_Ret)]; - __atomic_load( - std::addressof(__a->__a_value), std::addressof(*reinterpret_cast<_Ret*>(__mem)), __to_gcc_order(__order)); - return *reinterpret_cast<_Ret*>(__mem); +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) { + __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_load_inplace( - const _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t* __dst, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const volatile __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) { + _Tp __ret; + __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(const volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) { __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_exchange( - _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, memory_order __order) { - using _Ret = typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t; - alignas(alignof(_Ret)) unsigned char __mem[sizeof(_Ret)]; +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(const __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) { + __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) { + _Tp __ret; + __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) { + _Tp __ret; __atomic_exchange( - std::addressof(__a->__a_value), - std::addressof(__value), - std::addressof(*reinterpret_cast<_Ret*>(__mem)), - __to_gcc_order(__order)); - return *reinterpret_cast<_Ret*>(__mem); + std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) { + _Tp __ret; + __atomic_exchange( + std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; } template _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( - _Tp* __a, - typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t* __expected, - typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, + volatile __cxx_atomic_base_impl<_Tp>* __a, + _Tp* __expected, + _Tp __value, memory_order __success, memory_order __failure) { return __atomic_compare_exchange( @@ -180,11 +175,23 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( __to_gcc_failure_order(__failure)); } +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) { + return __atomic_compare_exchange( + std::addressof(__a->__a_value), + __expected, + std::addressof(__value), + false, + __to_gcc_order(__success), + __to_gcc_failure_order(__failure)); +} + template _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( - _Tp* __a, - typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t* __expected, - typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __value, + volatile __cxx_atomic_base_impl<_Tp>* __a, + _Tp* __expected, + _Tp __value, memory_order __success, memory_order __failure) { return __atomic_compare_exchange( @@ -196,6 +203,18 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( __to_gcc_failure_order(__failure)); } +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) { + return __atomic_compare_exchange( + std::addressof(__a->__a_value), + __expected, + std::addressof(__value), + true, + __to_gcc_order(__success), + __to_gcc_failure_order(__failure)); +} + template struct __skip_amt { enum { value = 1 }; @@ -214,44 +233,302 @@ template struct __skip_amt<_Tp[n]> {}; template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_fetch_add(_Tp* __a, _Td __delta, memory_order __order) { - return __atomic_fetch_add( - std::addressof(__a->__a_value), - __delta * __skip_amt::__underlying_t>::value, - __to_gcc_order(__order)); +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_add(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_fetch_sub(_Tp* __a, _Td __delta, memory_order __order) { - return __atomic_fetch_sub( - std::addressof(__a->__a_value), - __delta * __skip_amt::__underlying_t>::value, - __to_gcc_order(__order)); +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_sub(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_fetch_and( - _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __pattern, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_fetch_or( - _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __pattern, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_or(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); } template -_LIBCPP_HIDE_FROM_ABI typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __cxx_atomic_fetch_xor( - _Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __pattern, memory_order __order) { +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); } # define __cxx_atomic_is_lock_free(__s) __atomic_is_lock_free(__s, 0) -#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP +#elif defined(_LIBCPP_HAS_C_ATOMIC_IMP) + +template +struct __cxx_atomic_base_impl { + _LIBCPP_HIDE_FROM_ABI +# ifndef _LIBCPP_CXX03_LANG + __cxx_atomic_base_impl() _NOEXCEPT = default; +# else + __cxx_atomic_base_impl() _NOEXCEPT : __a_value() { + } +# endif // _LIBCPP_CXX03_LANG + _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {} + _LIBCPP_DISABLE_EXTENSION_WARNING _Atomic(_Tp) __a_value; +}; + +# define __cxx_atomic_is_lock_free(__s) __c11_atomic_is_lock_free(__s) + +_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_thread_fence(memory_order __order) _NOEXCEPT { + __c11_atomic_thread_fence(static_cast<__memory_order_underlying_t>(__order)); +} + +_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order) _NOEXCEPT { + __c11_atomic_signal_fence(static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val) _NOEXCEPT { + __c11_atomic_init(std::addressof(__a->__a_value), __val); +} +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) _NOEXCEPT { + __c11_atomic_init(std::addressof(__a->__a_value), __val); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_store(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val, memory_order __order) _NOEXCEPT { + __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) _NOEXCEPT { + __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const volatile* __a, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + return __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const* __a, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + return __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const volatile* __a, _Tp* __dst, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + *__dst = __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const* __a, _Tp* __dst, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + *__dst = __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __value, memory_order __order) _NOEXCEPT { + return __c11_atomic_exchange( + std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) _NOEXCEPT { + return __c11_atomic_exchange( + std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order)); +} + +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR memory_order __to_failure_order(memory_order __order) { + // Avoid switch statement to make this a constexpr. + return __order == memory_order_release + ? memory_order_relaxed + : (__order == memory_order_acq_rel ? memory_order_acquire : __order); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + __cxx_atomic_base_impl<_Tp> volatile* __a, + _Tp* __expected, + _Tp __value, + memory_order __success, + memory_order __failure) _NOEXCEPT { + return __c11_atomic_compare_exchange_strong( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) + _NOEXCEPT { + return __c11_atomic_compare_exchange_strong( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + __cxx_atomic_base_impl<_Tp> volatile* __a, + _Tp* __expected, + _Tp __value, + memory_order __success, + memory_order __failure) _NOEXCEPT { + return __c11_atomic_compare_exchange_weak( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) + _NOEXCEPT { + return __c11_atomic_compare_exchange_weak( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*>* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*>* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_and( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_and( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_or( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_or( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_xor( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_xor( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} + +#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP, _LIBCPP_HAS_C_ATOMIC_IMP + #ifdef _LIBCPP_ATOMIC_ONLY_USE_BUILTINS template @@ -536,7 +813,7 @@ template > #endif //_LIBCPP_ATOMIC_ONLY_USE_BUILTINS struct __cxx_atomic_impl : public _Base { - using __base = _Base; + static_assert(is_trivially_copyable<_Tp>::value, "std::atomic requires that 'T' be a trivially copyable type"); _LIBCPP_HIDE_FROM_ABI __cxx_atomic_impl() _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_impl(_Tp __value) _NOEXCEPT : _Base(__value) {} diff --git a/libcxx/include/__config b/libcxx/include/__config index e7d6551c867de..d356960e9e62b 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1183,9 +1183,7 @@ __sanitizer_verify_double_ended_contiguous_container(const void*, const void*, c # if __has_feature(cxx_atomic) || __has_extension(c_atomic) || __has_keyword(_Atomic) # define _LIBCPP_HAS_C_ATOMIC_IMP -# endif - -# if defined(_LIBCPP_COMPILER_GCC) || (__has_builtin(__atomic_load) && __has_builtin(__atomic_store) && __has_builtin(__atomic_exchange) && __has_builtin(__atomic_compare_exchange)) +# elif defined(_LIBCPP_COMPILER_GCC) # define _LIBCPP_HAS_GCC_ATOMIC_IMP # endif From 722217bc0963f2de9b0bf405551929a1b95b8753 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 1 Jan 2024 11:20:44 -0500 Subject: [PATCH 08/91] [libc++][atomic_ref] move __to_gcc_[failure_]order to its own header file --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__atomic/atomic_ref.h | 1 + libcxx/include/__atomic/cxx_atomic_impl.h | 27 +----------- libcxx/include/__atomic/to_gcc_order.h | 54 +++++++++++++++++++++++ libcxx/include/module.modulemap.in | 1 + 5 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 libcxx/include/__atomic/to_gcc_order.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 1da9cfbd3adf7..8e86e37efd20c 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -245,6 +245,7 @@ set(files __atomic/is_always_lock_free.h __atomic/kill_dependency.h __atomic/memory_order.h + __atomic/to_gcc_order.h __availability __bit/bit_cast.h __bit/bit_ceil.h diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index b4299804eccc3..ab232b221291f 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -21,6 +21,7 @@ #include <__atomic/check_memory_order.h> #include <__atomic/cxx_atomic_impl.h> #include <__atomic/is_always_lock_free.h> +#include <__atomic/to_gcc_order.h> #include <__config> #include <__memory/addressof.h> #include <__type_traits/is_floating_point.h> diff --git a/libcxx/include/__atomic/cxx_atomic_impl.h b/libcxx/include/__atomic/cxx_atomic_impl.h index 1a0b808a0cb1c..be5c1497873cc 100644 --- a/libcxx/include/__atomic/cxx_atomic_impl.h +++ b/libcxx/include/__atomic/cxx_atomic_impl.h @@ -11,6 +11,7 @@ #include <__atomic/is_always_lock_free.h> #include <__atomic/memory_order.h> +#include <__atomic/to_gcc_order.h> #include <__config> #include <__memory/addressof.h> #include <__type_traits/conditional.h> @@ -61,32 +62,6 @@ struct __cxx_atomic_base_impl { _Tp __a_value; }; -_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_order(memory_order __order) { - // Avoid switch statement to make this a constexpr. - return __order == memory_order_relaxed - ? __ATOMIC_RELAXED - : (__order == memory_order_acquire - ? __ATOMIC_ACQUIRE - : (__order == memory_order_release - ? __ATOMIC_RELEASE - : (__order == memory_order_seq_cst - ? __ATOMIC_SEQ_CST - : (__order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_CONSUME)))); -} - -_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_failure_order(memory_order __order) { - // Avoid switch statement to make this a constexpr. - return __order == memory_order_relaxed - ? __ATOMIC_RELAXED - : (__order == memory_order_acquire - ? __ATOMIC_ACQUIRE - : (__order == memory_order_release - ? __ATOMIC_RELAXED - : (__order == memory_order_seq_cst - ? __ATOMIC_SEQ_CST - : (__order == memory_order_acq_rel ? __ATOMIC_ACQUIRE : __ATOMIC_CONSUME)))); -} - template _LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { __cxx_atomic_assign_volatile(__a->__a_value, __val); diff --git a/libcxx/include/__atomic/to_gcc_order.h b/libcxx/include/__atomic/to_gcc_order.h new file mode 100644 index 0000000000000..d04c111addd31 --- /dev/null +++ b/libcxx/include/__atomic/to_gcc_order.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_TO_GCC_ORDER_H +#define _LIBCPP___ATOMIC_TO_GCC_ORDER_H + +#include <__atomic/memory_order.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if defined(__ATOMIC_RELAXED) && defined(__ATOMIC_CONSUME) && defined(__ATOMIC_ACQUIRE) && \ + defined(__ATOMIC_RELEASE) && defined(__ATOMIC_ACQ_REL) && defined(__ATOMIC_SEQ_CST) + +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_order(memory_order __order) { + // Avoid switch statement to make this a constexpr. + return __order == memory_order_relaxed + ? __ATOMIC_RELAXED + : (__order == memory_order_acquire + ? __ATOMIC_ACQUIRE + : (__order == memory_order_release + ? __ATOMIC_RELEASE + : (__order == memory_order_seq_cst + ? __ATOMIC_SEQ_CST + : (__order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_CONSUME)))); +} + +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_failure_order(memory_order __order) { + // Avoid switch statement to make this a constexpr. + return __order == memory_order_relaxed + ? __ATOMIC_RELAXED + : (__order == memory_order_acquire + ? __ATOMIC_ACQUIRE + : (__order == memory_order_release + ? __ATOMIC_RELAXED + : (__order == memory_order_seq_cst + ? __ATOMIC_SEQ_CST + : (__order == memory_order_acq_rel ? __ATOMIC_ACQUIRE : __ATOMIC_CONSUME)))); +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_TO_GCC_ORDER_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 9828c48e0587b..f320f2cc2a286 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1094,6 +1094,7 @@ module std_private_atomic_fence [system] { header "__atomic/fence. module std_private_atomic_is_always_lock_free [system] { header "__atomic/is_always_lock_free.h" } module std_private_atomic_kill_dependency [system] { header "__atomic/kill_dependency.h" } module std_private_atomic_memory_order [system] { header "__atomic/memory_order.h" } +module std_private_atomic_to_gcc_order [system] { header "__atomic/to_gcc_order.h" } module std_private_bit_bit_cast [system] { header "__bit/bit_cast.h" } module std_private_bit_bit_ceil [system] { header "__bit/bit_ceil.h" } From 1a0463faf88150d0b09786c6ac783d81edfb1513 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sun, 31 Dec 2023 21:51:25 -0500 Subject: [PATCH 09/91] [libc++][atomic_ref] Reimplement atomic_ref in terms of the GCC __atomic builtins --- libcxx/include/__atomic/atomic_ref.h | 84 +++++++++++++++++++--------- 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index ab232b221291f..2b54e17024516 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -19,8 +19,6 @@ #include <__assert> #include <__atomic/check_memory_order.h> -#include <__atomic/cxx_atomic_impl.h> -#include <__atomic/is_always_lock_free.h> #include <__atomic/to_gcc_order.h> #include <__config> #include <__memory/addressof.h> @@ -46,22 +44,22 @@ _LIBCPP_BEGIN_NAMESPACE_STD template && !is_same_v<_Tp, bool>, bool = is_floating_point_v<_Tp>> struct __atomic_ref_base { - mutable __cxx_atomic_impl<_Tp&> __a_; + _Tp* __ptr_; using value_type = _Tp; static constexpr size_t required_alignment = alignof(_Tp); - static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<_Tp>::__value; + static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_Tp), 0); - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __cxx_atomic_is_lock_free(sizeof(_Tp)); } + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), 0); } _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { _LIBCPP_ASSERT_UNCATEGORIZED( __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, "memory order argument to atomic store operation is invalid"); - __cxx_atomic_store(&__a_, __desired, __order); + __atomic_store(__ptr_, std::addressof(__desired), __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { @@ -75,13 +73,19 @@ struct __atomic_ref_base { __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "memory order argument to atomic load operation is invalid"); - return __cxx_atomic_load(&__a_, __order); + alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; + auto* __ret = reinterpret_cast<_Tp*>(__mem); + __atomic_load(__ptr_, __ret, __to_gcc_order(__order)); + return *__ret; } _LIBCPP_HIDE_FROM_ABI operator _Tp() const noexcept { return load(); } _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { - return __cxx_atomic_exchange(&__a_, __desired, __order); + alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; + auto* __ret = reinterpret_cast<_Tp*>(__mem); + __atomic_exchange(__ptr_, std::addressof(__desired), __ret, __to_gcc_order(__order)); + return *__ret; } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept @@ -90,7 +94,13 @@ struct __atomic_ref_base { __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, "failure memory order argument to weak atomic compare-and-exchange operation is invalid"); - return __cxx_atomic_compare_exchange_weak(&__a_, &__expected, __desired, __success, __failure); + return __atomic_compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + true, + __to_gcc_order(__success), + __to_gcc_order(__failure)); } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept @@ -99,16 +109,34 @@ struct __atomic_ref_base { __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, "failure memory order argument to strong atomic compare-and-exchange operation is invalid"); - return __cxx_atomic_compare_exchange_strong(&__a_, &__expected, __desired, __success, __failure); + return __atomic_compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + false, + __to_gcc_order(__success), + __to_gcc_order(__failure)); } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { - return __cxx_atomic_compare_exchange_weak(&__a_, &__expected, __desired, __order, __order); + return __atomic_compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + true, + __to_gcc_order(__order), + __to_gcc_failure_order(__order)); } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { - return __cxx_atomic_compare_exchange_strong(&__a_, &__expected, __desired, __order, __order); + return __atomic_compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + false, + __to_gcc_order(__order), + __to_gcc_failure_order(__order)); } _LIBCPP_HIDE_FROM_ABI void wait(_Tp __old, memory_order __order = memory_order::seq_cst) const noexcept @@ -117,12 +145,18 @@ struct __atomic_ref_base { __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "memory order argument to atomic wait operation is invalid"); - __cxx_atomic_wait(addressof(__a_), __old, __order); + // FIXME + (void)__old; + (void)__order; + } + _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { + // FIXME + } + _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { + // FIXME } - _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { __cxx_atomic_notify_one(addressof(__a_)); } - _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { __cxx_atomic_notify_all(addressof(__a_)); } - _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __a_(__obj) {} + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(&__obj) {} }; template @@ -137,19 +171,19 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/true, /*_IsFloatingPoint=*/false> _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_add(&this->__a_, __arg, __order); + return __atomic_fetch_add(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_sub(&this->__a_, __arg, __order); + return __atomic_fetch_sub(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_and(&this->__a_, __arg, __order); + return __atomic_fetch_and(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_or(&this->__a_, __arg, __order); + return __atomic_fetch_or(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_xor(&this->__a_, __arg, __order); + return __atomic_fetch_xor(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) const noexcept { return fetch_add(_Tp(1)); } @@ -175,10 +209,10 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/false, /*_IsFloatingPoint=*/true> _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_add(&this->__a_, __arg, __order); + return __atomic_fetch_add(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_sub(&this->__a_, __arg, __order); + return __atomic_fetch_sub(this->__ptr_, __arg, __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } @@ -210,10 +244,10 @@ struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { using difference_type = ptrdiff_t; _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_add(&this->__a_, __arg, __order); + return __atomic_fetch_add(this->__ptr_, __arg * sizeof(_Tp), __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __cxx_atomic_fetch_sub(&this->__a_, __arg, __order); + return __atomic_fetch_sub(this->__ptr_, __arg * sizeof(_Tp), __to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) const noexcept { return fetch_add(1); } From 5e5a5cdeee2c886c97b8619ebe2a8be28c6b281d Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 1 Jan 2024 12:08:43 -0500 Subject: [PATCH 10/91] [libc++][atomic_ref] add header to module map --- libcxx/include/module.modulemap.in | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index f320f2cc2a286..c361a542518a4 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1086,6 +1086,7 @@ module std_private_atomic_atomic_flag [system] { } module std_private_atomic_atomic_init [system] { header "__atomic/atomic_init.h" } module std_private_atomic_atomic_lock_free [system] { header "__atomic/atomic_lock_free.h" } +module std_private_atomic_atomic_ref [system] { header "__atomic/atomic_ref.h" } module std_private_atomic_atomic_sync [system] { header "__atomic/atomic_sync.h" } module std_private_atomic_check_memory_order [system] { header "__atomic/check_memory_order.h" } module std_private_atomic_contention_t [system] { header "__atomic/contention_t.h" } From d5525ada82081d38ec4a31905ade3f09db00c27c Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 1 Jan 2024 13:59:09 -0500 Subject: [PATCH 11/91] [libc++][atomic_ref] fixup atomic_{add,sub} for floating points --- libcxx/include/__atomic/atomic_ref.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 2b54e17024516..f552bf4b25735 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -209,10 +209,20 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/false, /*_IsFloatingPoint=*/true> _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_add(this->__ptr_, __arg, __to_gcc_order(__order)); + _Tp __old = this->load(memory_order_relaxed); + _Tp __new = __old + __arg; + while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { + __new = __old + __arg; + } + return __old; } _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_sub(this->__ptr_, __arg, __to_gcc_order(__order)); + _Tp __old = this->load(memory_order_relaxed); + _Tp __new = __old - __arg; + while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { + __new = __old - __arg; + } + return __old; } _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } From a974df059d5c4e683d3bf15ae42c97c59aebc850 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 1 Jan 2024 17:01:02 -0500 Subject: [PATCH 12/91] [libc++][atomic_ref] cleanup header includes --- libcxx/include/__atomic/atomic_ref.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index f552bf4b25735..3a904b3a7cbe3 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -23,13 +23,10 @@ #include <__config> #include <__memory/addressof.h> #include <__type_traits/is_floating_point.h> -#include <__type_traits/is_function.h> -#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> -#include -#include +#include <__type_traits/is_trivially_copyable.h> #include -#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -231,7 +228,7 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/false, /*_IsFloatingPoint=*/true> template struct atomic_ref : public __atomic_ref_base<_Tp> { - static_assert(is_trivially_copyable<_Tp>::value, "std::atomic_ref requires that 'T' be a trivially copyable type"); + static_assert(is_trivially_copyable_v<_Tp>, "std::atomic_ref requires that 'T' be a trivially copyable type"); using __base = __atomic_ref_base<_Tp>; From 41727813fb7bf67f70bb2d995b3a24a7d698bf55 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 1 Jan 2024 17:01:12 -0500 Subject: [PATCH 13/91] [libc++][atomic_ref] annotate wait, notify_one, and notify_all as expected failures --- libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 3ea9de240a192..66579c3f6d2ad 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: * // void notify_all() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index a3ae251ab770c..212596974f482 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: * // void notify_one() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index 51d3a79dd59a5..f32842989d031 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: * // void wait(T, memory_order = memory_order::seq_cst) const noexcept; From 02220bad91d27f1f1e6026b24805b256138800ec Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 5 Jan 2024 12:09:25 -0500 Subject: [PATCH 14/91] [libc++][atomic_ref] fix generic-modules build --- libcxx/include/module.modulemap.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index c361a542518a4..b2d4126844289 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1095,7 +1095,10 @@ module std_private_atomic_fence [system] { header "__atomic/fence. module std_private_atomic_is_always_lock_free [system] { header "__atomic/is_always_lock_free.h" } module std_private_atomic_kill_dependency [system] { header "__atomic/kill_dependency.h" } module std_private_atomic_memory_order [system] { header "__atomic/memory_order.h" } -module std_private_atomic_to_gcc_order [system] { header "__atomic/to_gcc_order.h" } +module std_private_atomic_to_gcc_order [system] { + header "__atomic/to_gcc_order.h" + export std_private_atomic_memory_order +} module std_private_bit_bit_cast [system] { header "__bit/bit_cast.h" } module std_private_bit_bit_ceil [system] { header "__bit/bit_ceil.h" } From 8cc91fb05928aae3b0413954a6027ba119a788c4 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 5 Jan 2024 14:13:17 -0500 Subject: [PATCH 15/91] [libc++][atomic_ref] uncomment `using std::atomic_ref;` in atomic module --- libcxx/modules/std/atomic.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/modules/std/atomic.inc b/libcxx/modules/std/atomic.inc index 88b31ccdb2084..efc45e3c0f4dd 100644 --- a/libcxx/modules/std/atomic.inc +++ b/libcxx/modules/std/atomic.inc @@ -22,7 +22,7 @@ export namespace std { // [atomics.ref.generic], class template atomic_ref // [atomics.ref.pointer], partial specialization for pointers - // using std::atomic_ref; + using std::atomic_ref; // [atomics.types.generic], class template atomic using std::atomic; From 28e4f55266b032ba47def16e3f022fd65f922d42 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 5 Jan 2024 17:48:30 -0500 Subject: [PATCH 16/91] [libc++][atomic_ref] add missing header include for uintptr_t caught by hardening mode CI builds --- libcxx/include/__atomic/atomic_ref.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 3a904b3a7cbe3..32bdb615593df 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -27,6 +27,7 @@ #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_copyable.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header From 0391ec0d79fbf21329fa1a4eeeccc5a3158c5533 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sat, 6 Jan 2024 21:44:20 -0500 Subject: [PATCH 17/91] [libc++][atomic_ref] Attempt to use __cxx_atomic_wait --- libcxx/include/__atomic/atomic_ref.h | 13 ++++--------- libcxx/include/__atomic/atomic_sync.h | 15 +++++++++++++++ .../std/atomics/atomics.ref/notify_all.pass.cpp | 1 - .../std/atomics/atomics.ref/notify_one.pass.cpp | 1 - libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 1 - 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 32bdb615593df..5944384490b4b 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -18,6 +18,7 @@ #define _LIBCPP___ATOMIC_ATOMIC_REF_H #include <__assert> +#include <__atomic/atomic_sync.h> #include <__atomic/check_memory_order.h> #include <__atomic/to_gcc_order.h> #include <__config> @@ -143,16 +144,10 @@ struct __atomic_ref_base { __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "memory order argument to atomic wait operation is invalid"); - // FIXME - (void)__old; - (void)__order; - } - _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { - // FIXME - } - _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { - // FIXME + __cxx_atomic_wait(__ptr_, __old, __order); } + _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { __cxx_atomic_notify_one(__ptr_); } + _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { __cxx_atomic_notify_all(__ptr_); } _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(&__obj) {} }; diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h index e1994ddde86c1..21a69f4fd62bb 100644 --- a/libcxx/include/__atomic/atomic_sync.h +++ b/libcxx/include/__atomic/atomic_sync.h @@ -27,6 +27,21 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct __is_cxx_atomic_impl : false_type {}; + +template +struct __is_cxx_atomic_impl<__cxx_atomic_impl<_Tp> > : true_type {}; + +template +_LIBCPP_HIDE_FROM_ABI __enable_if_t >::value, _Tp> +__cxx_atomic_load(_Tp* __ptr, memory_order __order) noexcept { + alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; + auto* __ret = reinterpret_cast<_Tp*>(__mem); + __atomic_load(__ptr, __ret, __to_gcc_order(__order)); + return *__ret; +} + #ifndef _LIBCPP_HAS_NO_THREADS _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*); diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 66579c3f6d2ad..3ea9de240a192 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -6,7 +6,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// XFAIL: * // void notify_all() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index 212596974f482..a3ae251ab770c 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -6,7 +6,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// XFAIL: * // void notify_one() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index f32842989d031..51d3a79dd59a5 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -6,7 +6,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// XFAIL: * // void wait(T, memory_order = memory_order::seq_cst) const noexcept; From 82fcdadb5b725cd4818429233065cb338f89f0e1 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sun, 7 Jan 2024 20:55:40 -0500 Subject: [PATCH 18/91] [libc++][atomic_ref] Fiddle with hardening-mode annotations in preconditions tests --- .../atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp | 2 +- .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 3a991c9351cd8..8d78a58524a6f 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index c9506f556129e..1c19116e90009 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index 3705167181519..2815287566066 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} // XFAIL: availability-verbose_abort-missing // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 4181b1c12c7db..9a017e7ba036c 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index f543bcc35295f..6de13404c2d2a 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index 2b1c920852747..e0c33cd207d68 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings From 4fec87cf1fd94fa34ee5b234c62a14ca95df0b91 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sun, 7 Jan 2024 20:57:52 -0500 Subject: [PATCH 19/91] [libc++][atomic_ref] Fix cxx03 CI build --- libcxx/include/__atomic/atomic_sync.h | 7 +++++-- libcxx/include/module.modulemap.in | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h index 21a69f4fd62bb..4a2d0fc21810e 100644 --- a/libcxx/include/__atomic/atomic_sync.h +++ b/libcxx/include/__atomic/atomic_sync.h @@ -12,6 +12,7 @@ #include <__atomic/contention_t.h> #include <__atomic/cxx_atomic_impl.h> #include <__atomic/memory_order.h> +#include <__atomic/to_gcc_order.h> #include <__availability> #include <__chrono/duration.h> #include <__config> @@ -19,6 +20,8 @@ #include <__thread/poll_with_backoff.h> #include <__thread/support.h> #include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/remove_cv.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -35,8 +38,8 @@ struct __is_cxx_atomic_impl<__cxx_atomic_impl<_Tp> > : true_type {}; template _LIBCPP_HIDE_FROM_ABI __enable_if_t >::value, _Tp> -__cxx_atomic_load(_Tp* __ptr, memory_order __order) noexcept { - alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; +__cxx_atomic_load(_Tp* __ptr, memory_order __order) _NOEXCEPT { + _ALIGNAS_TYPE(_Tp) unsigned char __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); __atomic_load(__ptr, __ret, __to_gcc_order(__order)); return *__ret; diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index b2d4126844289..71c9cee8b027a 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1087,7 +1087,10 @@ module std_private_atomic_atomic_flag [system] { module std_private_atomic_atomic_init [system] { header "__atomic/atomic_init.h" } module std_private_atomic_atomic_lock_free [system] { header "__atomic/atomic_lock_free.h" } module std_private_atomic_atomic_ref [system] { header "__atomic/atomic_ref.h" } -module std_private_atomic_atomic_sync [system] { header "__atomic/atomic_sync.h" } +module std_private_atomic_atomic_sync [system] { + header "__atomic/atomic_sync.h" + export std_private_atomic_to_gcc_order +} module std_private_atomic_check_memory_order [system] { header "__atomic/check_memory_order.h" } module std_private_atomic_contention_t [system] { header "__atomic/contention_t.h" } module std_private_atomic_cxx_atomic_impl [system] { header "__atomic/cxx_atomic_impl.h" } From f763a3a853ff0f97b89c4ae425b73b73e78e5775 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 15 Jan 2024 11:50:21 -0500 Subject: [PATCH 20/91] Revert "[libc++][atomic_ref] Fiddle with hardening-mode annotations in preconditions tests" This reverts commit a132470db3beae515ad47afef2f27e9d65e7303e. --- .../atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp | 2 +- .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 8d78a58524a6f..3a991c9351cd8 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: libcpp-hardening-mode=none // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index 1c19116e90009..c9506f556129e 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: libcpp-hardening-mode=none // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index 2815287566066..3705167181519 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: libcpp-hardening-mode=none // XFAIL: availability-verbose_abort-missing // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 9a017e7ba036c..4181b1c12c7db 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: libcpp-hardening-mode=none // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index 6de13404c2d2a..f543bcc35295f 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: libcpp-hardening-mode=none // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index e0c33cd207d68..2b1c920852747 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode={{extensive|debug}} +// UNSUPPORTED: libcpp-hardening-mode=none // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings From 259afbf1493667b7f2e46eef07b08803250d0aa9 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 15 Jan 2024 13:46:12 -0500 Subject: [PATCH 21/91] [libc++][atomic_ref] Robust against ADL lookup --- libcxx/include/__atomic/atomic_ref.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 5944384490b4b..3ba12cc3240e4 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -144,10 +144,10 @@ struct __atomic_ref_base { __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "memory order argument to atomic wait operation is invalid"); - __cxx_atomic_wait(__ptr_, __old, __order); + std::__cxx_atomic_wait(__ptr_, __old, __order); } - _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { __cxx_atomic_notify_one(__ptr_); } - _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { __cxx_atomic_notify_all(__ptr_); } + _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__cxx_atomic_notify_one(__ptr_); } + _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__cxx_atomic_notify_all(__ptr_); } _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(&__obj) {} }; From f0cbfec31bdf47031a337eb912895ecbe6016be8 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 16:37:16 -0500 Subject: [PATCH 22/91] [libc++][atomic_ref] Qualify all __to_gcc_order calls --- libcxx/include/__atomic/atomic_ref.h | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 3ba12cc3240e4..d0f532b11059d 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -58,7 +58,7 @@ struct __atomic_ref_base { _LIBCPP_ASSERT_UNCATEGORIZED( __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, "memory order argument to atomic store operation is invalid"); - __atomic_store(__ptr_, std::addressof(__desired), __to_gcc_order(__order)); + __atomic_store(__ptr_, std::addressof(__desired), std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { @@ -74,7 +74,7 @@ struct __atomic_ref_base { "memory order argument to atomic load operation is invalid"); alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); - __atomic_load(__ptr_, __ret, __to_gcc_order(__order)); + __atomic_load(__ptr_, __ret, std::__to_gcc_order(__order)); return *__ret; } @@ -83,7 +83,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); - __atomic_exchange(__ptr_, std::addressof(__desired), __ret, __to_gcc_order(__order)); + __atomic_exchange(__ptr_, std::addressof(__desired), __ret, std::__to_gcc_order(__order)); return *__ret; } _LIBCPP_HIDE_FROM_ABI bool @@ -98,8 +98,8 @@ struct __atomic_ref_base { std::addressof(__expected), std::addressof(__desired), true, - __to_gcc_order(__success), - __to_gcc_order(__failure)); + std::__to_gcc_order(__success), + std::__to_gcc_order(__failure)); } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept @@ -113,8 +113,8 @@ struct __atomic_ref_base { std::addressof(__expected), std::addressof(__desired), false, - __to_gcc_order(__success), - __to_gcc_order(__failure)); + std::__to_gcc_order(__success), + std::__to_gcc_order(__failure)); } _LIBCPP_HIDE_FROM_ABI bool @@ -124,8 +124,8 @@ struct __atomic_ref_base { std::addressof(__expected), std::addressof(__desired), true, - __to_gcc_order(__order), - __to_gcc_failure_order(__order)); + std::__to_gcc_order(__order), + std::__to_gcc_failure_order(__order)); } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { @@ -134,8 +134,8 @@ struct __atomic_ref_base { std::addressof(__expected), std::addressof(__desired), false, - __to_gcc_order(__order), - __to_gcc_failure_order(__order)); + std::__to_gcc_order(__order), + std::__to_gcc_failure_order(__order)); } _LIBCPP_HIDE_FROM_ABI void wait(_Tp __old, memory_order __order = memory_order::seq_cst) const noexcept @@ -164,19 +164,19 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/true, /*_IsFloatingPoint=*/false> _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_add(this->__ptr_, __arg, __to_gcc_order(__order)); + return __atomic_fetch_add(this->__ptr_, __arg, std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_sub(this->__ptr_, __arg, __to_gcc_order(__order)); + return __atomic_fetch_sub(this->__ptr_, __arg, std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_and(this->__ptr_, __arg, __to_gcc_order(__order)); + return __atomic_fetch_and(this->__ptr_, __arg, std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_or(this->__ptr_, __arg, __to_gcc_order(__order)); + return __atomic_fetch_or(this->__ptr_, __arg, std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_xor(this->__ptr_, __arg, __to_gcc_order(__order)); + return __atomic_fetch_xor(this->__ptr_, __arg, std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) const noexcept { return fetch_add(_Tp(1)); } @@ -247,10 +247,10 @@ struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { using difference_type = ptrdiff_t; _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_add(this->__ptr_, __arg * sizeof(_Tp), __to_gcc_order(__order)); + return __atomic_fetch_add(this->__ptr_, __arg * sizeof(_Tp), std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { - return __atomic_fetch_sub(this->__ptr_, __arg * sizeof(_Tp), __to_gcc_order(__order)); + return __atomic_fetch_sub(this->__ptr_, __arg * sizeof(_Tp), std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) const noexcept { return fetch_add(1); } From 46ab57281d04c465f06b03dcae816b1ae29d0f3f Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 16:56:56 -0500 Subject: [PATCH 23/91] [libc++][atomic_ref] Simplify inheritance from __atomic_ref_base --- libcxx/include/__atomic/atomic_ref.h | 85 ++++++++++++++++------------ 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index d0f532b11059d..be58359d6e957 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -21,11 +21,10 @@ #include <__atomic/atomic_sync.h> #include <__atomic/check_memory_order.h> #include <__atomic/to_gcc_order.h> +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> #include <__config> #include <__memory/addressof.h> -#include <__type_traits/is_floating_point.h> -#include <__type_traits/is_integral.h> -#include <__type_traits/is_same.h> #include <__type_traits/is_trivially_copyable.h> #include #include @@ -41,7 +40,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 -template && !is_same_v<_Tp, bool>, bool = is_floating_point_v<_Tp>> +template struct __atomic_ref_base { _Tp* __ptr_; @@ -153,16 +152,41 @@ struct __atomic_ref_base { }; template -struct __atomic_ref_base<_Tp, /*_IsIntegral=*/true, /*_IsFloatingPoint=*/false> - : public __atomic_ref_base<_Tp, false, false> { - using __base = __atomic_ref_base<_Tp, false, false>; +struct atomic_ref : public __atomic_ref_base<_Tp> { + static_assert(is_trivially_copyable_v<_Tp>, "std::atomic_ref requires that 'T' be a trivially copyable type"); - using difference_type = __base::value_type; + using __base = __atomic_ref_base<_Tp>; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } + + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; +}; - _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __base(__obj) {} +template + requires(std::integral<_Tp> && !std::same_as) +struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { + using __base = __atomic_ref_base<_Tp>; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } + + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + atomic_ref& operator=(const atomic_ref&) = delete; + + using difference_type = __base::value_type; + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { return __atomic_fetch_add(this->__ptr_, __arg, std::__to_gcc_order(__order)); } @@ -191,16 +215,23 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/true, /*_IsFloatingPoint=*/false> }; template -struct __atomic_ref_base<_Tp, /*_IsIntegral=*/false, /*_IsFloatingPoint=*/true> - : public __atomic_ref_base<_Tp, false, false> { - using __base = __atomic_ref_base<_Tp, false, false>; + requires std::floating_point<_Tp> +struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { + using __base = __atomic_ref_base<_Tp>; - using difference_type = __base::value_type; + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } - _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __base(__obj) {} + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + atomic_ref& operator=(const atomic_ref&) = delete; + + using difference_type = __base::value_type; + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { _Tp __old = this->load(memory_order_relaxed); _Tp __new = __old + __arg; @@ -223,26 +254,14 @@ struct __atomic_ref_base<_Tp, /*_IsIntegral=*/false, /*_IsFloatingPoint=*/true> }; template -struct atomic_ref : public __atomic_ref_base<_Tp> { - static_assert(is_trivially_copyable_v<_Tp>, "std::atomic_ref requires that 'T' be a trivially copyable type"); - - using __base = __atomic_ref_base<_Tp>; - - _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); - } +struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { + using __base = __atomic_ref_base<_Tp*>; - _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp*& __ptr) : __base(__ptr) {} - _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __desired) const noexcept { return __base::operator=(__desired); } atomic_ref& operator=(const atomic_ref&) = delete; -}; - -template -struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { - using __base = __atomic_ref_base<_Tp*>; using difference_type = ptrdiff_t; @@ -259,12 +278,6 @@ struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { _LIBCPP_HIDE_FROM_ABI _Tp* operator--() const noexcept { return fetch_sub(1) - 1; } _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __arg) const noexcept { return fetch_add(__arg) + __arg; } _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __arg) const noexcept { return fetch_sub(__arg) - __arg; } - - _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp*& __ptr) : __base(__ptr) {} - - _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __desired) const noexcept { return __base::operator=(__desired); } - - atomic_ref& operator=(const atomic_ref&) = delete; }; #endif // _LIBCPP_STD_VER >= 20 From f9edc9f08d91c7db347be1781802435f9e5b740b Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:05:22 -0500 Subject: [PATCH 24/91] [libc++][atomic_ref] Prefer snake_case --- libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp | 10 +++++----- .../atomics/atomics.ref/is_always_lock_free.pass.cpp | 10 +++++----- .../atomics/atomics.ref/required_alignment.pass.cpp | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp index 42890f4a537fc..d20f2cd5e4235 100644 --- a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp @@ -18,7 +18,7 @@ #include "test_macros.h" template -auto makeAtomicRef(T& obj) { +auto make_atomic_ref(T& obj) { // check that the constructor is explicit static_assert(!std::is_convertible_v>); static_assert(std::is_constructible_v, T&>); @@ -27,17 +27,17 @@ auto makeAtomicRef(T& obj) { void test() { int i = 0; - (void)makeAtomicRef(i); + (void)make_atomic_ref(i); float f = 0.f; - (void)makeAtomicRef(f); + (void)make_atomic_ref(f); int* p = &i; - (void)makeAtomicRef(p); + (void)make_atomic_ref(p); struct X { } x; - (void)makeAtomicRef(x); + (void)make_atomic_ref(x); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index 7f0548d251248..ad958b5d9cf35 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -19,7 +19,7 @@ #include "test_macros.h" template -void checkAlwaysLockFree(std::atomic_ref a) { +void check_always_lock_free(std::atomic_ref a) { if (std::atomic_ref::is_always_lock_free) { assert(a.is_lock_free()); } @@ -28,17 +28,17 @@ void checkAlwaysLockFree(std::atomic_ref a) { void test() { int i = 0; - checkAlwaysLockFree(std::atomic_ref(i)); + check_always_lock_free(std::atomic_ref(i)); float f = 0.f; - checkAlwaysLockFree(std::atomic_ref(f)); + check_always_lock_free(std::atomic_ref(f)); int* p = &i; - checkAlwaysLockFree(std::atomic_ref(p)); + check_always_lock_free(std::atomic_ref(p)); struct X { } x; - checkAlwaysLockFree(std::atomic_ref(x)); + check_always_lock_free(std::atomic_ref(x)); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp index 341c6d18707cd..f51a030b53283 100644 --- a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp @@ -12,20 +12,20 @@ #include template -void checkRequiredAlignment() { +void check_required_alignment() { static_assert(std::atomic_ref::required_alignment >= alignof(T)); } void test() { - checkRequiredAlignment(); - checkRequiredAlignment(); - checkRequiredAlignment(); + check_required_alignment(); + check_required_alignment(); + check_required_alignment(); struct Empty {}; - checkRequiredAlignment(); + check_required_alignment(); struct Trivial { int a; }; - checkRequiredAlignment(); + check_required_alignment(); } int main(int, char**) { From 2438001fa5bca3e9e5910078a3e67e4812a65b4c Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:16:20 -0500 Subject: [PATCH 25/91] [libc++][atomic_ref] Use proper _LIBCPP_ASSERT_* macro --- libcxx/include/__atomic/atomic_ref.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index be58359d6e957..08910340e654f 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -54,7 +54,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, "memory order argument to atomic store operation is invalid"); __atomic_store(__ptr_, std::addressof(__desired), std::__to_gcc_order(__order)); @@ -67,7 +67,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__order) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "memory order argument to atomic load operation is invalid"); @@ -88,7 +88,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, "failure memory order argument to weak atomic compare-and-exchange operation is invalid"); @@ -103,7 +103,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, "failure memory order argument to strong atomic compare-and-exchange operation is invalid"); @@ -139,7 +139,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI void wait(_Tp __old, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_WAIT_MEMORY_ORDER(__order) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "memory order argument to atomic wait operation is invalid"); @@ -158,8 +158,8 @@ struct atomic_ref : public __atomic_ref_base<_Tp> { using __base = __atomic_ref_base<_Tp>; _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); } _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; @@ -175,8 +175,8 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { using __base = __atomic_ref_base<_Tp>; _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); } _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; @@ -220,8 +220,8 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { using __base = __atomic_ref_base<_Tp>; _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_UNCATEGORIZED((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); } _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; From 255559f94d02c4dd1610368bfc80052044e62d84 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:34:00 -0500 Subject: [PATCH 26/91] [libc++][atomic_ref] Prefix assertion messages with "atomic_ref:" --- libcxx/include/__atomic/atomic_ref.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 08910340e654f..5b788f3a40f00 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -56,7 +56,7 @@ struct __atomic_ref_base { _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, - "memory order argument to atomic store operation is invalid"); + "atomic_ref: memory order argument to atomic store operation is invalid"); __atomic_store(__ptr_, std::addressof(__desired), std::__to_gcc_order(__order)); } @@ -70,7 +70,7 @@ struct __atomic_ref_base { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, - "memory order argument to atomic load operation is invalid"); + "atomic_ref: memory order argument to atomic load operation is invalid"); alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); __atomic_load(__ptr_, __ret, std::__to_gcc_order(__order)); @@ -91,7 +91,7 @@ struct __atomic_ref_base { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, - "failure memory order argument to weak atomic compare-and-exchange operation is invalid"); + "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); return __atomic_compare_exchange( __ptr_, std::addressof(__expected), @@ -106,7 +106,7 @@ struct __atomic_ref_base { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, - "failure memory order argument to strong atomic compare-and-exchange operation is invalid"); + "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); return __atomic_compare_exchange( __ptr_, std::addressof(__expected), @@ -142,7 +142,7 @@ struct __atomic_ref_base { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, - "memory order argument to atomic wait operation is invalid"); + "atomic_ref: memory order argument to atomic wait operation is invalid"); std::__cxx_atomic_wait(__ptr_, __old, __order); } _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__cxx_atomic_notify_one(__ptr_); } From 8ebfe2df8ac8ae1e864b04752579d48fce8527cd Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:39:38 -0500 Subject: [PATCH 27/91] [libc++][atomic_ref] Fix XFAIL annotations --- .../atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp | 2 +- .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 3a991c9351cd8..a343391308034 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -7,7 +7,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none -// XFAIL: availability-verbose_abort-missing +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index c9506f556129e..9d8bbebb70166 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -7,7 +7,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none -// XFAIL: availability-verbose_abort-missing +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index 3705167181519..a19f6516ff3e4 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -7,7 +7,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none -// XFAIL: availability-verbose_abort-missing +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 4181b1c12c7db..f94ab808b4317 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -7,7 +7,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none -// XFAIL: availability-verbose_abort-missing +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index f543bcc35295f..1d41c4341fb99 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -7,7 +7,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none -// XFAIL: availability-verbose_abort-missing +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index 2b1c920852747..5a68cabadb17b 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -7,7 +7,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none -// XFAIL: availability-verbose_abort-missing +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings // From a745599d47b298d295c7003cb3807063b7dccfec Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:42:50 -0500 Subject: [PATCH 28/91] [libc++][atomic_ref] Fixup conversion test --- libcxx/test/std/atomics/atomics.ref/convert.pass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index cdfd3442eac80..d4cd38efffbb9 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -20,7 +20,8 @@ void test_convert() { T x(T(1)); std::atomic_ref a(x); - assert(a == T(1)); + T converted = a; + assert(converted == T(1)); ASSERT_NOEXCEPT(T(a)); static_assert(std::is_nothrow_convertible_v, T>); From 07ecf37fad8b286e5ce859a67c70f1b91fa7b3bd Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:44:28 -0500 Subject: [PATCH 29/91] [libc++][atomic_ref] Drop test that the ctor is explicit since there is already a check --- .../atomics.ref/ctor.explicit.verify.cpp | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp deleted file mode 100644 index 3f1c133c643d6..0000000000000 --- a/libcxx/test/std/atomics/atomics.ref/ctor.explicit.verify.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// -// 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++14, c++17 - -// explicit atomic_ref(T&); - -#include - -template -void test(std::atomic_ref) {} - -void explicit_ctor() { - int i = 0; - // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} - test(i); - - float f = 0.f; - // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} - test(f); - - int* p = &i; - // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} - test(p); - - struct X { - } x; - // expected-error-re@*:* {{{{.*}}no matching function for call to 'test'}} - test(x); -} From ba4ec71734bbb73a887f36d1f1ba34ea7755e598 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:48:46 -0500 Subject: [PATCH 30/91] [libc++][atomic_ref] Fixup do not use -Wno-ctad-maybe-unsupported in CTAD tests --- libcxx/include/__atomic/atomic_ref.h | 2 ++ libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 5b788f3a40f00..4ba8bdcccf1cc 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -280,6 +280,8 @@ struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __arg) const noexcept { return fetch_sub(__arg) - __arg; } }; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(atomic_ref); + #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp index 62cfcc08aa042..27aaf2ecdb3c9 100644 --- a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// ADDITIONAL_COMPILE_FLAGS: -Wno-ctad-maybe-unsupported // From b476c80ecaab26d80c5f73c0819da98cd0a9f808 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 17:55:13 -0500 Subject: [PATCH 31/91] [libc++][atomic_ref] Rename {type -> requires-trivially-copyable}.verify.cpp --- .../{type.verify.cpp => requires-trivially-copyable.verify.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename libcxx/test/std/atomics/atomics.ref/{type.verify.cpp => requires-trivially-copyable.verify.cpp} (100%) diff --git a/libcxx/test/std/atomics/atomics.ref/type.verify.cpp b/libcxx/test/std/atomics/atomics.ref/requires-trivially-copyable.verify.cpp similarity index 100% rename from libcxx/test/std/atomics/atomics.ref/type.verify.cpp rename to libcxx/test/std/atomics/atomics.ref/requires-trivially-copyable.verify.cpp From 21bf0662d008b5e699e9642b4c46bb754bc1d054 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 18:09:46 -0500 Subject: [PATCH 32/91] [libc++][atomic_ref] Const the atomic_refs in the tests --- .../atomics.ref/assert.compare_exchange_strong.pass.cpp | 6 +++--- .../atomics.ref/assert.compare_exchange_weak.pass.cpp | 6 +++--- .../test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 6 +++--- .../test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 8 ++++---- .../test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 6 +++--- libcxx/test/std/atomics/atomics.ref/assign.pass.cpp | 2 +- .../std/atomics/atomics.ref/bitwise_and_assign.pass.cpp | 2 +- .../std/atomics/atomics.ref/bitwise_or_assign.pass.cpp | 2 +- .../std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp | 2 +- .../atomics/atomics.ref/compare_exchange_strong.pass.cpp | 6 +++--- .../atomics/atomics.ref/compare_exchange_weak.pass.cpp | 6 +++--- libcxx/test/std/atomics/atomics.ref/convert.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp | 2 +- .../std/atomics/atomics.ref/increment_decrement.pass.cpp | 2 +- .../std/atomics/atomics.ref/is_always_lock_free.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/load.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp | 2 +- .../atomics/atomics.ref/operator_minus_equals.pass.cpp | 4 ++-- .../std/atomics/atomics.ref/operator_plus_equals.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/store.pass.cpp | 2 +- libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 2 +- 27 files changed, 46 insertions(+), 46 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index a343391308034..aeab9f5ff3fb7 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -24,7 +24,7 @@ template void test_compare_exchange_strong_invalid_memory_order() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); } @@ -32,7 +32,7 @@ void test_compare_exchange_strong_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_release); }()), @@ -41,7 +41,7 @@ void test_compare_exchange_strong_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); }()), diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index 9d8bbebb70166..407146722f17c 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -24,7 +24,7 @@ template void test_compare_exchange_weak_invalid_memory_order() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); } @@ -32,7 +32,7 @@ void test_compare_exchange_weak_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_release); }()), @@ -41,7 +41,7 @@ void test_compare_exchange_weak_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); }()), diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index f94ab808b4317..34e7a2b56f0f0 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -24,14 +24,14 @@ template void test_load_invalid_memory_order() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); (void)a.load(std::memory_order_relaxed); } TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); (void)a.load(std::memory_order_release); }()), "memory order argument to atomic load operation is invalid"); @@ -39,7 +39,7 @@ void test_load_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); (void)a.load(std::memory_order_acq_rel); }()), "memory order argument to atomic load operation is invalid"); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index 1d41c4341fb99..12e21ea38b94a 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -24,14 +24,14 @@ template void test_store_invalid_memory_order() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.store(T(2), std::memory_order_relaxed); } TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.store(T(2), std::memory_order_consume); }()), "memory order argument to atomic store operation is invalid"); @@ -39,7 +39,7 @@ void test_store_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.store(T(2), std::memory_order_acquire); }()), "memory order argument to atomic store operation is invalid"); @@ -47,7 +47,7 @@ void test_store_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.store(T(2), std::memory_order_acq_rel); }()), "memory order argument to atomic store operation is invalid"); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index 5a68cabadb17b..7604132ff694c 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -24,14 +24,14 @@ template void test_wait_invalid_memory_order() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.wait(T(2), std::memory_order_relaxed); } TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.wait(T(2), std::memory_order_release); }()), "memory order argument to atomic wait operation is invalid"); @@ -39,7 +39,7 @@ void test_wait_invalid_memory_order() { TEST_LIBCPP_ASSERT_FAILURE( ([] { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.wait(T(2), std::memory_order_acq_rel); }()), "memory order argument to atomic wait operation is invalid"); diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index 95d29df70fe16..d971dd74e0279 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -18,7 +18,7 @@ template void test_assign() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a = T(2); assert(x == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index 68c64b9ab3458..d32648e1edee6 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -32,7 +32,7 @@ static_assert(!has_bitwise_and_assign>); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert((a &= T(2)) == T(0)); assert(x == T(0)); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index 20ec80697c70e..ffbf9fba7a097 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -32,7 +32,7 @@ static_assert(!has_bitwise_or_assign>); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert((a |= T(2)) == T(3)); assert(x == T(3)); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp index 2d41bf01f9562..a31faa7e58d90 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -32,7 +32,7 @@ static_assert(!has_bitwise_xor_assign>); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert((a ^= T(2)) == T(3)); assert(x == T(3)); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index b9dc84c04f766..7a9628b42e41e 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -20,7 +20,7 @@ template void test_compare_exchange_strong() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(1)); assert(a.compare_exchange_strong(t, T(2)) == true); @@ -34,7 +34,7 @@ void test_compare_exchange_strong() { } { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(1)); assert(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst) == true); @@ -48,7 +48,7 @@ void test_compare_exchange_strong() { } { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(1)); assert(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed) == true); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index 3d16be5e3a149..6eac7967b46db 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -20,7 +20,7 @@ template void test_compare_exchange_weak() { { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(1)); assert(a.compare_exchange_weak(t, T(2)) == true); @@ -34,7 +34,7 @@ void test_compare_exchange_weak() { } { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(1)); assert(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst) == true); @@ -48,7 +48,7 @@ void test_compare_exchange_weak() { } { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T t(T(1)); assert(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed) == true); diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index d4cd38efffbb9..b965607950b0f 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -18,7 +18,7 @@ template void test_convert() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); T converted = a; assert(converted == T(1)); diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index 75055bd8679bc..a4b9edd4620f1 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -18,7 +18,7 @@ template void test_exchange() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.exchange(T(2)) == T(1)); ASSERT_NOEXCEPT(a.exchange(T(2))); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index 84ad4f54a6b5c..e93538273b696 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -34,7 +34,7 @@ static_assert(!has_fetch_add>); template void test_arithmetic() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.fetch_add(T(2)) == T(1)); assert(x == T(3)); @@ -50,7 +50,7 @@ void test_pointer() { using U = std::remove_pointer_t; U t[9] = {}; T p{&t[1]}; - std::atomic_ref a(p); + std::atomic_ref const a(p); assert(a.fetch_add(2) == &t[1]); assert(a == &t[3]); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp index d837bc8f423c9..f83d9a65ad990 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -35,7 +35,7 @@ static_assert(!has_fetch_and>); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.fetch_and(T(2)) == T(1)); assert(x == T(0)); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp index 88a836810b002..ecb4ba3859f29 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -35,7 +35,7 @@ static_assert(!has_fetch_or>); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.fetch_or(T(2)) == T(1)); assert(x == T(3)); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 031f6f78a37c0..21041355f26d2 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -34,7 +34,7 @@ static_assert(!has_fetch_sub>); template void test_arithmetic() { T x(T(7)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.fetch_sub(T(4)) == T(7)); assert(x == T(3)); @@ -50,7 +50,7 @@ void test_pointer() { using U = std::remove_pointer_t; U t[9] = {}; T p{&t[7]}; - std::atomic_ref a(p); + std::atomic_ref const a(p); assert(a.fetch_sub(4) == &t[7]); assert(a == &t[3]); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index 2e2f913e9e242..49856567f8e8a 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -35,7 +35,7 @@ static_assert(!has_fetch_xor>); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.fetch_xor(T(2)) == T(1)); assert(x == T(3)); diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index dd1bcaa6f554f..586b5a17f82ad 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -50,7 +50,7 @@ static_assert(does_not_have_increment_nor_decrement_operators()); template void test_integral() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(++a == T(2)); assert(x == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index ad958b5d9cf35..25dec05f7fff0 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -19,7 +19,7 @@ #include "test_macros.h" template -void check_always_lock_free(std::atomic_ref a) { +void check_always_lock_free(std::atomic_ref const a) { if (std::atomic_ref::is_always_lock_free) { assert(a.is_lock_free()); } diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index fe3aaaf1edcf8..25171fc247c1c 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -18,7 +18,7 @@ template void test_load() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.load() == T(1)); ASSERT_NOEXCEPT(a.load()); diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 3ea9de240a192..7f7575583b6fe 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -21,7 +21,7 @@ template void test_notify_all() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); bool done = false; std::atomic started_num = 0; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index a3ae251ab770c..7139aae338543 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -21,7 +21,7 @@ template void test_notify_one() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); std::thread t = support::make_test_thread([&]() { a.store(T(3)); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index e7e25efb7acd2..583818aeb18b8 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -31,7 +31,7 @@ static_assert(!has_operator_minus_equals>); template void test_arithmetic() { T x(T(3)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert((a -= T(2)) == T(1)); assert(x == T(1)); @@ -43,7 +43,7 @@ void test_pointer() { using U = std::remove_pointer_t; U t[9] = {}; T p{&t[3]}; - std::atomic_ref a(p); + std::atomic_ref const a(p); assert((a -= 2) == &t[1]); assert(a == &t[1]); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index 1aeadffafaef8..196d30654f079 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -31,7 +31,7 @@ static_assert(!has_operator_plus_equals>); template void test_arithmetic() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert((a += T(2)) == T(3)); assert(x == T(3)); @@ -43,7 +43,7 @@ void test_pointer() { using U = std::remove_pointer_t; U t[9] = {}; T p{&t[1]}; - std::atomic_ref a(p); + std::atomic_ref const a(p); assert((a += 2) == &t[3]); assert(a == &t[3]); diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp index 102311bb43b23..0ecafe83f7a24 100644 --- a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -18,7 +18,7 @@ template void test_store() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); a.store(T(2)); assert(x == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index 51d3a79dd59a5..77d6b47146ac3 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -19,7 +19,7 @@ template void test_wait() { T x(T(1)); - std::atomic_ref a(x); + std::atomic_ref const a(x); assert(a.load() == T(1)); a.wait(T(0)); From 6df2fa87e4d3b1430beaf42b86086292a62b78a2 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 18:20:59 -0500 Subject: [PATCH 33/91] [libc++][atomic_ref] Let required_alignement test check both at runtime and compile time --- .../std/atomics/atomics.ref/required_alignment.pass.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp index f51a030b53283..e595f27262aaf 100644 --- a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp @@ -10,13 +10,14 @@ // static constexpr size_t required_alignment; #include +#include template -void check_required_alignment() { - static_assert(std::atomic_ref::required_alignment >= alignof(T)); +constexpr void check_required_alignment() { + assert(std::atomic_ref::required_alignment >= alignof(T)); } -void test() { +constexpr bool test() { check_required_alignment(); check_required_alignment(); check_required_alignment(); @@ -26,9 +27,11 @@ void test() { int a; }; check_required_alignment(); + return true; } int main(int, char**) { test(); + static_assert(test()); return 0; } From 05dad2c0d1deabd79d0816a6fc4a9a5c23114833 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 18:26:58 -0500 Subject: [PATCH 34/91] [libc++][atomic_ref] Add a release note and update the status page --- libcxx/docs/ReleaseNotes/19.rst | 1 + libcxx/docs/Status/Cxx20Papers.csv | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 908d46b711a5a..99e04d8cbf960 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -40,6 +40,7 @@ Implemented Papers - P2637R3 - Member ``visit`` - P2652R2 - Disallow User Specialization of ``allocator_traits`` +- P0019R8 - ``atomic_ref`` Improvements and New Features diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index d73088687975c..e7de3e0eea782 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -26,7 +26,7 @@ "`P0905R1 `__","CWG","Symmetry for spaceship","Jacksonville","","","|spaceship|" "`P0966R1 `__","LWG","``string::reserve``\ Should Not Shrink","Jacksonville","|Complete| [#note-P0966]_","12.0" "","","","","","","" -"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","","" +"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","[In Progress]","" "`P0458R2 `__","LWG","Checking for Existence of an Element in Associative Containers","Rapperswil","|Complete|","13.0" "`P0475R1 `__","LWG","LWG 2511: guaranteed copy elision for piecewise construction","Rapperswil","|Complete|","" "`P0476R2 `__","LWG","Bit-casting object representations","Rapperswil","|Complete|","14.0" From 991ccb67f5293ca20397ac41a6269e6867eae132 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 18:51:02 -0500 Subject: [PATCH 35/91] [libc++][atomic_ref] Update generated files --- libcxx/include/libcxx.imp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp index 69de4705f3788..76f785bd06c7d 100644 --- a/libcxx/include/libcxx.imp +++ b/libcxx/include/libcxx.imp @@ -235,6 +235,7 @@ { include: [ "<__atomic/atomic_flag.h>", "private", "", "public" ] }, { include: [ "<__atomic/atomic_init.h>", "private", "", "public" ] }, { include: [ "<__atomic/atomic_lock_free.h>", "private", "", "public" ] }, + { include: [ "<__atomic/atomic_ref.h>", "private", "", "public" ] }, { include: [ "<__atomic/atomic_sync.h>", "private", "", "public" ] }, { include: [ "<__atomic/check_memory_order.h>", "private", "", "public" ] }, { include: [ "<__atomic/contention_t.h>", "private", "", "public" ] }, @@ -243,6 +244,7 @@ { include: [ "<__atomic/is_always_lock_free.h>", "private", "", "public" ] }, { include: [ "<__atomic/kill_dependency.h>", "private", "", "public" ] }, { include: [ "<__atomic/memory_order.h>", "private", "", "public" ] }, + { include: [ "<__atomic/to_gcc_order.h>", "private", "", "public" ] }, { include: [ "<__bit/bit_cast.h>", "private", "", "public" ] }, { include: [ "<__bit/bit_ceil.h>", "private", "", "public" ] }, { include: [ "<__bit/bit_floor.h>", "private", "", "public" ] }, From bd870b0fd6ff061b1d3b254c264cd96858b57225 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 19:11:29 -0500 Subject: [PATCH 36/91] [libc++][atomic_ref] Fix clang-tidy warnings modernize-use-nullptr --- libcxx/include/__atomic/atomic_ref.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 4ba8bdcccf1cc..d8aaac92b303d 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -48,9 +48,9 @@ struct __atomic_ref_base { static constexpr size_t required_alignment = alignof(_Tp); - static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_Tp), 0); + static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_Tp), nullptr); - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), 0); } + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); } _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { From c10501cd405f168f6c5223894d377f572467660f Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 5 Feb 2024 22:39:26 -0500 Subject: [PATCH 37/91] [libc++][atomic_ref] Use std::same_as trick --- .../atomics.ref/bitwise_and_assign.pass.cpp | 4 +- .../atomics.ref/bitwise_or_assign.pass.cpp | 4 +- .../atomics.ref/bitwise_xor_assign.pass.cpp | 4 +- .../compare_exchange_strong.pass.cpp | 20 ++++++--- .../compare_exchange_weak.pass.cpp | 19 +++++--- .../std/atomics/atomics.ref/exchange.pass.cpp | 17 +++++--- .../atomics/atomics.ref/fetch_add.pass.cpp | 37 ++++++++++------ .../atomics/atomics.ref/fetch_and.pass.cpp | 19 +++++--- .../std/atomics/atomics.ref/fetch_or.pass.cpp | 21 ++++++--- .../atomics/atomics.ref/fetch_sub.pass.cpp | 37 ++++++++++------ .../atomics/atomics.ref/fetch_xor.pass.cpp | 21 ++++++--- .../atomics.ref/increment_decrement.pass.cpp | 43 ++++++++++++------- .../atomics.ref/is_always_lock_free.pass.cpp | 4 +- .../std/atomics/atomics.ref/load.pass.cpp | 17 +++++--- .../operator_minus_equals.pass.cpp | 7 ++- .../atomics.ref/operator_plus_equals.pass.cpp | 7 ++- 16 files changed, 192 insertions(+), 89 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index d32648e1edee6..396448cb4bc3f 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "test_macros.h" @@ -34,7 +35,8 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert((a &= T(2)) == T(0)); + std::same_as auto y = (a &= T(2)); + assert(y == T(0)); assert(x == T(0)); ASSERT_NOEXCEPT(a &= T(0)); } diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index ffbf9fba7a097..425a7538c3d54 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "test_macros.h" @@ -34,7 +35,8 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert((a |= T(2)) == T(3)); + std::same_as auto y = (a |= T(2)); + assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a &= T(0)); } diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp index a31faa7e58d90..6eaea88fdce67 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "test_macros.h" @@ -34,7 +35,8 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert((a ^= T(2)) == T(3)); + std::same_as auto y = (a ^= T(2)); + assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a ^= T(0)); } diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 7a9628b42e41e..8ea62925eda43 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include "test_macros.h" @@ -23,10 +24,12 @@ void test_compare_exchange_strong() { std::atomic_ref const a(x); T t(T(1)); - assert(a.compare_exchange_strong(t, T(2)) == true); + std::same_as auto y = a.compare_exchange_strong(t, T(2)); + assert(y == true); assert(a == T(2)); assert(t == T(1)); - assert(a.compare_exchange_strong(t, T(3)) == false); + y = a.compare_exchange_strong(t, T(3)); + assert(y == false); assert(a == T(2)); assert(t == T(2)); @@ -37,10 +40,12 @@ void test_compare_exchange_strong() { std::atomic_ref const a(x); T t(T(1)); - assert(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst) == true); + std::same_as auto y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst); + assert(y == true); assert(a == T(2)); assert(t == T(1)); - assert(a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst) == false); + y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst); + assert(y == false); assert(a == T(2)); assert(t == T(2)); @@ -51,10 +56,13 @@ void test_compare_exchange_strong() { std::atomic_ref const a(x); T t(T(1)); - assert(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed) == true); + std::same_as auto y = + a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed); + assert(y == true); assert(a == T(2)); assert(t == T(1)); - assert(a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed) == false); + y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed); + assert(y == false); assert(a == T(2)); assert(t == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index 6eac7967b46db..cd5455315b9fa 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -11,6 +11,7 @@ // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept; #include +#include #include #include @@ -23,10 +24,12 @@ void test_compare_exchange_weak() { std::atomic_ref const a(x); T t(T(1)); - assert(a.compare_exchange_weak(t, T(2)) == true); + std::same_as auto y = a.compare_exchange_weak(t, T(2)); + assert(y == true); assert(a == T(2)); assert(t == T(1)); - assert(a.compare_exchange_weak(t, T(3)) == false); + y = a.compare_exchange_weak(t, T(3)); + assert(y == false); assert(a == T(2)); assert(t == T(2)); @@ -37,10 +40,12 @@ void test_compare_exchange_weak() { std::atomic_ref const a(x); T t(T(1)); - assert(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst) == true); + std::same_as auto y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst); + assert(y == true); assert(a == T(2)); assert(t == T(1)); - assert(a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst) == false); + y = a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst); + assert(y == false); assert(a == T(2)); assert(t == T(2)); @@ -51,10 +56,12 @@ void test_compare_exchange_weak() { std::atomic_ref const a(x); T t(T(1)); - assert(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed) == true); + std::same_as auto y = a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed); + assert(y == true); assert(a == T(2)); assert(t == T(1)); - assert(a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed) == false); + y = a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed); + assert(y == false); assert(a == T(2)); assert(t == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index a4b9edd4620f1..f1e41ef8051a1 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "test_macros.h" @@ -20,11 +21,17 @@ void test_exchange() { T x(T(1)); std::atomic_ref const a(x); - assert(a.exchange(T(2)) == T(1)); - ASSERT_NOEXCEPT(a.exchange(T(2))); - - assert(a.exchange(T(3), std::memory_order_seq_cst) == T(2)); - ASSERT_NOEXCEPT(a.exchange(T(3), std::memory_order_seq_cst)); + { + std::same_as auto y = a.exchange(T(2)); + assert(y == T(1)); + ASSERT_NOEXCEPT(a.exchange(T(2))); + } + + { + std::same_as auto y = a.exchange(T(3), std::memory_order_seq_cst); + assert(y == T(2)); + ASSERT_NOEXCEPT(a.exchange(T(3), std::memory_order_seq_cst)); + } } void test() { diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index e93538273b696..11e0f30d3b822 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "test_macros.h" @@ -36,13 +37,19 @@ void test_arithmetic() { T x(T(1)); std::atomic_ref const a(x); - assert(a.fetch_add(T(2)) == T(1)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_add(T(0))); + { + std::same_as auto y = a.fetch_add(T(2)); + assert(y == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_add(T(0))); + } - assert(a.fetch_add(T(4), std::memory_order_relaxed) == T(3)); - assert(x == T(7)); - ASSERT_NOEXCEPT(a.fetch_add(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_add(T(4), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(7)); + ASSERT_NOEXCEPT(a.fetch_add(T(0), std::memory_order_relaxed)); + } } template @@ -52,13 +59,19 @@ void test_pointer() { T p{&t[1]}; std::atomic_ref const a(p); - assert(a.fetch_add(2) == &t[1]); - assert(a == &t[3]); - ASSERT_NOEXCEPT(a.fetch_add(0)); + { + std::same_as auto y = a.fetch_add(2); + assert(y == &t[1]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a.fetch_add(0)); + } - assert(a.fetch_add(4, std::memory_order_relaxed) == &t[3]); - assert(a == &t[7]); - ASSERT_NOEXCEPT(a.fetch_add(0, std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_add(4, std::memory_order_relaxed); + assert(y == &t[3]); + assert(a == &t[7]); + ASSERT_NOEXCEPT(a.fetch_add(0, std::memory_order_relaxed)); + } } void test() { diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp index f83d9a65ad990..b0eef527a58ee 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "test_macros.h" @@ -37,15 +38,21 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert(a.fetch_and(T(2)) == T(1)); - assert(x == T(0)); - ASSERT_NOEXCEPT(a.fetch_and(T(0))); + { + std::same_as auto y = a.fetch_and(T(2)); + assert(y == T(1)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a.fetch_and(T(0))); + } x = T(1); - assert(a.fetch_and(T(2), std::memory_order_relaxed) == T(1)); - assert(x == T(0)); - ASSERT_NOEXCEPT(a.fetch_and(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_and(T(2), std::memory_order_relaxed); + assert(y == T(1)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a.fetch_and(T(0), std::memory_order_relaxed)); + } } void test() { test_integral(); } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp index ecb4ba3859f29..53112b32e662f 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -10,6 +10,7 @@ // integral-type fetch_or(integral-type, memory_order = memory_order::seq_cst) const noexcept; #include +#include #include #include @@ -37,13 +38,19 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert(a.fetch_or(T(2)) == T(1)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_or(T(0))); - - assert(a.fetch_or(T(2), std::memory_order_relaxed) == T(3)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_or(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_or(T(2)); + assert(y == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_or(T(0))); + } + + { + std::same_as auto y = a.fetch_or(T(2), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_or(T(0), std::memory_order_relaxed)); + } } void test() { test_integral(); } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 21041355f26d2..96625020563d3 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "test_macros.h" @@ -36,13 +37,19 @@ void test_arithmetic() { T x(T(7)); std::atomic_ref const a(x); - assert(a.fetch_sub(T(4)) == T(7)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_sub(T(0))); + { + std::same_as auto y = a.fetch_sub(T(4)); + assert(y == T(7)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_sub(T(0))); + } - assert(a.fetch_sub(T(2), std::memory_order_relaxed) == T(3)); - assert(x == T(1)); - ASSERT_NOEXCEPT(a.fetch_sub(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_sub(T(2), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a.fetch_sub(T(0), std::memory_order_relaxed)); + } } template @@ -52,13 +59,19 @@ void test_pointer() { T p{&t[7]}; std::atomic_ref const a(p); - assert(a.fetch_sub(4) == &t[7]); - assert(a == &t[3]); - ASSERT_NOEXCEPT(a.fetch_sub(0)); + { + std::same_as auto y = a.fetch_sub(4); + assert(y == &t[7]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a.fetch_sub(0)); + } - assert(a.fetch_sub(2, std::memory_order_relaxed) == &t[3]); - assert(a == &t[1]); - ASSERT_NOEXCEPT(a.fetch_sub(0, std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_sub(2, std::memory_order_relaxed); + assert(y == &t[3]); + assert(a == &t[1]); + ASSERT_NOEXCEPT(a.fetch_sub(0, std::memory_order_relaxed)); + } } void test() { diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index 49856567f8e8a..cfeb544905603 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -10,6 +10,7 @@ // integral-type fetch_xor(integral-type, memory_order = memory_order::seq_cst) const noexcept; #include +#include #include #include @@ -37,13 +38,19 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert(a.fetch_xor(T(2)) == T(1)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_xor(T(0))); - - assert(a.fetch_xor(T(2), std::memory_order_relaxed) == T(3)); - assert(x == T(1)); - ASSERT_NOEXCEPT(a.fetch_xor(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_xor(T(2)); + assert(y == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_xor(T(0))); + } + + { + std::same_as auto y = a.fetch_xor(T(2), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a.fetch_xor(T(0), std::memory_order_relaxed)); + } } void test() { test_integral(); } diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index 586b5a17f82ad..1bad4a73a83ab 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include "test_macros.h" @@ -52,21 +53,33 @@ void test_integral() { T x(T(1)); std::atomic_ref const a(x); - assert(++a == T(2)); - assert(x == T(2)); - ASSERT_NOEXCEPT(++a); - - assert(--a == T(1)); - assert(x == T(1)); - ASSERT_NOEXCEPT(--a); - - assert(a++ == T(1)); - assert(x == T(2)); - ASSERT_NOEXCEPT(++a); - - assert(a-- == T(2)); - assert(x == T(1)); - ASSERT_NOEXCEPT(--a); + { + std::same_as auto y = ++a; + assert(y == T(2)); + assert(x == T(2)); + ASSERT_NOEXCEPT(++a); + } + + { + std::same_as auto y = --a; + assert(y == T(1)); + assert(x == T(1)); + ASSERT_NOEXCEPT(--a); + } + + { + std::same_as auto y = a++; + assert(y == T(1)); + assert(x == T(2)); + ASSERT_NOEXCEPT(a++); + } + + { + std::same_as auto y = a--; + assert(y == T(2)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a--); + } } void test() { test_integral(); } diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index 25dec05f7fff0..89da904e8fd46 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -15,13 +15,15 @@ #include #include +#include #include "test_macros.h" template void check_always_lock_free(std::atomic_ref const a) { if (std::atomic_ref::is_always_lock_free) { - assert(a.is_lock_free()); + std::same_as auto is_lock_free = a.is_lock_free(); + assert(is_lock_free); } ASSERT_NOEXCEPT(a.is_lock_free()); } diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index 25171fc247c1c..e83b9cf88f41d 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -10,6 +10,7 @@ // T load(memory_order = memory_order::seq_cst) const noexcept; #include +#include #include #include @@ -20,11 +21,17 @@ void test_load() { T x(T(1)); std::atomic_ref const a(x); - assert(a.load() == T(1)); - ASSERT_NOEXCEPT(a.load()); - - assert(a.load(std::memory_order_seq_cst) == T(1)); - ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); + { + std::same_as auto y = a.load(); + assert(y == T(1)); + ASSERT_NOEXCEPT(a.load()); + } + + { + std::same_as auto y = a.load(std::memory_order_seq_cst); + assert(y == T(1)); + ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); + } } void test() { diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index 583818aeb18b8..4265c0b6a5fb4 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "test_macros.h" @@ -33,7 +34,8 @@ void test_arithmetic() { T x(T(3)); std::atomic_ref const a(x); - assert((a -= T(2)) == T(1)); + std::same_as auto y = (a -= T(2)); + assert(y == T(1)); assert(x == T(1)); ASSERT_NOEXCEPT(a -= T(0)); } @@ -45,7 +47,8 @@ void test_pointer() { T p{&t[3]}; std::atomic_ref const a(p); - assert((a -= 2) == &t[1]); + std::same_as auto y = (a -= 2); + assert(y == &t[1]); assert(a == &t[1]); ASSERT_NOEXCEPT(a -= 0); } diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index 196d30654f079..a82ebae84481f 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -12,6 +12,7 @@ // T* operator+=(difference_type) const noexcept; #include +#include #include #include @@ -33,7 +34,8 @@ void test_arithmetic() { T x(T(1)); std::atomic_ref const a(x); - assert((a += T(2)) == T(3)); + std::same_as auto y = (a += T(2)); + assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a += T(0)); } @@ -45,7 +47,8 @@ void test_pointer() { T p{&t[1]}; std::atomic_ref const a(p); - assert((a += 2) == &t[3]); + std::same_as auto y = (a += 2); + assert(y == &t[3]); assert(a == &t[3]); ASSERT_NOEXCEPT(a += 0); } From 6d310d82b54061c29acb9b9cbff5e0db670bd01a Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 6 Feb 2024 08:24:35 -0500 Subject: [PATCH 38/91] [libc++][atomic_ref] Forgot to update assertion msg in tests --- .../atomics.ref/assert.compare_exchange_strong.pass.cpp | 4 ++-- .../atomics.ref/assert.compare_exchange_weak.pass.cpp | 4 ++-- libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 4 ++-- .../test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 6 +++--- libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index aeab9f5ff3fb7..5ccf2333c814f 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -36,7 +36,7 @@ void test_compare_exchange_strong_invalid_memory_order() { T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_release); }()), - "memory order argument to strong atomic compare-and-exchange operation is invalid"); + "atomic_ref: memory order argument to strong atomic compare-and-exchange operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -45,7 +45,7 @@ void test_compare_exchange_strong_invalid_memory_order() { T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); }()), - "memory order argument to strong atomic compare-and-exchange operation is invalid"); + "atomic_ref: memory order argument to strong atomic compare-and-exchange operation is invalid"); } int main(int, char**) { diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index 407146722f17c..017d15f8c673a 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -36,7 +36,7 @@ void test_compare_exchange_weak_invalid_memory_order() { T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_release); }()), - "memory order argument to weak atomic compare-and-exchange operation is invalid"); + "atomic_ref: memory order argument to weak atomic compare-and-exchange operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -45,7 +45,7 @@ void test_compare_exchange_weak_invalid_memory_order() { T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); }()), - "memory order argument to weak atomic compare-and-exchange operation is invalid"); + "atomic_ref: memory order argument to weak atomic compare-and-exchange operation is invalid"); } int main(int, char**) { diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 34e7a2b56f0f0..6bd5b603caf79 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -34,7 +34,7 @@ void test_load_invalid_memory_order() { std::atomic_ref const a(x); (void)a.load(std::memory_order_release); }()), - "memory order argument to atomic load operation is invalid"); + "atomic_ref: memory order argument to atomic load operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -42,7 +42,7 @@ void test_load_invalid_memory_order() { std::atomic_ref const a(x); (void)a.load(std::memory_order_acq_rel); }()), - "memory order argument to atomic load operation is invalid"); + "atomic_ref: memory order argument to atomic load operation is invalid"); } int main(int, char**) { diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index 12e21ea38b94a..d3290ad3afac9 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -34,7 +34,7 @@ void test_store_invalid_memory_order() { std::atomic_ref const a(x); a.store(T(2), std::memory_order_consume); }()), - "memory order argument to atomic store operation is invalid"); + "atomic_ref: memory order argument to atomic store operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -42,7 +42,7 @@ void test_store_invalid_memory_order() { std::atomic_ref const a(x); a.store(T(2), std::memory_order_acquire); }()), - "memory order argument to atomic store operation is invalid"); + "atomic_ref: memory order argument to atomic store operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -50,7 +50,7 @@ void test_store_invalid_memory_order() { std::atomic_ref const a(x); a.store(T(2), std::memory_order_acq_rel); }()), - "memory order argument to atomic store operation is invalid"); + "atomic_ref: memory order argument to atomic store operation is invalid"); } int main(int, char**) { diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index 7604132ff694c..4656e3e7e333b 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -34,7 +34,7 @@ void test_wait_invalid_memory_order() { std::atomic_ref const a(x); a.wait(T(2), std::memory_order_release); }()), - "memory order argument to atomic wait operation is invalid"); + "atomic_ref: memory order argument to atomic wait operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -42,7 +42,7 @@ void test_wait_invalid_memory_order() { std::atomic_ref const a(x); a.wait(T(2), std::memory_order_acq_rel); }()), - "memory order argument to atomic wait operation is invalid"); + "atomic_ref: memory order argument to atomic wait operation is invalid"); } int main(int, char**) { From 7d8a1c85385ecab368e0e52ca1fab11d5720c3c6 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 6 Feb 2024 09:38:27 -0500 Subject: [PATCH 39/91] [libc++][atomic_ref] Fix test compare_exchange_{strong,weak} assertion msg --- .../atomics.ref/assert.compare_exchange_strong.pass.cpp | 4 ++-- .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 5ccf2333c814f..bb9796d2d5c36 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -36,7 +36,7 @@ void test_compare_exchange_strong_invalid_memory_order() { T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_release); }()), - "atomic_ref: memory order argument to strong atomic compare-and-exchange operation is invalid"); + "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -45,7 +45,7 @@ void test_compare_exchange_strong_invalid_memory_order() { T t(T(2)); a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); }()), - "atomic_ref: memory order argument to strong atomic compare-and-exchange operation is invalid"); + "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); } int main(int, char**) { diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index 017d15f8c673a..b5b6f27bfad6c 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -36,7 +36,7 @@ void test_compare_exchange_weak_invalid_memory_order() { T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_release); }()), - "atomic_ref: memory order argument to weak atomic compare-and-exchange operation is invalid"); + "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); TEST_LIBCPP_ASSERT_FAILURE( ([] { @@ -45,7 +45,7 @@ void test_compare_exchange_weak_invalid_memory_order() { T t(T(2)); a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); }()), - "atomic_ref: memory order argument to weak atomic compare-and-exchange operation is invalid"); + "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); } int main(int, char**) { From 89424db3793f88edac857c79737c823010091858 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 6 Feb 2024 15:48:04 -0500 Subject: [PATCH 40/91] [libc++][atomic_ref] Forgot to use addressof in __atomic_ref_base constructor --- libcxx/include/__atomic/atomic_ref.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index d8aaac92b303d..880118648061b 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -44,6 +44,8 @@ template struct __atomic_ref_base { _Tp* __ptr_; + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {} + using value_type = _Tp; static constexpr size_t required_alignment = alignof(_Tp); @@ -147,8 +149,6 @@ struct __atomic_ref_base { } _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__cxx_atomic_notify_one(__ptr_); } _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__cxx_atomic_notify_all(__ptr_); } - - _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(&__obj) {} }; template From 956f4b3ae3d176ce88594993b68e3f89bc4e71ce Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 6 Feb 2024 22:46:41 -0500 Subject: [PATCH 41/91] [libc++][atomic_ref] Prepare the code for clearing padding bits --- libcxx/include/__atomic/atomic_ref.h | 56 +++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 880118648061b..126fa60e1816b 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -25,6 +25,7 @@ #include <__concepts/same_as.h> #include <__config> #include <__memory/addressof.h> +#include <__type_traits/has_unique_object_representation.h> #include <__type_traits/is_trivially_copyable.h> #include #include @@ -44,6 +45,24 @@ template struct __atomic_ref_base { _Tp* __ptr_; + // whether the object pointed to has padding AND we will actually ignore them + static constexpr bool __might_have_padding = +# if __has_builtin(__builtin_clear_padding) + !has_unique_object_representations_v<_Tp> && !same_as<_Tp, float> && !same_as<_Tp, double>; +# else + false; +# endif + + _LIBCPP_HIDE_FROM_ABI static _Tp* __clear_padding(_Tp& __val) noexcept { + _Tp* __ptr = std::addressof(__val); +# if __has_builtin(__builtin_clear_padding) + if constexpr (__might_have_padding) { + __builtin_clear_padding(__ptr); + } +# endif + return __ptr; + } + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {} using value_type = _Tp; @@ -59,7 +78,7 @@ struct __atomic_ref_base { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, "atomic_ref: memory order argument to atomic store operation is invalid"); - __atomic_store(__ptr_, std::addressof(__desired), std::__to_gcc_order(__order)); + __atomic_store(__ptr_, __clear_padding(__desired), std::__to_gcc_order(__order)); } _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { @@ -84,9 +103,34 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); - __atomic_exchange(__ptr_, std::addressof(__desired), __ret, std::__to_gcc_order(__order)); + __atomic_exchange(__ptr_, __clear_padding(__desired), __ret, std::__to_gcc_order(__order)); return *__ret; } + + _LIBCPP_HIDE_FROM_ABI static bool __compare_exchange( + _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { + if constexpr (!__might_have_padding) { + return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure); + } else { // _Tp has padding bits and __builtin_clear_padding is available + __clear_padding(*__desired); + _Tp __copy = *__expected; + __clear_padding(__copy); + while (true) { + _Tp __prev = __copy; + if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) { + return true; + } + _Tp __curr = __copy; + if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(_Tp)) != 0) { + // Value representation without padding bits do not compare equal -> + // write the current content of *ptr into *expected + std::memcpy(__expected, std::addressof(__copy), sizeof(_Tp)); + return false; + } + } + } + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { @@ -94,7 +138,7 @@ struct __atomic_ref_base { __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); - return __atomic_compare_exchange( + return __compare_exchange( __ptr_, std::addressof(__expected), std::addressof(__desired), @@ -109,7 +153,7 @@ struct __atomic_ref_base { __failure == memory_order::relaxed || __failure == memory_order::consume || __failure == memory_order::acquire || __failure == memory_order::seq_cst, "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); - return __atomic_compare_exchange( + return __compare_exchange( __ptr_, std::addressof(__expected), std::addressof(__desired), @@ -120,7 +164,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { - return __atomic_compare_exchange( + return __compare_exchange( __ptr_, std::addressof(__expected), std::addressof(__desired), @@ -130,7 +174,7 @@ struct __atomic_ref_base { } _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { - return __atomic_compare_exchange( + return __compare_exchange( __ptr_, std::addressof(__expected), std::addressof(__desired), From 6d5c9de025876f2f8c2a11877a682be5e5eb0405 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 7 Feb 2024 09:04:54 -0500 Subject: [PATCH 42/91] [libc++][atomic_ref] Include missing header for memcmp and memcpy --- libcxx/include/__atomic/atomic_ref.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 126fa60e1816b..425acdfdb7cd3 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -29,6 +29,7 @@ #include <__type_traits/is_trivially_copyable.h> #include #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header From 8ad10b6b0af000972e0656795e18735d84cb4fb7 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 7 Feb 2024 08:25:00 -0500 Subject: [PATCH 43/91] [libc++][atomic_ref] Avoid sneaky casting `T x(T(1))`` --- .../std/atomics/atomics.ref/convert.pass.cpp | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index b965607950b0f..1ac1d1ea3b28d 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -16,30 +16,33 @@ #include "test_macros.h" template -void test_convert() { - T x(T(1)); - std::atomic_ref const a(x); +void test_convert(T const& x) { + T copy = x; + std::atomic_ref const a(copy); T converted = a; - assert(converted == T(1)); + assert(converted == x); ASSERT_NOEXCEPT(T(a)); static_assert(std::is_nothrow_convertible_v, T>); } void test() { - test_convert(); + int i = 1; + test_convert(i); - test_convert(); + float f = 1; + test_convert(f); - test_convert(); + int* p = &i; + test_convert(p); struct X { int i; X(int ii) noexcept : i(ii) {} bool operator==(X o) const { return i == o.i; } - }; - test_convert(); + } x{1}; + test_convert(x); } int main(int, char**) { From ee7cb8080bded33f7d4aeae0de54379a43dafd13 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 7 Feb 2024 08:56:31 -0500 Subject: [PATCH 44/91] [libc++][atomic_ref] Check more types for is_always_lock_free --- .../atomics.ref/is_always_lock_free.pass.cpp | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index 89da904e8fd46..ef035a558b39f 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -28,6 +28,13 @@ void check_always_lock_free(std::atomic_ref const a) { ASSERT_NOEXCEPT(a.is_lock_free()); } +#define CHECK_ALWAYS_LOCK_FREE(T) \ + do { \ + typedef T type; \ + type obj{}; \ + check_always_lock_free(std::atomic_ref(obj)); \ + } while (0) + void test() { int i = 0; check_always_lock_free(std::atomic_ref(i)); @@ -38,9 +45,23 @@ void test() { int* p = &i; check_always_lock_free(std::atomic_ref(p)); - struct X { - } x; - check_always_lock_free(std::atomic_ref(x)); + CHECK_ALWAYS_LOCK_FREE(struct Empty{}); + CHECK_ALWAYS_LOCK_FREE(struct OneInt { int i; }); + CHECK_ALWAYS_LOCK_FREE(struct IntArr2 { int i[2]; }); + CHECK_ALWAYS_LOCK_FREE(struct FloatArr3 { float i[3]; }); + CHECK_ALWAYS_LOCK_FREE(struct LLIArr2 { long long int i[2]; }); + CHECK_ALWAYS_LOCK_FREE(struct LLIArr4 { long long int i[4]; }); + CHECK_ALWAYS_LOCK_FREE(struct LLIArr8 { long long int i[8]; }); + CHECK_ALWAYS_LOCK_FREE(struct LLIArr16 { long long int i[16]; }); + CHECK_ALWAYS_LOCK_FREE(struct Padding { + char c; /* padding */ + long long int i; + }); + CHECK_ALWAYS_LOCK_FREE(union IntFloat { + int i; + float f; + }); + CHECK_ALWAYS_LOCK_FREE(enum class CharEnumClass : char{foo}); } int main(int, char**) { From 6ef3362b1ba7b1a0bb49e674a7e060708c121940 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 7 Feb 2024 09:00:04 -0500 Subject: [PATCH 45/91] [libc++][atomic_ref] Use fake minimally aligned pointer in is_lock_free() --- libcxx/include/__atomic/atomic_ref.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 425acdfdb7cd3..bf5a45d4eb8d7 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -70,9 +70,12 @@ struct __atomic_ref_base { static constexpr size_t required_alignment = alignof(_Tp); - static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_Tp), nullptr); + static constexpr bool is_always_lock_free = + __atomic_always_lock_free(sizeof(_Tp), reinterpret_cast(-required_alignment)); - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); } + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { + return __atomic_is_lock_free(sizeof(_Tp), reinterpret_cast(-required_alignment)); + } _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { From ed91c8cbf4d87edbe5ba484217d66581c10c9691 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 9 Feb 2024 13:08:33 -0500 Subject: [PATCH 46/91] [libc++][atomic_ref] Fixup unsupported hardening mode fast --- .../atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp | 2 +- .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index bb9796d2d5c36..2b6ac0518e9ae 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index b5b6f27bfad6c..bc3ab73c7370b 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index a19f6516ff3e4..c20fbbbf91b25 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 6bd5b603caf79..1f35dd1f3a651 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index d3290ad3afac9..8e098dcbe2923 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index 4656e3e7e333b..c6f5a2861dcf0 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-hardening-mode=none +// UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -Wno-user-defined-warnings From dee15ac036b402a1158b825ab71dba125f753d52 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 4 Mar 2024 07:37:16 -0500 Subject: [PATCH 47/91] [libc++][atomic_ref] revert hack to be able to use atomic wait implementation --- libcxx/include/__atomic/atomic_ref.h | 20 ++++++++------------ libcxx/include/__atomic/atomic_sync.h | 17 ----------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index bf5a45d4eb8d7..2776b22b1c233 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -46,20 +46,10 @@ template struct __atomic_ref_base { _Tp* __ptr_; - // whether the object pointed to has padding AND we will actually ignore them - static constexpr bool __might_have_padding = -# if __has_builtin(__builtin_clear_padding) - !has_unique_object_representations_v<_Tp> && !same_as<_Tp, float> && !same_as<_Tp, double>; -# else - false; -# endif - _LIBCPP_HIDE_FROM_ABI static _Tp* __clear_padding(_Tp& __val) noexcept { _Tp* __ptr = std::addressof(__val); # if __has_builtin(__builtin_clear_padding) - if constexpr (__might_have_padding) { - __builtin_clear_padding(__ptr); - } + __builtin_clear_padding(__ptr); # endif return __ptr; } @@ -113,7 +103,13 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI static bool __compare_exchange( _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { - if constexpr (!__might_have_padding) { + if constexpr ( +# if __has_builtin(__builtin_clear_padding) + has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double>; +# else + true +# endif + ) { return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure); } else { // _Tp has padding bits and __builtin_clear_padding is available __clear_padding(*__desired); diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h index 4a2d0fc21810e..95fc76219d24d 100644 --- a/libcxx/include/__atomic/atomic_sync.h +++ b/libcxx/include/__atomic/atomic_sync.h @@ -20,8 +20,6 @@ #include <__thread/poll_with_backoff.h> #include <__thread/support.h> #include <__type_traits/decay.h> -#include <__type_traits/enable_if.h> -#include <__type_traits/remove_cv.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -30,21 +28,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template -struct __is_cxx_atomic_impl : false_type {}; - -template -struct __is_cxx_atomic_impl<__cxx_atomic_impl<_Tp> > : true_type {}; - -template -_LIBCPP_HIDE_FROM_ABI __enable_if_t >::value, _Tp> -__cxx_atomic_load(_Tp* __ptr, memory_order __order) _NOEXCEPT { - _ALIGNAS_TYPE(_Tp) unsigned char __mem[sizeof(_Tp)]; - auto* __ret = reinterpret_cast<_Tp*>(__mem); - __atomic_load(__ptr, __ret, __to_gcc_order(__order)); - return *__ret; -} - #ifndef _LIBCPP_HAS_NO_THREADS _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*); From 5c0c3c9ceca3e5f96462e965477432482870bf0b Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 4 Mar 2024 07:54:21 -0500 Subject: [PATCH 48/91] [libc++][atomic_ref] Use __atomic_wait following Hui's refactor --- libcxx/include/__atomic/atomic_ref.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 2776b22b1c233..d96ce1a7fd868 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -189,10 +189,20 @@ struct __atomic_ref_base { __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "atomic_ref: memory order argument to atomic wait operation is invalid"); - std::__cxx_atomic_wait(__ptr_, __old, __order); + std::__atomic_wait(*this, __old, __order); + } + _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__atomic_notify_one(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__atomic_notify_all(*this); } +}; + +template +struct __atomic_waitable_traits<__atomic_ref_base<_Tp>> { + static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_ref_base<_Tp>& __a, memory_order __order) { + return __a.load(__order); + } + static _LIBCPP_HIDE_FROM_ABI const _Tp* __atomic_contention_address(const __atomic_ref_base<_Tp>& __a) { + return __a.__ptr_; } - _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__cxx_atomic_notify_one(__ptr_); } - _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__cxx_atomic_notify_all(__ptr_); } }; template From 54220e59ea3b83345bd3c101022ff95623036a67 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 5 Mar 2024 21:53:12 -0500 Subject: [PATCH 49/91] [libc++][atomic_ref] Suppress clang-tidy diagnostic when __builtin_clear_padding is not available --- libcxx/include/__atomic/atomic_ref.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index d96ce1a7fd868..43247472ad5f5 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -107,7 +107,7 @@ struct __atomic_ref_base { # if __has_builtin(__builtin_clear_padding) has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double>; # else - true + true // NOLINT(readability-simplify-boolean-expr) # endif ) { return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure); From c185cfdfc586f2d1ddb0da81f8c03fdf43095230 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 5 Mar 2024 23:50:38 -0500 Subject: [PATCH 50/91] [libc++][atomic_ref] Remove stray semicolon --- libcxx/include/__atomic/atomic_ref.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 43247472ad5f5..595d3495cf1c8 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -105,7 +105,7 @@ struct __atomic_ref_base { _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { if constexpr ( # if __has_builtin(__builtin_clear_padding) - has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double>; + has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double> # else true // NOLINT(readability-simplify-boolean-expr) # endif From 55ee31acd2a354b2f0b93c88866643a6efc1d556 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 6 Mar 2024 12:11:10 -0500 Subject: [PATCH 51/91] [libc++][atomic_ref] Mark P0019 as "Complete" --- libcxx/docs/Status/Cxx20Papers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index c5fee3bc5d59c..7660a2f92cd24 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -26,7 +26,7 @@ "`P0905R1 `__","CWG","Symmetry for spaceship","Jacksonville","","","|spaceship|" "`P0966R1 `__","LWG","``string::reserve``\ Should Not Shrink","Jacksonville","|Complete| [#note-P0966]_","12.0" "","","","","","","" -"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","[In Progress]","" +"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","[Complete]","" "`P0458R2 `__","LWG","Checking for Existence of an Element in Associative Containers","Rapperswil","|Complete|","13.0" "`P0475R1 `__","LWG","LWG 2511: guaranteed copy elision for piecewise construction","Rapperswil","|Complete|","" "`P0476R2 `__","LWG","Bit-casting object representations","Rapperswil","|Complete|","14.0" From bc5a5dfbc9def0eb42a315c268eb81c019941b63 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 6 Mar 2024 12:12:05 -0500 Subject: [PATCH 52/91] [libc++][atomic_ref] Per review put typedefs together --- libcxx/include/__atomic/atomic_ref.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 595d3495cf1c8..9abc4af418d8c 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -228,6 +228,8 @@ template struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { using __base = __atomic_ref_base<_Tp>; + using difference_type = __base::value_type; + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, "atomic_ref ctor: referenced object must be aligned to required_alignment"); @@ -239,8 +241,6 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { atomic_ref& operator=(const atomic_ref&) = delete; - using difference_type = __base::value_type; - _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { return __atomic_fetch_add(this->__ptr_, __arg, std::__to_gcc_order(__order)); } @@ -273,6 +273,8 @@ template struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { using __base = __atomic_ref_base<_Tp>; + using difference_type = __base::value_type; + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, "atomic_ref ctor: referenced object must be aligned to required_alignment"); @@ -284,8 +286,6 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { atomic_ref& operator=(const atomic_ref&) = delete; - using difference_type = __base::value_type; - _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { _Tp __old = this->load(memory_order_relaxed); _Tp __new = __old + __arg; @@ -311,14 +311,14 @@ template struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { using __base = __atomic_ref_base<_Tp*>; + using difference_type = ptrdiff_t; + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp*& __ptr) : __base(__ptr) {} _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __desired) const noexcept { return __base::operator=(__desired); } atomic_ref& operator=(const atomic_ref&) = delete; - using difference_type = ptrdiff_t; - _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { return __atomic_fetch_add(this->__ptr_, __arg * sizeof(_Tp), std::__to_gcc_order(__order)); } From 4616b46638399a75792dc8374a1350e45fa69d16 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 8 Mar 2024 13:20:37 -0500 Subject: [PATCH 53/91] [libc++][atomic_ref] Fixup release note --- libcxx/docs/ReleaseNotes/19.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index ed11ff06d63f8..8b698b667a520 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -44,7 +44,7 @@ Implemented Papers - P2495R3 - Interfacing ``stringstream``s with ``string_view`` - P2302R4 - ``std::ranges::contains`` - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with`` -- P0019R8 - ``atomic_ref`` +- P0019R8 - ``std::atomic_ref`` Improvements and New Features ----------------------------- From fe1027c9d9b7b27042825178f57d5bcfd9df3f6b Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 8 Mar 2024 13:53:07 -0500 Subject: [PATCH 54/91] [libc++][atomic_ref] Propose new is_[always_]lock_free implementation w/o fake minimally aligned ptr --- libcxx/include/__atomic/atomic_ref.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 9abc4af418d8c..2e937dd9b8165 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -61,11 +61,9 @@ struct __atomic_ref_base { static constexpr size_t required_alignment = alignof(_Tp); static constexpr bool is_always_lock_free = - __atomic_always_lock_free(sizeof(_Tp), reinterpret_cast(-required_alignment)); + __atomic_always_lock_free(sizeof(_Tp), __builtin_align_up(static_cast<_Tp*>(nullptr), required_alignment)); - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { - return __atomic_is_lock_free(sizeof(_Tp), reinterpret_cast(-required_alignment)); - } + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); } _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { From e2b1529021e7c293f671195a7b8aed4b0b534343 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 8 Mar 2024 14:43:01 -0500 Subject: [PATCH 55/91] [libc++][atomic_ref] GCC does not provide __builtin_align_up --- libcxx/include/__atomic/atomic_ref.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 2e937dd9b8165..b13176ced480b 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -61,7 +61,7 @@ struct __atomic_ref_base { static constexpr size_t required_alignment = alignof(_Tp); static constexpr bool is_always_lock_free = - __atomic_always_lock_free(sizeof(_Tp), __builtin_align_up(static_cast<_Tp*>(nullptr), required_alignment)); + __atomic_always_lock_free(sizeof(_Tp), reinterpret_cast(-required_alignment)); _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); } From d935cb41c2556cdcc908da635ad7b6ff58518e6b Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 11 Mar 2024 15:40:41 -0400 Subject: [PATCH 56/91] [libc++][atomic_ref] Prefer reinterpret_cast to C-style cast and qualify addressof calls in constructor precondition checks --- libcxx/include/__atomic/atomic_ref.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index b13176ced480b..2b42e07d52e24 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -210,8 +210,9 @@ struct atomic_ref : public __atomic_ref_base<_Tp> { using __base = __atomic_ref_base<_Tp>; _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + reinterpret_cast(std::addressof(__obj)) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); } _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; @@ -229,8 +230,9 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { using difference_type = __base::value_type; _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + reinterpret_cast(std::addressof(__obj)) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); } _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; @@ -274,8 +276,9 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { using difference_type = __base::value_type; _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { - _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((uintptr_t)addressof(__obj) % __base::required_alignment == 0, - "atomic_ref ctor: referenced object must be aligned to required_alignment"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + reinterpret_cast(std::addressof(__obj)) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); } _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; From dabe768bd64b4e6fb52704a56e0bb25f85fc4fe5 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 11 Mar 2024 15:43:30 -0400 Subject: [PATCH 57/91] [libc++][atomic_ref] Add comment suggested by Louis to describe how the compare exchange with clear padding works --- libcxx/include/__atomic/atomic_ref.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 2b42e07d52e24..aadc048e0e7a5 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -113,6 +113,11 @@ struct __atomic_ref_base { __clear_padding(*__desired); _Tp __copy = *__expected; __clear_padding(__copy); + // The algorithm we use here is basically to perform `__atomic_compare_exchange` on the + // values until it has either succeeded, or failed because the value representation of the + // objects involved was different. This is why we loop around __atomic_compare_exchange: + // we basically loop until its failure is caused by the value representation of the objects + // being different, not only their object representation. while (true) { _Tp __prev = __copy; if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) { From 3ec8d6872cbb0ced07e66946d582fdbd4c15afd9 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 11 Mar 2024 15:59:23 -0400 Subject: [PATCH 58/91] [libc++][atomic_ref] Use protected access specifier in __atomic_ref_base --- libcxx/include/__atomic/atomic_ref.h | 76 +++++++++++++++------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index aadc048e0e7a5..76818c06fa6ac 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -44,8 +44,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD template struct __atomic_ref_base { +protected: _Tp* __ptr_; + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {} + _LIBCPP_HIDE_FROM_ABI static _Tp* __clear_padding(_Tp& __val) noexcept { _Tp* __ptr = std::addressof(__val); # if __has_builtin(__builtin_clear_padding) @@ -54,8 +57,44 @@ struct __atomic_ref_base { return __ptr; } - _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {} + _LIBCPP_HIDE_FROM_ABI static bool __compare_exchange( + _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { + if constexpr ( +# if __has_builtin(__builtin_clear_padding) + has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double> +# else + true // NOLINT(readability-simplify-boolean-expr) +# endif + ) { + return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure); + } else { // _Tp has padding bits and __builtin_clear_padding is available + __clear_padding(*__desired); + _Tp __copy = *__expected; + __clear_padding(__copy); + // The algorithm we use here is basically to perform `__atomic_compare_exchange` on the + // values until it has either succeeded, or failed because the value representation of the + // objects involved was different. This is why we loop around __atomic_compare_exchange: + // we basically loop until its failure is caused by the value representation of the objects + // being different, not only their object representation. + while (true) { + _Tp __prev = __copy; + if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) { + return true; + } + _Tp __curr = __copy; + if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(_Tp)) != 0) { + // Value representation without padding bits do not compare equal -> + // write the current content of *ptr into *expected + std::memcpy(__expected, std::addressof(__copy), sizeof(_Tp)); + return false; + } + } + } + } + friend struct __atomic_waitable_traits<__atomic_ref_base<_Tp>>; + +public: using value_type = _Tp; static constexpr size_t required_alignment = alignof(_Tp); @@ -99,41 +138,6 @@ struct __atomic_ref_base { return *__ret; } - _LIBCPP_HIDE_FROM_ABI static bool __compare_exchange( - _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { - if constexpr ( -# if __has_builtin(__builtin_clear_padding) - has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double> -# else - true // NOLINT(readability-simplify-boolean-expr) -# endif - ) { - return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure); - } else { // _Tp has padding bits and __builtin_clear_padding is available - __clear_padding(*__desired); - _Tp __copy = *__expected; - __clear_padding(__copy); - // The algorithm we use here is basically to perform `__atomic_compare_exchange` on the - // values until it has either succeeded, or failed because the value representation of the - // objects involved was different. This is why we loop around __atomic_compare_exchange: - // we basically loop until its failure is caused by the value representation of the objects - // being different, not only their object representation. - while (true) { - _Tp __prev = __copy; - if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) { - return true; - } - _Tp __curr = __copy; - if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(_Tp)) != 0) { - // Value representation without padding bits do not compare equal -> - // write the current content of *ptr into *expected - std::memcpy(__expected, std::addressof(__copy), sizeof(_Tp)); - return false; - } - } - } - } - _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { From 54b62305d733938976fe9a772ede7a19cebcc978 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 11 Mar 2024 16:03:15 -0400 Subject: [PATCH 59/91] [libc++][atomic_ref] Specify release in cxx20 status table --- libcxx/docs/Status/Cxx20Papers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index 7660a2f92cd24..9955f0a2dfdc5 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -26,7 +26,7 @@ "`P0905R1 `__","CWG","Symmetry for spaceship","Jacksonville","","","|spaceship|" "`P0966R1 `__","LWG","``string::reserve``\ Should Not Shrink","Jacksonville","|Complete| [#note-P0966]_","12.0" "","","","","","","" -"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","[Complete]","" +"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","[Complete]","19.0" "`P0458R2 `__","LWG","Checking for Existence of an Element in Associative Containers","Rapperswil","|Complete|","13.0" "`P0475R1 `__","LWG","LWG 2511: guaranteed copy elision for piecewise construction","Rapperswil","|Complete|","" "`P0476R2 `__","LWG","Bit-casting object representations","Rapperswil","|Complete|","14.0" From 8a29a08bde6a9c252b05ea7476093d5f65cd7f6c Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 11 Mar 2024 16:05:10 -0400 Subject: [PATCH 60/91] [libc++][atomic_ref] __clear_padding and __compare_exchange can be private --- libcxx/include/__atomic/atomic_ref.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 76818c06fa6ac..1d532cc7de170 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -49,6 +49,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {} +private: _LIBCPP_HIDE_FROM_ABI static _Tp* __clear_padding(_Tp& __val) noexcept { _Tp* __ptr = std::addressof(__val); # if __has_builtin(__builtin_clear_padding) From e2e4c6caf76e3184debc4fe7f46dfeb3bb3509fe Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Mon, 11 Mar 2024 16:08:31 -0400 Subject: [PATCH 61/91] [libc++][atomic_ref] Prefer std::byte for raw memory buffers --- libcxx/include/__atomic/atomic_ref.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 1d532cc7de170..9b0c83d72f415 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -124,7 +124,7 @@ struct __atomic_ref_base { __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || __order == memory_order::seq_cst, "atomic_ref: memory order argument to atomic load operation is invalid"); - alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; + alignas(_Tp) byte __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); __atomic_load(__ptr_, __ret, std::__to_gcc_order(__order)); return *__ret; @@ -133,7 +133,7 @@ struct __atomic_ref_base { _LIBCPP_HIDE_FROM_ABI operator _Tp() const noexcept { return load(); } _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { - alignas(_Tp) unsigned char __mem[sizeof(_Tp)]; + alignas(_Tp) byte __mem[sizeof(_Tp)]; auto* __ret = reinterpret_cast<_Tp*>(__mem); __atomic_exchange(__ptr_, __clear_padding(__desired), __ret, std::__to_gcc_order(__order)); return *__ret; From 4d7c3a86435db02e8f14f4fbe6afa6726ecda912 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 13 Mar 2024 13:59:24 -0400 Subject: [PATCH 62/91] [libc++][atomic_ref] Instantiate tests for more types --- .../std/atomics/atomics.ref/assign.pass.cpp | 35 +++--- .../atomics.ref/bitwise_and_assign.pass.cpp | 47 ++++--- .../atomics.ref/bitwise_or_assign.pass.cpp | 47 ++++--- .../atomics.ref/bitwise_xor_assign.pass.cpp | 46 ++++--- .../compare_exchange_strong.pass.cpp | 117 +++++++++--------- .../compare_exchange_weak.pass.cpp | 117 +++++++++--------- .../std/atomics/atomics.ref/convert.pass.cpp | 38 +++--- .../std/atomics/atomics.ref/ctor.pass.cpp | 32 ++--- .../atomics/atomics.ref/deduction.pass.cpp | 38 +++--- .../std/atomics/atomics.ref/exchange.pass.cpp | 47 ++++--- .../atomics/atomics.ref/fetch_add.pass.cpp | 97 ++++++++------- .../atomics/atomics.ref/fetch_and.pass.cpp | 63 ++++++---- .../std/atomics/atomics.ref/fetch_or.pass.cpp | 61 +++++---- .../atomics/atomics.ref/fetch_xor.pass.cpp | 59 +++++---- .../atomics.ref/increment_decrement.pass.cpp | 83 +++++++------ .../std/atomics/atomics.ref/load.pass.cpp | 47 ++++--- .../atomics/atomics.ref/notify_all.pass.cpp | 85 +++++++------ .../atomics/atomics.ref/notify_one.pass.cpp | 43 ++++--- .../operator_minus_equals.pass.cpp | 65 +++++----- .../atomics.ref/operator_plus_equals.pass.cpp | 65 +++++----- .../std/atomics/atomics.ref/store.pass.cpp | 37 +++--- .../std/atomics/atomics.ref/wait.pass.cpp | 65 +++++----- 22 files changed, 702 insertions(+), 632 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index d971dd74e0279..95ff08c3417b0 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -13,35 +13,34 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_assign() { - T x(T(1)); - std::atomic_ref const a(x); +struct TestAssign { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); - a = T(2); - assert(x == T(2)); + a = T(2); + assert(x == T(2)); - ASSERT_NOEXCEPT(a = T(0)); - static_assert(std::is_nothrow_assignable_v, T>); + ASSERT_NOEXCEPT(a = T(0)); + static_assert(std::is_nothrow_assignable_v, T>); - static_assert(!std::is_copy_assignable_v>); -} + static_assert(!std::is_copy_assignable_v>); + } +}; void test() { - test_assign(); + TestEachIntegralType()(); - test_assign(); + TestEachFloatingPointType()(); - test_assign(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_assign(); + TestAssign()(); + TestAssign()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index 396448cb4bc3f..4e60a1360df15 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -14,34 +14,43 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template concept has_bitwise_and_assign = requires { std::declval() &= std::declval(); }; -static_assert(!has_bitwise_and_assign>); -static_assert(!has_bitwise_and_assign>); -static_assert(!has_bitwise_and_assign>); -static_assert(!has_bitwise_and_assign>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveBitwiseAndAssign { + void operator()() const { static_assert(!has_bitwise_and_assign>); } }; -static_assert(!has_bitwise_and_assign>); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - std::same_as auto y = (a &= T(2)); - assert(y == T(0)); - assert(x == T(0)); - ASSERT_NOEXCEPT(a &= T(0)); -} +struct TestBitwiseAndAssign { + void operator()() const { + static_assert(std::is_integral_v); + + T x(T(1)); + std::atomic_ref const a(x); + + std::same_as auto y = (a &= T(2)); + assert(y == T(0)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a &= T(0)); + } +}; + +void test() { + TestEachIntegralType()(); -void test() { test_integral(); } + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestDoesNotHaveBitwiseAndAssign()(); + TestDoesNotHaveBitwiseAndAssign()(); + TestDoesNotHaveBitwiseAndAssign()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index 425a7538c3d54..a153c1c58725a 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -14,34 +14,43 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template concept has_bitwise_or_assign = requires { std::declval() |= std::declval(); }; -static_assert(!has_bitwise_or_assign>); -static_assert(!has_bitwise_or_assign>); -static_assert(!has_bitwise_or_assign>); -static_assert(!has_bitwise_or_assign>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template < typename T> +struct TestDoesNotHaveBitwiseOrAssign { + void operator()() const { static_assert(!has_bitwise_or_assign>); } }; -static_assert(!has_bitwise_or_assign>); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - std::same_as auto y = (a |= T(2)); - assert(y == T(3)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a &= T(0)); -} +struct TestBitwiseOrAssign { + void operator()() const { + static_assert(std::is_integral_v); + + T x(T(1)); + std::atomic_ref const a(x); + + std::same_as auto y = (a |= T(2)); + assert(y == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a &= T(0)); + } +}; + +void test() { + TestEachIntegralType()(); -void test() { test_integral(); } + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestDoesNotHaveBitwiseOrAssign()(); + TestDoesNotHaveBitwiseOrAssign()(); + TestDoesNotHaveBitwiseOrAssign()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp index 6eaea88fdce67..42c758d50883b 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -14,34 +14,42 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template concept has_bitwise_xor_assign = requires { std::declval() ^= std::declval(); }; -static_assert(!has_bitwise_xor_assign>); -static_assert(!has_bitwise_xor_assign>); -static_assert(!has_bitwise_xor_assign>); -static_assert(!has_bitwise_xor_assign>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveBitwiseXorAssign { + void operator()() const { static_assert(!has_bitwise_xor_assign>); } }; -static_assert(!has_bitwise_xor_assign>); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - std::same_as auto y = (a ^= T(2)); - assert(y == T(3)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a ^= T(0)); -} +struct TestBitwiseXorAssign { + void operator()() const { + static_assert(std::is_integral_v); + + T x(T(1)); + std::atomic_ref const a(x); + + std::same_as auto y = (a ^= T(2)); + assert(y == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a ^= T(0)); + } +}; + +void test() { + TestEachIntegralType()(); -void test() { test_integral(); } + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestDoesNotHaveBitwiseXorAssign()(); + TestDoesNotHaveBitwiseXorAssign()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 8ea62925eda43..9ac89ff5005d8 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -15,74 +15,73 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_compare_exchange_strong() { - { - T x(T(1)); - std::atomic_ref const a(x); - - T t(T(1)); - std::same_as auto y = a.compare_exchange_strong(t, T(2)); - assert(y == true); - assert(a == T(2)); - assert(t == T(1)); - y = a.compare_exchange_strong(t, T(3)); - assert(y == false); - assert(a == T(2)); - assert(t == T(2)); - - ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2))); +struct TestCompareExchangeStrong { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + + T t(T(1)); + std::same_as auto y = a.compare_exchange_strong(t, T(2)); + assert(y == true); + assert(a == T(2)); + assert(t == T(1)); + y = a.compare_exchange_strong(t, T(3)); + assert(y == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2))); + } + { + T x(T(1)); + std::atomic_ref const a(x); + + T t(T(1)); + std::same_as auto y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst); + assert(y == true); + assert(a == T(2)); + assert(t == T(1)); + y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst); + assert(y == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst)); + } + { + T x(T(1)); + std::atomic_ref const a(x); + + T t(T(1)); + std::same_as auto y = + a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed); + assert(y == true); + assert(a == T(2)); + assert(t == T(1)); + y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed); + assert(y == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed)); + } } - { - T x(T(1)); - std::atomic_ref const a(x); - - T t(T(1)); - std::same_as auto y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst); - assert(y == true); - assert(a == T(2)); - assert(t == T(1)); - y = a.compare_exchange_strong(t, T(3), std::memory_order_seq_cst); - assert(y == false); - assert(a == T(2)); - assert(t == T(2)); - - ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst)); - } - { - T x(T(1)); - std::atomic_ref const a(x); - - T t(T(1)); - std::same_as auto y = - a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed); - assert(y == true); - assert(a == T(2)); - assert(t == T(1)); - y = a.compare_exchange_strong(t, T(3), std::memory_order_release, std::memory_order_relaxed); - assert(y == false); - assert(a == T(2)); - assert(t == T(2)); - - ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed)); - } -} +}; void test() { - test_compare_exchange_strong(); + TestEachIntegralType()(); - test_compare_exchange_strong(); + TestEachFloatingPointType()(); - test_compare_exchange_strong(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_compare_exchange_strong(); + TestCompareExchangeStrong()(); + TestCompareExchangeStrong()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index cd5455315b9fa..6b4c3e757c863 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -15,74 +15,73 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_compare_exchange_weak() { - { - T x(T(1)); - std::atomic_ref const a(x); - - T t(T(1)); - std::same_as auto y = a.compare_exchange_weak(t, T(2)); - assert(y == true); - assert(a == T(2)); - assert(t == T(1)); - y = a.compare_exchange_weak(t, T(3)); - assert(y == false); - assert(a == T(2)); - assert(t == T(2)); - - ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2))); +struct TestCompareExchangeWeak { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + + T t(T(1)); + std::same_as auto y = a.compare_exchange_weak(t, T(2)); + assert(y == true); + assert(a == T(2)); + assert(t == T(1)); + y = a.compare_exchange_weak(t, T(3)); + assert(y == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2))); + } + { + T x(T(1)); + std::atomic_ref const a(x); + + T t(T(1)); + std::same_as auto y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst); + assert(y == true); + assert(a == T(2)); + assert(t == T(1)); + y = a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst); + assert(y == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst)); + } + { + T x(T(1)); + std::atomic_ref const a(x); + + T t(T(1)); + std::same_as auto y = + a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed); + assert(y == true); + assert(a == T(2)); + assert(t == T(1)); + y = a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed); + assert(y == false); + assert(a == T(2)); + assert(t == T(2)); + + ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed)); + } } - { - T x(T(1)); - std::atomic_ref const a(x); - - T t(T(1)); - std::same_as auto y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst); - assert(y == true); - assert(a == T(2)); - assert(t == T(1)); - y = a.compare_exchange_weak(t, T(3), std::memory_order_seq_cst); - assert(y == false); - assert(a == T(2)); - assert(t == T(2)); - - ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst)); - } - { - T x(T(1)); - std::atomic_ref const a(x); - - T t(T(1)); - std::same_as auto y = a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed); - assert(y == true); - assert(a == T(2)); - assert(t == T(1)); - y = a.compare_exchange_weak(t, T(3), std::memory_order_release, std::memory_order_relaxed); - assert(y == false); - assert(a == T(2)); - assert(t == T(2)); - - ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed)); - } -} +}; void test() { - test_compare_exchange_weak(); + TestEachIntegralType()(); - test_compare_exchange_weak(); + TestEachFloatingPointType()(); - test_compare_exchange_weak(); + TestEachPointerType()(); - struct X { - int i; - //X() = default; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_compare_exchange_weak(); + TestCompareExchangeWeak()(); + TestCompareExchangeWeak()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index 1ac1d1ea3b28d..d72d56edab57c 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -13,36 +13,34 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_convert(T const& x) { - T copy = x; - std::atomic_ref const a(copy); +struct TestConvert { + void operator()() const { + T x(T(1)); - T converted = a; - assert(converted == x); + T copy = x; + std::atomic_ref const a(copy); - ASSERT_NOEXCEPT(T(a)); - static_assert(std::is_nothrow_convertible_v, T>); -} + T converted = a; + assert(converted == x); + + ASSERT_NOEXCEPT(T(a)); + static_assert(std::is_nothrow_convertible_v, T>); + } +}; void test() { - int i = 1; - test_convert(i); + TestEachIntegralType()(); - float f = 1; - test_convert(f); + TestEachFloatingPointType()(); - int* p = &i; - test_convert(p); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - } x{1}; - test_convert(x); + TestConvert()(); + TestConvert()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp index d20f2cd5e4235..0514a9c9310f9 100644 --- a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp @@ -15,29 +15,31 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -auto make_atomic_ref(T& obj) { - // check that the constructor is explicit - static_assert(!std::is_convertible_v>); - static_assert(std::is_constructible_v, T&>); - return std::atomic_ref(obj); -} +struct TestCtor { + void operator()() const { + // check that the constructor is explicit + static_assert(!std::is_convertible_v>); + static_assert(std::is_constructible_v, T&>); + + T x(T(0)); + std::atomic_ref a(x); + (void)a; + } +}; void test() { - int i = 0; - (void)make_atomic_ref(i); + TestEachIntegralType()(); - float f = 0.f; - (void)make_atomic_ref(f); + TestEachFloatingPointType()(); - int* p = &i; - (void)make_atomic_ref(p); + TestEachPointerType()(); - struct X { - } x; - (void)make_atomic_ref(x); + TestCtor()(); + TestCtor()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp index 27aaf2ecdb3c9..03b8782f2db11 100644 --- a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp @@ -10,26 +10,32 @@ // +// explicit atomic_ref(T&); + #include #include +#include "atomic_helpers.h" +#include "test_macros.h" + +template +struct TestDeduction { + void operator()() const { + T x(T(0)); + std::atomic_ref a(x); + ASSERT_SAME_TYPE(decltype(a), std::atomic_ref); + } +}; + void test() { - int i = 0; - std::atomic_ref a0(i); - static_assert(std::is_same_v>); - - float f = 0.f; - std::atomic_ref a1(f); - static_assert(std::is_same_v>); - - int* p = &i; - std::atomic_ref a2(p); - static_assert(std::is_same_v>); - - struct X { - } x; - std::atomic_ref a3(x); - static_assert(std::is_same_v>); + TestEachIntegralType()(); + + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestDeduction()(); + TestDeduction()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index f1e41ef8051a1..e88dba0cac143 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -14,39 +14,38 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_exchange() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.exchange(T(2)); - assert(y == T(1)); - ASSERT_NOEXCEPT(a.exchange(T(2))); +struct TestExchange { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); + + { + std::same_as auto y = a.exchange(T(2)); + assert(y == T(1)); + ASSERT_NOEXCEPT(a.exchange(T(2))); + } + + { + std::same_as auto y = a.exchange(T(3), std::memory_order_seq_cst); + assert(y == T(2)); + ASSERT_NOEXCEPT(a.exchange(T(3), std::memory_order_seq_cst)); + } } - - { - std::same_as auto y = a.exchange(T(3), std::memory_order_seq_cst); - assert(y == T(2)); - ASSERT_NOEXCEPT(a.exchange(T(3), std::memory_order_seq_cst)); - } -} +}; void test() { - test_exchange(); + TestEachIntegralType()(); - test_exchange(); + TestEachFloatingPointType()(); - test_exchange(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_exchange(); + TestExchange()(); + TestExchange()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index 11e0f30d3b822..f90029046fdef 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -16,6 +16,7 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template @@ -24,62 +25,66 @@ concept has_fetch_add = requires { std::declval().fetch_add(std::declval(), std::declval()); }; -static_assert(!has_fetch_add>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveFetchAdd { + void operator()() const { static_assert(!has_fetch_add>); } }; -static_assert(!has_fetch_add>); template -void test_arithmetic() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.fetch_add(T(2)); - assert(y == T(1)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_add(T(0))); - } +struct TestFetchAdd { + void operator()() const { + if constexpr (std::is_arithmetic_v) { + T x(T(1)); + std::atomic_ref const a(x); - { - std::same_as auto y = a.fetch_add(T(4), std::memory_order_relaxed); - assert(y == T(3)); - assert(x == T(7)); - ASSERT_NOEXCEPT(a.fetch_add(T(0), std::memory_order_relaxed)); - } -} + { + std::same_as auto y = a.fetch_add(T(2)); + assert(y == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_add(T(0))); + } -template -void test_pointer() { - using U = std::remove_pointer_t; - U t[9] = {}; - T p{&t[1]}; - std::atomic_ref const a(p); - - { - std::same_as auto y = a.fetch_add(2); - assert(y == &t[1]); - assert(a == &t[3]); - ASSERT_NOEXCEPT(a.fetch_add(0)); - } + { + std::same_as auto y = a.fetch_add(T(4), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(7)); + ASSERT_NOEXCEPT(a.fetch_add(T(0), std::memory_order_relaxed)); + } + } else if constexpr (std::is_pointer_v) { + using U = std::remove_pointer_t; + U t[9] = {}; + T p{&t[1]}; + std::atomic_ref const a(p); - { - std::same_as auto y = a.fetch_add(4, std::memory_order_relaxed); - assert(y == &t[3]); - assert(a == &t[7]); - ASSERT_NOEXCEPT(a.fetch_add(0, std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_add(2); + assert(y == &t[1]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a.fetch_add(0)); + } + + { + std::same_as auto y = a.fetch_add(4, std::memory_order_relaxed); + assert(y == &t[3]); + assert(a == &t[7]); + ASSERT_NOEXCEPT(a.fetch_add(0, std::memory_order_relaxed)); + } + } else { + static_assert(std::is_void_v); + } } -} +}; void test() { - test_arithmetic(); - test_arithmetic(); + TestEachIntegralType()(); + + TestEachFloatingPointType()(); + + TestEachPointerType()(); - test_pointer(); - test_pointer(); + TestDoesNotHaveFetchAdd()(); + TestDoesNotHaveFetchAdd()(); + TestDoesNotHaveFetchAdd()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp index b0eef527a58ee..588c2b41ace21 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -14,6 +14,7 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template @@ -22,40 +23,48 @@ concept has_fetch_and = requires { std::declval().fetch_and(std::declval(), std::declval()); }; -static_assert(!has_fetch_and>); -static_assert(!has_fetch_and>); -static_assert(!has_fetch_and>); -static_assert(!has_fetch_and>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveFetchAnd { + void operator()() const { static_assert(!has_fetch_and>); } }; -static_assert(!has_fetch_and>); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.fetch_and(T(2)); - assert(y == T(1)); - assert(x == T(0)); - ASSERT_NOEXCEPT(a.fetch_and(T(0))); - } +struct TestFetchAnd { + void operator()() const { + static_assert(std::is_integral_v); + + T x(T(1)); + std::atomic_ref const a(x); - x = T(1); + { + std::same_as auto y = a.fetch_and(T(2)); + assert(y == T(1)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a.fetch_and(T(0))); + } - { - std::same_as auto y = a.fetch_and(T(2), std::memory_order_relaxed); - assert(y == T(1)); - assert(x == T(0)); - ASSERT_NOEXCEPT(a.fetch_and(T(0), std::memory_order_relaxed)); + x = T(1); + + { + std::same_as auto y = a.fetch_and(T(2), std::memory_order_relaxed); + assert(y == T(1)); + assert(x == T(0)); + ASSERT_NOEXCEPT(a.fetch_and(T(0), std::memory_order_relaxed)); + } } -} +}; + +void test() { + TestEachIntegralType()(); + + TestEachFloatingPointType()(); -void test() { test_integral(); } + TestEachPointerType()(); + + TestDoesNotHaveFetchAnd()(); + TestDoesNotHaveFetchAnd()(); + TestDoesNotHaveFetchAnd()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp index 53112b32e662f..657eff5b1ca85 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -14,6 +14,7 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template @@ -22,38 +23,46 @@ concept has_fetch_or = requires { std::declval().fetch_or(std::declval(), std::declval()); }; -static_assert(!has_fetch_or>); -static_assert(!has_fetch_or>); -static_assert(!has_fetch_or>); -static_assert(!has_fetch_or>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveFetchOr { + void operator()() const { static_assert(!has_fetch_or>); } }; -static_assert(!has_fetch_or>); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.fetch_or(T(2)); - assert(y == T(1)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_or(T(0))); - } +struct TestFetchOr { + void operator()() const { + static_assert(std::is_integral_v); + + T x(T(1)); + std::atomic_ref const a(x); - { - std::same_as auto y = a.fetch_or(T(2), std::memory_order_relaxed); - assert(y == T(3)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_or(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_or(T(2)); + assert(y == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_or(T(0))); + } + + { + std::same_as auto y = a.fetch_or(T(2), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_or(T(0), std::memory_order_relaxed)); + } } -} +}; + +void test() { + TestEachIntegralType()(); + + TestEachFloatingPointType()(); -void test() { test_integral(); } + TestEachPointerType()(); + + TestDoesNotHaveFetchOr()(); + TestDoesNotHaveFetchOr()(); + TestDoesNotHaveFetchOr()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index cfeb544905603..21cc0a699ec62 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -14,6 +14,7 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template @@ -22,38 +23,44 @@ concept has_fetch_xor = requires { std::declval().fetch_xor(std::declval(), std::declval()); }; -static_assert(!has_fetch_xor>); -static_assert(!has_fetch_xor>); -static_assert(!has_fetch_xor>); -static_assert(!has_fetch_xor>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveFetchXor { + void operator()() const { static_assert(!has_fetch_xor>); } }; -static_assert(!has_fetch_xor>); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.fetch_xor(T(2)); - assert(y == T(1)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_xor(T(0))); - } +struct TestFetchXor { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); + + { + std::same_as auto y = a.fetch_xor(T(2)); + assert(y == T(1)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_xor(T(0))); + } - { - std::same_as auto y = a.fetch_xor(T(2), std::memory_order_relaxed); - assert(y == T(3)); - assert(x == T(1)); - ASSERT_NOEXCEPT(a.fetch_xor(T(0), std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_xor(T(2), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a.fetch_xor(T(0), std::memory_order_relaxed)); + } } -} +}; -void test() { test_integral(); } +void test() { + TestEachIntegralType()(); + + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestDoesNotHaveFetchXor()(); + TestDoesNotHaveFetchXor()(); + TestDoesNotHaveFetchXor()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index 1bad4a73a83ab..bf972d45b8250 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -17,6 +17,7 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template @@ -37,52 +38,58 @@ constexpr bool does_not_have_increment_nor_decrement_operators() { !has_post_decrement_operator; } -static_assert(does_not_have_increment_nor_decrement_operators()); -static_assert(does_not_have_increment_nor_decrement_operators()); -static_assert(does_not_have_increment_nor_decrement_operators()); -static_assert(does_not_have_increment_nor_decrement_operators()); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveIncrementDecrement { + void operator()() const { static_assert(does_not_have_increment_nor_decrement_operators()); } }; -static_assert(does_not_have_increment_nor_decrement_operators()); template -void test_integral() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = ++a; - assert(y == T(2)); - assert(x == T(2)); - ASSERT_NOEXCEPT(++a); +struct TestIncrementDecrement { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); + + { + std::same_as auto y = ++a; + assert(y == T(2)); + assert(x == T(2)); + ASSERT_NOEXCEPT(++a); + } + + { + std::same_as auto y = --a; + assert(y == T(1)); + assert(x == T(1)); + ASSERT_NOEXCEPT(--a); + } + + { + std::same_as auto y = a++; + assert(y == T(1)); + assert(x == T(2)); + ASSERT_NOEXCEPT(a++); + } + + { + std::same_as auto y = a--; + assert(y == T(2)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a--); + } } +}; - { - std::same_as auto y = --a; - assert(y == T(1)); - assert(x == T(1)); - ASSERT_NOEXCEPT(--a); - } +void test() { + TestEachIntegralType()(); - { - std::same_as auto y = a++; - assert(y == T(1)); - assert(x == T(2)); - ASSERT_NOEXCEPT(a++); - } + TestEachFloatingPointType()(); - { - std::same_as auto y = a--; - assert(y == T(2)); - assert(x == T(1)); - ASSERT_NOEXCEPT(a--); - } -} + TestEachPointerType()(); -void test() { test_integral(); } + TestDoesNotHaveIncrementDecrement()(); + TestDoesNotHaveIncrementDecrement()(); + TestDoesNotHaveIncrementDecrement()(); +} int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index e83b9cf88f41d..3bb8342002ccf 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -14,39 +14,38 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_load() { - T x(T(1)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.load(); - assert(y == T(1)); - ASSERT_NOEXCEPT(a.load()); +struct TestLoad { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); + + { + std::same_as auto y = a.load(); + assert(y == T(1)); + ASSERT_NOEXCEPT(a.load()); + } + + { + std::same_as auto y = a.load(std::memory_order_seq_cst); + assert(y == T(1)); + ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); + } } - - { - std::same_as auto y = a.load(std::memory_order_seq_cst); - assert(y == T(1)); - ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); - } -} +}; void test() { - test_load(); + TestEachIntegralType()(); - test_load(); + TestEachFloatingPointType()(); - test_load(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_load(); + TestLoad()(); + TestLoad()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 7f7575583b6fe..7dfbb7ef023cd 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -15,69 +15,68 @@ #include #include +#include "atomic_helpers.h" #include "make_test_thread.h" #include "test_macros.h" template -void test_notify_all() { - T x(T(1)); - std::atomic_ref const a(x); +struct TestNotifyAll { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); - bool done = false; - std::atomic started_num = 0; - std::atomic wait_done_num = 0; + bool done = false; + std::atomic started_num = 0; + std::atomic wait_done_num = 0; - constexpr auto number_of_threads = 8; - std::vector threads; - threads.reserve(number_of_threads); + constexpr auto number_of_threads = 8; + std::vector threads; + threads.reserve(number_of_threads); - for (auto j = 0; j < number_of_threads; ++j) { - threads.push_back(support::make_test_thread([&a, &started_num, &done, &wait_done_num] { - started_num.fetch_add(1, std::memory_order::relaxed); + for (auto j = 0; j < number_of_threads; ++j) { + threads.push_back(support::make_test_thread([&a, &started_num, &done, &wait_done_num] { + started_num.fetch_add(1, std::memory_order::relaxed); - a.wait(T(1)); - wait_done_num.fetch_add(1, std::memory_order::relaxed); + a.wait(T(1)); + wait_done_num.fetch_add(1, std::memory_order::relaxed); - // likely to fail if wait did not block - assert(done); - })); - } + // likely to fail if wait did not block + assert(done); + })); + } - while (started_num.load(std::memory_order::relaxed) != number_of_threads) { - std::this_thread::yield(); - } + while (started_num.load(std::memory_order::relaxed) != number_of_threads) { + std::this_thread::yield(); + } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); - done = true; - a.store(T(3)); - a.notify_all(); + done = true; + a.store(T(3)); + a.notify_all(); - // notify_all should unblock all the threads so that the loop below won't stuck - while (wait_done_num.load(std::memory_order::relaxed) != number_of_threads) { - std::this_thread::yield(); - } + // notify_all should unblock all the threads so that the loop below won't stuck + while (wait_done_num.load(std::memory_order::relaxed) != number_of_threads) { + std::this_thread::yield(); + } - for (auto& thread : threads) { - thread.join(); - } + for (auto& thread : threads) { + thread.join(); + } - ASSERT_NOEXCEPT(a.notify_all()); -} + ASSERT_NOEXCEPT(a.notify_all()); + } +}; void test() { - test_notify_all(); + TestEachIntegralType()(); - test_notify_all(); + TestEachFloatingPointType()(); - test_notify_all(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_notify_all(); + TestNotifyAll()(); + TestNotifyAll()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index 7139aae338543..5dda26ca1178f 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -15,37 +15,36 @@ #include #include +#include "atomic_helpers.h" #include "make_test_thread.h" #include "test_macros.h" template -void test_notify_one() { - T x(T(1)); - std::atomic_ref const a(x); - - std::thread t = support::make_test_thread([&]() { - a.store(T(3)); - a.notify_one(); - }); - a.wait(T(1)); - assert(a.load() == T(3)); - t.join(); - ASSERT_NOEXCEPT(a.notify_one()); -} +struct TestNotifyOne { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); + + std::thread t = support::make_test_thread([&]() { + a.store(T(3)); + a.notify_one(); + }); + a.wait(T(1)); + assert(a.load() == T(3)); + t.join(); + ASSERT_NOEXCEPT(a.notify_one()); + } +}; void test() { - test_notify_one(); + TestEachIntegralType()(); - test_notify_one(); + TestEachFloatingPointType()(); - test_notify_one(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_notify_one(); + TestNotifyOne()(); + TestNotifyOne()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index 4265c0b6a5fb4..e61ddacba06ba 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -16,49 +16,54 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template concept has_operator_minus_equals = requires { std::declval() -= std::declval(); }; -static_assert(!has_operator_minus_equals>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveOperatorMinusEquals { + void operator()() const { static_assert(!has_operator_minus_equals>); } }; -static_assert(!has_operator_minus_equals>); template -void test_arithmetic() { - T x(T(3)); - std::atomic_ref const a(x); - - std::same_as auto y = (a -= T(2)); - assert(y == T(1)); - assert(x == T(1)); - ASSERT_NOEXCEPT(a -= T(0)); -} +struct TestOperatorMinusEquals { + void operator()() const { + if constexpr (std::is_arithmetic_v) { + T x(T(3)); + std::atomic_ref const a(x); -template -void test_pointer() { - using U = std::remove_pointer_t; - U t[9] = {}; - T p{&t[3]}; - std::atomic_ref const a(p); + std::same_as auto y = (a -= T(2)); + assert(y == T(1)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a -= T(0)); + } else if constexpr (std::is_pointer_v) { + using U = std::remove_pointer_t; + U t[9] = {}; + T p{&t[3]}; + std::atomic_ref const a(p); - std::same_as auto y = (a -= 2); - assert(y == &t[1]); - assert(a == &t[1]); - ASSERT_NOEXCEPT(a -= 0); -} + std::same_as auto y = (a -= 2); + assert(y == &t[1]); + assert(a == &t[1]); + ASSERT_NOEXCEPT(a -= 0); + } else { + static_assert(std::is_void_v); + } + } +}; void test() { - test_arithmetic(); - test_arithmetic(); + TestEachIntegralType()(); + + TestEachFloatingPointType()(); + + TestEachPointerType()(); - test_pointer(); - test_pointer(); + TestDoesNotHaveOperatorMinusEquals()(); + TestDoesNotHaveOperatorMinusEquals()(); + TestDoesNotHaveOperatorMinusEquals()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index a82ebae84481f..b96294797cf4d 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -16,49 +16,54 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template concept has_operator_plus_equals = requires { std::declval() += std::declval(); }; -static_assert(!has_operator_plus_equals>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveOperatorPlusEquals { + void operator()() const { static_assert(!has_operator_plus_equals>); } }; -static_assert(!has_operator_plus_equals>); template -void test_arithmetic() { - T x(T(1)); - std::atomic_ref const a(x); - - std::same_as auto y = (a += T(2)); - assert(y == T(3)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a += T(0)); -} +struct TestOperatorPlusEquals { + void operator()() const { + if constexpr (std::is_arithmetic_v) { + T x(T(1)); + std::atomic_ref const a(x); -template -void test_pointer() { - using U = std::remove_pointer_t; - U t[9] = {}; - T p{&t[1]}; - std::atomic_ref const a(p); + std::same_as auto y = (a += T(2)); + assert(y == T(3)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a += T(0)); + } else if constexpr (std::is_pointer_v) { + using U = std::remove_pointer_t; + U t[9] = {}; + T p{&t[1]}; + std::atomic_ref const a(p); - std::same_as auto y = (a += 2); - assert(y == &t[3]); - assert(a == &t[3]); - ASSERT_NOEXCEPT(a += 0); -} + std::same_as auto y = (a += 2); + assert(y == &t[3]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a += 0); + } else { + static_assert(std::is_void_v); + } + } +}; void test() { - test_arithmetic(); - test_arithmetic(); + TestEachIntegralType()(); + + TestEachFloatingPointType()(); + + TestEachPointerType()(); - test_pointer(); - test_pointer(); + TestDoesNotHaveOperatorPlusEquals()(); + TestDoesNotHaveOperatorPlusEquals()(); + TestDoesNotHaveOperatorPlusEquals()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp index 0ecafe83f7a24..92e5a0b0ac1f0 100644 --- a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -13,35 +13,34 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template -void test_store() { - T x(T(1)); - std::atomic_ref const a(x); +struct TestStore { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); - a.store(T(2)); - assert(x == T(2)); - ASSERT_NOEXCEPT(a.store(T(1))); + a.store(T(2)); + assert(x == T(2)); + ASSERT_NOEXCEPT(a.store(T(1))); - a.store(T(3), std::memory_order_seq_cst); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.store(T(0), std::memory_order_seq_cst)); -} + a.store(T(3), std::memory_order_seq_cst); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.store(T(0), std::memory_order_seq_cst)); + } +}; void test() { - test_store(); + TestEachIntegralType()(); - test_store(); + TestEachFloatingPointType()(); - test_store(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_store(); + TestStore()(); + TestStore()(); } int main(int, char**) { diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index 77d6b47146ac3..a11458675f1c8 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -13,50 +13,49 @@ #include #include +#include "atomic_helpers.h" #include "make_test_thread.h" #include "test_macros.h" template -void test_wait() { - T x(T(1)); - std::atomic_ref const a(x); +struct TestWait { + void operator()() const { + T x(T(1)); + std::atomic_ref const a(x); - assert(a.load() == T(1)); - a.wait(T(0)); - std::thread t1 = support::make_test_thread([&]() { - a.store(T(3)); - a.notify_one(); - }); - a.wait(T(1)); - assert(a.load() == T(3)); - t1.join(); - ASSERT_NOEXCEPT(a.wait(T(0))); + assert(a.load() == T(1)); + a.wait(T(0)); + std::thread t1 = support::make_test_thread([&]() { + a.store(T(3)); + a.notify_one(); + }); + a.wait(T(1)); + assert(a.load() == T(3)); + t1.join(); + ASSERT_NOEXCEPT(a.wait(T(0))); - assert(a.load() == T(3)); - a.wait(T(0), std::memory_order_seq_cst); - std::thread t2 = support::make_test_thread([&]() { - a.store(T(5)); - a.notify_one(); - }); - a.wait(T(3), std::memory_order_seq_cst); - assert(a.load() == T(5)); - t2.join(); - ASSERT_NOEXCEPT(a.wait(T(0), std::memory_order_seq_cst)); -} + assert(a.load() == T(3)); + a.wait(T(0), std::memory_order_seq_cst); + std::thread t2 = support::make_test_thread([&]() { + a.store(T(5)); + a.notify_one(); + }); + a.wait(T(3), std::memory_order_seq_cst); + assert(a.load() == T(5)); + t2.join(); + ASSERT_NOEXCEPT(a.wait(T(0), std::memory_order_seq_cst)); + } +}; void test() { - test_wait(); + TestEachIntegralType()(); - test_wait(); + TestEachFloatingPointType()(); - test_wait(); + TestEachPointerType()(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_wait(); + TestWait()(); + TestWait()(); } int main(int, char**) { From e4da1e06756a57797bba10f9f05b2c2485c9b543 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 13 Mar 2024 19:31:33 -0400 Subject: [PATCH 63/91] [libc++][atomic_ref] Instantiate libcxx tests for more types --- .../assert.compare_exchange_strong.pass.cpp | 71 +++++++++-------- .../assert.compare_exchange_weak.pass.cpp | 71 +++++++++-------- .../atomics/atomics.ref/assert.load.pass.cpp | 65 ++++++++-------- .../atomics/atomics.ref/assert.store.pass.cpp | 77 ++++++++++--------- .../atomics/atomics.ref/assert.wait.pass.cpp | 65 ++++++++-------- 5 files changed, 187 insertions(+), 162 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 2b6ac0518e9ae..34617364e0a6c 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -18,46 +18,51 @@ #include +#include "atomic_helpers.h" #include "check_assertion.h" template -void test_compare_exchange_strong_invalid_memory_order() { - { - T x(T(1)); - std::atomic_ref const a(x); - T t(T(2)); - a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); +struct TestCompareExchangeStrongInvalidMemoryOrder { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + T t(T(2)); + a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + T t(T(2)); + a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_release); + }()), + "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + T t(T(2)); + a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); + }()), + "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); } +}; + +void test() { + TestEachIntegralType()(); - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - T t(T(2)); - a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_release); - }()), - "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); - - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - T t(T(2)); - a.compare_exchange_strong(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); - }()), - "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestCompareExchangeStrongInvalidMemoryOrder()(); + TestCompareExchangeStrongInvalidMemoryOrder()(); } int main(int, char**) { - test_compare_exchange_strong_invalid_memory_order(); - test_compare_exchange_strong_invalid_memory_order(); - test_compare_exchange_strong_invalid_memory_order(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_compare_exchange_strong_invalid_memory_order(); - + test(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index bc3ab73c7370b..8edd633449025 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -18,46 +18,51 @@ #include +#include "atomic_helpers.h" #include "check_assertion.h" template -void test_compare_exchange_weak_invalid_memory_order() { - { - T x(T(1)); - std::atomic_ref const a(x); - T t(T(2)); - a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); +struct TestCompareExchangeWeakInvalidMemoryOrder { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + T t(T(2)); + a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + T t(T(2)); + a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_release); + }()), + "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + T t(T(2)); + a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); + }()), + "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); } +}; + +void test() { + TestEachIntegralType()(); - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - T t(T(2)); - a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_release); - }()), - "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); - - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - T t(T(2)); - a.compare_exchange_weak(t, T(3), std::memory_order_relaxed, std::memory_order_acq_rel); - }()), - "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestCompareExchangeWeakInvalidMemoryOrder()(); + TestCompareExchangeWeakInvalidMemoryOrder()(); } int main(int, char**) { - test_compare_exchange_weak_invalid_memory_order(); - test_compare_exchange_weak_invalid_memory_order(); - test_compare_exchange_weak_invalid_memory_order(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_compare_exchange_weak_invalid_memory_order(); - + test(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 1f35dd1f3a651..54a399a16bed9 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -18,43 +18,48 @@ #include +#include "atomic_helpers.h" #include "check_assertion.h" template -void test_load_invalid_memory_order() { - { - T x(T(1)); - std::atomic_ref const a(x); - (void)a.load(std::memory_order_relaxed); +struct TestLoadInvalidMemoryOrder { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + (void)a.load(std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + (void)a.load(std::memory_order_release); + }()), + "atomic_ref: memory order argument to atomic load operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + (void)a.load(std::memory_order_acq_rel); + }()), + "atomic_ref: memory order argument to atomic load operation is invalid"); } +}; + +void test() { + TestEachIntegralType()(); - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - (void)a.load(std::memory_order_release); - }()), - "atomic_ref: memory order argument to atomic load operation is invalid"); - - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - (void)a.load(std::memory_order_acq_rel); - }()), - "atomic_ref: memory order argument to atomic load operation is invalid"); + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestLoadInvalidMemoryOrder()(); + TestLoadInvalidMemoryOrder()(); } int main(int, char**) { - test_load_invalid_memory_order(); - test_load_invalid_memory_order(); - test_load_invalid_memory_order(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_load_invalid_memory_order(); - + test(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index 8e098dcbe2923..44183fcb895e3 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -18,51 +18,56 @@ #include +#include "atomic_helpers.h" #include "check_assertion.h" template -void test_store_invalid_memory_order() { - { - T x(T(1)); - std::atomic_ref const a(x); - a.store(T(2), std::memory_order_relaxed); +struct TestStoreInvalidMemoryOrder { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + a.store(T(2), std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + a.store(T(2), std::memory_order_consume); + }()), + "atomic_ref: memory order argument to atomic store operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + a.store(T(2), std::memory_order_acquire); + }()), + "atomic_ref: memory order argument to atomic store operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + a.store(T(2), std::memory_order_acq_rel); + }()), + "atomic_ref: memory order argument to atomic store operation is invalid"); } +}; - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - a.store(T(2), std::memory_order_consume); - }()), - "atomic_ref: memory order argument to atomic store operation is invalid"); +void test() { + TestEachIntegralType()(); - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - a.store(T(2), std::memory_order_acquire); - }()), - "atomic_ref: memory order argument to atomic store operation is invalid"); + TestEachFloatingPointType()(); - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - a.store(T(2), std::memory_order_acq_rel); - }()), - "atomic_ref: memory order argument to atomic store operation is invalid"); + TestEachPointerType()(); + + TestStoreInvalidMemoryOrder()(); + TestStoreInvalidMemoryOrder()(); } int main(int, char**) { - test_store_invalid_memory_order(); - test_store_invalid_memory_order(); - test_store_invalid_memory_order(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_store_invalid_memory_order(); - + test(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index c6f5a2861dcf0..a9c960e27e04d 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -18,43 +18,48 @@ #include +#include "atomic_helpers.h" #include "check_assertion.h" template -void test_wait_invalid_memory_order() { - { - T x(T(1)); - std::atomic_ref const a(x); - a.wait(T(2), std::memory_order_relaxed); +struct TestWaitInvalidMemoryOrder { + void operator()() const { + { + T x(T(1)); + std::atomic_ref const a(x); + a.wait(T(2), std::memory_order_relaxed); + } + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + a.wait(T(2), std::memory_order_release); + }()), + "atomic_ref: memory order argument to atomic wait operation is invalid"); + + TEST_LIBCPP_ASSERT_FAILURE( + ([] { + T x(T(1)); + std::atomic_ref const a(x); + a.wait(T(2), std::memory_order_acq_rel); + }()), + "atomic_ref: memory order argument to atomic wait operation is invalid"); } +}; + +void test() { + TestEachIntegralType()(); - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - a.wait(T(2), std::memory_order_release); - }()), - "atomic_ref: memory order argument to atomic wait operation is invalid"); - - TEST_LIBCPP_ASSERT_FAILURE( - ([] { - T x(T(1)); - std::atomic_ref const a(x); - a.wait(T(2), std::memory_order_acq_rel); - }()), - "atomic_ref: memory order argument to atomic wait operation is invalid"); + TestEachFloatingPointType()(); + + TestEachPointerType()(); + + TestWaitInvalidMemoryOrder()(); + TestWaitInvalidMemoryOrder()(); } int main(int, char**) { - test_wait_invalid_memory_order(); - test_wait_invalid_memory_order(); - test_wait_invalid_memory_order(); - struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } - }; - test_wait_invalid_memory_order(); - + test(); return 0; } From e09ac7a2361e7591c40f2ba40917602df5d21892 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 13 Mar 2024 21:44:55 -0400 Subject: [PATCH 64/91] [libc++][atomic_ref] assert integral type --- .../test/std/atomics/atomics.ref/increment_decrement.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index bf972d45b8250..2240b23b12501 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -46,6 +46,8 @@ struct TestDoesNotHaveIncrementDecrement { template struct TestIncrementDecrement { void operator()() const { + static_assert(std::is_integral_v); + T x(T(1)); std::atomic_ref const a(x); From cee65ac76bd0449228bf8cd3db0312ef3e54aa7e Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 13 Mar 2024 21:45:42 -0400 Subject: [PATCH 65/91] [libc++][atomic_ref] casually disable long double tests that failed --- .../atomics.ref/compare_exchange_strong.pass.cpp | 11 +---------- .../atomics.ref/compare_exchange_weak.pass.cpp | 11 +---------- .../test/std/atomics/atomics.ref/notify_all.pass.cpp | 11 +---------- .../test/std/atomics/atomics.ref/notify_one.pass.cpp | 11 +---------- libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 11 +---------- 5 files changed, 5 insertions(+), 50 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 9ac89ff5005d8..18177c6cb99d1 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -73,16 +73,7 @@ struct TestCompareExchangeStrong { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestCompareExchangeStrong()(); - TestCompareExchangeStrong()(); -} +void test() { TestEachAtomicType()(); } int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index 6b4c3e757c863..13da04b746003 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -73,16 +73,7 @@ struct TestCompareExchangeWeak { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestCompareExchangeWeak()(); - TestCompareExchangeWeak()(); -} +void test() { TestEachAtomicType()(); } int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 7dfbb7ef023cd..a19da3f8e40e5 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -68,16 +68,7 @@ struct TestNotifyAll { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestNotifyAll()(); - TestNotifyAll()(); -} +void test() { TestEachAtomicType()(); } int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index 5dda26ca1178f..287522abfa728 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -36,16 +36,7 @@ struct TestNotifyOne { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestNotifyOne()(); - TestNotifyOne()(); -} +void test() { TestEachAtomicType()(); } int main(int, char**) { test(); diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index a11458675f1c8..b763a94979eac 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -47,16 +47,7 @@ struct TestWait { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestWait()(); - TestWait()(); -} +void test() { TestEachAtomicType()(); } int main(int, char**) { test(); From 7e68d6c6fafa564552a2f3361c1116b1ad4cce22 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Thu, 14 Mar 2024 08:26:22 -0400 Subject: [PATCH 66/91] [libc++][atomic_ref] assert integral type in xor --- libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index 21cc0a699ec62..4e7e29caac143 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -31,6 +31,8 @@ struct TestDoesNotHaveFetchXor { template struct TestFetchXor { void operator()() const { + static_assert(std::is_integral_v); + T x(T(1)); std::atomic_ref const a(x); From 3cc65a58347c829544a44aeb6805259448e1731f Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Thu, 14 Mar 2024 08:29:02 -0400 Subject: [PATCH 67/91] [libc++][atomic_ref] forgot fetch_sub --- .../atomics/atomics.ref/fetch_sub.pass.cpp | 97 ++++++++++--------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 96625020563d3..5d7abeecc804d 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -16,6 +16,7 @@ #include #include +#include "atomic_helpers.h" #include "test_macros.h" template @@ -24,62 +25,66 @@ concept has_fetch_sub = requires { std::declval().fetch_sub(std::declval(), std::declval()); }; -static_assert(!has_fetch_sub>); -struct X { - int i; - X(int ii) noexcept : i(ii) {} - bool operator==(X o) const { return i == o.i; } +template +struct TestDoesNotHaveFetchSub { + void operator()() const { static_assert(!has_fetch_sub>); } }; -static_assert(!has_fetch_sub>); template -void test_arithmetic() { - T x(T(7)); - std::atomic_ref const a(x); - - { - std::same_as auto y = a.fetch_sub(T(4)); - assert(y == T(7)); - assert(x == T(3)); - ASSERT_NOEXCEPT(a.fetch_sub(T(0))); - } +struct TestFetchSub { + void operator()() const { + if constexpr (std::is_arithmetic_v) { + T x(T(7)); + std::atomic_ref const a(x); - { - std::same_as auto y = a.fetch_sub(T(2), std::memory_order_relaxed); - assert(y == T(3)); - assert(x == T(1)); - ASSERT_NOEXCEPT(a.fetch_sub(T(0), std::memory_order_relaxed)); - } -} + { + std::same_as auto y = a.fetch_sub(T(4)); + assert(y == T(7)); + assert(x == T(3)); + ASSERT_NOEXCEPT(a.fetch_sub(T(0))); + } -template -void test_pointer() { - using U = std::remove_pointer_t; - U t[9] = {}; - T p{&t[7]}; - std::atomic_ref const a(p); - - { - std::same_as auto y = a.fetch_sub(4); - assert(y == &t[7]); - assert(a == &t[3]); - ASSERT_NOEXCEPT(a.fetch_sub(0)); - } + { + std::same_as auto y = a.fetch_sub(T(2), std::memory_order_relaxed); + assert(y == T(3)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a.fetch_sub(T(0), std::memory_order_relaxed)); + } + } else if constexpr (std::is_pointer_v) { + using U = std::remove_pointer_t; + U t[9] = {}; + T p{&t[7]}; + std::atomic_ref const a(p); - { - std::same_as auto y = a.fetch_sub(2, std::memory_order_relaxed); - assert(y == &t[3]); - assert(a == &t[1]); - ASSERT_NOEXCEPT(a.fetch_sub(0, std::memory_order_relaxed)); + { + std::same_as auto y = a.fetch_sub(4); + assert(y == &t[7]); + assert(a == &t[3]); + ASSERT_NOEXCEPT(a.fetch_sub(0)); + } + + { + std::same_as auto y = a.fetch_sub(2, std::memory_order_relaxed); + assert(y == &t[3]); + assert(a == &t[1]); + ASSERT_NOEXCEPT(a.fetch_sub(0, std::memory_order_relaxed)); + } + } else { + static_assert(std::is_void_v); + } } -} +}; void test() { - test_arithmetic(); - test_arithmetic(); + TestEachIntegralType()(); + + TestEachFloatingPointType()(); + + TestEachPointerType()(); - test_pointer(); - test_pointer(); + TestDoesNotHaveFetchSub()(); + TestDoesNotHaveFetchSub()(); + TestDoesNotHaveFetchSub()(); } int main(int, char**) { From f64b44f0e870732ea069fb406577d57fc44d6a92 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 29 Mar 2024 21:31:05 -0400 Subject: [PATCH 68/91] [libc++][atomic_ref] Add tests that actually check the aromicity --- .../std/atomics/atomics.ref/assign.pass.cpp | 5 + .../compare_exchange_strong.pass.cpp | 140 +++++++++++++++++ .../compare_exchange_weak.pass.cpp | 145 ++++++++++++++++++ .../std/atomics/atomics.ref/convert.pass.cpp | 5 + .../atomics/atomics.ref/fetch_add.pass.cpp | 21 +++ .../atomics/atomics.ref/fetch_sub.pass.cpp | 21 +++ .../std/atomics/atomics.ref/load.pass.cpp | 17 ++ .../operator_minus_equals.pass.cpp | 8 + .../atomics.ref/operator_plus_equals.pass.cpp | 8 + .../std/atomics/atomics.ref/store.pass.cpp | 21 +++ .../std/atomics/atomics.ref/test_helper.h | 137 +++++++++++++++++ .../std/atomics/atomics.ref/wait.pass.cpp | 29 ++++ 12 files changed, 557 insertions(+) create mode 100644 libcxx/test/std/atomics/atomics.ref/test_helper.h diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index 95ff08c3417b0..d47d262e91a4f 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -14,6 +14,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -29,6 +30,10 @@ struct TestAssign { static_assert(std::is_nothrow_assignable_v, T>); static_assert(!std::is_copy_assignable_v>); + + auto assign = [](std::atomic_ref const& y, T, T new_val) { y = new_val; }; + auto load = [](std::atomic_ref const& y) { return y.load(); }; + test_seq_cst(assign, load); } }; diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 18177c6cb99d1..4e38a6cc30195 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -16,6 +16,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -70,6 +71,145 @@ struct TestCompareExchangeStrong { ASSERT_NOEXCEPT(a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed)); } + + // success memory_order::release + { + auto store = [](std::atomic_ref const& x, T old_val, T new_val) { + auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order::relaxed); + assert(r); + }; + + auto load = [](std::atomic_ref const& x) { return x.load(std::memory_order::acquire); }; + test_acquire_release(store, load); + + auto store_one_arg = [](std::atomic_ref const& x, T old_val, T new_val) { + auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release); + assert(r); + }; + test_acquire_release(store_one_arg, load); + } + + // success memory_order::acquire + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; + + auto load = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order::relaxed)) { + } + return val; + }; + test_acquire_release(store, load); + + auto load_one_arg = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) { + } + return val; + }; + test_acquire_release(store, load_one_arg); + } + + // success memory_order::acq_rel + { + auto store = [](std::atomic_ref const& x, T old_val, T new_val) { + auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed); + assert(r); + }; + auto load = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) { + } + return val; + }; + test_acquire_release(store, load); + + auto store_one_arg = [](std::atomic_ref const& x, T old_val, T new_val) { + auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel); + assert(r); + }; + auto load_one_arg = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) { + } + return val; + }; + test_acquire_release(store_one_arg, load_one_arg); + } + + // success memory_oreder::seq_cst + { + auto store = [](std::atomic_ref const& x, T old_val, T new_val) { + auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed); + assert(r); + }; + auto load = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) { + } + return val; + }; + test_seq_cst(store, load); + + auto store_one_arg = [](std::atomic_ref const& x, T old_val, T new_val) { + auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst); + assert(r); + }; + auto load_one_arg = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst)) { + } + return val; + }; + test_seq_cst(store_one_arg, load_one_arg); + } + + // failure memory_order::acquire + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; + auto load = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = + x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire); + assert(!r); + return result; + }; + test_acquire_release(store, load); + + auto load_one_arg = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acquire); + assert(!r); + return result; + }; + test_acquire_release(store, load_one_arg); + + // acq_rel replaced by acquire + auto load_one_arg_acq_rel = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order::acq_rel); + assert(!r); + return result; + }; + test_acquire_release(store, load_one_arg_acq_rel); + } + + // failure memory_order::seq_cst + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); }; + auto load = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = + x.compare_exchange_strong(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst); + assert(!r); + return result; + }; + test_seq_cst(store, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index 13da04b746003..ec9d1d3880828 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -16,6 +16,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -70,6 +71,150 @@ struct TestCompareExchangeWeak { ASSERT_NOEXCEPT(a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed)); } + + // success memory_order::release + { + auto store = [](std::atomic_ref const& x, T old_val, T new_val) { + // could fail spuriously, so put it in a loop + while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release, std::memory_order::relaxed)) { + } + }; + + auto load = [](std::atomic_ref const& x) { return x.load(std::memory_order::acquire); }; + test_acquire_release(store, load); + + auto store_one_arg = [](std::atomic_ref const& x, T old_val, T new_val) { + // could fail spuriously, so put it in a loop + while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release)) { + } + }; + test_acquire_release(store_one_arg, load); + } + + // success memory_order::acquire + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; + auto load = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_weak(val, val, std::memory_order::acquire, std::memory_order::relaxed)) { + } + return val; + }; + test_acquire_release(store, load); + + auto load_one_arg = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_weak(val, val, std::memory_order::acquire)) { + } + return val; + }; + test_acquire_release(store, load_one_arg); + } + + // success memory_order::acq_rel + { + auto store = [](std::atomic_ref const& x, T old_val, T new_val) { + // could fail spuriously, so put it in a loop + while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel, std::memory_order::relaxed)) { + } + }; + auto load = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel, std::memory_order::relaxed)) { + } + return val; + }; + test_acquire_release(store, load); + + auto store_one_arg = [](std::atomic_ref const& x, T old_val, T new_val) { + // could fail spuriously, so put it in a loop + while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel)) { + } + }; + auto load_one_arg = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel)) { + } + return val; + }; + test_acquire_release(store_one_arg, load_one_arg); + } + + // success memory_order::seq_cst + { + auto store = [](std::atomic_ref const& x, T old_val, T new_val) { + // could fail spuriously, so put it in a loop + while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed)) { + } + }; + auto load = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order::relaxed)) { + } + return val; + }; + test_seq_cst(store, load); + + auto store_one_arg = [](std::atomic_ref const& x, T old_val, T new_val) { + // could fail spuriously, so put it in a loop + while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst)) { + } + }; + auto load_one_arg = [](std::atomic_ref const& x) { + auto val = x.load(std::memory_order::relaxed); + while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst)) { + } + return val; + }; + test_seq_cst(store_one_arg, load_one_arg); + } + + // failure memory_order::acquire + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; + auto load = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = + x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::acquire); + assert(!r); + return result; + }; + test_acquire_release(store, load); + + auto load_one_arg = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acquire); + assert(!r); + return result; + }; + test_acquire_release(store, load_one_arg); + + // acq_rel replaced by acquire + auto load_one_arg_acq_rel = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order::acq_rel); + assert(!r); + return result; + }; + test_acquire_release(store, load_one_arg_acq_rel); + } + + // failure memory_order::seq_cst + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); }; + auto load = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + T unexpected(T(255)); + bool r = + x.compare_exchange_weak(unexpected, unexpected, std::memory_order::relaxed, std::memory_order::seq_cst); + assert(!r); + return result; + }; + test_seq_cst(store, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index d72d56edab57c..2f5f64b5008aa 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -14,6 +14,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -29,6 +30,10 @@ struct TestConvert { ASSERT_NOEXCEPT(T(a)); static_assert(std::is_nothrow_convertible_v, T>); + + auto store = [](std::atomic_ref const& y, T, T new_val) { y.store(new_val); }; + auto load = [](std::atomic_ref const& y) { return static_cast(y); }; + test_seq_cst(store, load); } }; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index f90029046fdef..0d1ab2b079cfd 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -17,6 +17,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -72,6 +73,26 @@ struct TestFetchAdd { } else { static_assert(std::is_void_v); } + + // memory_order::release + { + auto fetch_add = [](std::atomic_ref const& x, T old_val, T new_val) { + x.fetch_add(new_val - old_val, std::memory_order::release); + }; + auto load = [](std::atomic_ref const& x) { return x.load(std::memory_order::acquire); }; + test_acquire_release(fetch_add, load); + } + + // memory_order::seq_cst + { + auto fetch_add_no_arg = [](std::atomic_ref const& x, T old_val, T new_val) { x.fetch_add(new_val - old_val); }; + auto fetch_add_with_order = [](std::atomic_ref const& x, T old_val, T new_val) { + x.fetch_add(new_val - old_val, std::memory_order::seq_cst); + }; + auto load = [](std::atomic_ref const& x) { return x.load(); }; + test_seq_cst(fetch_add_no_arg, load); + test_seq_cst(fetch_add_with_order, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 5d7abeecc804d..50c944b266c17 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -17,6 +17,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -72,6 +73,26 @@ struct TestFetchSub { } else { static_assert(std::is_void_v); } + + // memory_order::release + { + auto fetch_sub = [](std::atomic_ref const& x, T old_val, T new_val) { + x.fetch_sub(old_val - new_val, std::memory_order::release); + }; + auto load = [](std::atomic_ref const& x) { return x.load(std::memory_order::acquire); }; + test_acquire_release(fetch_sub, load); + } + + // memory_order::seq_cst + { + auto fetch_sub_no_arg = [](std::atomic_ref const& x, T old_val, T new_val) { x.fetch_sub(old_val - new_val); }; + auto fetch_sub_with_order = [](std::atomic_ref const& x, T old_val, T new_val) { + x.fetch_sub(old_val - new_val, std::memory_order::seq_cst); + }; + auto load = [](std::atomic_ref const& x) { return x.load(); }; + test_seq_cst(fetch_sub_no_arg, load); + test_seq_cst(fetch_sub_with_order, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index 3bb8342002ccf..6d11c572232c9 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -15,6 +15,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -34,6 +35,22 @@ struct TestLoad { assert(y == T(1)); ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); } + + // memory_order::seq_cst + { + auto store = [](std::atomic_ref const& y, T, T new_val) { y.store(new_val); }; + auto load_no_arg = [](std::atomic_ref const& y) { return y.load(); }; + auto load_with_order = [](std::atomic_ref const& y) { return y.load(std::memory_order::seq_cst); }; + test_seq_cst(store, load_no_arg); + test_seq_cst(store, load_with_order); + } + + // memory_order::release + { + auto store = [](std::atomic_ref const& y, T, T new_val) { y.store(new_val, std::memory_order::release); }; + auto load = [](std::atomic_ref const& y) { return y.load(std::memory_order::acquire); }; + test_acquire_release(store, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index e61ddacba06ba..759e3f8565de3 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -17,6 +17,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -51,6 +52,13 @@ struct TestOperatorMinusEquals { } else { static_assert(std::is_void_v); } + + // memory_order::seq_cst + { + auto minus_equals = [](std::atomic_ref const& x, T old_val, T new_val) { x -= (old_val - new_val); }; + auto load = [](std::atomic_ref const& x) { return x.load(); }; + test_seq_cst(minus_equals, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index b96294797cf4d..e61e7d25d0f2d 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -17,6 +17,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -51,6 +52,13 @@ struct TestOperatorPlusEquals { } else { static_assert(std::is_void_v); } + + // memory_order::seq_cst + { + auto plus_equals = [](std::atomic_ref const& x, T old_val, T new_val) { x += (new_val - old_val); }; + auto load = [](std::atomic_ref const& x) { return x.load(); }; + test_seq_cst(plus_equals, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp index 92e5a0b0ac1f0..e3f4769062adc 100644 --- a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -14,6 +14,7 @@ #include #include "atomic_helpers.h" +#include "test_helper.h" #include "test_macros.h" template @@ -29,6 +30,26 @@ struct TestStore { a.store(T(3), std::memory_order_seq_cst); assert(x == T(3)); ASSERT_NOEXCEPT(a.store(T(0), std::memory_order_seq_cst)); + + // TODO memory_order::relaxed + + // memory_order::seq_cst + { + auto store_no_arg = [](std::atomic_ref const& y, T, T new_val) { y.store(new_val); }; + auto store_with_order = [](std::atomic_ref const& y, T, T new_val) { + y.store(new_val, std::memory_order::seq_cst); + }; + auto load = [](std::atomic_ref const& y) { return y.load(); }; + test_seq_cst(store_no_arg, load); + test_seq_cst(store_with_order, load); + } + + // memory_order::release + { + auto store = [](std::atomic_ref const& y, T, T new_val) { y.store(new_val, std::memory_order::release); }; + auto load = [](std::atomic_ref const& y) { return y.load(std::memory_order::acquire); }; + test_acquire_release(store, load); + } } }; diff --git a/libcxx/test/std/atomics/atomics.ref/test_helper.h b/libcxx/test/std/atomics/atomics.ref/test_helper.h new file mode 100644 index 0000000000000..dc8cc10744ab0 --- /dev/null +++ b/libcxx/test/std/atomics/atomics.ref/test_helper.h @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_STD_ATOMICS_ATOMIC_REF_TEST_HELPER_H +#define TEST_STD_ATOMICS_ATOMIC_REF_TEST_HELPER_H + +#include +#include +#include +#include + +#include "test_macros.h" + +#ifndef TEST_HAS_NO_THREADS +# include "make_test_thread.h" +# include +#endif + +template +bool equals(T x, T y) { + return x == y; +} + +template +T make_value(int i) { + assert(i == 0 || i == 1); + if constexpr (std::is_pointer_v) { + // So that pointers returned can be subtracted from one another + static std::remove_const_t> d[2]; + return &d[i]; + } else { + return T(i); + } +} + +// Test that all threads see the exact same sequence of events +// Test will pass 100% if store_op and load_op are correctly +// affecting the memory with seq_cst order +template +void test_seq_cst(StoreOp store_op, LoadOp load_op) { +#ifndef TEST_HAS_NO_THREADS + for (int i = 0; i < 100; ++i) { + T old_value(make_value(0)); + T new_value(make_value(1)); + + T copy_x = old_value; + std::atomic_ref const x(copy_x); + T copy_y = old_value; + std::atomic_ref const y(copy_y); + + std::atomic_bool x_updated_first(false); + std::atomic_bool y_updated_first(false); + + auto t1 = support::make_test_thread([&] { store_op(x, old_value, new_value); }); + + auto t2 = support::make_test_thread([&] { store_op(y, old_value, new_value); }); + + auto t3 = support::make_test_thread([&] { + while (!equals(load_op(x), new_value)) { + std::this_thread::yield(); + } + if (!equals(load_op(y), new_value)) { + x_updated_first.store(true, std::memory_order_relaxed); + } + }); + + auto t4 = support::make_test_thread([&] { + while (!equals(load_op(y), new_value)) { + std::this_thread::yield(); + } + if (!equals(load_op(x), new_value)) { + y_updated_first.store(true, std::memory_order_relaxed); + } + }); + + t1.join(); + t2.join(); + t3.join(); + t4.join(); + // thread 3 and thread 4 cannot see different orders of storing x and y + assert(!(x_updated_first && y_updated_first)); + } +#else + (void)store_op; + (void)load_op; +#endif +} + +// Test that all writes before the store are seen by other threads after the load +// Test will pass 100% if store_op and load_op are correctly +// affecting the memory with acquire-release order +template +void test_acquire_release(StoreOp store_op, LoadOp load_op) { +#ifndef TEST_HAS_NO_THREADS + for (auto i = 0; i < 100; ++i) { + T old_value(make_value(0)); + T new_value(make_value(1)); + + T copy = old_value; + std::atomic_ref const at(copy); + int non_atomic = 5; + + constexpr auto number_of_threads = 8; + std::vector threads; + threads.reserve(number_of_threads); + + for (auto j = 0; j < number_of_threads; ++j) { + threads.push_back(support::make_test_thread([&at, &non_atomic, load_op, new_value] { + while (!equals(load_op(at), new_value)) { + std::this_thread::yield(); + } + // Other thread's writes before the release store are visible + // in this thread's read after the acquire load + assert(non_atomic == 6); + })); + } + + non_atomic = 6; + store_op(at, old_value, new_value); + + for (auto& thread : threads) { + thread.join(); + } + } +#else + (void)store_op; + (void)load_op; +#endif +} + +#endif // TEST_STD_ATOMICS_ATOMIC_REF_TEST_HELPER_H + diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index b763a94979eac..ccc97974e306e 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -15,6 +15,7 @@ #include "atomic_helpers.h" #include "make_test_thread.h" +#include "test_helper.h" #include "test_macros.h" template @@ -44,6 +45,34 @@ struct TestWait { assert(a.load() == T(5)); t2.join(); ASSERT_NOEXCEPT(a.wait(T(0), std::memory_order_seq_cst)); + + // memory_order::acquire + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val, std::memory_order::release); }; + auto load = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + x.wait(T(255), std::memory_order::acquire); + return result; + }; + test_acquire_release(store, load); + } + + // memory_order::seq_cst + { + auto store = [](std::atomic_ref const& x, T, T new_val) { x.store(new_val); }; + auto load_no_arg = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + x.wait(T(255)); + return result; + }; + auto load_with_order = [](std::atomic_ref const& x) { + auto result = x.load(std::memory_order::relaxed); + x.wait(T(255), std::memory_order::seq_cst); + return result; + }; + test_seq_cst(store, load_no_arg); + test_seq_cst(store, load_with_order); + } } }; From 8101affe3cd31d2cbb358a709f8f4cb684295996 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 29 Mar 2024 21:56:42 -0400 Subject: [PATCH 69/91] [libc++][atomic_ref] delete trailing empty line in test helper that clang-format didnt like --- libcxx/test/std/atomics/atomics.ref/test_helper.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libcxx/test/std/atomics/atomics.ref/test_helper.h b/libcxx/test/std/atomics/atomics.ref/test_helper.h index dc8cc10744ab0..225a70c5a16ca 100644 --- a/libcxx/test/std/atomics/atomics.ref/test_helper.h +++ b/libcxx/test/std/atomics/atomics.ref/test_helper.h @@ -134,4 +134,3 @@ void test_acquire_release(StoreOp store_op, LoadOp load_op) { } #endif // TEST_STD_ATOMICS_ATOMIC_REF_TEST_HELPER_H - From ef5fb5a070e5b9ec2585491b1752cfbb9afd53ef Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Sun, 31 Mar 2024 21:40:20 -0400 Subject: [PATCH 70/91] [libc++][atomic_ref] fix redeclaration of x shadow warning --- .../std/atomics/atomics.ref/wait.pass.cpp | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index ccc97974e306e..8201c62f010ab 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -21,30 +21,32 @@ template struct TestWait { void operator()() const { - T x(T(1)); - std::atomic_ref const a(x); + { + T x(T(1)); + std::atomic_ref const a(x); - assert(a.load() == T(1)); - a.wait(T(0)); - std::thread t1 = support::make_test_thread([&]() { - a.store(T(3)); - a.notify_one(); - }); - a.wait(T(1)); - assert(a.load() == T(3)); - t1.join(); - ASSERT_NOEXCEPT(a.wait(T(0))); + assert(a.load() == T(1)); + a.wait(T(0)); + std::thread t1 = support::make_test_thread([&]() { + a.store(T(3)); + a.notify_one(); + }); + a.wait(T(1)); + assert(a.load() == T(3)); + t1.join(); + ASSERT_NOEXCEPT(a.wait(T(0))); - assert(a.load() == T(3)); - a.wait(T(0), std::memory_order_seq_cst); - std::thread t2 = support::make_test_thread([&]() { - a.store(T(5)); - a.notify_one(); - }); - a.wait(T(3), std::memory_order_seq_cst); - assert(a.load() == T(5)); - t2.join(); - ASSERT_NOEXCEPT(a.wait(T(0), std::memory_order_seq_cst)); + assert(a.load() == T(3)); + a.wait(T(0), std::memory_order_seq_cst); + std::thread t2 = support::make_test_thread([&]() { + a.store(T(5)); + a.notify_one(); + }); + a.wait(T(3), std::memory_order_seq_cst); + assert(a.load() == T(5)); + t2.join(); + ASSERT_NOEXCEPT(a.wait(T(0), std::memory_order_seq_cst)); + } // memory_order::acquire { From 919e8c9a7b7de704735648decb1c1ed69cb68b2a Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 3 May 2024 13:06:35 -0400 Subject: [PATCH 71/91] [libc++][atomic_ref] Mark notify_{all,one}/wait test as unsupported with no threads --- libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index a19da3f8e40e5..4874204411fff 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: no-threads // void notify_all() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index 287522abfa728..ee47befd7cf46 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: no-threads // void notify_one() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index 8201c62f010ab..051401d9d3229 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: no-threads // void wait(T, memory_order = memory_order::seq_cst) const noexcept; From 6815d2b984a0777f9c04dcbbed3244515f5f6d80 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:01:06 -0400 Subject: [PATCH 72/91] [libc++][atomic_ref] Fixup AtomicRef status entry --- libcxx/docs/Status/Cxx20Papers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index 0516f2bf4acff..a42748ba27367 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -26,7 +26,7 @@ "`P0905R1 `__","CWG","Symmetry for spaceship","Jacksonville","|Complete|","7.0","|spaceship|" "`P0966R1 `__","LWG","``string::reserve``\ Should Not Shrink","Jacksonville","|Complete| [#note-P0966]_","12.0" "","","","","","","" -"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","[Complete]","19.0" +"`P0019R8 `__","LWG","Atomic Ref","Rapperswil","|Complete|","19.0" "`P0458R2 `__","LWG","Checking for Existence of an Element in Associative Containers","Rapperswil","|Complete|","13.0" "`P0475R1 `__","LWG","LWG 2511: guaranteed copy elision for piecewise construction","Rapperswil","|Complete|","" "`P0476R2 `__","LWG","Bit-casting object representations","Rapperswil","|Complete|","14.0" From 049b3d7a67d4771b33ca2fddcbb2997745cb3688 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:03:18 -0400 Subject: [PATCH 73/91] [libc++][atomic_ref] Also mark P1643R1 (add wait/notify to atomic_ref) as complete --- libcxx/docs/Status/Cxx20Papers.csv | 2 +- libcxx/include/__atomic/atomic_ref.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index a42748ba27367..8421392792941 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -125,7 +125,7 @@ "`P1612R1 `__","LWG","Relocate Endian's Specification","Cologne","|Complete|","10.0" "`P1614R2 `__","LWG","The Mothership has Landed","Cologne","|In Progress|","" "`P1638R1 `__","LWG","basic_istream_view::iterator should not be copyable","Cologne","|Complete|","16.0","|ranges|" -"`P1643R1 `__","LWG","Add wait/notify to atomic_ref","Cologne","","" +"`P1643R1 `__","LWG","Add wait/notify to atomic_ref","Cologne","|Complete|","19.0" "`P1644R0 `__","LWG","Add wait/notify to atomic","Cologne","","" "`P1650R0 `__","LWG","Output std::chrono::days with 'd' suffix","Cologne","|Complete|","16.0" "`P1651R0 `__","LWG","bind_front should not unwrap reference_wrapper","Cologne","|Complete|","13.0" diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index 9b0c83d72f415..bb4063869819b 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -62,7 +62,7 @@ struct __atomic_ref_base { _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { if constexpr ( # if __has_builtin(__builtin_clear_padding) - has_unique_object_representations_v<_Tp> || same_as<_Tp, float> || same_as<_Tp, double> + has_unique_object_representations_v<_Tp> || floating_point<_Tp> # else true // NOLINT(readability-simplify-boolean-expr) # endif From 505ddb58ce9bd2f96e71c4bb5044206ed8a8279b Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:17:13 -0400 Subject: [PATCH 74/91] [libc++][atomic_ref] Add empty line before the first REQUIRES --- .../atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp | 1 + .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 1 + libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 1 + libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 1 + libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 1 + libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 1 + 6 files changed, 6 insertions(+) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 34617364e0a6c..7c14cc975f4da 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index 8edd633449025..327889eb37351 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index c20fbbbf91b25..2330cc5de0bee 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index 54a399a16bed9..aa35ada636ecd 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index 44183fcb895e3..9e62d01bd1973 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index a9c960e27e04d..bdbbb8c38193f 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-hardening-mode=none || libcpp-hardening-mode=fast From a593fa070340b7af78e29f27b3ff1e18f81ba522 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:19:22 -0400 Subject: [PATCH 75/91] [libc++][atomic_ref] Add comment where no assertion is expected to fail --- .../atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp | 2 +- .../atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp | 2 +- libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 7c14cc975f4da..0c73356dbc685 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -25,7 +25,7 @@ template struct TestCompareExchangeStrongInvalidMemoryOrder { void operator()() const { - { + { // no assertion should trigger here T x(T(1)); std::atomic_ref const a(x); T t(T(2)); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index 327889eb37351..f0b00d4f5eb3e 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -25,7 +25,7 @@ template struct TestCompareExchangeWeakInvalidMemoryOrder { void operator()() const { - { + { // no assertion should trigger here T x(T(1)); std::atomic_ref const a(x); T t(T(2)); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index 2330cc5de0bee..2f6b4c08910bc 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -21,7 +21,7 @@ #include "check_assertion.h" int main(int, char**) { - { + { // no assertion should trigger here char c[8]; float* f = new (c) float(3.14f); [[maybe_unused]] std::atomic_ref r(*f); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index aa35ada636ecd..cacad816f4566 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -25,7 +25,7 @@ template struct TestLoadInvalidMemoryOrder { void operator()() const { - { + { // no assertion should trigger here T x(T(1)); std::atomic_ref const a(x); (void)a.load(std::memory_order_relaxed); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index 9e62d01bd1973..c66796cada47a 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -25,7 +25,7 @@ template struct TestStoreInvalidMemoryOrder { void operator()() const { - { + { // no assertion should trigger here T x(T(1)); std::atomic_ref const a(x); a.store(T(2), std::memory_order_relaxed); diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index bdbbb8c38193f..9d479f35ea98a 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -25,7 +25,7 @@ template struct TestWaitInvalidMemoryOrder { void operator()() const { - { + { // no assertion should trigger here T x(T(1)); std::atomic_ref const a(x); a.wait(T(2), std::memory_order_relaxed); From 0a033620a1e10a1ca394b99d65ac598fed33e13c Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:20:38 -0400 Subject: [PATCH 76/91] [libc++][atomic_ref] Prefer TestEachAtomicType --- .../assert.compare_exchange_strong.pass.cpp | 13 +------------ .../assert.compare_exchange_weak.pass.cpp | 13 +------------ .../libcxx/atomics/atomics.ref/assert.load.pass.cpp | 13 +------------ .../atomics/atomics.ref/assert.store.pass.cpp | 13 +------------ .../libcxx/atomics/atomics.ref/assert.wait.pass.cpp | 13 +------------ 5 files changed, 5 insertions(+), 60 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp index 0c73356dbc685..066ed1191dd05 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_strong.pass.cpp @@ -52,18 +52,7 @@ struct TestCompareExchangeStrongInvalidMemoryOrder { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestCompareExchangeStrongInvalidMemoryOrder()(); - TestCompareExchangeStrongInvalidMemoryOrder()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp index f0b00d4f5eb3e..e83a143df3f04 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.compare_exchange_weak.pass.cpp @@ -52,18 +52,7 @@ struct TestCompareExchangeWeakInvalidMemoryOrder { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestCompareExchangeWeakInvalidMemoryOrder()(); - TestCompareExchangeWeakInvalidMemoryOrder()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp index cacad816f4566..bc92b3dc36225 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.load.pass.cpp @@ -49,18 +49,7 @@ struct TestLoadInvalidMemoryOrder { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestLoadInvalidMemoryOrder()(); - TestLoadInvalidMemoryOrder()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp index c66796cada47a..ab0d4a220c94f 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.store.pass.cpp @@ -57,18 +57,7 @@ struct TestStoreInvalidMemoryOrder { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestStoreInvalidMemoryOrder()(); - TestStoreInvalidMemoryOrder()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp index 9d479f35ea98a..dcec2fb628545 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.wait.pass.cpp @@ -49,18 +49,7 @@ struct TestWaitInvalidMemoryOrder { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestWaitInvalidMemoryOrder()(); - TestWaitInvalidMemoryOrder()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } From 41b1effda9dcd554771dfff982c56f2dc9350783 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:21:29 -0400 Subject: [PATCH 77/91] [libc++][atomic_ref] Improve misaligned objects test --- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index 2f6b4c08910bc..e5225d76f82c9 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -17,20 +17,22 @@ // Preconditions: The referenced object is aligned to required_alignment. #include +#include #include "check_assertion.h" int main(int, char**) { { // no assertion should trigger here - char c[8]; + alignas(float) std::byte c[sizeof(float)]; float* f = new (c) float(3.14f); [[maybe_unused]] std::atomic_ref r(*f); } TEST_LIBCPP_ASSERT_FAILURE( ([] { + alignas(float) std::byte c[2 * sizeof(float)]; // intentionally larger char c[8]; - float* f = new (c + 1) float(3.14f); + float* f = new (c + 1) float(3.14f); // intentionally misaligned [[maybe_unused]] std::atomic_ref r(*f); }()), "atomic_ref ctor: referenced object must be aligned to required_alignment"); From 4279d70deccbb8c372db6d3aad9c9e38c3df01ab Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:24:04 -0400 Subject: [PATCH 78/91] [libc++][atomic_ref] Add a comment for the definition of is_always_lock_free --- libcxx/include/__atomic/atomic_ref.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libcxx/include/__atomic/atomic_ref.h b/libcxx/include/__atomic/atomic_ref.h index bb4063869819b..156f1961151c1 100644 --- a/libcxx/include/__atomic/atomic_ref.h +++ b/libcxx/include/__atomic/atomic_ref.h @@ -100,6 +100,10 @@ struct __atomic_ref_base { static constexpr size_t required_alignment = alignof(_Tp); + // The __atomic_always_lock_free builtin takes into account the alignment of the pointer if provided, + // so we create a fake pointer with a suitable alignment when querying it. Note that we are guaranteed + // that the pointer is going to be aligned properly at runtime because that is a (checked) precondition + // of atomic_ref's constructor. static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_Tp), reinterpret_cast(-required_alignment)); From 12ecd1d51483db32439e14bbdb08d7d6ac8ccd98 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Tue, 7 May 2024 22:43:05 -0400 Subject: [PATCH 79/91] [libc++][atomic_ref] Fix typo memory_or[e]der --- .../std/atomics/atomics.ref/compare_exchange_strong.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 4e38a6cc30195..8b30ea338cfcc 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -137,7 +137,7 @@ struct TestCompareExchangeStrong { test_acquire_release(store_one_arg, load_one_arg); } - // success memory_oreder::seq_cst + // success memory_order::seq_cst { auto store = [](std::atomic_ref const& x, T old_val, T new_val) { auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order::relaxed); From d7ff8c971056d754cc728a1b7b455812d60a3bbf Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 07:56:40 -0400 Subject: [PATCH 80/91] [libc++][atomic_ref] Inline test() into main and use TestEachAtomicType --- libcxx/test/std/atomics/atomics.ref/assign.pass.cpp | 13 +------------ .../atomics/atomics.ref/bitwise_and_assign.pass.cpp | 5 +---- .../atomics/atomics.ref/bitwise_or_assign.pass.cpp | 5 +---- .../atomics/atomics.ref/bitwise_xor_assign.pass.cpp | 6 ++---- .../atomics.ref/compare_exchange_strong.pass.cpp | 4 +--- .../atomics.ref/compare_exchange_weak.pass.cpp | 4 +--- .../test/std/atomics/atomics.ref/convert.pass.cpp | 13 +------------ libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp | 13 +------------ .../test/std/atomics/atomics.ref/deduction.pass.cpp | 13 +------------ .../test/std/atomics/atomics.ref/exchange.pass.cpp | 13 +------------ .../test/std/atomics/atomics.ref/fetch_add.pass.cpp | 5 +---- .../test/std/atomics/atomics.ref/fetch_and.pass.cpp | 6 +----- .../test/std/atomics/atomics.ref/fetch_or.pass.cpp | 5 +---- .../test/std/atomics/atomics.ref/fetch_sub.pass.cpp | 5 +---- .../test/std/atomics/atomics.ref/fetch_xor.pass.cpp | 5 +---- .../atomics.ref/increment_decrement.pass.cpp | 5 +---- libcxx/test/std/atomics/atomics.ref/load.pass.cpp | 13 +------------ .../std/atomics/atomics.ref/notify_all.pass.cpp | 4 +--- .../std/atomics/atomics.ref/notify_one.pass.cpp | 4 +--- .../atomics.ref/operator_minus_equals.pass.cpp | 5 +---- .../atomics.ref/operator_plus_equals.pass.cpp | 5 +---- libcxx/test/std/atomics/atomics.ref/store.pass.cpp | 13 +------------ libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 4 +--- 23 files changed, 24 insertions(+), 144 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index d47d262e91a4f..98652907fc7aa 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -37,18 +37,7 @@ struct TestAssign { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestAssign()(); - TestAssign()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index 4e60a1360df15..a77ad58e6e46e 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -40,7 +40,7 @@ struct TestBitwiseAndAssign { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -50,9 +50,6 @@ void test() { TestDoesNotHaveBitwiseAndAssign()(); TestDoesNotHaveBitwiseAndAssign()(); TestDoesNotHaveBitwiseAndAssign()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index a153c1c58725a..cc1251b30f5c7 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -40,7 +40,7 @@ struct TestBitwiseOrAssign { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -50,9 +50,6 @@ void test() { TestDoesNotHaveBitwiseOrAssign()(); TestDoesNotHaveBitwiseOrAssign()(); TestDoesNotHaveBitwiseOrAssign()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp index 42c758d50883b..7e4b79e451c05 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -40,18 +40,16 @@ struct TestBitwiseXorAssign { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); TestEachPointerType()(); + TestDoesNotHaveBitwiseXorAssign()(); TestDoesNotHaveBitwiseXorAssign()(); TestDoesNotHaveBitwiseXorAssign()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 8b30ea338cfcc..6b22757185ce4 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -213,9 +213,7 @@ struct TestCompareExchangeStrong { } }; -void test() { TestEachAtomicType()(); } - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index ec9d1d3880828..8ed313e0e5b5b 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -218,9 +218,7 @@ struct TestCompareExchangeWeak { } }; -void test() { TestEachAtomicType()(); } - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index 2f5f64b5008aa..e7ced1c1f360b 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -37,18 +37,7 @@ struct TestConvert { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestConvert()(); - TestConvert()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp index 0514a9c9310f9..d6c647406abf5 100644 --- a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp @@ -31,18 +31,7 @@ struct TestCtor { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestCtor()(); - TestCtor()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp index 03b8782f2db11..24a399ac4711e 100644 --- a/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/deduction.pass.cpp @@ -27,18 +27,7 @@ struct TestDeduction { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestDeduction()(); - TestDeduction()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index e88dba0cac143..ed97e04aefc97 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -37,18 +37,7 @@ struct TestExchange { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestExchange()(); - TestExchange()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index 0d1ab2b079cfd..bf7dd3cec20f8 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -96,7 +96,7 @@ struct TestFetchAdd { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -106,9 +106,6 @@ void test() { TestDoesNotHaveFetchAdd()(); TestDoesNotHaveFetchAdd()(); TestDoesNotHaveFetchAdd()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp index 588c2b41ace21..471fda4962d06 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -54,7 +54,7 @@ struct TestFetchAnd { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -64,9 +64,5 @@ void test() { TestDoesNotHaveFetchAnd()(); TestDoesNotHaveFetchAnd()(); TestDoesNotHaveFetchAnd()(); -} - -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp index 657eff5b1ca85..f6a329b7ecf6d 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -52,7 +52,7 @@ struct TestFetchOr { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -62,9 +62,6 @@ void test() { TestDoesNotHaveFetchOr()(); TestDoesNotHaveFetchOr()(); TestDoesNotHaveFetchOr()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 50c944b266c17..7ee5d138a0580 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -96,7 +96,7 @@ struct TestFetchSub { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -106,9 +106,6 @@ void test() { TestDoesNotHaveFetchSub()(); TestDoesNotHaveFetchSub()(); TestDoesNotHaveFetchSub()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index 4e7e29caac143..d1e29db787f4c 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -52,7 +52,7 @@ struct TestFetchXor { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -62,9 +62,6 @@ void test() { TestDoesNotHaveFetchXor()(); TestDoesNotHaveFetchXor()(); TestDoesNotHaveFetchXor()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index 2240b23b12501..d57d7295cbe5a 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -81,7 +81,7 @@ struct TestIncrementDecrement { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -91,9 +91,6 @@ void test() { TestDoesNotHaveIncrementDecrement()(); TestDoesNotHaveIncrementDecrement()(); TestDoesNotHaveIncrementDecrement()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index 6d11c572232c9..bab77eedefad7 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -54,18 +54,7 @@ struct TestLoad { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestLoad()(); - TestLoad()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 4874204411fff..dd56335f84553 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -69,9 +69,7 @@ struct TestNotifyAll { } }; -void test() { TestEachAtomicType()(); } - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index ee47befd7cf46..1fa5ee8767fcd 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -37,9 +37,7 @@ struct TestNotifyOne { } }; -void test() { TestEachAtomicType()(); } - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index 759e3f8565de3..91e96e06fe9a1 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -62,7 +62,7 @@ struct TestOperatorMinusEquals { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -72,9 +72,6 @@ void test() { TestDoesNotHaveOperatorMinusEquals()(); TestDoesNotHaveOperatorMinusEquals()(); TestDoesNotHaveOperatorMinusEquals()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index e61e7d25d0f2d..45e1704b9f857 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -62,7 +62,7 @@ struct TestOperatorPlusEquals { } }; -void test() { +int main(int, char**) { TestEachIntegralType()(); TestEachFloatingPointType()(); @@ -72,9 +72,6 @@ void test() { TestDoesNotHaveOperatorPlusEquals()(); TestDoesNotHaveOperatorPlusEquals()(); TestDoesNotHaveOperatorPlusEquals()(); -} -int main(int, char**) { - test(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp index e3f4769062adc..533257eb23220 100644 --- a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -53,18 +53,7 @@ struct TestStore { } }; -void test() { - TestEachIntegralType()(); - - TestEachFloatingPointType()(); - - TestEachPointerType()(); - - TestStore()(); - TestStore()(); -} - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index 051401d9d3229..df64336126e01 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -79,9 +79,7 @@ struct TestWait { } }; -void test() { TestEachAtomicType()(); } - int main(int, char**) { - test(); + TestEachAtomicType()(); return 0; } From 7492f36cd9eb81410cac246590d65b00edefb1ef Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 08:04:18 -0400 Subject: [PATCH 81/91] [libc++][atomic_ref] check return type with same_as decltype(auto) idiom --- libcxx/test/std/atomics/atomics.ref/assign.pass.cpp | 3 ++- .../std/atomics/atomics.ref/bitwise_and_assign.pass.cpp | 2 +- .../std/atomics/atomics.ref/bitwise_or_assign.pass.cpp | 2 +- .../std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp | 2 +- .../atomics/atomics.ref/compare_exchange_strong.pass.cpp | 6 +++--- .../atomics/atomics.ref/compare_exchange_weak.pass.cpp | 6 +++--- libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp | 8 ++++---- libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp | 4 ++-- libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp | 8 ++++---- libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp | 4 ++-- .../std/atomics/atomics.ref/increment_decrement.pass.cpp | 8 ++++---- .../std/atomics/atomics.ref/is_always_lock_free.pass.cpp | 5 +++-- libcxx/test/std/atomics/atomics.ref/load.pass.cpp | 4 ++-- .../atomics/atomics.ref/operator_minus_equals.pass.cpp | 4 ++-- .../std/atomics/atomics.ref/operator_plus_equals.pass.cpp | 4 ++-- .../std/atomics/atomics.ref/required_alignment.pass.cpp | 3 ++- 18 files changed, 42 insertions(+), 39 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index 98652907fc7aa..6e418e3e46df6 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -23,7 +23,8 @@ struct TestAssign { T x(T(1)); std::atomic_ref const a(x); - a = T(2); + std::same_as decltype(auto) y = (a = T(2)); + assert(y == T(2)); assert(x == T(2)); ASSERT_NOEXCEPT(a = T(0)); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index a77ad58e6e46e..e67065a10ffde 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -33,7 +33,7 @@ struct TestBitwiseAndAssign { T x(T(1)); std::atomic_ref const a(x); - std::same_as auto y = (a &= T(2)); + std::same_as decltype(auto) y = (a &= T(2)); assert(y == T(0)); assert(x == T(0)); ASSERT_NOEXCEPT(a &= T(0)); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index cc1251b30f5c7..8824c1c8659f6 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -33,7 +33,7 @@ struct TestBitwiseOrAssign { T x(T(1)); std::atomic_ref const a(x); - std::same_as auto y = (a |= T(2)); + std::same_as decltype(auto) y = (a |= T(2)); assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a &= T(0)); diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp index 7e4b79e451c05..ac4c55aeb517a 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -33,7 +33,7 @@ struct TestBitwiseXorAssign { T x(T(1)); std::atomic_ref const a(x); - std::same_as auto y = (a ^= T(2)); + std::same_as decltype(auto) y = (a ^= T(2)); assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a ^= T(0)); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 6b22757185ce4..4e4168ab96158 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -27,7 +27,7 @@ struct TestCompareExchangeStrong { std::atomic_ref const a(x); T t(T(1)); - std::same_as auto y = a.compare_exchange_strong(t, T(2)); + std::same_as decltype(auto) y = a.compare_exchange_strong(t, T(2)); assert(y == true); assert(a == T(2)); assert(t == T(1)); @@ -43,7 +43,7 @@ struct TestCompareExchangeStrong { std::atomic_ref const a(x); T t(T(1)); - std::same_as auto y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst); + std::same_as decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_seq_cst); assert(y == true); assert(a == T(2)); assert(t == T(1)); @@ -59,7 +59,7 @@ struct TestCompareExchangeStrong { std::atomic_ref const a(x); T t(T(1)); - std::same_as auto y = + std::same_as decltype(auto) y = a.compare_exchange_strong(t, T(2), std::memory_order_release, std::memory_order_relaxed); assert(y == true); assert(a == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index 8ed313e0e5b5b..2493ab8ee61df 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -27,7 +27,7 @@ struct TestCompareExchangeWeak { std::atomic_ref const a(x); T t(T(1)); - std::same_as auto y = a.compare_exchange_weak(t, T(2)); + std::same_as decltype(auto) y = a.compare_exchange_weak(t, T(2)); assert(y == true); assert(a == T(2)); assert(t == T(1)); @@ -43,7 +43,7 @@ struct TestCompareExchangeWeak { std::atomic_ref const a(x); T t(T(1)); - std::same_as auto y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst); + std::same_as decltype(auto) y = a.compare_exchange_weak(t, T(2), std::memory_order_seq_cst); assert(y == true); assert(a == T(2)); assert(t == T(1)); @@ -59,7 +59,7 @@ struct TestCompareExchangeWeak { std::atomic_ref const a(x); T t(T(1)); - std::same_as auto y = + std::same_as decltype(auto) y = a.compare_exchange_weak(t, T(2), std::memory_order_release, std::memory_order_relaxed); assert(y == true); assert(a == T(2)); diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index ed97e04aefc97..9353863c5ba9c 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -24,13 +24,13 @@ struct TestExchange { std::atomic_ref const a(x); { - std::same_as auto y = a.exchange(T(2)); + std::same_as decltype(auto) y = a.exchange(T(2)); assert(y == T(1)); ASSERT_NOEXCEPT(a.exchange(T(2))); } { - std::same_as auto y = a.exchange(T(3), std::memory_order_seq_cst); + std::same_as decltype(auto) y = a.exchange(T(3), std::memory_order_seq_cst); assert(y == T(2)); ASSERT_NOEXCEPT(a.exchange(T(3), std::memory_order_seq_cst)); } diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index bf7dd3cec20f8..c56f044c98220 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -39,14 +39,14 @@ struct TestFetchAdd { std::atomic_ref const a(x); { - std::same_as auto y = a.fetch_add(T(2)); + std::same_as decltype(auto) y = a.fetch_add(T(2)); assert(y == T(1)); assert(x == T(3)); ASSERT_NOEXCEPT(a.fetch_add(T(0))); } { - std::same_as auto y = a.fetch_add(T(4), std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_add(T(4), std::memory_order_relaxed); assert(y == T(3)); assert(x == T(7)); ASSERT_NOEXCEPT(a.fetch_add(T(0), std::memory_order_relaxed)); @@ -58,14 +58,14 @@ struct TestFetchAdd { std::atomic_ref const a(p); { - std::same_as auto y = a.fetch_add(2); + std::same_as decltype(auto) y = a.fetch_add(2); assert(y == &t[1]); assert(a == &t[3]); ASSERT_NOEXCEPT(a.fetch_add(0)); } { - std::same_as auto y = a.fetch_add(4, std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_add(4, std::memory_order_relaxed); assert(y == &t[3]); assert(a == &t[7]); ASSERT_NOEXCEPT(a.fetch_add(0, std::memory_order_relaxed)); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp index 471fda4962d06..6122dee98cba5 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -37,7 +37,7 @@ struct TestFetchAnd { std::atomic_ref const a(x); { - std::same_as auto y = a.fetch_and(T(2)); + std::same_as decltype(auto) y = a.fetch_and(T(2)); assert(y == T(1)); assert(x == T(0)); ASSERT_NOEXCEPT(a.fetch_and(T(0))); @@ -46,7 +46,7 @@ struct TestFetchAnd { x = T(1); { - std::same_as auto y = a.fetch_and(T(2), std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_and(T(2), std::memory_order_relaxed); assert(y == T(1)); assert(x == T(0)); ASSERT_NOEXCEPT(a.fetch_and(T(0), std::memory_order_relaxed)); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp index f6a329b7ecf6d..7d5fc8d57a8aa 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -37,14 +37,14 @@ struct TestFetchOr { std::atomic_ref const a(x); { - std::same_as auto y = a.fetch_or(T(2)); + std::same_as decltype(auto) y = a.fetch_or(T(2)); assert(y == T(1)); assert(x == T(3)); ASSERT_NOEXCEPT(a.fetch_or(T(0))); } { - std::same_as auto y = a.fetch_or(T(2), std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_or(T(2), std::memory_order_relaxed); assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a.fetch_or(T(0), std::memory_order_relaxed)); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 7ee5d138a0580..ce6ca5224318f 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -39,14 +39,14 @@ struct TestFetchSub { std::atomic_ref const a(x); { - std::same_as auto y = a.fetch_sub(T(4)); + std::same_as decltype(auto) y = a.fetch_sub(T(4)); assert(y == T(7)); assert(x == T(3)); ASSERT_NOEXCEPT(a.fetch_sub(T(0))); } { - std::same_as auto y = a.fetch_sub(T(2), std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_sub(T(2), std::memory_order_relaxed); assert(y == T(3)); assert(x == T(1)); ASSERT_NOEXCEPT(a.fetch_sub(T(0), std::memory_order_relaxed)); @@ -58,14 +58,14 @@ struct TestFetchSub { std::atomic_ref const a(p); { - std::same_as auto y = a.fetch_sub(4); + std::same_as decltype(auto) y = a.fetch_sub(4); assert(y == &t[7]); assert(a == &t[3]); ASSERT_NOEXCEPT(a.fetch_sub(0)); } { - std::same_as auto y = a.fetch_sub(2, std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_sub(2, std::memory_order_relaxed); assert(y == &t[3]); assert(a == &t[1]); ASSERT_NOEXCEPT(a.fetch_sub(0, std::memory_order_relaxed)); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index d1e29db787f4c..517710f15e838 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -37,14 +37,14 @@ struct TestFetchXor { std::atomic_ref const a(x); { - std::same_as auto y = a.fetch_xor(T(2)); + std::same_as decltype(auto) y = a.fetch_xor(T(2)); assert(y == T(1)); assert(x == T(3)); ASSERT_NOEXCEPT(a.fetch_xor(T(0))); } { - std::same_as auto y = a.fetch_xor(T(2), std::memory_order_relaxed); + std::same_as decltype(auto) y = a.fetch_xor(T(2), std::memory_order_relaxed); assert(y == T(3)); assert(x == T(1)); ASSERT_NOEXCEPT(a.fetch_xor(T(0), std::memory_order_relaxed)); diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index d57d7295cbe5a..65db7ac5cebb7 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -52,28 +52,28 @@ struct TestIncrementDecrement { std::atomic_ref const a(x); { - std::same_as auto y = ++a; + std::same_as decltype(auto) y = ++a; assert(y == T(2)); assert(x == T(2)); ASSERT_NOEXCEPT(++a); } { - std::same_as auto y = --a; + std::same_as decltype(auto) y = --a; assert(y == T(1)); assert(x == T(1)); ASSERT_NOEXCEPT(--a); } { - std::same_as auto y = a++; + std::same_as decltype(auto) y = a++; assert(y == T(1)); assert(x == T(2)); ASSERT_NOEXCEPT(a++); } { - std::same_as auto y = a--; + std::same_as decltype(auto) y = a--; assert(y == T(2)); assert(x == T(1)); ASSERT_NOEXCEPT(a--); diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index ef035a558b39f..711b4f526b913 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -21,8 +21,9 @@ template void check_always_lock_free(std::atomic_ref const a) { - if (std::atomic_ref::is_always_lock_free) { - std::same_as auto is_lock_free = a.is_lock_free(); + std::same_as decltype(auto) is_always_lock_free = std::atomic_ref::is_always_lock_free; + if (is_always_lock_free) { + std::same_as decltype(auto) is_lock_free = a.is_lock_free(); assert(is_lock_free); } ASSERT_NOEXCEPT(a.is_lock_free()); diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index bab77eedefad7..0a4ec95bc8caf 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -25,13 +25,13 @@ struct TestLoad { std::atomic_ref const a(x); { - std::same_as auto y = a.load(); + std::same_as decltype(auto) y = a.load(); assert(y == T(1)); ASSERT_NOEXCEPT(a.load()); } { - std::same_as auto y = a.load(std::memory_order_seq_cst); + std::same_as decltype(auto) y = a.load(std::memory_order_seq_cst); assert(y == T(1)); ASSERT_NOEXCEPT(a.load(std::memory_order_seq_cst)); } diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index 91e96e06fe9a1..efbbe949c15af 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -35,7 +35,7 @@ struct TestOperatorMinusEquals { T x(T(3)); std::atomic_ref const a(x); - std::same_as auto y = (a -= T(2)); + std::same_as decltype(auto) y = (a -= T(2)); assert(y == T(1)); assert(x == T(1)); ASSERT_NOEXCEPT(a -= T(0)); @@ -45,7 +45,7 @@ struct TestOperatorMinusEquals { T p{&t[3]}; std::atomic_ref const a(p); - std::same_as auto y = (a -= 2); + std::same_as decltype(auto) y = (a -= 2); assert(y == &t[1]); assert(a == &t[1]); ASSERT_NOEXCEPT(a -= 0); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index 45e1704b9f857..4b20b56769463 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -35,7 +35,7 @@ struct TestOperatorPlusEquals { T x(T(1)); std::atomic_ref const a(x); - std::same_as auto y = (a += T(2)); + std::same_as decltype(auto) y = (a += T(2)); assert(y == T(3)); assert(x == T(3)); ASSERT_NOEXCEPT(a += T(0)); @@ -45,7 +45,7 @@ struct TestOperatorPlusEquals { T p{&t[1]}; std::atomic_ref const a(p); - std::same_as auto y = (a += 2); + std::same_as decltype(auto) y = (a += 2); assert(y == &t[3]); assert(a == &t[3]); ASSERT_NOEXCEPT(a += 0); diff --git a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp index e595f27262aaf..d94998fc83d59 100644 --- a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp @@ -14,7 +14,8 @@ template constexpr void check_required_alignment() { - assert(std::atomic_ref::required_alignment >= alignof(T)); + std::same_as decltype(auto) required_alignment = std::atomic_ref::required_alignment; + assert(required_alignment >= alignof(T)); } constexpr bool test() { From 3d6645b182128d3e6d2b5c783378f0ce48f1e4ad Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 08:39:13 -0400 Subject: [PATCH 82/91] [libc++][atomic_ref] improve operator&= test --- .../std/atomics/atomics.ref/bitwise_and_assign.pass.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index e67065a10ffde..a674154da336b 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -33,10 +33,14 @@ struct TestBitwiseAndAssign { T x(T(1)); std::atomic_ref const a(x); - std::same_as decltype(auto) y = (a &= T(2)); + std::same_as decltype(auto) y = (a &= T(1)); + assert(y == T(1)); + assert(x == T(1)); + ASSERT_NOEXCEPT(a &= T(0)); + + y = (a &= T(2)); assert(y == T(0)); assert(x == T(0)); - ASSERT_NOEXCEPT(a &= T(0)); } }; From 75d3a665d691f3cd11ff49801a3fcbc0cd35e403 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 08:39:39 -0400 Subject: [PATCH 83/91] [libc++][atomic_ref] Fix typo in noexecpt check for operator|= --- libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index 8824c1c8659f6..1872f508f8e2c 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -36,7 +36,7 @@ struct TestBitwiseOrAssign { std::same_as decltype(auto) y = (a |= T(2)); assert(y == T(3)); assert(x == T(3)); - ASSERT_NOEXCEPT(a &= T(0)); + ASSERT_NOEXCEPT(a |= T(0)); } }; From 9b81d05a89d92d61c9451cc452a1db2a2f0f1253 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 08:41:41 -0400 Subject: [PATCH 84/91] [libc++][atomic_ref] Add missing header include --- libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp index d94998fc83d59..86e0cba4dbf02 100644 --- a/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/required_alignment.pass.cpp @@ -11,6 +11,7 @@ #include #include +#include template constexpr void check_required_alignment() { From 6ae8d85a5909d6201d571b5776da130ebed65436 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 09:05:29 -0400 Subject: [PATCH 85/91] [libc++][atomic_ref] Fix shadowed declaration warning --- .../std/atomics/atomics.ref/assign.pass.cpp | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index 6e418e3e46df6..a3a5e09179d03 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -20,21 +20,25 @@ template struct TestAssign { void operator()() const { - T x(T(1)); - std::atomic_ref const a(x); + { + T x(T(1)); + std::atomic_ref const a(x); - std::same_as decltype(auto) y = (a = T(2)); - assert(y == T(2)); - assert(x == T(2)); + std::same_as decltype(auto) y = (a = T(2)); + assert(y == T(2)); + assert(x == T(2)); - ASSERT_NOEXCEPT(a = T(0)); - static_assert(std::is_nothrow_assignable_v, T>); + ASSERT_NOEXCEPT(a = T(0)); + static_assert(std::is_nothrow_assignable_v, T>); - static_assert(!std::is_copy_assignable_v>); + static_assert(!std::is_copy_assignable_v>); + } - auto assign = [](std::atomic_ref const& y, T, T new_val) { y = new_val; }; - auto load = [](std::atomic_ref const& y) { return y.load(); }; - test_seq_cst(assign, load); + { + auto assign = [](std::atomic_ref const& y, T, T new_val) { y = new_val; }; + auto load = [](std::atomic_ref const& y) { return y.load(); }; + test_seq_cst(assign, load); + } } }; From 8fef446edc942260549bec2b1231880ed097fd86 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 10:07:12 -0400 Subject: [PATCH 86/91] [libc++][atomic_ref] Fix silly redefinition of a buffer of raw unitialized memory --- libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp index e5225d76f82c9..ef3705d1db275 100644 --- a/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp +++ b/libcxx/test/libcxx/atomics/atomics.ref/assert.ctor.pass.cpp @@ -31,8 +31,7 @@ int main(int, char**) { TEST_LIBCPP_ASSERT_FAILURE( ([] { alignas(float) std::byte c[2 * sizeof(float)]; // intentionally larger - char c[8]; - float* f = new (c + 1) float(3.14f); // intentionally misaligned + float* f = new (c + 1) float(3.14f); // intentionally misaligned [[maybe_unused]] std::atomic_ref r(*f); }()), "atomic_ref ctor: referenced object must be aligned to required_alignment"); From 856d2dd99c17dbdb83d276a203812c3699fefd73 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 11:48:23 -0400 Subject: [PATCH 87/91] [libc++][atomic_ref] Add XFAIL: !has-64-bit-atomics --- libcxx/test/std/atomics/atomics.ref/assign.pass.cpp | 1 + .../test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp | 1 + .../test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp | 1 + .../std/atomics/atomics.ref/compare_exchange_strong.pass.cpp | 1 + .../std/atomics/atomics.ref/compare_exchange_weak.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/convert.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp | 1 + .../test/std/atomics/atomics.ref/increment_decrement.pass.cpp | 1 + .../test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp | 3 ++- libcxx/test/std/atomics/atomics.ref/load.pass.cpp | 1 + .../std/atomics/atomics.ref/operator_minus_equals.pass.cpp | 1 + .../test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/store.pass.cpp | 1 + 20 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index a3a5e09179d03..5ca82b90b242f 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // T operator=(T) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp index a674154da336b..2be1e9962880c 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_and_assign.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type operator&=(integral-type) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp index 1872f508f8e2c..5c22c8a2b2b6c 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_or_assign.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type operator|=(integral-type) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp index ac4c55aeb517a..4dc4fd307f581 100644 --- a/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/bitwise_xor_assign.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type operator|=(integral-type) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 4e4168ab96158..00540fe0f877c 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept; // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index 2493ab8ee61df..aca22fccb56b0 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // bool compare_exchange_weak(T&, T, memory_order, memory_order) const noexcept; // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index e7ced1c1f360b..26e141b635d2a 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // operator T() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp index d6c647406abf5..ac0fea478ba66 100644 --- a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index 9353863c5ba9c..8c6019a0b408e 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // T exchange(T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index c56f044c98220..cbb9d917aba9d 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type fetch_add(integral-type, memory_order = memory_order::seq_cst) const noexcept; // floating-point-type fetch_add(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp index 6122dee98cba5..8f0bec21fe721 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_and.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type fetch_and(integral-type, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp index 7d5fc8d57a8aa..2045868fde425 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_or.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type fetch_or(integral-type, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index ce6ca5224318f..37f07044b0baa 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type fetch_sub(integral-type, memory_order = memory_order::seq_cst) const noexcept; // floating-point-type fetch_sub(floating-point-type, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp index 517710f15e838..aade87f961f1b 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_xor.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type fetch_xor(integral-type, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp index 65db7ac5cebb7..c84c89b4d2b4d 100644 --- a/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type operator++(int) const noexcept; // integral-type operator--(int) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index 711b4f526b913..1f59f8389b636 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -5,8 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// + // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index 0a4ec95bc8caf..456a3a0bf9ef9 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // T load(memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index efbbe949c15af..bb745a117533d 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type operator-=(integral-type) const noexcept; // floating-point-type operator-=(floating-point-type) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index 4b20b56769463..68611e2014570 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // integral-type operator+=(integral-type) const noexcept; // floating-point-type operator+=(floating-point-type) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp index 533257eb23220..740bd62801349 100644 --- a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -6,6 +6,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// XFAIL: !has-64-bit-atomics // void store(T, memory_order = memory_order::seq_cst) const noexcept; From e39d2615435906040a32684b3b2092dcbafb0d23 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 11:48:53 -0400 Subject: [PATCH 88/91] [libc++][atomic_ref] Add XFAIL: !has-64-bit-atomics and XFAIL: availability-synchronization_library-missing for wait/notify --- libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp | 2 ++ libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp | 2 ++ libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index dd56335f84553..46422df57b953 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -7,6 +7,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: no-threads +// XFAIL: availability-synchronization_library-missing +// XFAIL: !has-64-bit-atomics // void notify_all() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index 1fa5ee8767fcd..106e3d7145dd6 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -7,6 +7,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: no-threads +// XFAIL: availability-synchronization_library-missing +// XFAIL: !has-64-bit-atomics // void notify_one() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index df64336126e01..ee6e59ba5482f 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -7,6 +7,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: no-threads +// XFAIL: availability-synchronization_library-missing +// XFAIL: !has-64-bit-atomics // void wait(T, memory_order = memory_order::seq_cst) const noexcept; From ee8a50ea55e9c7ba70193c0e50f1c48ab19ebd6c Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Wed, 8 May 2024 23:17:05 -0400 Subject: [PATCH 89/91] [libc++][atomic_ref] Fixup fetch_{add,sub} do not use TestEachFloatingPointType --- libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp | 3 ++- libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp | 3 ++- .../std/atomics/atomics.ref/operator_minus_equals.pass.cpp | 3 ++- .../test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp index cbb9d917aba9d..908a6879bd066 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_add.pass.cpp @@ -100,7 +100,8 @@ struct TestFetchAdd { int main(int, char**) { TestEachIntegralType()(); - TestEachFloatingPointType()(); + TestFetchAdd()(); + TestFetchAdd()(); TestEachPointerType()(); diff --git a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp index 37f07044b0baa..545604530ada1 100644 --- a/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/fetch_sub.pass.cpp @@ -100,7 +100,8 @@ struct TestFetchSub { int main(int, char**) { TestEachIntegralType()(); - TestEachFloatingPointType()(); + TestFetchSub()(); + TestFetchSub()(); TestEachPointerType()(); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp index bb745a117533d..571d626035fac 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_minus_equals.pass.cpp @@ -66,7 +66,8 @@ struct TestOperatorMinusEquals { int main(int, char**) { TestEachIntegralType()(); - TestEachFloatingPointType()(); + TestOperatorMinusEquals()(); + TestOperatorMinusEquals()(); TestEachPointerType()(); diff --git a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp index 68611e2014570..de48ea56f57ff 100644 --- a/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/operator_plus_equals.pass.cpp @@ -66,7 +66,8 @@ struct TestOperatorPlusEquals { int main(int, char**) { TestEachIntegralType()(); - TestEachFloatingPointType()(); + TestOperatorPlusEquals()(); + TestOperatorPlusEquals()(); TestEachPointerType()(); From 47d3cde9ac61b63569c2a82d99a0086555e38172 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Thu, 9 May 2024 07:03:13 -0400 Subject: [PATCH 90/91] [libc++][atomic_ref] Add XFAIL: !has-1024-bit-atomics to "fix" the windows builds --- libcxx/test/std/atomics/atomics.ref/assign.pass.cpp | 1 + .../std/atomics/atomics.ref/compare_exchange_strong.pass.cpp | 1 + .../test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/convert.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/load.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/store.pass.cpp | 1 + libcxx/test/std/atomics/atomics.ref/wait.pass.cpp | 1 + 10 files changed, 10 insertions(+) diff --git a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp index 5ca82b90b242f..3887211752c6f 100644 --- a/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/assign.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // T operator=(T) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp index 00540fe0f877c..72b2f444c476c 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_strong.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // bool compare_exchange_strong(T&, T, memory_order, memory_order) const noexcept; // bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp index aca22fccb56b0..5219a8e3714f9 100644 --- a/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/compare_exchange_weak.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // bool compare_exchange_weak(T&, T, memory_order, memory_order) const noexcept; // bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp index 26e141b635d2a..2a58a5ea6ae2a 100644 --- a/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/convert.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // operator T() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp index 8c6019a0b408e..cd998d46b7e8f 100644 --- a/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/exchange.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // T exchange(T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp index 456a3a0bf9ef9..feed0fbaed842 100644 --- a/libcxx/test/std/atomics/atomics.ref/load.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/load.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // T load(memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp index 46422df57b953..382b19f8c1d78 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_all.pass.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: no-threads // XFAIL: availability-synchronization_library-missing // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // void notify_all() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp index 106e3d7145dd6..611e67417e4dc 100644 --- a/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/notify_one.pass.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: no-threads // XFAIL: availability-synchronization_library-missing // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // void notify_one() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp index 740bd62801349..ea01a3d02a34f 100644 --- a/libcxx/test/std/atomics/atomics.ref/store.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/store.pass.cpp @@ -7,6 +7,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // void store(T, memory_order = memory_order::seq_cst) const noexcept; diff --git a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp index ee6e59ba5482f..e5310febf5c5e 100644 --- a/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/wait.pass.cpp @@ -9,6 +9,7 @@ // UNSUPPORTED: no-threads // XFAIL: availability-synchronization_library-missing // XFAIL: !has-64-bit-atomics +// XFAIL: !has-1024-bit-atomics // void wait(T, memory_order = memory_order::seq_cst) const noexcept; From 9c85f188387ed70878286e257d3e38e5f720b2a6 Mon Sep 17 00:00:00 2001 From: Damien L-G Date: Fri, 10 May 2024 13:50:12 -0400 Subject: [PATCH 91/91] [libc++][atomic_ref] Attempt to drop XFAIL: !has-64-bit-atomics in a couple places to see if it fixes the Armv7-M picolibc builds --- libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp | 1 - libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp index ac0fea478ba66..d6c647406abf5 100644 --- a/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/ctor.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// XFAIL: !has-64-bit-atomics // diff --git a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp index 1f59f8389b636..94f65e3b4b669 100644 --- a/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp +++ b/libcxx/test/std/atomics/atomics.ref/is_always_lock_free.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// XFAIL: !has-64-bit-atomics //