From cf53dbab6a3ca27c17c1223d7e0757f683acd5fb Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 24 May 2024 01:40:51 +0800 Subject: [PATCH] Add member `difference_type` to `atomic` and its friends It seems intentional that `atomic(_ref)` are SFINAE-friendly on atomic pointer arithmetic. So this PR adds another mediate base class to avoid breaking the SFINAE-friendliness. Also updates the comments in `Dev11_0863628_atomic_compare_exchange/test.cpp` to cite WG21-N4981. --- stl/inc/atomic | 14 ++- .../test.cpp | 85 +++++++++++++-- tests/std/tests/P0019R8_atomic_ref/test.cpp | 101 +++++++++++++++--- 3 files changed, 177 insertions(+), 23 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 5944c9e5aa8..5f7e7300499 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -2122,14 +2122,24 @@ struct _Atomic_pointer<_Ty&> : _Atomic_storage<_Ty&> { } }; +template +struct _Atomic_nonobject_pointer : _Atomic_storage<_Ty> { + using _Base = _Atomic_storage<_Ty>; + using difference_type = ptrdiff_t; + + using _Base::_Base; +}; + #define ATOMIC_VAR_INIT(_Value) \ { _Value } template using _Choose_atomic_base2_t = typename _Select && !is_same_v>::template _Apply<_Atomic_integral_facade<_Ty>, - typename _Select && is_object_v>>::template _Apply< - _Atomic_pointer<_Ty>, _Atomic_storage<_Ty>>>; + typename _Select>::template _Apply< + typename _Select>>::template _Apply<_Atomic_pointer<_Ty>, + _Atomic_nonobject_pointer<_Ty>>, + _Atomic_storage<_Ty>>>; #if _HAS_CXX20 template diff --git a/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp b/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp index 82e8a7aba72..ac20085e433 100644 --- a/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp +++ b/tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -20,14 +21,18 @@ using namespace std; #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -// N3797 29.6.5 [atomics.types.operations.req]/21: -// bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile noexcept; -// bool A::compare_exchange_weak(C & expected, C desired, memory_order order = memory_order_seq_cst) noexcept; -// bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) volatile -// noexcept; bool A::compare_exchange_strong(C & expected, C desired, memory_order order = memory_order_seq_cst) -// noexcept; When only one memory_order argument is supplied, the value of success is order, and the value of failure is -// order except that a value of memory_order_acq_rel shall be replaced by the value memory_order_acquire and a value of -// memory_order_release shall be replaced by the value memory_order_relaxed. +// N4981 [atomics.types.operations]/23: +// bool compare_exchange_weak(T& expected, T desired, +// memory_order order = memory_order::seq_cst) volatile noexcept; +// bool compare_exchange_weak(T& expected, T desired, +// memory_order order = memory_order::seq_cst) noexcept; +// bool compare_exchange_strong(T& expected, T desired, +// memory_order order = memory_order::seq_cst) volatile noexcept; +// bool compare_exchange_strong(T& expected, T desired, +// memory_order order = memory_order::seq_cst) noexcept; +// When only one memory_order argument is supplied, the value of success is order, and the value of failure is order +// except that a value of memory_order::acq_rel shall be replaced by the value memory_order::acquire and a value of +// memory_order::release shall be replaced by the value memory_order::relaxed. template void test(T t) { @@ -553,6 +558,70 @@ void test_double_identical_results() { #endif // _HAS_CXX20 } +// Also test GH-4688 ": atomic_ref and atomic lack difference_type" +template +constexpr bool atomic_has_member_difference_type = false; +template +constexpr bool atomic_has_member_difference_type::difference_type>> = true; + +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, signed char>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, short>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, int>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, long>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, long long>); +STATIC_ASSERT(atomic_has_member_difference_type&& + is_same_v::difference_type, unsigned char>); +STATIC_ASSERT(atomic_has_member_difference_type&& + is_same_v::difference_type, unsigned short>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, unsigned int>); +STATIC_ASSERT(atomic_has_member_difference_type&& + is_same_v::difference_type, unsigned long>); +STATIC_ASSERT(atomic_has_member_difference_type&& + is_same_v::difference_type, unsigned long long>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, char>); +#ifdef __cpp_char8_t +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, char8_t>); +#endif // defined(__cpp_char8_t) +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, char16_t>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, char32_t>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, wchar_t>); + +#if _HAS_CXX20 // P0020R6 Floating Point Atomic +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, float>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, double>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, long double>); +#else // _HAS_CXX20 / !_HAS_CXX20 +STATIC_ASSERT(!atomic_has_member_difference_type); +STATIC_ASSERT(!atomic_has_member_difference_type); +STATIC_ASSERT(!atomic_has_member_difference_type); +#endif // ^^^ !_HAS_CXX20 ^^^ + +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); + +STATIC_ASSERT(atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT(atomic_has_member_difference_type&& + is_same_v::difference_type, ptrdiff_t>); +STATIC_ASSERT( + atomic_has_member_difference_type&& is_same_v::difference_type, ptrdiff_t>); + +STATIC_ASSERT(!atomic_has_member_difference_type); +STATIC_ASSERT(!atomic_has_member_difference_type); +STATIC_ASSERT(!atomic_has_member_difference_type>); +STATIC_ASSERT(!atomic_has_member_difference_type>); +STATIC_ASSERT(!atomic_has_member_difference_type>); + int main() { X x = {1729}; test(x); diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index a687cc97da1..7a06132a0d4 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -1,22 +1,9 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#if defined(TEST_CMPXCHG16B) && (defined(__clang__) || !defined(_M_X64)) -// Skip Clang because it would require the -mcx16 compiler option. -// Skip non-x64 because _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B is always 1 for ARM64, and is forbidden to be 1 for 32-bit. -int main() {} -#else // ^^^ skip test / run test vvv - #include -#include #include -#include -#include -#include -#include -#include #include -#include struct bigint { int value; @@ -40,6 +27,94 @@ struct int128 { } }; +// Also test GH-4688 ": atomic_ref and atomic lack difference_type" +template +constexpr bool atomic_ref_has_member_difference_type = requires { typename std::atomic_ref::difference_type; }; + +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, signed char>); +static_assert( + atomic_ref_has_member_difference_type && std::is_same_v::difference_type, short>); +static_assert(atomic_ref_has_member_difference_type && std::is_same_v::difference_type, int>); +static_assert( + atomic_ref_has_member_difference_type && std::is_same_v::difference_type, long>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, long long>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, unsigned char>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, unsigned short>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, unsigned int>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, unsigned long>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, unsigned long long>); +static_assert( + atomic_ref_has_member_difference_type && std::is_same_v::difference_type, char>); +#ifdef __cpp_char8_t +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, char8_t>); +#endif // defined(__cpp_char8_t) +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, char16_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, char32_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, wchar_t>); + +static_assert( + atomic_ref_has_member_difference_type && std::is_same_v::difference_type, float>); +static_assert( + atomic_ref_has_member_difference_type && std::is_same_v::difference_type, double>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, long double>); + +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); + +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); +static_assert(atomic_ref_has_member_difference_type + && std::is_same_v::difference_type, std::ptrdiff_t>); + +static_assert(!atomic_ref_has_member_difference_type); +static_assert(!atomic_ref_has_member_difference_type); +static_assert(!atomic_ref_has_member_difference_type); +static_assert(!atomic_ref_has_member_difference_type); + +#if defined(TEST_CMPXCHG16B) && (defined(__clang__) || !defined(_M_X64)) +// Skip Clang because it would require the -mcx16 compiler option. +// Skip non-x64 because _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B is always 1 for ARM64, and is forbidden to be 1 for 32-bit. +int main() {} +#else // ^^^ skip test / run test vvv + +#include +#include +#include +#include +#include +#include +#include + // code reuse of ../P1135R6_atomic_flag_test/test.cpp