diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1224,7 +1224,9 @@ #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 diff --git a/libcxx/include/atomic b/libcxx/include/atomic --- a/libcxx/include/atomic +++ b/libcxx/include/atomic @@ -136,11 +136,16 @@ }; template -struct atomic_ref +struct atomic_ref // since C++20 { static constexpr bool is_always_lock_free; static constexpr size_t required_alignment; + explicit atomic_ref(T& obj) noexcept; + atomic_ref(const atomic_ref&) noexcept; + T operator=(T desired) const noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + bool is_lock_free() const noexcept; void store(T desr, memory_order m = memory_order_seq_cst) const noexcept; T load(memory_order m = memory_order_seq_cst) const noexcept; @@ -153,17 +158,13 @@ memory_order m = memory_order_seq_cst) const noexcept; bool compare_exchange_strong(T& expc, T desr, memory_order m = memory_order_seq_cst) const noexcept; - - explicit atomic_ref(T& obj) noexcept; - atomic_ref(const atomic_ref&) noexcept; - T operator=(T desired) const noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; }; template <> struct atomic { static constexpr bool is_always_lock_free; + bool is_lock_free() const volatile noexcept; bool is_lock_free() const noexcept; void store(integral desr, memory_order m = memory_order_seq_cst) volatile noexcept; @@ -237,11 +238,16 @@ }; template <> -struct atomic_ref +struct atomic_ref // since C++20 { static constexpr bool is_always_lock_free; static constexpr size_t required_alignment; + explicit atomic_ref(integral& obj) noexcept; + atomic_ref(const atomic_ref&) noexcept; + integral operator=(integral desired) const noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + bool is_lock_free() const noexcept; void store(T desr, memory_order m = memory_order_seq_cst) const noexcept; integral load(memory_order m = memory_order_seq_cst) const noexcept; @@ -261,11 +267,6 @@ integral fetch_or(integral op, memory_order m = memory_order_seq_cst) const noexcept; integral fetch_xor(integral op, memory_order m = memory_order_seq_cst) const noexcept; - explicit atomic_ref(integral& obj) noexcept; - atomic_ref(const atomic_ref&) noexcept; - integral operator=(integral desired) const noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - integral operator++(int) const noexcept; integral operator--(int) const noexcept; integral operator++() const noexcept; @@ -335,11 +336,16 @@ }; template -struct atomic_ref +struct atomic_ref // since C++20 { static constexpr bool is_always_lock_free; static constexpr size_t required_alignment; + explicit atomic_ref(T* obj) noexcept; + atomic_ref(const atomic_ref&) noexcept; + T* operator=(T* desired) const noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + bool is_lock_free() const noexcept; void store(T* desr, memory_order m = memory_order_seq_cst) const noexcept; T* load(memory_order m = memory_order_seq_cst) const noexcept; @@ -356,11 +362,6 @@ T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept; T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept; - explicit atomic_ref(T* obj) noexcept; - atomic_ref(const atomic_ref&) noexcept; - T* operator=(T* desired) const noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - T* operator++(int) const noexcept; T* operator--(int) const noexcept; T* operator++() const noexcept; @@ -772,56 +773,20 @@ _Tp __a_value; }; -#elif defined(_LIBCPP_HAS_C_ATOMIC_IMP) - -template -struct __choose_atomic { - using type = _Atomic(_Tp); -}; - -template -struct __choose_underlying { - using type = _Tp; -}; - -template -struct __cxx_atomic_base_impl { - - _LIBCPP_INLINE_VISIBILITY -#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) {} - using __backing_atomic = typename conditional::value, __choose_underlying<_Tp>, __choose_atomic<_Tp>>::type::type; - using __contained_t = _Tp; - - _LIBCPP_DISABLE_EXTENSION_WARNING __backing_atomic __a_value; -}; - -#endif - -#if defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) || defined(_LIBCPP_HAS_C_ATOMIC_IMP) - -template class TemplateTp_> +template class _TemplateTp> struct __is_instantiation_of : false_type { }; -template class TemplateTp_> -struct __is_instantiation_of, TemplateTp_> : true_type {}; +template class _TemplateTp> +struct __is_instantiation_of<_TemplateTp<_Tp>, _TemplateTp> : true_type {}; -template ::type, __cxx_atomic_base_impl>::value, bool>::type> +template ::type, __cxx_atomic_base_impl>::value, bool>::type> struct __cxx_atomic_base_impl_traits { - static constexpr bool __is_value_volatile = is_volatile::value; - static constexpr bool __is_value_ref = is_reference::value; - using __underlying_t = typename remove_volatile::type>::type; + 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; }; -#endif - -#if defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) _LIBCPP_INLINE_VISIBILITY 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: @@ -981,143 +946,7 @@ #define __cxx_atomic_is_lock_free(__s) __atomic_is_lock_free(__s, 0) -#elif defined(_LIBCPP_HAS_C_ATOMIC_IMP) - -#define __cxx_atomic_is_lock_free(__s) __c11_atomic_is_lock_free(__s) - -_LIBCPP_INLINE_VISIBILITY inline -void __cxx_atomic_thread_fence(memory_order __order) _NOEXCEPT { - __c11_atomic_thread_fence(static_cast<__memory_order_underlying_t>(__order)); -} - -_LIBCPP_INLINE_VISIBILITY inline -void __cxx_atomic_signal_fence(memory_order __order) _NOEXCEPT { - __c11_atomic_signal_fence(static_cast<__memory_order_underlying_t>(__order)); -} - -template -struct __annotate_with_qualifiers { - using __const_qualified = typename conditional::value, const Tp_, Tp_>::type; - using __type = typename conditional::value, volatile __const_qualified, __const_qualified>::type; -}; - -template::__is_value_ref, bool>::type = 0> -_LIBCPP_INLINE_VISIBILITY inline -typename __annotate_with_qualifiers<_Atomic(typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t), _Tp>::__type* -__cxx_atomic_pointer_to_data(_Tp* __value) { - return &__value->__a_value; -} - -template::__is_value_ref, bool>::type = 0> -_LIBCPP_INLINE_VISIBILITY inline -typename __annotate_with_qualifiers<_Atomic(typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t), _Tp>::__type* -__cxx_atomic_pointer_to_data(_Tp* __value) { - return reinterpret_cast::__underlying_t), _Tp>::__type*>(&__value->__a_value); -} - -template -_LIBCPP_INLINE_VISIBILITY -void __cxx_atomic_init(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val) _NOEXCEPT { - __c11_atomic_init(__cxx_atomic_pointer_to_data(__a), __val); -} - -template -_LIBCPP_INLINE_VISIBILITY -void __cxx_atomic_store(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __val, memory_order __order) _NOEXCEPT { - __c11_atomic_store(__cxx_atomic_pointer_to_data(__a), __val, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_INLINE_VISIBILITY -typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_load(_Tp const* __a, memory_order __order) _NOEXCEPT { - auto __ptr_to_atomic_val = __cxx_atomic_pointer_to_data(__a); - using __ptr_type = typename remove_const::type; - return __c11_atomic_load(const_cast<__ptr_type>(__ptr_to_atomic_val), static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_INLINE_VISIBILITY -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) _NOEXCEPT { - return __c11_atomic_exchange(__cxx_atomic_pointer_to_data(__a), __value, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_INLINE_VISIBILITY 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, - memory_order __success, memory_order __failure) _NOEXCEPT { - return __c11_atomic_compare_exchange_strong( - __cxx_atomic_pointer_to_data(__a), __expected, __value, - static_cast<__memory_order_underlying_t>(__success), - static_cast<__memory_order_underlying_t>(__failure)); -} - -template -_LIBCPP_INLINE_VISIBILITY -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, - memory_order __success, memory_order __failure) _NOEXCEPT { - return __c11_atomic_compare_exchange_weak(__cxx_atomic_pointer_to_data(__a), __expected, __value, - static_cast<__memory_order_underlying_t>(__success), - static_cast<__memory_order_underlying_t>(__failure)); -} - -template::__is_value_pointer, bool>::type = 0> -_LIBCPP_INLINE_VISIBILITY -typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_fetch_add(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __delta, - memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_add(__cxx_atomic_pointer_to_data(__a), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template::__is_value_pointer, bool>::type = 0> -_LIBCPP_INLINE_VISIBILITY -typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_fetch_add(_Tp* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_add(__cxx_atomic_pointer_to_data(__a), __delta, static_cast<__memory_order_underlying_t>(__order)); -} - -template::__is_value_pointer, bool>::type = 0> -_LIBCPP_INLINE_VISIBILITY -typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_fetch_sub(_Tp* __a, typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t __delta, - memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_sub(__cxx_atomic_pointer_to_data(__a), __delta, static_cast<__memory_order_underlying_t>(__order)); -} -template::__is_value_pointer, bool>::type = 0> -_LIBCPP_INLINE_VISIBILITY -typename __cxx_atomic_base_impl_traits<_Tp>::__underlying_t -__cxx_atomic_fetch_sub(_Tp* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { - return __c11_atomic_fetch_sub(__cxx_atomic_pointer_to_data(__a), __delta, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_INLINE_VISIBILITY -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) _NOEXCEPT { - return __c11_atomic_fetch_and(__cxx_atomic_pointer_to_data(__a), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_INLINE_VISIBILITY -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) _NOEXCEPT { - return __c11_atomic_fetch_or(__cxx_atomic_pointer_to_data(__a), __pattern, static_cast<__memory_order_underlying_t>(__order)); -} - -template -_LIBCPP_INLINE_VISIBILITY -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) _NOEXCEPT { - return __c11_atomic_fetch_xor(__cxx_atomic_pointer_to_data(__a), __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 template _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/test/std/atomics/atomics.types.generic/address.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/address.pass.cpp --- a/libcxx/test/std/atomics/atomics.types.generic/address.pass.cpp +++ b/libcxx/test/std/atomics/atomics.types.generic/address.pass.cpp @@ -143,6 +143,11 @@ static constexpr bool is_always_lock_free; static constexpr size_t required_alignment; + explicit atomic_ref(T* obj) noexcept; + atomic_ref(const atomic_ref&) noexcept; + T* operator=(T* desired) const noexcept; + atomic_ref& operator=(const atomic_ref&) = delete; + bool is_lock_free() const noexcept; void store(T* desr, memory_order m = memory_order_seq_cst) const noexcept; T* load(memory_order m = memory_order_seq_cst) const noexcept; @@ -159,11 +164,6 @@ T* fetch_add(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept; T* fetch_sub(ptrdiff_t op, memory_order m = memory_order_seq_cst) noexcept; - explicit atomic_ref(T* obj) noexcept; - atomic_ref(const atomic_ref&) noexcept; - T* operator=(T* desired) const noexcept; - atomic_ref& operator=(const atomic_ref&) = delete; - T* operator++(int) const noexcept; T* operator--(int) const noexcept; T* operator++() const noexcept; diff --git a/libcxx/test/std/atomics/atomics.types.generic/assign_to_atomic_ref_deleted.fail.cpp b/libcxx/test/std/atomics/atomics.types.generic/assign_to_atomic_ref_deleted.fail.cpp --- a/libcxx/test/std/atomics/atomics.types.generic/assign_to_atomic_ref_deleted.fail.cpp +++ b/libcxx/test/std/atomics/atomics.types.generic/assign_to_atomic_ref_deleted.fail.cpp @@ -13,7 +13,12 @@ // { // static constexpr bool is_always_lock_free; // static constexpr size_t required_alignment; - +// +// explicit atomic_ref(T& obj) noexcept; +// atomic_ref(const atomic_ref&) noexcept; +// T operator=(T desired) const noexcept; +// atomic_ref& operator=(const atomic_ref&) = delete; +// // bool is_lock_free() const noexcept; // void store(T desr, memory_order m = memory_order_seq_cst) const noexcept; // T load(memory_order m = memory_order_seq_cst) const noexcept; @@ -26,11 +31,6 @@ // memory_order m = memory_order_seq_cst) const noexcept; // bool compare_exchange_strong(T& expc, T desr, // memory_order m = memory_order_seq_cst) const noexcept; - -// explicit atomic_ref(T& obj) noexcept; -// atomic_ref(const atomic_ref&) noexcept; -// T operator=(T desired) const noexcept; -// atomic_ref& operator=(const atomic_ref&) = delete; // }; #include @@ -41,7 +41,7 @@ int val = 1; std::atomic_ref t0(val); std::atomic_ref t1(val); - t0 = t1; + t0 = t1; // expected-error {{object of type 'std::atomic_ref' cannot be assigned because its copy assignment operator is implicitly deleted}} return 0; } diff --git a/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable.pass.cpp --- a/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable.pass.cpp +++ b/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable.pass.cpp @@ -57,7 +57,12 @@ // { // static constexpr bool is_always_lock_free; // static constexpr size_t required_alignment; - +// +// explicit atomic_ref(T& obj) noexcept; +// atomic_ref(const atomic_ref&) noexcept; +// T operator=(T desired) const noexcept; +// atomic_ref& operator=(const atomic_ref&) = delete; +// // bool is_lock_free() const noexcept; // void store(T desr, memory_order m = memory_order_seq_cst) const noexcept; // T load(memory_order m = memory_order_seq_cst) const noexcept; @@ -70,11 +75,6 @@ // memory_order m = memory_order_seq_cst) const noexcept; // bool compare_exchange_strong(T& expc, T desr, // memory_order m = memory_order_seq_cst) const noexcept; - -// explicit atomic_ref(T& obj) noexcept; -// atomic_ref(const atomic_ref&) noexcept; -// T operator=(T desired) const noexcept; -// atomic_ref& operator=(const atomic_ref&) = delete; // }; #include diff --git a/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable_ref.fail.cpp b/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable_ref.fail.cpp --- a/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable_ref.fail.cpp +++ b/libcxx/test/std/atomics/atomics.types.generic/trivially_copyable_ref.fail.cpp @@ -45,9 +45,9 @@ int i_; }; -template +template void test(T t) { - std::atomic_ref t0(t); + std::atomic_ref t0(t); // expected-error@atomic:* {{static_assert failed due to requirement 'is_trivially_copyable::value' "std::atomic_ref<_Tp> requires that '_Tp' be a trivially copyable type"}} } int main(int, char**) {