From 9070ced534874ec53355702a592a5964501467d0 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 30 Dec 2024 19:44:13 +0800 Subject: [PATCH 01/13] Implement P3323R1 --- stl/inc/atomic | 208 +++++++++++------- stl/inc/yvals_core.h | 4 + tests/libcxx/expected_results.txt | 3 + tests/std/tests/P0019R8_atomic_ref/test.cpp | 223 ++++++++++++++++---- 4 files changed, 324 insertions(+), 114 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 9f4da0a47e3..7801e874abe 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -473,7 +473,7 @@ void _Atomic_wait_direct( const _Value_type _Observed_bytes = _STD _Atomic_reinterpret_as<_Value_type>(_This->load(_Order)); if (_Expected_bytes != _Observed_bytes) { #if _CMPXCHG_MASK_OUT_PADDING_BITS - using _TVal = remove_reference_t<_Ty>; + using _TVal = _Remove_cvref_t<_Ty>; if constexpr (_Might_have_non_value_bits<_TVal>) { _Storage_for<_TVal> _Mask{_Form_mask}; const _Value_type _Mask_val = _STD _Atomic_reinterpret_as<_Value_type>(_Mask._Ref()); @@ -581,7 +581,7 @@ struct _Atomic_storage { // Provides operations common to all specializations of std::atomic, load, store, exchange, and CAS. // Locking version used when hardware has no atomic operations for sizeof(_Ty). - using _TVal = remove_reference_t<_Ty>; + using _TVal = _Remove_cvref_t<_Ty>; using _Guard = _Atomic_lock_guard::_Spinlock>; _Atomic_storage() = default; @@ -713,7 +713,7 @@ public: template struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics - using _TVal = remove_reference_t<_Ty>; + using _TVal = _Remove_cvref_t<_Ty>; _Atomic_storage() = default; @@ -814,7 +814,7 @@ struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics template struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics - using _TVal = remove_reference_t<_Ty>; + using _TVal = _Remove_cvref_t<_Ty>; _Atomic_storage() = default; @@ -914,7 +914,7 @@ struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics template struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics - using _TVal = remove_reference_t<_Ty>; + using _TVal = _Remove_cvref_t<_Ty>; _Atomic_storage() = default; @@ -1014,7 +1014,7 @@ struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics template struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics - using _TVal = remove_reference_t<_Ty>; + using _TVal = _Remove_cvref_t<_Ty>; _Atomic_storage() = default; @@ -1135,7 +1135,7 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics template struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics // TRANSITION, ABI: replace '_Ty&' with '_Ty' in this specialization - using _TVal = remove_reference_t<_Ty&>; + using _TVal = _Remove_cvref_t<_Ty&>; _Atomic_storage() = default; @@ -1615,11 +1615,17 @@ constexpr bool _Deprecate_non_lock_free_volatile = true; template _CXX20_DEPRECATE_VOLATILE constexpr bool _Deprecate_non_lock_free_volatile<_Ty, false> = true; +#if _HAS_CXX20 +#define _REQUIRES_CLAUSE(...) requires (__VA_ARGS__) +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv +#define _REQUIRES_CLAUSE(...) +#endif // ^^^ !_HAS_CXX20 ^^^ + template struct _Atomic_integral_facade : _Atomic_integral<_Ty> { // provides operator overloads and other support for atomic integral specializations using _Base = _Atomic_integral<_Ty>; - using difference_type = _Ty; + using difference_type = remove_cv_t<_Ty>; using _Base::_Base; @@ -1747,87 +1753,88 @@ template struct _Atomic_integral_facade<_Ty&> : _Atomic_integral<_Ty&> { // provides operator overloads and other support for atomic integral specializations using _Base = _Atomic_integral<_Ty&>; - using difference_type = _Ty; + using difference_type = remove_cv_t<_Ty>; + using typename _Base::_TVal; using _Base::_Base; - _NODISCARD static _Ty _Negate(const _Ty _Value) noexcept { // returns two's complement negated value of _Value - return static_cast<_Ty>(0U - static_cast>(_Value)); + _NODISCARD static _TVal _Negate(const _TVal _Value) noexcept { // returns two's complement negated value of _Value + return static_cast<_TVal>(0U - static_cast>(_Value)); } - _Ty fetch_add(const _Ty _Operand) const noexcept { + _TVal fetch_add(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand); } - _Ty fetch_add(const _Ty _Operand, const memory_order _Order) const noexcept { + _TVal fetch_add(const _TVal _Operand, const memory_order _Order) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_add(_Operand, _Order); } - _Ty fetch_sub(const _Ty _Operand) const noexcept { + _TVal fetch_sub(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(_Negate(_Operand)); } - _Ty fetch_sub(const _Ty _Operand, const memory_order _Order) const noexcept { + _TVal fetch_sub(const _TVal _Operand, const memory_order _Order) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(_Negate(_Operand), _Order); } - _Ty operator++(int) const noexcept { + _TVal operator++(int) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(0); } - _Ty operator++() const noexcept { + _TVal operator++() const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::operator++(); } - _Ty operator--(int) const noexcept { + _TVal operator--(int) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(0); } - _Ty operator--() const noexcept { + _TVal operator--() const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::operator--(); } - _Ty operator+=(const _Ty _Operand) const noexcept { + _TVal operator+=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return static_cast<_Ty>(fetch_add(_Operand) + _Operand); } - _Ty operator-=(const _Ty _Operand) const noexcept { + _TVal operator-=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return static_cast<_Ty>(fetch_sub(_Operand) - _Operand); } - _Ty fetch_and(const _Ty _Operand) const noexcept { + _TVal fetch_and(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand); } - _Ty fetch_and(const _Ty _Operand, const memory_order _Order) const noexcept { + _TVal fetch_and(const _TVal _Operand, const memory_order _Order) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_and(_Operand, _Order); } - _Ty fetch_or(const _Ty _Operand) const noexcept { + _TVal fetch_or(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand); } - _Ty fetch_or(const _Ty _Operand, const memory_order _Order) const noexcept { + _TVal fetch_or(const _TVal _Operand, const memory_order _Order) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_or(_Operand, _Order); } - _Ty fetch_xor(const _Ty _Operand) const noexcept { + _TVal fetch_xor(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand); } - _Ty fetch_xor(const _Ty _Operand, const memory_order _Order) const noexcept { + _TVal fetch_xor(const _TVal _Operand, const memory_order _Order) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return const_cast<_Atomic_integral_facade*>(this)->_Base::fetch_xor(_Operand, _Order); } - _Ty operator&=(const _Ty _Operand) const noexcept { + _TVal operator&=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return static_cast<_Ty>(fetch_and(_Operand) & _Operand); } - _Ty operator|=(const _Ty _Operand) const noexcept { + _TVal operator|=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return static_cast<_Ty>(fetch_or(_Operand) | _Operand); } - _Ty operator^=(const _Ty _Operand) const noexcept { + _TVal operator^=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return static_cast<_Ty>(fetch_xor(_Operand) ^ _Operand); } }; @@ -1837,7 +1844,7 @@ template struct _Atomic_floating : _Atomic_storage<_Ty> { // provides atomic floating-point operations using _Base = _Atomic_storage<_Ty>; - using difference_type = _Ty; + using difference_type = remove_cv_t<_Ty>; using _Base::_Base; @@ -1891,12 +1898,15 @@ template struct _Atomic_floating<_Ty&> : _Atomic_storage<_Ty&> { // provides atomic floating-point operations using _Base = _Atomic_storage<_Ty&>; - using difference_type = _Ty; + using difference_type = remove_cv_t<_Ty>; + using typename _Base::_TVal; using _Base::_Base; - _Ty fetch_add(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) const noexcept { - _Ty _Temp{this->load(memory_order_relaxed)}; + _TVal fetch_add(const _TVal _Operand, const memory_order _Order = memory_order_seq_cst) const noexcept + requires (!is_const_v<_Ty>) + { + _TVal _Temp{this->load(memory_order_relaxed)}; while (!const_cast<_Atomic_floating*>(this)->_Base::compare_exchange_strong( _Temp, _Temp + _Operand, _Order)) { // keep trying } @@ -1904,8 +1914,10 @@ struct _Atomic_floating<_Ty&> : _Atomic_storage<_Ty&> { return _Temp; } - _Ty fetch_sub(const _Ty _Operand, const memory_order _Order = memory_order_seq_cst) const noexcept { - _Ty _Temp{this->load(memory_order_relaxed)}; + _TVal fetch_sub(const _TVal _Operand, const memory_order _Order = memory_order_seq_cst) const noexcept + requires (!is_const_v<_Ty>) + { + _TVal _Temp{this->load(memory_order_relaxed)}; while (!const_cast<_Atomic_floating*>(this)->_Base::compare_exchange_strong( _Temp, _Temp - _Operand, _Order)) { // keep trying } @@ -1913,11 +1925,15 @@ struct _Atomic_floating<_Ty&> : _Atomic_storage<_Ty&> { return _Temp; } - _Ty operator+=(const _Ty _Operand) const noexcept { + _TVal operator+=(const _TVal _Operand) const noexcept + requires (!is_const_v<_Ty>) + { return fetch_add(_Operand) + _Operand; } - _Ty operator-=(const _Ty _Operand) const noexcept { + _TVal operator-=(const _TVal _Operand) const noexcept + requires (!is_const_v<_Ty>) + { return fetch_sub(_Operand) - _Operand; } }; @@ -2023,10 +2039,12 @@ template struct _Atomic_pointer<_Ty&> : _Atomic_storage<_Ty&> { using _Base = _Atomic_storage<_Ty&>; using difference_type = ptrdiff_t; + using typename _Base::_TVal; using _Base::_Base; - _Ty fetch_add(const ptrdiff_t _Diff, const memory_order _Order = memory_order_seq_cst) const noexcept { + _TVal fetch_add(const ptrdiff_t _Diff, const memory_order _Order = memory_order_seq_cst) const noexcept + _REQUIRES_CLAUSE(!is_const_v<_Ty>) { const ptrdiff_t _Shift_bytes = static_cast(static_cast(_Diff) * sizeof(remove_pointer_t<_Ty>)); ptrdiff_t _Result; @@ -2040,39 +2058,42 @@ struct _Atomic_pointer<_Ty&> : _Atomic_storage<_Ty&> { return reinterpret_cast<_Ty>(_Result); } - _Ty fetch_sub(const ptrdiff_t _Diff) const noexcept { + _TVal fetch_sub(const ptrdiff_t _Diff) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(static_cast(0 - static_cast(_Diff))); } - _Ty fetch_sub(const ptrdiff_t _Diff, const memory_order _Order) const noexcept { + _TVal fetch_sub(const ptrdiff_t _Diff, const memory_order _Order) const noexcept + _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(static_cast(0 - static_cast(_Diff)), _Order); } - _Ty operator++(int) const noexcept { + _TVal operator++(int) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(1); } - _Ty operator++() const noexcept { + _TVal operator++() const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(1) + 1; } - _Ty operator--(int) const noexcept { + _TVal operator--(int) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(-1); } - _Ty operator--() const noexcept { + _TVal operator--() const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(-1) - 1; } - _Ty operator+=(const ptrdiff_t _Diff) const noexcept { + _TVal operator+=(const ptrdiff_t _Diff) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(_Diff) + _Diff; } - _Ty operator-=(const ptrdiff_t _Diff) const noexcept { + _TVal operator-=(const ptrdiff_t _Diff) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { return fetch_add(static_cast(0 - static_cast(_Diff))) - _Diff; } }; +#undef _REQUIRES_CLAUSE + template struct _Atomic_nonobject_pointer : _Atomic_storage<_Ty> { using _Base = _Atomic_storage<_Ty>; @@ -2081,15 +2102,22 @@ struct _Atomic_nonobject_pointer : _Atomic_storage<_Ty> { using _Base::_Base; }; +template +struct _Atomic_nonobject_pointer<_Ty&> : _Atomic_storage<_Ty&> { + using _Base = _Atomic_storage<_Ty&>; + + 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>::template _Apply< - typename _Select>>::template _Apply<_Atomic_pointer<_Ty>, - _Atomic_nonobject_pointer<_Ty>>, - _Atomic_storage<_Ty>>>; + typename _Select && !is_same_v>>::template _Apply< + _Atomic_integral_facade<_Ty>, typename _Select>::template _Apply< + typename _Select>>::template _Apply< + _Atomic_pointer<_Ty>, _Atomic_nonobject_pointer<_Ty>>, + _Atomic_storage<_Ty>>>; #if _HAS_CXX20 template @@ -2106,10 +2134,13 @@ private: using _Base = _Choose_atomic_base_t<_Ty>; public: - static_assert(is_trivially_copyable_v<_Ty> && is_copy_constructible_v<_Ty> && is_move_constructible_v<_Ty> - && is_copy_assignable_v<_Ty> && is_move_assignable_v<_Ty>, - "atomic requires T to be trivially copyable, copy constructible, move constructible, copy assignable, " - "and move assignable."); + static_assert(is_trivially_copyable_v<_Ty>, "atomic requires T to be trivially copyable."); + static_assert(is_copy_constructible_v<_Ty>, "atomic requires T to be copy constructible."); + static_assert(is_move_constructible_v<_Ty>, "atomic requires T to be move constructible."); + static_assert(is_copy_assignable_v<_Ty>, "atomic requires T to be copy assignable."); + static_assert(is_move_assignable_v<_Ty>, "atomic requires T to be move assignable."); + static_assert(!is_const_v<_Ty>, "atomic requires T to be non-const."); + static_assert(!is_volatile_v<_Ty>, "atomic requires T to be non-volatile."); using value_type = _Ty; @@ -2276,7 +2307,7 @@ private: public: static_assert(is_trivially_copyable_v<_Ty>, "atomic_ref requires T to be trivially copyable."); - using value_type = _Ty; + using value_type = remove_cv_t<_Ty>; explicit atomic_ref(_Ty& _Value) noexcept /* strengthened */ : _Base(_Value) { if constexpr (is_always_lock_free) { @@ -2295,66 +2326,97 @@ public: static constexpr size_t required_alignment = is_always_lock_free ? sizeof(_Ty) : alignof(_Ty); + static_assert(is_always_lock_free || !is_volatile_v<_Ty>, + "atomic_ref requires T to be non-volatile when it is not always lock-free."); + _NODISCARD bool is_lock_free() const noexcept { return is_always_lock_free; } - void store(const _Ty _Value) const noexcept { + void store(const value_type _Value) const noexcept + requires (!is_const_v<_Ty>) + { const_cast(this)->_Base::store(_Value); } - void store(const _Ty _Value, const memory_order _Order) const noexcept { + void store(const value_type _Value, const memory_order _Order) const noexcept + requires (!is_const_v<_Ty>) + { const_cast(this)->_Base::store(_Value, _Order); } - _Ty operator=(const _Ty _Value) const noexcept { + value_type operator=(const value_type _Value) const noexcept + requires (!is_const_v<_Ty>) + { store(_Value); return _Value; } - _Ty exchange(const _Ty _Value) const noexcept { + value_type exchange(const value_type _Value) const noexcept + requires (!is_const_v<_Ty>) + { return const_cast(this)->_Base::exchange(_Value); } - _Ty exchange(const _Ty _Value, const memory_order _Order) const noexcept { + value_type exchange(const value_type _Value, const memory_order _Order) const noexcept + requires (!is_const_v<_Ty>) + { return const_cast(this)->_Base::exchange(_Value, _Order); } - bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired) const noexcept { + bool compare_exchange_strong(value_type& _Expected, const value_type _Desired) const noexcept + requires (!is_const_v<_Ty>) + { return const_cast(this)->_Base::compare_exchange_strong(_Expected, _Desired); } - bool compare_exchange_strong(_Ty& _Expected, const _Ty _Desired, const memory_order _Order) const noexcept { + bool compare_exchange_strong( + value_type& _Expected, const value_type _Desired, const memory_order _Order) const noexcept + requires (!is_const_v<_Ty>) + { return const_cast(this)->_Base::compare_exchange_strong(_Expected, _Desired, _Order); } - bool compare_exchange_strong( - _Ty& _Expected, const _Ty _Desired, const memory_order _Success, const memory_order _Failure) const noexcept { + bool compare_exchange_strong(value_type& _Expected, const value_type _Desired, const memory_order _Success, + const memory_order _Failure) const noexcept + requires (!is_const_v<_Ty>) + { return compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } - bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired) const noexcept { + bool compare_exchange_weak(value_type& _Expected, const value_type _Desired) const noexcept + requires (!is_const_v<_Ty>) + { return compare_exchange_strong(_Expected, _Desired); } - bool compare_exchange_weak(_Ty& _Expected, const _Ty _Desired, const memory_order _Order) const noexcept { + bool compare_exchange_weak( + value_type& _Expected, const value_type _Desired, const memory_order _Order) const noexcept + requires (!is_const_v<_Ty>) + { return compare_exchange_strong(_Expected, _Desired, _Order); } - bool compare_exchange_weak( - _Ty& _Expected, const _Ty _Desired, const memory_order _Success, const memory_order _Failure) const noexcept { + bool compare_exchange_weak(value_type& _Expected, const value_type _Desired, const memory_order _Success, + const memory_order _Failure) const noexcept + requires (!is_const_v<_Ty>) + { return compare_exchange_strong(_Expected, _Desired, _Combine_cas_memory_orders(_Success, _Failure)); } - operator _Ty() const noexcept { + operator value_type() const noexcept { return this->load(); } - void notify_one() const noexcept { + void notify_one() const noexcept + requires (!is_const_v<_Ty>) + { const_cast(this)->_Base::notify_one(); } - void notify_all() const noexcept { + void notify_all() const noexcept + requires (!is_const_v<_Ty>) + { const_cast(this)->_Base::notify_all(); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index ce83ff45727..5f3c4a3f1f3 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -80,6 +80,8 @@ // (__cpp_lib_freestanding_algorithm and __cpp_lib_freestanding_array only) // P2937R0 Freestanding Library: Remove strtok // P2968R2 Make std::ignore A First-Class Object +// P3323R1 Forbid atomic, Specify atomic_ref +// (for atomic) // _HAS_CXX17 directly controls: // P0005R4 not_fn() @@ -315,6 +317,8 @@ // P2909R4 Fix Formatting Of Code Units As Integers // P2997R1 Removing The Common Reference Requirement From The Indirectly Invocable Concepts // P3136R1 Retiring Niebloids +// P3323R1 Forbid atomic, Specify atomic_ref +// (for atomic_ref) // _HAS_CXX20 indirectly controls: // P0619R4 Removing C++17-Deprecated Features diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3329d34b8f1..cdb0473ae6b 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -126,6 +126,9 @@ std/language.support/support.limits/support.limits.general/mdspan.version.compil # libc++ has not implemented P2937R0: "Freestanding Library: Remove strtok" std/language.support/support.limits/support.limits.general/cstring.version.compile.pass.cpp FAIL +# libc++ has not implemented P3323R1: "Forbid atomic, Specify atomic_ref" +std/atomics/atomics.ref/member_types.compile.pass.cpp FAIL + # Various bogosity (LLVM-D141004), warning C6011: Dereferencing NULL pointer # Note: The :1 (ASan) configuration doesn't run static analysis. std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp:0 FAIL diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 8edf08cfd9e..e304cfca17b 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -34,50 +34,191 @@ struct int128 { } }; -// Also test GH-4688 ": atomic_ref and atomic lack difference_type" +// Also test constraints and conditional existance of difference_type specified by +// P3323R1 "Forbid atomic, Specify atomic_ref". + +template +void test_atomic_ref_constraints_single() { // COMPILE-ONLY + using TD = std::remove_cv_t; + using AR = std::atomic_ref; + + static_assert(std::is_same_v); + static_assert(requires(const AR& r, std::memory_order ord) { + r.operator TD(); + { r.load() } -> std::same_as; + { r.load(ord) } -> std::same_as; + }); + + if constexpr (!std::is_const_v) { + static_assert(requires(const AR& r, TD v, TD& vx, std::memory_order ord1, std::memory_order ord2) { + { r.store(v) } -> std::same_as; + { r.store(v, ord1) } -> std::same_as; + { r = v } -> std::same_as; + { r.exchange(v) } -> std::same_as; + { r.exchange(v, ord1) } -> std::same_as; + { r.compare_exchange_weak(vx, v) } -> std::same_as; + { r.compare_exchange_weak(vx, v, ord1) } -> std::same_as; + { r.compare_exchange_weak(vx, v, ord1, ord2) } -> std::same_as; + { r.compare_exchange_strong(vx, v) } -> std::same_as; + { r.compare_exchange_strong(vx, v, ord1) } -> std::same_as; + { r.compare_exchange_strong(vx, v, ord1, ord2) } -> std::same_as; + { r.notify_one() } -> std::same_as; + { r.notify_all() } -> std::same_as; + }); + } else { + static_assert(!requires(const AR& r, TD v) { r.store(v); }); + static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.store(v, ord); }); + static_assert(!requires(const AR& r, TD v) { r = v; }); + static_assert(!requires(const AR& r, TD v) { r.exchange(v); }); + static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.exchange(v, ord); }); + static_assert(!requires(const AR& r, TD& v1, TD v2) { r.compare_exchange_weak(v1, v2); }); + static_assert( + !requires(const AR& r, TD& v1, TD v2, std::memory_order ord) { r.compare_exchange_weak(v1, v2, ord); }); + static_assert(!requires(const AR& r, TD& v1, TD v2, std::memory_order ord1, std::memory_order ord2) { + r.compare_exchange_weak(v1, v2, ord1, ord2); + }); + static_assert(!requires(const AR& r, TD& v1, TD v2) { r.compare_exchange_strong(v1, v2); }); + static_assert( + !requires(const AR& r, TD& v1, TD v2, std::memory_order ord) { r.compare_exchange_strong(v1, v2, ord); }); + static_assert(!requires(const AR& r, TD& v1, TD v2, std::memory_order ord1, std::memory_order ord2) { + r.compare_exchange_strong(v1, v2, ord1, ord2); + }); + static_assert(!requires(const AR& r) { r.notify_one(); }); + static_assert(!requires(const AR& r) { r.notify_all(); }); + } + + constexpr bool has_difference_type = (std::is_arithmetic_v && !std::is_same_v) + || (std::is_pointer_v && std::is_object_v>); + + if constexpr (has_difference_type) { + if constexpr (std::is_arithmetic_v) { + static_assert(std::is_same_v); + } else { + static_assert(std::is_same_v); + } + } else { + static_assert(!requires { typename AR::difference_type; }); + } + + if constexpr (has_difference_type && !std::is_const_v) { + static_assert(requires(const AR& r, AR::difference_type d, std::memory_order ord) { + { r.fetch_add(d) } -> std::same_as; + { r.fetch_add(d, ord) } -> std::same_as; + { r.fetch_sub(d) } -> std::same_as; + { r.fetch_sub(d, ord) } -> std::same_as; + { r += d } -> std::same_as; + { r -= d } -> std::same_as; + }); + } else { + static_assert(!requires(const AR& r, AR::difference_type d) { r.fetch_add(d); }); + static_assert(!requires(const AR& r, AR::difference_type d, std::memory_order ord) { r.fetch_add(d, ord); }); + static_assert(!requires(const AR& r, AR::difference_type d) { r.fetch_sub(d); }); + static_assert(!requires(const AR& r, AR::difference_type d, std::memory_order ord) { r.fetch_sub(d, ord); }); + static_assert(!requires(const AR& r, AR::difference_type d) { r += d; }); + static_assert(!requires(const AR& r, AR::difference_type d) { r -= d; }); + } + + if constexpr (has_difference_type && !std::is_floating_point_v && !std::is_const_v) { + static_assert(requires(const AR& r) { + { ++r } -> std::same_as; + { r++ } -> std::same_as; + { --r } -> std::same_as; + { r-- } -> std::same_as; + }); + } else { + static_assert(!requires(const AR& r) { ++r; }); + static_assert(!requires(const AR& r) { r++; }); + static_assert(!requires(const AR& r) { --r; }); + static_assert(!requires(const AR& r) { r--; }); + } + + if constexpr (std::is_integral_v && !std::is_same_v && !std::is_const_v) { + static_assert(requires(const AR& r, TD v, std::memory_order ord) { + { r.fetch_and(v) } -> std::same_as; + { r.fetch_and(v, ord) } -> std::same_as; + { r.fetch_or(v) } -> std::same_as; + { r.fetch_or(v, ord) } -> std::same_as; + { r.fetch_xor(v) } -> std::same_as; + { r.fetch_xor(v, ord) } -> std::same_as; + { r &= v } -> std::same_as; + { r |= v } -> std::same_as; + { r ^= v } -> std::same_as; + }); + } else { + static_assert(!requires(const AR& r, TD v) { r.fetch_and(v); }); + static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.fetch_and(v, ord); }); + static_assert(!requires(const AR& r, TD v) { r.fetch_or(v); }); + static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.fetch_or(v, ord); }); + static_assert(!requires(const AR& r, TD v) { r.fetch_xor(v); }); + static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.fetch_xor(v, ord); }); + static_assert(!requires(const AR& r, TD v) { r &= v; }); + static_assert(!requires(const AR& r, TD v) { r |= v; }); + static_assert(!requires(const AR& r, TD v) { r ^= v; }); + } +} + template -constexpr bool atomic_ref_has_member_difference_type = requires { typename std::atomic_ref::difference_type; }; - -static_assert(std::is_same_v::difference_type, signed char>); -static_assert(std::is_same_v::difference_type, short>); -static_assert(std::is_same_v::difference_type, int>); -static_assert(std::is_same_v::difference_type, long>); -static_assert(std::is_same_v::difference_type, long long>); -static_assert(std::is_same_v::difference_type, unsigned char>); -static_assert(std::is_same_v::difference_type, unsigned short>); -static_assert(std::is_same_v::difference_type, unsigned int>); -static_assert(std::is_same_v::difference_type, unsigned long>); -static_assert(std::is_same_v::difference_type, unsigned long long>); -static_assert(std::is_same_v::difference_type, char>); +void test_atomic_ref_constraints_cv() { // COMPILE-ONLY + static_assert(!std::is_const_v && !std::is_volatile_v); + test_atomic_ref_constraints_single(); + test_atomic_ref_constraints_single(); + if constexpr (std::atomic_ref::is_always_lock_free) { + test_atomic_ref_constraints_single(); + test_atomic_ref_constraints_single(); + } +} + +void test_atomic_ref_constraints() { // COMPILE-ONLY + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); #ifdef __cpp_char8_t -static_assert(std::is_same_v::difference_type, char8_t>); + test_atomic_ref_constraints_cv(); #endif // defined(__cpp_char8_t) -static_assert(std::is_same_v::difference_type, char16_t>); -static_assert(std::is_same_v::difference_type, char32_t>); -static_assert(std::is_same_v::difference_type, wchar_t>); - -static_assert(std::is_same_v::difference_type, float>); -static_assert(std::is_same_v::difference_type, double>); -static_assert(std::is_same_v::difference_type, long double>); - -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); - -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(std::is_same_v::difference_type, std::ptrdiff_t>); -static_assert(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); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); +} // code reuse of ../P1135R6_atomic_flag_test/test.cpp From b2503e525d3228e20d79a3bef6244a7f73bbef1e Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 9 Jan 2025 02:29:12 +0800 Subject: [PATCH 02/13] Necessary `const_cast` and test coverage for instantiation --- stl/inc/atomic | 39 +++++++++----- tests/std/tests/P0019R8_atomic_ref/test.cpp | 58 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 7801e874abe..b374f944dcc 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -468,7 +468,8 @@ struct _Atomic_storage; template void _Atomic_wait_direct( const _Atomic_storage<_Ty>* const _This, _Value_type _Expected_bytes, const memory_order _Order) noexcept { - const auto _Storage_ptr = _STD addressof(_This->_Storage); + const auto _Storage_ptr = + const_cast(static_cast(_STD addressof(_This->_Storage))); for (;;) { const _Value_type _Observed_bytes = _STD _Atomic_reinterpret_as<_Value_type>(_This->load(_Order)); if (_Expected_bytes != _Observed_bytes) { @@ -801,11 +802,13 @@ struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics } void notify_one() noexcept { - ::__std_atomic_notify_one_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_one_direct(_Storage_ptr); } void notify_all() noexcept { - ::__std_atomic_notify_all_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_all_direct(_Storage_ptr); } #endif // _HAS_CXX20 @@ -901,11 +904,13 @@ struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics } void notify_one() noexcept { - ::__std_atomic_notify_one_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_one_direct(_Storage_ptr); } void notify_all() noexcept { - ::__std_atomic_notify_all_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_all_direct(_Storage_ptr); } #endif // _HAS_CXX20 @@ -1001,11 +1006,13 @@ struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics } void notify_one() noexcept { - ::__std_atomic_notify_one_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_one_direct(_Storage_ptr); } void notify_all() noexcept { - ::__std_atomic_notify_all_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_all_direct(_Storage_ptr); } #endif // _HAS_CXX20 @@ -1120,11 +1127,13 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics } void notify_one() noexcept { - ::__std_atomic_notify_one_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_one_direct(_Storage_ptr); } void notify_all() noexcept { - ::__std_atomic_notify_all_direct(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_all_direct(_Storage_ptr); } #endif // _HAS_CXX20 @@ -1252,8 +1261,8 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics &_Expected_temp._Low); #else // ^^^ _M_ARM64, _M_ARM64EC / _M_X64 vvv (void) _Order; - _Result = _InterlockedCompareExchange128( - &reinterpret_cast(_Storage), _Desired_bytes._High, _Desired_bytes._Low, &_Expected_temp._Low); + _Result = _InterlockedCompareExchange128(&reinterpret_cast(_Storage), _Desired_bytes._High, + _Desired_bytes._Low, &_Expected_temp._Low); #endif // ^^^ _M_X64 ^^^ if (_Result == 0) { _CSTD memcpy(_STD addressof(_Expected), &_Expected_temp, sizeof(_TVal)); @@ -1264,7 +1273,7 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics #if _HAS_CXX20 void wait(_TVal _Expected, memory_order _Order = memory_order_seq_cst) const noexcept { - const auto _Storage_ptr = _STD addressof(_Storage); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); const auto _Expected_ptr = _STD addressof(_Expected); _Int128 _Expected_bytes = reinterpret_cast(_Expected); @@ -1294,11 +1303,13 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics } void notify_one() noexcept { - ::__std_atomic_notify_one_indirect(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_one_indirect(_Storage_ptr); } void notify_all() noexcept { - ::__std_atomic_notify_all_indirect(_STD addressof(_Storage)); + const auto _Storage_ptr = const_cast(static_cast(_STD addressof(_Storage))); + ::__std_atomic_notify_all_indirect(_Storage_ptr); } #endif // _HAS_CXX20 diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index e304cfca17b..78fb068b20e 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -43,11 +43,22 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY using AR = std::atomic_ref; static_assert(std::is_same_v); - static_assert(requires(const AR& r, std::memory_order ord) { + static_assert(requires(const AR& r, TD v, std::memory_order ord) { r.operator TD(); { r.load() } -> std::same_as; { r.load(ord) } -> std::same_as; + { r.wait(v) } -> std::same_as; + { r.wait(v, ord) } -> std::same_as; }); + { + [[maybe_unused]] auto instantiator = [](const AR& r, TD v, std::memory_order ord) { + (void) r.operator TD(); + (void) r.load(); + (void) r.load(ord); + r.wait(v); + r.wait(v, ord); + }; + } if constexpr (!std::is_const_v) { static_assert(requires(const AR& r, TD v, TD& vx, std::memory_order ord1, std::memory_order ord2) { @@ -65,6 +76,23 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY { r.notify_one() } -> std::same_as; { r.notify_all() } -> std::same_as; }); + + [[maybe_unused]] auto instantiator = [](const AR& r, TD v, TD& vx, std::memory_order ord1, + std::memory_order ord2) { + (void) r.store(v); + (void) r.store(v, ord1); + (void) (r = v); + (void) r.exchange(v); + (void) r.exchange(v, ord1); + (void) r.compare_exchange_weak(vx, v); + (void) r.compare_exchange_weak(vx, v, ord1); + (void) r.compare_exchange_weak(vx, v, ord1, ord2); + (void) r.compare_exchange_strong(vx, v); + (void) r.compare_exchange_strong(vx, v, ord1); + (void) r.compare_exchange_strong(vx, v, ord1, ord2); + r.notify_one(); + r.notify_all(); + }; } else { static_assert(!requires(const AR& r, TD v) { r.store(v); }); static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.store(v, ord); }); @@ -109,6 +137,15 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY { r += d } -> std::same_as; { r -= d } -> std::same_as; }); + + [[maybe_unused]] auto instantiator = [](const AR& r, AR::difference_type d, std::memory_order ord) { + (void) r.fetch_add(d); + (void) r.fetch_add(d, ord); + (void) r.fetch_sub(d); + (void) r.fetch_sub(d, ord); + (void) (r += d); + (void) (r -= d); + }; } else { static_assert(!requires(const AR& r, AR::difference_type d) { r.fetch_add(d); }); static_assert(!requires(const AR& r, AR::difference_type d, std::memory_order ord) { r.fetch_add(d, ord); }); @@ -125,6 +162,13 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY { --r } -> std::same_as; { r-- } -> std::same_as; }); + + [[maybe_unused]] auto instantiator = [](const AR& r) { + (void) ++r; + (void) r++; + (void) --r; + (void) r--; + }; } else { static_assert(!requires(const AR& r) { ++r; }); static_assert(!requires(const AR& r) { r++; }); @@ -144,6 +188,18 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY { r |= v } -> std::same_as; { r ^= v } -> std::same_as; }); + + [[maybe_unused]] auto instantiator = [](const AR& r, TD v, std::memory_order ord) { + (void) r.fetch_and(v); + (void) r.fetch_and(v, ord); + (void) r.fetch_or(v); + (void) r.fetch_or(v, ord); + (void) r.fetch_xor(v); + (void) r.fetch_xor(v, ord); + (void) (r &= v); + (void) (r |= v); + (void) (r ^= v); + }; } else { static_assert(!requires(const AR& r, TD v) { r.fetch_and(v); }); static_assert(!requires(const AR& r, TD v, std::memory_order ord) { r.fetch_and(v, ord); }); From 730487a1de57a88f42813bd620c6d8d4a16d616c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 12:41:10 -0800 Subject: [PATCH 03/13] Fix typo. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 78fb068b20e..343b737b725 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -34,7 +34,7 @@ struct int128 { } }; -// Also test constraints and conditional existance of difference_type specified by +// Also test constraints and conditional existence of difference_type specified by // P3323R1 "Forbid atomic, Specify atomic_ref". template From 32dd8fe12609df761edc07c37cf813646db2d494 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 13:15:11 -0800 Subject: [PATCH 04/13] `static_cast<_Ty>` => `static_cast<_TVal>` --- stl/inc/atomic | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index b374f944dcc..97316eaae09 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1806,11 +1806,11 @@ struct _Atomic_integral_facade<_Ty&> : _Atomic_integral<_Ty&> { } _TVal operator+=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { - return static_cast<_Ty>(fetch_add(_Operand) + _Operand); + return static_cast<_TVal>(fetch_add(_Operand) + _Operand); } _TVal operator-=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { - return static_cast<_Ty>(fetch_sub(_Operand) - _Operand); + return static_cast<_TVal>(fetch_sub(_Operand) - _Operand); } _TVal fetch_and(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { @@ -1838,15 +1838,15 @@ struct _Atomic_integral_facade<_Ty&> : _Atomic_integral<_Ty&> { } _TVal operator&=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { - return static_cast<_Ty>(fetch_and(_Operand) & _Operand); + return static_cast<_TVal>(fetch_and(_Operand) & _Operand); } _TVal operator|=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { - return static_cast<_Ty>(fetch_or(_Operand) | _Operand); + return static_cast<_TVal>(fetch_or(_Operand) | _Operand); } _TVal operator^=(const _TVal _Operand) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { - return static_cast<_Ty>(fetch_xor(_Operand) ^ _Operand); + return static_cast<_TVal>(fetch_xor(_Operand) ^ _Operand); } }; From d529f865f0af2a12fbf2d48770fa192f02e6b29f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 13:21:39 -0800 Subject: [PATCH 05/13] `reinterpret_cast<_Ty>` => `reinterpret_cast<_TVal>` --- stl/inc/atomic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 97316eaae09..7c2f005132f 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -2066,7 +2066,7 @@ struct _Atomic_pointer<_Ty&> : _Atomic_storage<_Ty&> { _ATOMIC_CHOOSE_INTRINSIC(static_cast(_Order), _Result, _InterlockedExchangeAdd64, _STD _Atomic_address_as(this->_Storage), _Shift_bytes); #endif // ^^^ 64 bits ^^^ - return reinterpret_cast<_Ty>(_Result); + return reinterpret_cast<_TVal>(_Result); } _TVal fetch_sub(const ptrdiff_t _Diff) const noexcept _REQUIRES_CLAUSE(!is_const_v<_Ty>) { From c8f1fa06731d0e406a71aa9cc8212a64c7e9621a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 13:45:11 -0800 Subject: [PATCH 06/13] `_Atomic_integral_facade` and `_Atomic_floating` should never see `cv T`. --- stl/inc/atomic | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 7c2f005132f..e42a4033c90 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1635,8 +1635,11 @@ _CXX20_DEPRECATE_VOLATILE constexpr bool _Deprecate_non_lock_free_volatile<_Ty, template struct _Atomic_integral_facade : _Atomic_integral<_Ty> { // provides operator overloads and other support for atomic integral specializations + _STL_INTERNAL_STATIC_ASSERT(!is_const_v<_Ty>); + _STL_INTERNAL_STATIC_ASSERT(!is_volatile_v<_Ty>); + using _Base = _Atomic_integral<_Ty>; - using difference_type = remove_cv_t<_Ty>; + using difference_type = _Ty; using _Base::_Base; @@ -1854,8 +1857,11 @@ struct _Atomic_integral_facade<_Ty&> : _Atomic_integral<_Ty&> { template struct _Atomic_floating : _Atomic_storage<_Ty> { // provides atomic floating-point operations + _STL_INTERNAL_STATIC_ASSERT(!is_const_v<_Ty>); + _STL_INTERNAL_STATIC_ASSERT(!is_volatile_v<_Ty>); + using _Base = _Atomic_storage<_Ty>; - using difference_type = remove_cv_t<_Ty>; + using difference_type = _Ty; using _Base::_Base; From 50200e44beaee1067607839cc9cee1a1622cc92a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 14:12:16 -0800 Subject: [PATCH 07/13] Include ``. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 343b737b725..779e14c154f 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include From 14336bb1bfd51da6dd1caef433a2f7aad20f8920 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 14:20:42 -0800 Subject: [PATCH 08/13] Add missing `wchar_t`, drop repeated `bool`. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 779e14c154f..ae743a6a70e 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -238,10 +238,10 @@ void test_atomic_ref_constraints() { // COMPILE-ONLY test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); #ifdef __cpp_char8_t test_atomic_ref_constraints_cv(); #endif // defined(__cpp_char8_t) - test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); From dea178b246e2f481ed52f04a9cc3120f931cbde9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 14:23:20 -0800 Subject: [PATCH 09/13] `char*` => `int*` to fix duplication. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index ae743a6a70e..bab3e98f3f6 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -253,10 +253,10 @@ void test_atomic_ref_constraints() { // COMPILE-ONLY test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); - test_atomic_ref_constraints_cv(); - test_atomic_ref_constraints_cv(); - test_atomic_ref_constraints_cv(); - test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); From d6c0f8d874377cd27ed3fe553084f8b453a51236 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 14:51:17 -0800 Subject: [PATCH 10/13] store() is a void kitty. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index bab3e98f3f6..63d6cbe63ac 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -80,8 +80,8 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY [[maybe_unused]] auto instantiator = [](const AR& r, TD v, TD& vx, std::memory_order ord1, std::memory_order ord2) { - (void) r.store(v); - (void) r.store(v, ord1); + r.store(v); + r.store(v, ord1); (void) (r = v); (void) r.exchange(v); (void) r.exchange(v, ord1); From 7d6f5c71ad7407a4ae97937c9b5a826962e29bf2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 14:57:23 -0800 Subject: [PATCH 11/13] Style: `is_same_v` => `is_same_v` --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 63d6cbe63ac..3b2afefa960 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -177,7 +177,7 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY static_assert(!requires(const AR& r) { r--; }); } - if constexpr (std::is_integral_v && !std::is_same_v && !std::is_const_v) { + if constexpr (std::is_integral_v && !std::is_same_v && !std::is_const_v) { static_assert(requires(const AR& r, TD v, std::memory_order ord) { { r.fetch_and(v) } -> std::same_as; { r.fetch_and(v, ord) } -> std::same_as; From 5dce51a180f2d7cffffce69402a99322107a57e1 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 10 Jan 2025 15:06:53 -0800 Subject: [PATCH 12/13] Add `void*` test coverage. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 3b2afefa960..ad351d42b23 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -248,6 +248,11 @@ void test_atomic_ref_constraints() { // COMPILE-ONLY test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); + test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); test_atomic_ref_constraints_cv(); From 403436ec12d9184af40550dc50972cc213a57f8a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 13 Jan 2025 14:52:31 -0800 Subject: [PATCH 13/13] Add compiler bug workaround. --- tests/std/tests/P0019R8_atomic_ref/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index ad351d42b23..47f42a78be0 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -53,7 +53,11 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY }); { [[maybe_unused]] auto instantiator = [](const AR& r, TD v, std::memory_order ord) { +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2343282 (void) r.operator TD(); +#else // ^^^ no workaround / workaround vvv + [[maybe_unused]] TD td = r; +#endif // ^^^ workaround ^^^ (void) r.load(); (void) r.load(ord); r.wait(v);