From ec800526f8aa4b375d0a6f07903ca2d1addb160a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 20:57:33 +0100 Subject: [PATCH 1/8] Add tests for new vector and bitset reference swaps and assignments. --- .../test.cpp | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp b/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp index 4e3b174f6fe..1cba3009571 100644 --- a/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp +++ b/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp @@ -2,7 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include +#include #include using namespace std; @@ -10,7 +12,7 @@ using namespace std; static const auto is_true = [](bool b) { return b; }; static const auto is_false = [](bool b) { return !b; }; -int main() { +void check_values_match() { vector x(100, false); vector y(100, true); @@ -27,3 +29,50 @@ int main() { assert(!y[34]); assert(all_of(y.begin() + 35, y.end(), is_true)); } + +template +void check_P3612(T& collection) { + + auto ref0 = collection[0]; + auto const ref1 = collection[1]; + + // assignments from bool + ref0 = true; + ref1 = false; + // assignments from reference + ref0 = ref1; + ref1 = ref0; + + collection[0] = true; + collection[1] = false; + + swap(collection[0], collection[1]); // swap(reference, reference) + assert(!collection[0]); + + bool b = true; + swap(collection[0], b); // swap(reference, bool) + assert(collection[0]); + + swap(b, collection[0]); // swap(bool, reference) + assert(!collection[0]); +} + +template +constexpr bool has_noexcept_copy_ctor = noexcept(T(std::declval())); + +int main() { + check_values_match(); + + + constexpr size_t N = 10; + vector vector(N); + bitset bitset(0); + + check_P3612(vector); + check_P3612(bitset); + + static_assert(std::is_nothrow_copy_constructible_v, ""); + static_assert(std::is_nothrow_copy_constructible_v, ""); + static_assert(has_noexcept_copy_ctor, ""); + static_assert(has_noexcept_copy_ctor, ""); +} From 4bed2e4fdea0dfa680bf247f0e7315472eb5eb09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 20:58:39 +0100 Subject: [PATCH 2/8] Add swap to bitset::reference, add operator=(bool) const. --- stl/inc/bitset | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index 13ed3252884..37bee702c9e 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -85,7 +85,7 @@ public: friend bitset; public: - _CONSTEXPR23 reference(const reference&) = default; + _CONSTEXPR23 reference(const reference& _Bitref) noexcept = default; _CONSTEXPR23 ~reference() noexcept {} // TRANSITION, ABI @@ -99,6 +99,11 @@ public: return *this; } + _CONSTEXPR23 const reference& operator=(const bool _Val) const noexcept { + _Pbitset->_Set_unchecked(_Mypos, _Val); + return *this; + } + _NODISCARD _CONSTEXPR23 bool operator~() const noexcept { return !_Pbitset->_Subscript(_Mypos); } @@ -112,6 +117,22 @@ public: return *this; } + friend constexpr void swap(reference _Left, reference _Right) noexcept { + bool _Val = _Left; // NOT _STD swap + _Left = _Right; + _Right = _Val; + } + + friend constexpr void swap(reference _Left, bool& _Right) noexcept { + bool _Val = _Left; // NOT _STD swap + _Left = _Right; + _Right = _Val; + } + + friend constexpr void swap(bool& _Left, reference _Right) noexcept { + swap(_Right, _Left); + } + private: _CONSTEXPR23 reference(bitset<_Bits>& _Bitset, const size_t _Pos) noexcept : _Pbitset(&_Bitset), _Mypos(_Pos) {} From 8c0a262e2ca3bd737c405b2a76ecdcfbbfc890c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 21:00:06 +0100 Subject: [PATCH 3/8] Add swap to vector::reference, make operator=(bool) const available outside of C++23 mode. Deprecate static swap(ref, ref) --- stl/inc/vector | 17 +++++++++++++---- stl/inc/yvals_core.h | 11 ++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index dafac7c5933..df0b06a4579 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -2461,7 +2461,7 @@ private: using _Difference_type = typename _Mybase::_Difference_type; public: - _CONSTEXPR20 _Vb_reference(const _Vb_reference&) = default; + _CONSTEXPR20 _Vb_reference(const _Vb_reference&) noexcept = default; _CONSTEXPR20 _Vb_reference(const _Mybase& _Right) noexcept : _Mybase(_Right._Myptr, _Right._Myoff, _Right._Getcont()) {} @@ -2480,8 +2480,7 @@ public: return *this; } -#if _HAS_CXX23 - constexpr const _Vb_reference& operator=(bool _Val) const noexcept { + _CONSTEXPR20 const _Vb_reference& operator=(bool _Val) const noexcept { if (_Val) { *const_cast<_Vbase*>(_Getptr()) |= _Mask(); } else { @@ -2490,7 +2489,6 @@ public: return *this; } -#endif // _HAS_CXX23 _CONSTEXPR20 void flip() noexcept { *const_cast<_Vbase*>(_Getptr()) ^= _Mask(); @@ -2517,6 +2515,16 @@ public: _Right = _Val; } + friend _CONSTEXPR20 void swap(_Vb_reference _Left, bool& _Right) noexcept { + bool _Val = _Left; // NOT _STD swap + _Left = _Right; + _Right = _Val; + } + + friend _CONSTEXPR20 void swap(bool& _Left, _Vb_reference _Right) noexcept { + swap(_Right, _Left); + } + protected: _CONSTEXPR20 _Vbase _Mask() const noexcept { return static_cast<_Vbase>(1) << this->_Myoff; @@ -3509,6 +3517,7 @@ public: } } + _DEPRECATE_VECTOR_BOOL_STATIC_REFERENCE_SWAP static _CONSTEXPR20 void swap(reference _Left, reference _Right) noexcept { bool _Val = _Left; // NOT _STD swap _Left = _Right; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 0ccf71729ed..9e5d1570992 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1512,7 +1512,16 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define _DEPRECATE_LOCALE_EMPTY #endif // ^^^ warning disabled ^^^ -// next warning number: STL4049 +#if !defined(_SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING) +#define _DEPRECATE_VECTOR_BOOL_STATIC_REFERENCE_SWAP \ + [[deprecated("warning STL4049: Static std::vector::swap(reference, reference) is deprecated. " \ + "Use non-member function swap(reference, reference) instead. You can define " \ + "_SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING to suppress this warning.")]] +#else // ^^^ warning enabled / warning disabled vvv +#define _DEPRECATE_VECTOR_BOOL_STATIC_REFERENCE_SWAP +#endif // ^^^ warning disabled ^^^ + +// next warning number: STL4050 // next error number: STL1013 From 3ab06008989bd874be58def9688f76d23db7e967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 21:39:15 +0100 Subject: [PATCH 4/8] Mark libcxx test std/containers/sequences/vector.bool/reference.swap.pass.cpp as expected FAIL due to std::vector::swap(reference, reference) --- tests/libcxx/expected_results.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 343abccc27a..1181d6470b8 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -149,6 +149,9 @@ std/atomics/atomics.ref/member_types.compile.pass.cpp FAIL std/thread/futures/futures.promise/uses_allocator.pass.cpp FAIL std/thread/futures/futures.task/futures.task.members/ctor2.compile.pass.cpp FAIL +# libc++ has not implemented P3612R1 "Harmonize Proxy-Reference Operations" +std/containers/sequences/vector.bool/reference.swap.pass.cpp FAIL + # Various bogosity (LLVM-D141004) std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/ctor_does_not_allocate.pass.cpp FAIL std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/sync_with_default_resource.pass.cpp FAIL From 8f21bc73d2147f48d28171904beba62aaf6f20c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 21:41:22 +0100 Subject: [PATCH 5/8] Mention the implemented paper P3612R1 in yvals_core.h --- stl/inc/yvals_core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 9e5d1570992..e7546097cd3 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -84,6 +84,7 @@ // P3323R1 Forbid atomic, Specify atomic_ref // (for atomic) // P3503R3 Make Type-Erased Allocator Use In promise And packaged_task Consistent +// P3612R1 Harmonize Proxy-Reference Operations // _HAS_CXX17 directly controls: // P0005R4 not_fn() From 5c9abf0cb65e47293f610676d8181d86abe438ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 12 Nov 2025 21:53:25 +0100 Subject: [PATCH 6/8] Silence deprecation warning in tr1 vector test. --- .../std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp | 3 +++ tests/tr1/tests/vector/test.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp b/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp index 1cba3009571..2e696aff889 100644 --- a/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp +++ b/tests/std/tests/Dev10_816787_swap_vector_bool_elements/test.cpp @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// This test was extended with functionality needed for +// P3612R1: Harmonize Proxy-Reference Operations + #include #include #include diff --git a/tests/tr1/tests/vector/test.cpp b/tests/tr1/tests/vector/test.cpp index 3ed42a456d5..97ec389feb6 100644 --- a/tests/tr1/tests/vector/test.cpp +++ b/tests/tr1/tests/vector/test.cpp @@ -4,6 +4,9 @@ // test #define TEST_NAME "" +// Since P3612R1 the static vector::swap(reference, reference) is deprecated +#define _SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING + #include "tdefs.h" #include #include From d81ed9188b2022f0a8ba65bbe8d192761d737a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Thu, 13 Nov 2025 13:38:13 +0100 Subject: [PATCH 7/8] Remove meaningless argument name from defaulted copy ctor. --- stl/inc/bitset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/bitset b/stl/inc/bitset index 37bee702c9e..e928bc86065 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -85,7 +85,7 @@ public: friend bitset; public: - _CONSTEXPR23 reference(const reference& _Bitref) noexcept = default; + _CONSTEXPR23 reference(const reference&) noexcept = default; _CONSTEXPR23 ~reference() noexcept {} // TRANSITION, ABI From 2418738b22749b35390acd1b9133cabb0bbd113e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Michal?= Date: Wed, 19 Nov 2025 12:55:58 +0100 Subject: [PATCH 8/8] Deprecate std::vector::swap(reference, reference) only in C++26 mode. --- stl/inc/yvals_core.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e7546097cd3..073fb1362fb 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -84,7 +84,6 @@ // P3323R1 Forbid atomic, Specify atomic_ref // (for atomic) // P3503R3 Make Type-Erased Allocator Use In promise And packaged_task Consistent -// P3612R1 Harmonize Proxy-Reference Operations // _HAS_CXX17 directly controls: // P0005R4 not_fn() @@ -416,6 +415,10 @@ // P2614R2 Deprecating float_denorm_style, numeric_limits::has_denorm, numeric_limits::has_denorm_loss // Other C++23 deprecation warnings +// _HAS_CXX26 and _SILENCE_ALL_CXX26_DEPRECATION_WARNINGS control: +// P3612R1 Harmonize Proxy-Reference Operations +// Other C++26 deprecation warnings + // Parallel Algorithms Notes // C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms. // This implementation parallelizes several common algorithm calls, but not all. @@ -1513,11 +1516,14 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define _DEPRECATE_LOCALE_EMPTY #endif // ^^^ warning disabled ^^^ -#if !defined(_SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING) -#define _DEPRECATE_VECTOR_BOOL_STATIC_REFERENCE_SWAP \ - [[deprecated("warning STL4049: Static std::vector::swap(reference, reference) is deprecated. " \ - "Use non-member function swap(reference, reference) instead. You can define " \ - "_SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING to suppress this warning.")]] + +#if _HAS_CXX26 && !defined(_SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING) \ + && !defined(_SILENCE_ALL_CXX26_DEPRECATION_WARNINGS) +#define _DEPRECATE_VECTOR_BOOL_STATIC_REFERENCE_SWAP \ + [[deprecated("warning STL4049: Static std::vector::swap(reference, reference) is deprecated by C++26 (see " \ + "LWG-3638 and P3612R1). Use non-member function swap(reference, reference) instead. You can define " \ + "_SILENCE_VECTOR_BOOL_STATIC_REFERENCE_SWAP_DEPRECATION_WARNING or " \ + "_SILENCE_ALL_CXX26_DEPRECATION_WARNINGS to suppress this warning.")]] #else // ^^^ warning enabled / warning disabled vvv #define _DEPRECATE_VECTOR_BOOL_STATIC_REFERENCE_SWAP #endif // ^^^ warning disabled ^^^