From 665cc4d17cf6206288e7e341bcb4034f526dcebc Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Feb 2023 16:05:38 +0800 Subject: [PATCH 01/40] Implement LWG-3870 --- stl/inc/memory | 25 +++++++++++++++++-------- stl/inc/xmemory | 4 ++-- stl/inc/xutility | 17 ++++------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 3ddb1c45401..ca0861c59c4 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -2872,6 +2872,15 @@ _NODISCARD_SMART_PTR_ALLOC } #if _HAS_CXX20 +template +_NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { + if constexpr (is_pointer_v<_PtrTy>) { + return static_cast(_Ptr); + } else { + return static_cast(_STD addressof(*_Ptr)); + } +} + template struct _Allocate_n_ptr { _Alloc& _Al; @@ -2930,10 +2939,10 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_Ty>> _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al); + ::new (_STD _Voidify_unfancy(_Constructor._Ptr)) _Refc(_Al); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); return _Ret; } @@ -2946,10 +2955,10 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_Ty>> _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _Val); + ::new (_STD _Voidify_unfancy(_Constructor._Ptr)) _Refc(_Al, _Val); shared_ptr<_Ty> _Ret; const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); return _Ret; } @@ -2964,9 +2973,9 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_T _Alblock _Rebound(_Al); _Alloc_construct_ptr _Constructor{_Rebound}; _Constructor._Allocate(); - ::new (_Voidify_iter(_Constructor._Ptr)) _Refc(_Al, _For_overwrite_tag{}); + ::new (_STD _Voidify_unfancy(_Constructor._Ptr)) _Refc(_Al, _For_overwrite_tag{}); const auto _Ptr = static_cast*>(_Constructor._Ptr->_Storage._Value); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); } else { // make a shared_ptr to non-array object using _Refoa = _Ref_count_obj_alloc3, _Alloc>; @@ -2974,9 +2983,9 @@ _NODISCARD_SMART_PTR_ALLOC enable_if_t, shared_ptr<_T _Alblock _Rebound(_Al); _Alloc_construct_ptr<_Alblock> _Constructor{_Rebound}; _Constructor._Allocate(); - _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); + _STD _Construct_in_place(*_Constructor._Ptr, _Al, _For_overwrite_tag{}); const auto _Ptr = reinterpret_cast<_Ty*>(_STD addressof(_Constructor._Ptr->_Storage._Value)); - _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _Unfancy(_Constructor._Release())); + _Ret._Set_ptr_rep_and_enable_shared(_Ptr, _STD _Unfancy(_Constructor._Release())); } return _Ret; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 8a0bffa8a5c..f5c721a1ba8 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -674,7 +674,7 @@ struct _Default_allocator_traits { // traits for std::allocator } else #endif // _HAS_CXX20 { - ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); + ::new (static_cast(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); } } @@ -966,7 +966,7 @@ public: template _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void construct(_Objty* const _Ptr, _Types&&... _Args) { - ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); + ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); } template diff --git a/stl/inc/xutility b/stl/inc/xutility index c53c060d248..9ffb0f9c816 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -230,15 +230,6 @@ struct _Get_rebind_alias<_Ty, _Other, void_t; }; -template -_NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept { - if constexpr (is_pointer_v<_Iter>) { - return const_cast(static_cast(_It)); - } else { - return const_cast(static_cast(_STD addressof(*_It))); - } -} - #if _HAS_CXX20 #ifdef __EDG__ // TRANSITION, DevCom-1691516 _EXPORT_STD template ()) _Ty(_STD declval<_Types>()...))>* = nullptr> #endif // TRANSITION, DevCom-1691516 constexpr _Ty* construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( - noexcept(::new(_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { - _MSVC_CONSTEXPR return ::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...); + noexcept(::new(static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { + _MSVC_CONSTEXPR return ::new (static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...); } #endif // _HAS_CXX20 @@ -262,13 +253,13 @@ _CONSTEXPR20 void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( } else #endif // _HAS_CXX20 { - ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); + ::new (static_cast(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); } } template void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { - ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; + ::new (static_cast(_STD addressof(_Obj))) _Ty; } template From facff8a88dbc42557ac03a602d84639fe673ef5c Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Feb 2023 16:56:36 +0800 Subject: [PATCH 02/40] Fix `_Default_allocator_traits::construct` --- stl/inc/xmemory | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index f5c721a1ba8..17fad181c90 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -669,13 +669,10 @@ struct _Default_allocator_traits { // traits for std::allocator template static _CONSTEXPR20 void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); - } else -#endif // _HAS_CXX20 - { - ::new (static_cast(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); - } + _STD construct_at(_Ptr, _STD forward<_Types>(_Args)...); +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv + ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); +#endif // ^^^ !_HAS_CXX20 ^^^ } template From 0b6efe9c2ca842d01d5cc5cc2331e808afc744a1 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Feb 2023 21:44:41 +0800 Subject: [PATCH 03/40] Restore some needed cv-removing cases --- stl/inc/memory | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index ca0861c59c4..98e4a8881f2 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -936,6 +936,20 @@ namespace ranges { #endif // _HAS_CXX17 +template +_NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { + if constexpr (is_pointer_v<_PtrTy>) { + return const_cast(static_cast(_Ptr)); + } else { + return const_cast(static_cast(_STD addressof(*_Ptr))); + } +} + +template +void _Construct_cv_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { + ::new (_STD _Voidify_unfancy(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); +} + #if _HAS_DEPRECATED_RAW_STORAGE_ITERATOR _EXPORT_STD template class _CXX17_DEPRECATE_RAW_STORAGE_ITERATOR raw_storage_iterator { // wrap stores to raw buffer as output iterator @@ -957,12 +971,12 @@ public: } raw_storage_iterator& operator=(const _Ty& _Val) { // construct value designated by stored iterator - _Construct_in_place(*_Next, _Val); + _STD _Construct_cv_in_place(*_Next, _Val); return *this; } raw_storage_iterator& operator=(_Ty&& _Val) { // construct value designated by stored iterator - _Construct_in_place(*_Next, _STD move(_Val)); + _STD _Construct_cv_in_place(*_Next, _STD move(_Val)); return *this; } @@ -2075,6 +2089,11 @@ _Dx* get_deleter(const shared_ptr<_Ty>&) noexcept = delete; // requires static R struct _For_overwrite_tag { explicit _For_overwrite_tag() = default; }; + +template +void _Default_construct_cv_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { + ::new (_STD _Voidify_unfancy(_STD addressof(_Obj))) _Ty; +} #endif // _HAS_CXX20 template @@ -2084,12 +2103,12 @@ public: explicit _Ref_count_obj2(_Types&&... _Args) : _Ref_count_base() { #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { - _Default_construct_in_place(_Storage._Value); + _STD _Default_construct_cv_in_place(_Storage._Value); ((void) _Args, ...); } else #endif // _HAS_CXX20 { - _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); + _STD _Construct_cv_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); } } @@ -2204,12 +2223,12 @@ struct _NODISCARD _Uninitialized_rev_destroying_backout { template void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment - _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); + _STD _Construct_cv_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } void _Emplace_back_for_overwrite() { - _Default_construct_in_place(*_Last); + _STD _Default_construct_cv_in_place(*_Last); ++_Last; } @@ -2872,15 +2891,6 @@ _NODISCARD_SMART_PTR_ALLOC } #if _HAS_CXX20 -template -_NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { - if constexpr (is_pointer_v<_PtrTy>) { - return static_cast(_Ptr); - } else { - return static_cast(_STD addressof(*_Ptr)); - } -} - template struct _Allocate_n_ptr { _Alloc& _Al; From a2e06f7b406f3b93e6519c47eebfb6e13c32824f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Feb 2023 23:50:31 +0800 Subject: [PATCH 04/40] Skip libcxx tests --- tests/libcxx/expected_results.txt | 12 ++++++++++++ tests/libcxx/skipped_tests.txt | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index bb5eda0dd71..518a8eb6d59 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -122,6 +122,18 @@ std/strings/string.view/string.view.cons/from_range.pass.cpp FAIL std/strings/string.view/string.view.cons/from_string1.compile.fail.cpp FAIL std/strings/string.view/string.view.cons/from_string2.compile.fail.cpp FAIL +# libc++ doesn't implement LWG-3870 +std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp FAIL + # libc++ doesn't implement P1957R2 "Converting from `T*` to `bool` should be considered narrowing" std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.assign/T.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index f7cd2590acc..8b3a3c166b6 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -122,6 +122,18 @@ strings\string.view\string.view.cons\from_range.pass.cpp strings\string.view\string.view.cons\from_string1.compile.fail.cpp strings\string.view\string.view.cons\from_string2.compile.fail.cpp +# libc++ doesn't implement LWG-3870 +utilities\memory\specialized.algorithms\uninitialized.construct.default\ranges_uninitialized_default_construct.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.construct.default\ranges_uninitialized_default_construct_n.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.construct.value\ranges_uninitialized_value_construct.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.construct.value\ranges_uninitialized_value_construct.pass_n.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.copy\ranges_uninitialized_copy.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.copy\ranges_uninitialized_copy_n.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.fill\ranges_uninitialized_fill.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.fill.n\ranges_uninitialized_fill_n.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.move\ranges_uninitialized_move.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.move\ranges_uninitialized_move_n.pass.cpp + # libc++ doesn't implement P1957R2 "Converting from `T*` to `bool` should be considered narrowing" utilities\variant\variant.variant\variant.assign\conv.pass.cpp utilities\variant\variant.variant\variant.assign\T.pass.cpp From e5df38fa957a75aef43b4cfa68d2a968d0dacf2d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 18 Feb 2023 01:06:09 +0800 Subject: [PATCH 05/40] Remove invalidated test coverage --- .../test.cpp | 4 ++ .../tests/GH_000431_copy_move_family/test.cpp | 65 ++++--------------- .../test.compile.pass.cpp | 5 +- .../test.cpp | 43 ++++++------ .../tests/VSO_0180469_fill_family/test.cpp | 15 +++-- 5 files changed, 55 insertions(+), 77 deletions(-) diff --git a/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp b/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp index e3b01dad3f4..40e289d093b 100644 --- a/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp +++ b/tests/std/tests/Dev11_0920385_list_sort_allocator/test.cpp @@ -282,7 +282,9 @@ int main() { test_1119194(); test_1184701(); test_LWG_2455(); +#if !_HAS_CXX20 // support removed in C++20 by P0619R4 test_allocator_construct_const(); +#endif // !_HAS_CXX20 } // Also test DevDiv-1119194 "The STL should handle allocators that aren't assignable". @@ -465,6 +467,7 @@ void test_LWG_2455() { } } +#if !_HAS_CXX20 // support removed in C++20 by P0619R4 void test_allocator_construct_const() { // Annex D actually requires the default allocator to const_cast here // See N4659 D.9 [depr.default.allocator]/6 @@ -476,3 +479,4 @@ void test_allocator_construct_const() { allocator_traits>::construct(alloc, exampleCptr, 1729); assert(example == 1729); } +#endif // !_HAS_CXX20 diff --git a/tests/std/tests/GH_000431_copy_move_family/test.cpp b/tests/std/tests/GH_000431_copy_move_family/test.cpp index f3f135b5466..9486d75d7f6 100644 --- a/tests/std/tests/GH_000431_copy_move_family/test.cpp +++ b/tests/std/tests/GH_000431_copy_move_family/test.cpp @@ -639,41 +639,6 @@ void test_algorithms(CopyFn copy_fn) { } } -template -void test_uninitialized_algorithms(CopyFn copy_fn) { - test_algorithms(copy_fn); - - { // Test const destination - int src[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int expected[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int dst[10]{}; - - copy_fn(begin(src), end(src), cbegin(dst)); - - assert(equal(begin(expected), end(expected), begin(dst), end(dst))); - } - - { // Test move_iterator with const destination - int src[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int expected[10] = {5, 7, 3, 4, 6, 4, 7, 1, 9, 5}; - int dst[10]{}; - - copy_fn(make_move_iterator(begin(src)), make_move_iterator(end(src)), cbegin(dst)); - - assert(equal(begin(expected), end(expected), begin(dst), end(dst))); - } - - { // Test vector with const destination - vector src = {3, 6, 4, 7, 3}; - vector expected = {3, 6, 4, 7, 3}; - vector dst = {0, 0, 0, 0, 0}; - - copy_fn(begin(src), end(src), cbegin(dst)); - - assert(equal(begin(expected), end(expected), begin(dst), end(dst))); - } -} - int main() { test_algorithms([](auto begin, auto end, auto out) { copy(begin, end, out); }); test_algorithms([](auto begin, auto end, auto out) { copy_n(begin, distance(begin, end), out); }); @@ -682,14 +647,12 @@ int main() { test_algorithms([](auto begin, auto end, auto out) { move(begin, end, out); }); test_algorithms([](auto begin, auto end, auto out) { move_backward(begin, end, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { uninitialized_copy(begin, end, out); }); - test_uninitialized_algorithms( - [](auto begin, auto end, auto out) { uninitialized_copy_n(begin, distance(begin, end), out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_copy(begin, end, out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_copy_n(begin, distance(begin, end), out); }); #if _HAS_CXX17 - test_uninitialized_algorithms([](auto begin, auto end, auto out) { uninitialized_move(begin, end, out); }); - test_uninitialized_algorithms( - [](auto begin, auto end, auto out) { uninitialized_move_n(begin, distance(begin, end), out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_move(begin, end, out); }); + test_algorithms([](auto begin, auto end, auto out) { uninitialized_move_n(begin, distance(begin, end), out); }); #endif // _HAS_CXX17 #ifdef __cpp_lib_concepts @@ -714,35 +677,35 @@ int main() { } }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy(begin, end, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms( + test_algorithms( [](auto begin, auto end, auto out) { ranges::uninitialized_copy(begin, end, out, unreachable_sentinel); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy(begin, unreachable_sentinel, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy_n(begin, distance(begin, end), out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_copy_n(begin, distance(begin, end), out, unreachable_sentinel); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move(begin, end, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms( + test_algorithms( [](auto begin, auto end, auto out) { ranges::uninitialized_move(begin, end, out, unreachable_sentinel); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move(begin, unreachable_sentinel, out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move_n(begin, distance(begin, end), out, next(out, distance(begin, end))); }); - test_uninitialized_algorithms([](auto begin, auto end, auto out) { + test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move_n(begin, distance(begin, end), out, unreachable_sentinel); }); #endif // __cpp_lib_concepts diff --git a/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp b/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp index c842f06b844..b202e15c05d 100644 --- a/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp +++ b/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp @@ -29,7 +29,10 @@ void test_algorithms(Rng& rng) { (void) ranges::mismatch(rng, other); (void) ranges::mismatch(other, rng); - if constexpr (is_lvalue_reference_v> && ranges::forward_range) { + using range_ref_t = is_lvalue_reference_v>; + using range_deref_t = remove_reference_t; + if constexpr (is_lvalue_reference_v && !is_const_v && !is_volatile_v + && ranges::forward_range) { (void) ranges::uninitialized_copy(rng.begin(), rng.end(), other.begin(), other.end()); (void) ranges::uninitialized_copy(other.begin(), other.end(), rng.begin(), rng.end()); (void) ranges::uninitialized_copy(rng, other); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 57c64806081..1654dd44b9f 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -72,17 +72,19 @@ constexpr bool destroy_at_noexcept() { #endif // __cpp_lib_concepts static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); +#if 0 // TRANSITION, construct_at is underconstrained for cv T* +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +#endif // 0 struct X {}; @@ -100,9 +102,11 @@ struct indestructible { }; static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); -static_assert(can_construct_at); +#if 0 // TRANSITION, construct_at is underconstrained for cv T* +static_assert(!can_construct_at); +static_assert(!can_construct_at); +static_assert(!can_construct_at); +#endif // 0 static_assert(can_construct_at); static_assert(can_construct_at); @@ -118,9 +122,11 @@ static_assert(!can_construct_at); // The following static_asserts test our strengthening of noexcept static_assert(construct_at_noexcept()); -static_assert(construct_at_noexcept()); -static_assert(construct_at_noexcept()); -static_assert(construct_at_noexcept()); +#if 0 // TRANSITION, construct_at is underconstrained for cv T* +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); +static_assert(!construct_at_noexcept()); +#endif // 0 static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); @@ -195,21 +201,20 @@ void test_array(const T& val) { (void) val; alignas(T) unsigned char storage[sizeof(T) * N]; - using U = conditional_t, const volatile T, T>; - const auto ptr = reinterpret_cast(storage); + const auto ptr = reinterpret_cast(storage); for (auto i = 0; i < N; ++i) { construct_at(ptr + i, val); } - destroy_at(reinterpret_cast(ptr)); + destroy_at(reinterpret_cast(ptr)); #ifdef __cpp_lib_concepts for (auto i = 0; i < N; ++i) { ranges::construct_at(ptr + i, val); } - ranges::destroy_at(reinterpret_cast(ptr)); + ranges::destroy_at(reinterpret_cast(ptr)); #endif // __cpp_lib_concepts } diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 52bc0a41a5d..9b812cc9177 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include using namespace std; @@ -62,13 +63,15 @@ void test_fill() { test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { fill_n(buff + start, end - start, value); }); - test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { - uninitialized_fill(buff + start, buff + end, value); - }); + if constexpr (!is_const_v && !is_volatile_v) { + test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { + uninitialized_fill(buff + start, buff + end, value); + }); - test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { - uninitialized_fill_n(buff + start, end - start, value); - }); + test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { + uninitialized_fill_n(buff + start, end - start, value); + }); + } } } From 888f57da20bc58d6fc99713d1d994aa40b62ea99 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 18 Feb 2023 01:30:04 +0800 Subject: [PATCH 06/40] Fix typo for libc++ tests and unblock one test Also analyze similar failing cases --- tests/libcxx/expected_results.txt | 13 +++++-------- tests/libcxx/skipped_tests.txt | 13 +++++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 518a8eb6d59..3d1a67f0831 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -81,6 +81,10 @@ std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_ma # Too many constexpr operations std/utilities/charconv/charconv.to.chars/integral.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/op_or_eq.pass.cpp FAIL +std/utilities/template.bitset/bitset.members/right_shift_eq.pass.cpp FAIL # libc++ has not implemented P2505R5: "Monadic Functions for std::expected" std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp FAIL @@ -126,7 +130,7 @@ std/strings/string.view/string.view.cons/from_string2.compile.fail.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp FAIL -std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass_n.pass.cpp FAIL +std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp FAIL @@ -919,13 +923,6 @@ std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put. # Not analyzed. These tests use characters that cannot be represented in legacy character encodings std/utilities/format/format.functions/ascii.pass.cpp FAIL -# Not analyzed. "constexpr evaluation hit maximum step limit; possible infinite loop?" -std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/op_or_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/right_shift_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/to_string.pass.cpp:1 FAIL - # Not analyzed std/algorithms/alg.modifying.operations/alg.random.sample/ranges_sample.pass.cpp FAIL std/algorithms/alg.modifying.operations/alg.rotate/ranges_rotate.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 8b3a3c166b6..7de059841b3 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -81,6 +81,10 @@ utilities\utility\mem.res\mem.res.pool\mem.res.pool.mem\unsync_deallocate_matche # Too many constexpr operations utilities\charconv\charconv.to.chars\integral.pass.cpp +utilities\template.bitset\bitset.members\left_shift_eq.pass.cpp +utilities\template.bitset\bitset.members\op_and_eq.pass.cpp +utilities\template.bitset\bitset.members\op_or_eq.pass.cpp +utilities\template.bitset\bitset.members\right_shift_eq.pass.cpp # libc++ has not implemented P2505R5: "Monadic Functions for std::expected" language.support\support.limits\support.limits.general\expected.version.compile.pass.cpp @@ -126,7 +130,7 @@ strings\string.view\string.view.cons\from_string2.compile.fail.cpp utilities\memory\specialized.algorithms\uninitialized.construct.default\ranges_uninitialized_default_construct.pass.cpp utilities\memory\specialized.algorithms\uninitialized.construct.default\ranges_uninitialized_default_construct_n.pass.cpp utilities\memory\specialized.algorithms\uninitialized.construct.value\ranges_uninitialized_value_construct.pass.cpp -utilities\memory\specialized.algorithms\uninitialized.construct.value\ranges_uninitialized_value_construct.pass_n.pass.cpp +utilities\memory\specialized.algorithms\uninitialized.construct.value\ranges_uninitialized_value_construct_n.pass.cpp utilities\memory\specialized.algorithms\uninitialized.copy\ranges_uninitialized_copy.pass.cpp utilities\memory\specialized.algorithms\uninitialized.copy\ranges_uninitialized_copy_n.pass.cpp utilities\memory\specialized.algorithms\uninitialized.fill\ranges_uninitialized_fill.pass.cpp @@ -919,13 +923,6 @@ localization\locale.categories\category.numeric\locale.nm.put\facet.num.put.memb # Not analyzed. These tests use characters that cannot be represented in legacy character encodings utilities\format\format.functions\ascii.pass.cpp -# Not analyzed. "constexpr evaluation hit maximum step limit; possible infinite loop?" -utilities\template.bitset\bitset.members\left_shift_eq.pass.cpp -utilities\template.bitset\bitset.members\op_and_eq.pass.cpp -utilities\template.bitset\bitset.members\op_or_eq.pass.cpp -utilities\template.bitset\bitset.members\right_shift_eq.pass.cpp -utilities\template.bitset\bitset.members\to_string.pass.cpp - # Not analyzed algorithms\alg.modifying.operations\alg.random.sample\ranges_sample.pass.cpp algorithms\alg.modifying.operations\alg.rotate\ranges_rotate.pass.cpp From 1214db4ab82758ac26a97af5eeb716cddcb61332 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 18 Feb 2023 01:36:56 +0800 Subject: [PATCH 07/40] Fix copy-pasta and furtherly remove invalidated cases --- .../test.compile.pass.cpp | 4 ++-- .../test.cpp | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp b/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp index b202e15c05d..1a352806106 100644 --- a/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp +++ b/tests/std/tests/GH_002992_unwrappable_iter_sent_pairs/test.compile.pass.cpp @@ -29,8 +29,8 @@ void test_algorithms(Rng& rng) { (void) ranges::mismatch(rng, other); (void) ranges::mismatch(other, rng); - using range_ref_t = is_lvalue_reference_v>; - using range_deref_t = remove_reference_t; + using range_ref_t = ranges::range_reference_t; + using range_deref_t = remove_reference_t; if constexpr (is_lvalue_reference_v && !is_const_v && !is_volatile_v && ranges::forward_range) { (void) ranges::uninitialized_copy(rng.begin(), rng.end(), other.begin(), other.end()); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 1654dd44b9f..77fd16f4760 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -179,20 +179,6 @@ void test_runtime(const Ty& val) { assert(*asPtrTy == val); ranges::destroy_at(asPtrTy); #endif // __cpp_lib_concepts - - // test voidify: - const auto asCv = static_cast(asPtrTy); - memset(storage, 42, sizeof(Ty)); - assert(asPtrTy == construct_at(asCv, val)); - assert(const_cast(*asCv) == val); - destroy_at(asCv); - -#ifdef __cpp_lib_concepts - memset(storage, 42, sizeof(Ty)); - assert(asPtrTy == ranges::construct_at(asCv, val)); - assert(const_cast(*asCv) == val); - ranges::destroy_at(asCv); -#endif // __cpp_lib_concepts } template From 49344daa31741efeb28a2cd801d9582860b095c4 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 18 Feb 2023 01:44:43 +0800 Subject: [PATCH 08/40] Eliminate `if constexpr` for C++14 --- .../tests/VSO_0180469_fill_family/test.cpp | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 9b812cc9177..f066ed216dd 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -52,6 +52,19 @@ void test_case_fill(CharT value, Func fillCall) { } } +template +void test_fill_unqual() { + const CharT testCases[] = {cast(-100), cast(-1), cast(0), cast(1), cast(100)}; + + for (CharT testCase : testCases) { + test_case_fill(testCase, + [](BuffT* buff, CharT value, size_t start, size_t end) { fill(buff + start, buff + end, value); }); + + test_case_fill(testCase, + [](BuffT* buff, CharT value, size_t start, size_t end) { fill_n(buff + start, end - start, value); }); + } +} + template void test_fill() { const CharT testCases[] = {cast(-100), cast(-1), cast(0), cast(1), cast(100)}; @@ -63,15 +76,13 @@ void test_fill() { test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { fill_n(buff + start, end - start, value); }); - if constexpr (!is_const_v && !is_volatile_v) { - test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { - uninitialized_fill(buff + start, buff + end, value); - }); + test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { + uninitialized_fill(buff + start, buff + end, value); + }); - test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { - uninitialized_fill_n(buff + start, end - start, value); - }); - } + test_case_fill(testCase, [](BuffT* buff, CharT value, size_t start, size_t end) { + uninitialized_fill_n(buff + start, end - start, value); + }); } } @@ -136,9 +147,9 @@ int main() { test_fill(); test_fill(); - test_fill(); // Test GH-1183 + test_fill_unqual(); // Test GH-1183 #ifdef __cpp_lib_byte - test_fill(); // Test GH-1556 + test_fill_unqual(); // Test GH-1556 #endif // __cpp_lib_byte test_uninitialized_fill( From b63282f3a6368ed7cb9bf77352235a46e2a4bfd8 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 18 Feb 2023 02:38:44 +0800 Subject: [PATCH 09/40] Skip more cases --- .../test.cpp | 2 ++ tests/std/tests/VSO_0180469_fill_family/test.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 77fd16f4760..3cd2223a044 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -129,9 +129,11 @@ static_assert(!construct_at_noexcept()); #endif // 0 static_assert(!construct_at_noexcept()); +#if 0 // TRANSITION, construct_at is underconstrained for cv T* static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); +#endif // 0 static_assert(destroy_at_noexcept()); static_assert(destroy_at_noexcept()); diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index f066ed216dd..d6898732bca 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -53,7 +53,7 @@ void test_case_fill(CharT value, Func fillCall) { } template -void test_fill_unqual() { +void test_fill_volatile() { const CharT testCases[] = {cast(-100), cast(-1), cast(0), cast(1), cast(100)}; for (CharT testCase : testCases) { @@ -147,9 +147,9 @@ int main() { test_fill(); test_fill(); - test_fill_unqual(); // Test GH-1183 + test_fill_volatile(); // Test GH-1183 #ifdef __cpp_lib_byte - test_fill_unqual(); // Test GH-1556 + test_fill_volatile(); // Test GH-1556 #endif // __cpp_lib_byte test_uninitialized_fill( From 0bd49e6c2b631abfbc11a7e7abf225cd0a2d5be5 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 15:02:40 +0800 Subject: [PATCH 10/40] Fix `optional` and add test coverage --- stl/inc/optional | 28 ++++---- tests/std/tests/P0220R1_optional/test.cpp | 84 +++++++++++++++++++++++ 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/stl/inc/optional b/stl/inc/optional index a86eaa23be7..e67dac9eba5 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -71,7 +71,7 @@ template > struct _Optional_destruct_base { // either contains a value of _Ty or is empty (trivial destructor) union { _Nontrivial_dummy_type _Dummy; - remove_const_t<_Ty> _Value; + remove_cv_t<_Ty> _Value; }; bool _Has_value; @@ -98,7 +98,7 @@ template struct _Optional_destruct_base<_Ty, false> { // either contains a value of _Ty or is empty (non-trivial destructor) union { _Nontrivial_dummy_type _Dummy; - remove_const_t<_Ty> _Value; + remove_cv_t<_Ty> _Value; }; bool _Has_value; @@ -154,7 +154,7 @@ struct _Optional_construct_base : _Optional_destruct_base<_Ty> { is_nothrow_assignable_v<_Ty&, _Ty2>&& is_nothrow_constructible_v<_Ty, _Ty2>) { // assign / initialize the contained value from _Right if (this->_Has_value) { - this->_Value = _STD forward<_Ty2>(_Right); + static_cast<_Ty&>(this->_Value) = _STD forward<_Ty2>(_Right); } else { _Construct(_STD forward<_Ty2>(_Right)); } @@ -425,7 +425,7 @@ public: "optional::value_or(U) requires U to be convertible to T (N4828 [optional.observe]/18)."); if (this->_Has_value) { - return this->_Value; + return static_cast(this->_Value); } return static_cast>(_STD forward<_Ty2>(_Right)); @@ -439,7 +439,7 @@ public: "optional::value_or(U) requires U to be convertible to T (N4828 [optional.observe]/20)."); if (this->_Has_value) { - return _STD move(this->_Value); + return static_cast<_Ty&&>(this->_Value); } return static_cast>(_STD forward<_Ty2>(_Right)); @@ -455,7 +455,7 @@ public: "(N4901 [optional.monadic]/2)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), this->_Value); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&>(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -470,7 +470,7 @@ public: "(N4901 [optional.monadic]/2)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), this->_Value); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -485,7 +485,7 @@ public: "(N4901 [optional.monadic]/5)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _STD move(this->_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&&>(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -500,7 +500,7 @@ public: "(N4901 [optional.monadic]/5)."); if (this->_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _STD move(this->_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast(this->_Value)); } else { return remove_cvref_t<_Uty>{}; } @@ -518,7 +518,8 @@ public: "(N4901 [optional.monadic]/8)."); if (this->_Has_value) { - return optional<_Uty>{_Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), this->_Value}; + return optional<_Uty>{ + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&>(this->_Value)}; } else { return optional<_Uty>{}; } @@ -536,7 +537,8 @@ public: "(N4901 [optional.monadic]/8)."); if (this->_Has_value) { - return optional<_Uty>{_Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), this->_Value}; + return optional<_Uty>{ + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast(this->_Value)}; } else { return optional<_Uty>{}; } @@ -555,7 +557,7 @@ public: if (this->_Has_value) { return optional<_Uty>{ - _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(this->_Value)}; + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&&>(this->_Value)}; } else { return optional<_Uty>{}; } @@ -574,7 +576,7 @@ public: if (this->_Has_value) { return optional<_Uty>{ - _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(this->_Value)}; + _Construct_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast(this->_Value)}; } else { return optional<_Uty>{}; } diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index 33644626f10..9dded6ac532 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -8226,6 +8226,88 @@ namespace msvc { testMove(); } } // namespace gh2458 + + namespace assign_cv { + template + struct TypeIdentityImpl { + using type = T; + }; + template + using TypeIdentity = typename TypeIdentityImpl::type; + + struct CvAssignable { + CvAssignable() = default; + CvAssignable(const CvAssignable&) = default; + CvAssignable(CvAssignable&&) = default; + CvAssignable& operator=(const CvAssignable&) = default; + CvAssignable& operator=(CvAssignable&&) = default; + + template + CvAssignable(const volatile TypeIdentity&) noexcept {} + template + CvAssignable(const volatile TypeIdentity&&) noexcept {} + + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&) noexcept { + return *this; + } + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&&) noexcept { + return *this; + } + + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&) const volatile noexcept { + return *this; + } + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&&) const volatile noexcept { + return *this; + } + }; + + void run_test() { + using std::swap; + { + std::optional oc{}; + oc.emplace(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + + std::optional ov{}; + ov.emplace(0); + swap(ov, ov); + ov = ov; + ov = std::move(ov); + + std::optional ocv{}; + ocv.emplace(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + } + { + std::optional oc{}; + oc.emplace(CvAssignable{}); + swap(oc, oc); + oc = oc; + oc = std::move(oc); + + std::optional ov{}; + ov.emplace(CvAssignable{}); + swap(ov, ov); + ov = ov; + ov = std::move(ov); + + std::optional ocv{}; + ocv.emplace(CvAssignable{}); + swap(ocv, ocv); + ocv = ocv; + ocv = std::move(ocv); + } + } + } // namespace assign_cv } // namespace msvc int main() { @@ -8328,4 +8410,6 @@ int main() { msvc::vso614907::run_test(); msvc::gh2458::run_test(); + + msvc::assign_cv::run_test(); } From 30abcfe8c8926960ef2989cbb145ba57c1581866 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 15:06:08 +0800 Subject: [PATCH 11/40] Fix `variant` and add test coverage --- stl/inc/variant | 6 +- tests/std/tests/P0088R3_variant/test.cpp | 83 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/stl/inc/variant b/stl/inc/variant index c0008799ea1..670c5b4af3e 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -377,7 +377,7 @@ class _Variant_storage_ { // Storage for variant alterna public: static constexpr size_t _Size = 1 + sizeof...(_Rest); union { - remove_const_t<_First> _Head; + remove_cv_t<_First> _Head; _Variant_storage<_Rest...> _Tail; }; @@ -412,7 +412,7 @@ class _Variant_storage_ { // Storage for variant altern public: static constexpr size_t _Size = 1 + sizeof...(_Rest); union { - remove_const_t<_First> _Head; + remove_cv_t<_First> _Head; _Variant_storage<_Rest...> _Tail; }; @@ -457,7 +457,7 @@ public: // wrapper to enable minimal hats-in-variants support. template struct _Variant_item { - remove_const_t<_Ty> _Item; + remove_cv_t<_Ty> _Item; template constexpr _Variant_item(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 7c71757d6cf..7ea68859081 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -7850,6 +7850,88 @@ namespace msvc { #endif // _HAS_CXX20 } } // namespace gh2770 + + namespace assign_cv { + template + struct TypeIdentityImpl { + using type = T; + }; + template + using TypeIdentity = typename TypeIdentityImpl::type; + + struct CvAssignable { + CvAssignable() = default; + CvAssignable(const CvAssignable&) = default; + CvAssignable(CvAssignable&&) = default; + CvAssignable& operator=(const CvAssignable&) = default; + CvAssignable& operator=(CvAssignable&&) = default; + + template + CvAssignable(const volatile TypeIdentity&) noexcept {} + template + CvAssignable(const volatile TypeIdentity&&) noexcept {} + + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&) noexcept { + return *this; + } + template + constexpr CvAssignable& operator=(const volatile TypeIdentity&&) noexcept { + return *this; + } + + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&) const volatile noexcept { + return *this; + } + template + constexpr const volatile CvAssignable& operator=(const volatile TypeIdentity&&) const volatile noexcept { + return *this; + } + }; + + void run_test() { + using std::swap; + { + std::variant oc{}; + oc.emplace<0>(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + + std::variant ov{}; + ov.emplace<0>(0); + swap(ov, ov); + ov = ov; + ov = std::move(ov); + + std::variant ocv{}; + ocv.emplace<0>(0); + STATIC_ASSERT(!std::is_copy_assignable_v); + STATIC_ASSERT(!std::is_move_assignable_v); + STATIC_ASSERT(!std::is_swappable_v); + } + { + std::variant oc{}; + oc.emplace<0>(CvAssignable{}); + swap(oc, oc); + oc = oc; + oc = std::move(oc); + + std::variant ov{}; + ov.emplace<0>(CvAssignable{}); + swap(ov, ov); + ov = ov; + ov = std::move(ov); + + std::variant ocv{}; + ocv.emplace<0>(CvAssignable{}); + swap(ocv, ocv); + ocv = ocv; + ocv = std::move(ocv); + } + } + } // namespace assign_cv } // namespace msvc int main() { @@ -7916,6 +7998,7 @@ int main() { msvc::vso492097::run_test(); msvc::DevCom1031281::run_test(); msvc::gh2770::run_test(); + msvc::assign_cv::run_test(); } #else // ^^^ not x86 or not /analyze / x86 /analyze vvv int main() {} From 5837c3171e98f2f788f3eb4d173abc3d5daf969f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 15:57:27 +0800 Subject: [PATCH 12/40] Fix `_Variantish` and add test coverage --- stl/inc/iterator | 104 ++++++++++-------- .../tests/P0896R4_common_iterator/test.cpp | 82 ++++++++++++++ 2 files changed, 141 insertions(+), 45 deletions(-) diff --git a/stl/inc/iterator b/stl/inc/iterator index 6af048c0988..ed2ef562cf3 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -585,10 +585,10 @@ public: // clang-format on switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -605,10 +605,10 @@ public: : _Contains{_That._Contains} { switch (_Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -625,10 +625,10 @@ public: : _Contains{_That._Contains} { switch (_Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _STD move(_That._First)); + _STD _Construct_in_place(_First, _STD move(_That._Get_first())); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _STD move(_That._Second)); + _STD _Construct_in_place(_Second, _STD move(_That._Get_second())); break; case _Variantish_state::_Nothing: break; @@ -656,10 +656,10 @@ public: if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: - _First = _That._First; + _Get_first() = _That._Get_first(); break; case _Variantish_state::_Holds_second: - _Second = _That._Second; + _Get_second() = _That._Get_second(); break; case _Variantish_state::_Nothing: break; @@ -672,10 +672,10 @@ public: switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -701,10 +701,10 @@ public: if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: - _First = _STD move(_That._First); + _Get_first() = _STD move(_That._Get_first()); break; case _Variantish_state::_Holds_second: - _Second = _STD move(_That._Second); + _Get_second() = _STD move(_That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -717,10 +717,10 @@ public: switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _STD move(_That._First)); + _STD _Construct_in_place(_First, _STD move(_That._Get_first())); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _STD move(_That._Second)); + _STD _Construct_in_place(_Second, _STD move(_That._Get_second())); break; case _Variantish_state::_Nothing: break; @@ -741,10 +741,10 @@ public: if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: - _First = _That._First; + _Get_first() = _That._Get_first(); break; case _Variantish_state::_Holds_second: - _Second = _That._Second; + _Get_second() = _That._Get_second(); break; case _Variantish_state::_Nothing: break; @@ -757,10 +757,10 @@ public: switch (_That._Contains) { case _Variantish_state::_Holds_first: - _Construct_in_place(_First, _That._First); + _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: - _Construct_in_place(_Second, _That._Second); + _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -780,10 +780,10 @@ public: if (_Left._Contains == _Right._Contains) { switch (_Left._Contains) { case _Variantish_state::_Holds_first: - _RANGES swap(_Left._First, _Right._First); + _RANGES swap(_Left._Get_first(), _Right._Get_first()); break; case _Variantish_state::_Holds_second: - _RANGES swap(_Left._Second, _Right._Second); + _RANGES swap(_Left._Get_first(), _Right._Get_second()); break; case _Variantish_state::_Nothing: break; @@ -810,6 +810,20 @@ public: } } + _NODISCARD constexpr _Ty1& _Get_first() noexcept { + return _First; + } + _NODISCARD constexpr const _Ty1& _Get_first() const noexcept { + return _First; + } + + _NODISCARD constexpr _Ty2& _Get_second() noexcept { + return _Second; + } + _NODISCARD constexpr const _Ty2& _Get_second() const noexcept { + return _Second; + } + constexpr void _Clear() noexcept { _Raw_clear(); _Contains = _Variantish_state::_Nothing; @@ -819,7 +833,7 @@ public: constexpr void _Emplace_first(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty1, _Types...>) { _Clear(); - _Construct_in_place(_First, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_First, _STD forward<_Types>(_Args)...); _Contains = _Variantish_state::_Holds_first; } @@ -827,13 +841,13 @@ public: constexpr void _Emplace_second(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty2, _Types...>) { _Clear(); - _Construct_in_place(_Second, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Second, _STD forward<_Types>(_Args)...); _Contains = _Variantish_state::_Holds_second; } union { - _Ty1 _First; - _Ty2 _Second; + remove_cv_t<_Ty1> _First; + remove_cv_t<_Ty2> _Second; }; _Variantish_state _Contains; @@ -848,7 +862,7 @@ concept _Use_postfix_proxy = !requires(_Iter& __it) { { *__it++ } -> _Can_refere // clang-format on _EXPORT_STD template _Se> - requires (!same_as<_Iter, _Se> && copyable<_Iter>) + requires(!same_as<_Iter, _Se> && copyable<_Iter>) class common_iterator { private: struct _Proxy_base { @@ -896,7 +910,7 @@ public: _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return *_Val._First; + return *_Val._Get_first(); } _NODISCARD constexpr decltype(auto) operator*() const @@ -906,7 +920,7 @@ public: _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return *_Val._First; + return *_Val._Get_first(); } // clang-format off @@ -920,9 +934,9 @@ public: "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Has_member_arrow || is_pointer_v<_Iter>) { - return _Val._First; + return _Val._Get_first(); } else if constexpr (is_reference_v>) { - auto&& _Tmp = *_Val._First; + auto&& _Tmp = *_Val._Get_first(); return _STD addressof(_Tmp); } else { class _Arrow_proxy : private _Proxy_base { @@ -936,7 +950,7 @@ public: } }; - return _Arrow_proxy{*_Val._First}; + return _Arrow_proxy{*_Val._Get_first()}; } } @@ -945,7 +959,7 @@ public: _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be incremented if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - ++_Val._First; + ++_Val._Get_first(); return *this; } @@ -956,7 +970,7 @@ public: #endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (forward_iterator<_Iter>) { common_iterator _Tmp = *this; - ++_Val._First; + ++_Val._Get_first(); return _Tmp; } else if constexpr (_Use_postfix_proxy<_Iter>) { class _Postfix_proxy : private _Proxy_base { @@ -970,11 +984,11 @@ public: } }; - _Postfix_proxy _Tmp{*_Val._First}; - ++_Val._First; + _Postfix_proxy _Tmp{*_Val._Get_first()}; + ++_Val._Get_first(); return _Tmp; } else { - return _Val._First++; + return _Val._Get_first()++; } } @@ -992,16 +1006,16 @@ public: if (_Left._Val._Contains == _Variantish_state::_Holds_first) { if (_Right_val._Contains == _Variantish_state::_Holds_first) { if constexpr (equality_comparable_with<_Iter, _OIter>) { - return _Left._Val._First == _Right_val._First; + return _Left._Val._Get_first() == _Right_val._Get_first(); } else { return true; } } else { - return _Left._Val._First == _Right_val._Second; + return _Left._Val._Get_first() == _Right_val._Get_second(); } } else { if (_Right_val._Contains == _Variantish_state::_Holds_first) { - return _Left._Val._Second == _Right_val._First; + return _Left._Val._Get_second() == _Right_val._Get_first(); } else { return true; } @@ -1021,13 +1035,13 @@ public: if (_Left._Val._Contains == _Variantish_state::_Holds_first) { if (_Right_val._Contains == _Variantish_state::_Holds_first) { - return _Left._Val._First - _Right_val._First; + return _Left._Val._Get_first() - _Right_val._Get_first(); } else { - return _Left._Val._First - _Right_val._Second; + return _Left._Val._Get_first() - _Right_val._Get_second(); } } else { if (_Right_val._Contains == _Variantish_state::_Holds_first) { - return _Left._Val._Second - _Right_val._First; + return _Left._Val._Get_second() - _Right_val._Get_first(); } else { return 0; } @@ -1035,26 +1049,26 @@ public: } _NODISCARD_FRIEND constexpr iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& _Right) noexcept( - noexcept(_RANGES iter_move(_Right._Val._First))) + noexcept(_RANGES iter_move(_Right._Val._Get_first()))) requires input_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Right._Val._Contains == _Variantish_state::_Holds_first, "can only iter_move from common_iterator if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _RANGES iter_move(_Right._Val._First); + return _RANGES iter_move(_Right._Val._Get_first()); } template _OIter, class _OSe> friend constexpr void iter_swap(const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) noexcept( - noexcept(_RANGES iter_swap(_Left._Val._First, _Right._Get_val()._First))) { + noexcept(_RANGES iter_swap(_Left._Val._Get_first(), _Right._Get_val()._Get_first()))) { auto& _Right_val = _Right._Get_val(); #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left._Val._Contains == _Variantish_state::_Holds_first && _Right_val._Contains == _Variantish_state::_Holds_first, "can only iter_swap common_iterators if both hold iterators"); #endif // _ITERATOR_DEBUG_LEVEL != 0 - return _RANGES iter_swap(_Left._Val._First, _Right_val._First); + return _RANGES iter_swap(_Left._Val._Get_first(), _Right_val._Get_first()); } _NODISCARD constexpr _Variantish<_Iter, _Se>& _Get_val() noexcept { diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index d1736b99cfd..f0cb161e6be 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -332,6 +332,86 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY common_iterator it; } +struct VolatileSentinel { + VolatileSentinel() = default; + VolatileSentinel(const VolatileSentinel&) = default; + VolatileSentinel(VolatileSentinel&&) = default; + VolatileSentinel& operator=(const VolatileSentinel&) = default; + VolatileSentinel& operator=(VolatileSentinel&&) = default; + + explicit constexpr VolatileSentinel(const char* p) noexcept : ptr_{p} {} + + template + constexpr VolatileSentinel(const volatile type_identity_t& other) noexcept + : ptr_{other.ptr_} {} + template + constexpr VolatileSentinel(const volatile type_identity_t&& other) noexcept + : ptr_{other.ptr_} {} + + template + VolatileSentinel& operator=(volatile type_identity_t& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + VolatileSentinel& operator=(volatile type_identity_t&& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + VolatileSentinel& operator=(const volatile type_identity_t& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + VolatileSentinel& operator=(const volatile type_identity_t&& rhs) noexcept { + ptr_ = rhs.ptr_; + return *this; + } + + template + volatile VolatileSentinel& operator=(const volatile type_identity_t& rhs) volatile noexcept { + ptr_ = rhs.ptr_; + return *this; + } + template + volatile VolatileSentinel& operator=(const volatile type_identity_t&& rhs) volatile noexcept { + ptr_ = rhs.ptr_; + return *this; + } + + friend constexpr bool operator==(const char* const lhs, VolatileSentinel rhs) noexcept { + return lhs == rhs.ptr_; + } + + friend constexpr auto operator-(const char* const lhs, VolatileSentinel rhs) noexcept { + return lhs - rhs.ptr_; + } + + friend constexpr auto operator-(VolatileSentinel lhs, const char* const rhs) noexcept { + return lhs.ptr_ - rhs; + } + + const char* ptr_ = nullptr; +}; + +// constexpr-incompatible +void test_volatile() { + using std::swap; + using ci = common_iterator; + + ci it{static_cast(nullptr)}; + ci se{VolatileSentinel{static_cast(nullptr)}}; + + assert(it == se); + assert(it - se == 0); + assert(se - it == 0); + + swap(it, it); + it = it; + it = move(it); +} + int main() { with_writable_iterators::call(); static_assert(with_writable_iterators::call()); @@ -344,4 +424,6 @@ int main() { test_lwg_3574(); static_assert(test_lwg_3574()); + + test_volatile(); // constexpr-incompatible } From 7debf788a94476826a396c0394d862475aa9cee3 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 16:19:30 +0800 Subject: [PATCH 13/40] Fix boxes and add incomplete test coverage --- stl/inc/ranges | 112 +++++++++--------- tests/std/tests/P0896R4_views_single/test.cpp | 33 ++++++ 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 78b1c04e432..94b89141595 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -286,7 +286,7 @@ namespace ranges { requires copy_constructible<_Ty> : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); } } @@ -296,7 +296,7 @@ namespace ranges { constexpr _Movable_box(_Movable_box&& _That) : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); } } @@ -311,14 +311,14 @@ namespace ranges { { if (_Engaged) { if (_That._Engaged) { - _Val = _That._Val; + static_cast<_Ty&>(_Val) = static_cast(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); _Engaged = true; } else { // nothing to do @@ -341,7 +341,7 @@ namespace ranges { } if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); _Engaged = true; } @@ -359,14 +359,14 @@ namespace ranges { { if (_Engaged) { if (_That._Engaged) { - _Val = _STD move(_That._Val); + static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); _Engaged = true; } else { // nothing to do @@ -387,7 +387,7 @@ namespace ranges { } if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); _Engaged = true; } @@ -409,7 +409,7 @@ namespace ranges { private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; bool _Engaged; }; @@ -451,7 +451,7 @@ namespace ranges { { if (_STD addressof(_That) != this) { _Val.~_Ty(); - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); } return *this; @@ -460,7 +460,7 @@ namespace ranges { constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept { if (_STD addressof(_That) != this) { _Val.~_Ty(); - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); } return *this; @@ -478,7 +478,7 @@ namespace ranges { } private: - /* [[no_unique_address]] */ _Ty _Val{}; + /* [[no_unique_address]] */ remove_cv_t<_Ty> _Val{}; }; template @@ -503,7 +503,7 @@ namespace ranges { requires copy_constructible<_Ty> : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); } } @@ -513,7 +513,7 @@ namespace ranges { constexpr _Defaultabox(_Defaultabox&& _That) : _Engaged{_That._Engaged} { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); } } @@ -521,7 +521,7 @@ namespace ranges { requires convertible_to constexpr _Defaultabox(const _Defaultabox<_Uty>& _That) : _Engaged{_That} { if (_That) { - _Construct_in_place(_Val, *_That); + _STD _Construct_in_place(_Val, *_That); } } @@ -529,7 +529,7 @@ namespace ranges { requires convertible_to<_Uty, _Ty> constexpr _Defaultabox(_Defaultabox<_Uty>&& _That) : _Engaged{_That} { if (_That) { - _Construct_in_place(_Val, _STD move(*_That)); + _STD _Construct_in_place(_Val, _STD move(*_That)); } } @@ -544,14 +544,14 @@ namespace ranges { { if (_Engaged) { if (_That._Engaged) { - _Val = _That._Val; + static_cast<_Ty&>(_Val) = static_cast(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _That._Val); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); _Engaged = true; } else { // nothing to do @@ -569,14 +569,14 @@ namespace ranges { is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) /* strengthened */ { if (_Engaged) { if (_That._Engaged) { - _Val = _STD move(_That._Val); + static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val); } else { _Val.~_Ty(); _Engaged = false; } } else { if (_That._Engaged) { - _Construct_in_place(_Val, _STD move(_That._Val)); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); _Engaged = true; } else { // nothing to do @@ -589,9 +589,9 @@ namespace ranges { constexpr _Defaultabox& operator=(_Ty&& _That) noexcept( is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) { if (_Engaged) { - _Val = _STD move(_That); + static_cast<_Ty&>(_Val) = _STD move(_That); } else { - _Construct_in_place(_Val, _STD move(_That)); + _STD _Construct_in_place(_Val, _STD move(_That)); _Engaged = true; } @@ -603,9 +603,9 @@ namespace ranges { requires copyable<_Ty> { if (_Engaged) { - _Val = _That; + static_cast<_Ty&>(_Val) = _That; } else { - _Construct_in_place(_Val, _That); + _STD _Construct_in_place(_Val, _That); _Engaged = true; } @@ -632,14 +632,16 @@ namespace ranges { } } - _NODISCARD constexpr bool operator==(const _Defaultabox& _That) const noexcept(noexcept(_Val == _That._Val)) { + _NODISCARD constexpr bool operator==(const _Defaultabox& _That) const + noexcept(noexcept(static_cast(_Val) == static_cast(_That._Val))) { _STL_INTERNAL_STATIC_ASSERT(equality_comparable<_Ty>); - return _Engaged == _That._Engaged && (!_Engaged || _Val == _That._Val); + return _Engaged == _That._Engaged + && (!_Engaged || static_cast(_Val) == static_cast(_That._Val)); } private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; bool _Engaged = false; }; @@ -771,7 +773,7 @@ namespace ranges { _Engaged = false; } - _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); _Engaged = true; return _Val; @@ -779,7 +781,7 @@ namespace ranges { private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; bool _Engaged = false; }; @@ -814,13 +816,13 @@ namespace ranges { template constexpr _Ty& _Emplace(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { - _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Val, _STD forward<_Types>(_Args)...); return _Val; } private: union { - _Ty _Val; + remove_cv_t<_Ty> _Val; }; }; @@ -4047,18 +4049,18 @@ namespace ranges { template constexpr _Ret _Visit_inner_it(auto&& _Func) const { if (_Inner_it._Contains == _Variantish_state::_Holds_first) { - return _Func(_Inner_it._First); + return _Func(_Inner_it._Get_first()); } else if (_Inner_it._Contains == _Variantish_state::_Holds_second) { - return _Func(_Inner_it._Second); + return _Func(_Inner_it._Get_second()); } else { - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } } constexpr void _Satisfy() { for (;;) { if (_Inner_it._Contains == _Variantish_state::_Holds_first) { - if (_Inner_it._First != _RANGES end(_Parent->_Pattern)) { + if (_Inner_it._Get_first() != _RANGES end(_Parent->_Pattern)) { break; } @@ -4068,7 +4070,7 @@ namespace ranges { _STL_INTERNAL_CHECK(_Inner_it._Contains == _Variantish_state::_Holds_second); auto&& _Inner = _Get_inner(); - if (_Inner_it._Second != _RANGES end(_Inner)) { + if (_Inner_it._Get_second() != _RANGES end(_Inner)) { break; } @@ -4107,13 +4109,13 @@ namespace ranges { : _Outer_it{_STD move(_It._Outer_it)}, _Parent{_It._Parent} { switch (_It._Inner_it._Contains) { case _Variantish_state::_Holds_first: - _Inner_it._Emplace_first(_STD move(_It._Inner_it._First)); + _Inner_it._Emplace_first(_STD move(_It._Inner_it._Get_first())); break; case _Variantish_state::_Holds_second: - _Inner_it._Emplace_second(_STD move(_It._Inner_it._Second)); + _Inner_it._Emplace_second(_STD move(_It._Inner_it._Get_second())); break; case _Variantish_state::_Nothing: - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } } @@ -4125,13 +4127,13 @@ namespace ranges { constexpr _Iterator& operator++() { switch (_Inner_it._Contains) { case _Variantish_state::_Holds_first: - ++_Inner_it._First; + ++_Inner_it._Get_first(); break; case _Variantish_state::_Holds_second: - ++_Inner_it._Second; + ++_Inner_it._Get_second(); break; case _Variantish_state::_Nothing: - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } _Satisfy(); return *this; @@ -4161,7 +4163,7 @@ namespace ranges { for (;;) { if (_Inner_it._Contains == _Variantish_state::_Holds_first) { - auto& _It = _Inner_it._First; + auto& _It = _Inner_it._Get_first(); if (_It == _RANGES begin(_Parent->_Pattern)) { --_Outer_it; auto&& _Inner = *_Outer_it; @@ -4170,7 +4172,7 @@ namespace ranges { break; } } else if (_Inner_it._Contains == _Variantish_state::_Holds_second) { - auto& _It = _Inner_it._Second; + auto& _It = _Inner_it._Get_second(); auto&& _Inner = *_Outer_it; if (_It == _RANGES begin(_Inner)) { _Inner_it._Emplace_first(_RANGES end(_Parent->_Pattern)); @@ -4178,19 +4180,19 @@ namespace ranges { break; } } else { - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } } switch (_Inner_it._Contains) { case _Variantish_state::_Holds_first: - --_Inner_it._First; + --_Inner_it._Get_first(); break; case _Variantish_state::_Holds_second: - --_Inner_it._Second; + --_Inner_it._Get_second(); break; case _Variantish_state::_Nothing: - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } return *this; } @@ -4217,9 +4219,9 @@ namespace ranges { switch (_Left._Inner_it._Contains) { case _Variantish_state::_Holds_first: - return _Left._Inner_it._First == _Right._Inner_it._First; + return _Left._Inner_it._Get_first() == _Right._Inner_it._Get_first(); case _Variantish_state::_Holds_second: - return _Left._Inner_it._Second == _Right._Inner_it._Second; + return _Left._Inner_it._Get_second() == _Right._Inner_it._Get_second(); case _Variantish_state::_Nothing: return true; } @@ -4240,9 +4242,9 @@ namespace ranges { case _Variantish_state::_Holds_first: switch (_Right._Inner_it._Contains) { case _Variantish_state::_Holds_first: - return _RANGES iter_swap(_Left._Inner_it._First, _Right._Inner_it._First); + return _RANGES iter_swap(_Left._Inner_it._Get_first(), _Right._Inner_it._Get_first()); case _Variantish_state::_Holds_second: - return _RANGES iter_swap(_Left._Inner_it._First, _Right._Inner_it._Second); + return _RANGES iter_swap(_Left._Inner_it._Get_first(), _Right._Inner_it._Get_second()); case _Variantish_state::_Nothing: break; } @@ -4250,9 +4252,9 @@ namespace ranges { case _Variantish_state::_Holds_second: switch (_Right._Inner_it._Contains) { case _Variantish_state::_Holds_first: - return _RANGES iter_swap(_Left._Inner_it._Second, _Right._Inner_it._First); + return _RANGES iter_swap(_Left._Inner_it._Get_second(), _Right._Inner_it._Get_first()); case _Variantish_state::_Holds_second: - return _RANGES iter_swap(_Left._Inner_it._Second, _Right._Inner_it._Second); + return _RANGES iter_swap(_Left._Inner_it._Get_second(), _Right._Inner_it._Get_second()); case _Variantish_state::_Nothing: break; } @@ -4261,7 +4263,7 @@ namespace ranges { break; } - _Throw_bad_variant_access(); + _STD _Throw_bad_variant_access(); } }; diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index 18149b0566d..5f9ec0fcd2f 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -153,6 +153,36 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY (void) views::single(non_trivially_destructible{}); } +struct VolatileConstructible { + VolatileConstructible() = default; + VolatileConstructible(const VolatileConstructible&) = default; + VolatileConstructible(VolatileConstructible&&) = default; + VolatileConstructible& operator=(const VolatileConstructible&) = default; + VolatileConstructible& operator=(VolatileConstructible&&) = default; + + template + constexpr VolatileConstructible(const volatile type_identity_t&) noexcept {} + template + constexpr VolatileConstructible(const volatile type_identity_t&&) noexcept {} +}; + +constexpr bool test_cv() { + { + ranges::single_view sv{}; + sv = sv; + sv = move(sv); + } + { + ranges::single_view svv{}; + svv = svv; + svv = move(svv); + } + [[maybe_unused]] ranges::single_view svc{}; + [[maybe_unused]] ranges::single_view svcv{}; + + return true; +} + int main() { static_assert(test_one_type(42, 42)); test_one_type(42, 42); @@ -162,4 +192,7 @@ int main() { test_one_type(only_copy_constructible{42}, 42); test_one_type(string{"Hello, World!"}, "Hello, World!"); + + static_assert(test_cv()); + assert(test_cv()); } From 7da757bf001f5a3cc533eb6d5d67041bf731143e Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 16:31:12 +0800 Subject: [PATCH 14/40] Clang-format --- stl/inc/iterator | 2 +- tests/std/tests/P0896R4_common_iterator/test.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/stl/inc/iterator b/stl/inc/iterator index ed2ef562cf3..3c9c56bc108 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -862,7 +862,7 @@ concept _Use_postfix_proxy = !requires(_Iter& __it) { { *__it++ } -> _Can_refere // clang-format on _EXPORT_STD template _Se> - requires(!same_as<_Iter, _Se> && copyable<_Iter>) + requires (!same_as<_Iter, _Se> && copyable<_Iter>) class common_iterator { private: struct _Proxy_base { diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index f0cb161e6be..248a010536d 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -342,11 +342,9 @@ struct VolatileSentinel { explicit constexpr VolatileSentinel(const char* p) noexcept : ptr_{p} {} template - constexpr VolatileSentinel(const volatile type_identity_t& other) noexcept - : ptr_{other.ptr_} {} + constexpr VolatileSentinel(const volatile type_identity_t& other) noexcept : ptr_{other.ptr_} {} template - constexpr VolatileSentinel(const volatile type_identity_t&& other) noexcept - : ptr_{other.ptr_} {} + constexpr VolatileSentinel(const volatile type_identity_t&& other) noexcept : ptr_{other.ptr_} {} template VolatileSentinel& operator=(volatile type_identity_t& rhs) noexcept { From b9cb652c5a2d0432955cd0934a3028d752bf95a9 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 18:17:42 +0800 Subject: [PATCH 15/40] Try to fix `` and tests --- stl/inc/xsmf_control.h | 35 +++++++++++++++++++---- tests/std/tests/P0088R3_variant/test.cpp | 24 ++++++++-------- tests/std/tests/P0220R1_optional/test.cpp | 24 ++++++++-------- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/stl/inc/xsmf_control.h b/stl/inc/xsmf_control.h index 82898832342..530ff8c0296 100644 --- a/stl/inc/xsmf_control.h +++ b/stl/inc/xsmf_control.h @@ -34,10 +34,20 @@ struct _Non_trivial_copy : _Base { // non-trivial copy construction facade _Non_trivial_copy& operator=(_Non_trivial_copy&&) = default; }; +template +struct _Deleted_copy : _Base { // deleted copy construction facade + using _Base::_Base; + + _Deleted_copy() = default; + _Deleted_copy(const _Deleted_copy&) = delete; + _Deleted_copy(_Deleted_copy&&) = default; + _Deleted_copy& operator=(const _Deleted_copy&) = default; + _Deleted_copy& operator=(_Deleted_copy&&) = default; +}; + template -using _SMF_control_copy = conditional_t< - conjunction_v..., negation...>>>, - _Non_trivial_copy<_Base>, _Base>; +using _SMF_control_copy = conditional_t...>, _Base, + conditional_t...>, _Non_trivial_copy<_Base>, _Deleted_copy<_Base>>>; template @@ -56,9 +66,22 @@ struct _Non_trivial_move : _SMF_control_copy<_Base, _Types...> { // non-trivial }; template -using _SMF_control_move = conditional_t< - conjunction_v..., negation...>>>, - _Non_trivial_move<_Base, _Types...>, _SMF_control_copy<_Base, _Types...>>; +struct _Deleted_move : _SMF_control_copy<_Base, _Types...> { // deleted move construction facade + using _Mybase = _SMF_control_copy<_Base, _Types...>; + using _Mybase::_Mybase; + + _Deleted_move() = default; + _Deleted_move(const _Deleted_move&) = default; + _Deleted_move(_Deleted_move&&) = delete; + _Deleted_move& operator=(const _Deleted_move&) = default; + _Deleted_move& operator=(_Deleted_move&&) = default; +}; + +template +using _SMF_control_move = + conditional_t...>, _SMF_control_copy<_Base, _Types...>, + conditional_t...>, _Non_trivial_move<_Base, _Types...>, + _Deleted_move<_Base, _Types...>>>; template diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 7ea68859081..afff726fc50 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -7899,11 +7899,11 @@ namespace msvc { STATIC_ASSERT(!std::is_move_assignable_v); STATIC_ASSERT(!std::is_swappable_v); - std::variant ov{}; + std::variant ov{}, ov2{}; ov.emplace<0>(0); swap(ov, ov); - ov = ov; - ov = std::move(ov); + ov = ov2; + ov = std::move(ov2); std::variant ocv{}; ocv.emplace<0>(0); @@ -7912,23 +7912,23 @@ namespace msvc { STATIC_ASSERT(!std::is_swappable_v); } { - std::variant oc{}; + std::variant oc{}, oc2{}; oc.emplace<0>(CvAssignable{}); swap(oc, oc); - oc = oc; - oc = std::move(oc); + oc = oc2; + oc = std::move(oc2); - std::variant ov{}; + std::variant ov{}, ov2{}; ov.emplace<0>(CvAssignable{}); swap(ov, ov); - ov = ov; - ov = std::move(ov); + ov = ov2; + ov = std::move(ov2); - std::variant ocv{}; + std::variant ocv{}, ocv2{}; ocv.emplace<0>(CvAssignable{}); swap(ocv, ocv); - ocv = ocv; - ocv = std::move(ocv); + ocv = ocv2; + ocv = std::move(ocv2); } } } // namespace assign_cv diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index 9dded6ac532..deda271f76e 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -8275,11 +8275,11 @@ namespace msvc { STATIC_ASSERT(!std::is_move_assignable_v); STATIC_ASSERT(!std::is_swappable_v); - std::optional ov{}; + std::optional ov{}, ov2{}; ov.emplace(0); swap(ov, ov); - ov = ov; - ov = std::move(ov); + ov = ov2; + ov = std::move(ov2); std::optional ocv{}; ocv.emplace(0); @@ -8288,23 +8288,23 @@ namespace msvc { STATIC_ASSERT(!std::is_swappable_v); } { - std::optional oc{}; + std::optional oc{}, oc2{}; oc.emplace(CvAssignable{}); swap(oc, oc); - oc = oc; - oc = std::move(oc); + oc = oc2; + oc = std::move(oc2); - std::optional ov{}; + std::optional ov{}, ov2{}; ov.emplace(CvAssignable{}); swap(ov, ov); - ov = ov; - ov = std::move(ov); + ov = ov2; + ov = std::move(ov2); - std::optional ocv{}; + std::optional ocv{}, ocv2{}; ocv.emplace(CvAssignable{}); swap(ocv, ocv); - ocv = ocv; - ocv = std::move(ocv); + ocv = ocv2; + ocv = std::move(ocv2); } } } // namespace assign_cv From 95a945b3012348d14f304eb2444a8f95b4692f8a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 18:25:22 +0800 Subject: [PATCH 16/40] Missed fixes --- tests/std/tests/P0896R4_common_iterator/test.cpp | 4 ++-- tests/std/tests/P0896R4_views_single/test.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index 248a010536d..332a1380d47 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -406,8 +406,8 @@ void test_volatile() { assert(se - it == 0); swap(it, it); - it = it; - it = move(it); + it = se; + it = move(se); } int main() { diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index 5f9ec0fcd2f..d4037cdb3cf 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -168,14 +168,14 @@ struct VolatileConstructible { constexpr bool test_cv() { { - ranges::single_view sv{}; - sv = sv; - sv = move(sv); + ranges::single_view sv{}, sv2{}; + sv = sv2; + sv = move(sv2); } { - ranges::single_view svv{}; - svv = svv; - svv = move(svv); + ranges::single_view svv{}, svv2{}; + svv = svv2; + svv = move(svv2); } [[maybe_unused]] ranges::single_view svc{}; [[maybe_unused]] ranges::single_view svcv{}; From 91de15e1f8c6f22474012b9c5c8b3b746fe5e04a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 19 Feb 2023 19:25:19 +0800 Subject: [PATCH 17/40] Ignore deprecation for test --- tests/std/tests/P0896R4_common_iterator/test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index 332a1380d47..748e99da5e5 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#pragma warning(disable : 5215) // volatile function arguments are deprecated in C++20 + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-volatile" // volatile function arguments are deprecated in C++20 +#endif // __clang__ + #include #include #include From 35a950e12c5a5564e065cbfa7cd5bce49b36a51c Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 21 Feb 2023 23:41:29 +0800 Subject: [PATCH 18/40] ``: speculatively implement LWG-3891 --- stl/inc/expected | 88 +++++++++++----------- tests/std/tests/P0323R12_expected/test.cpp | 73 ++++++++++++++++++ 2 files changed, 117 insertions(+), 44 deletions(-) diff --git a/stl/inc/expected b/stl/inc/expected index 9d4a583cfd0..f628c75cd3f 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -209,7 +209,7 @@ public: && is_copy_constructible_v<_Ty> && is_copy_constructible_v<_Err>) : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), _Other._Value); + _STD construct_at(_STD addressof(_Value), static_cast(_Other._Value)); } else { _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected); } @@ -226,7 +226,7 @@ public: && is_move_constructible_v<_Ty> && is_move_constructible_v<_Err>) : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), _STD move(_Other._Value)); + _STD construct_at(_STD addressof(_Value), static_cast<_Ty&&>(_Other._Value)); } else { _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected)); } @@ -259,7 +259,7 @@ public: && is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), _Other._Value); + _STD construct_at(_STD addressof(_Value), static_cast(_Other._Value)); } else { _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected); } @@ -272,7 +272,7 @@ public: is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_constructible_v<_Err, _UErr>) // strengthened : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), _STD move(_Other._Value)); + _STD construct_at(_STD addressof(_Value), static_cast<_Uty&&>(_Other._Value)); } else { _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected)); } @@ -358,7 +358,7 @@ public: template static constexpr void _Reinit_expected(_First& _New_val, _Second& _Old_val, _Args&&... _Vals) noexcept( - is_nothrow_constructible_v<_First, _Args...>) // strengthened + is_nothrow_constructible_v<_First, _Args...>) { if constexpr (is_nothrow_constructible_v<_First, _Args...>) { if constexpr (!is_trivially_destructible_v<_Second>) { @@ -391,11 +391,11 @@ public: && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { if (_Has_value && _Other._Has_value) { - _Value = _Other._Value; + static_cast<_Ty&>(_Value) = static_cast(_Other._Value); } else if (_Has_value) { _Reinit_expected(_Unexpected, _Value, _Other._Unexpected); } else if (_Other._Has_value) { - _Reinit_expected(_Value, _Unexpected, _Other._Value); + _Reinit_expected(_Value, _Unexpected, static_cast(_Other._Value)); } else { _Unexpected = _Other._Unexpected; } @@ -412,11 +412,11 @@ public: && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { if (_Has_value && _Other._Has_value) { - _Value = _STD move(_Other._Value); + static_cast<_Ty&>(_Value) = static_cast<_Ty&&>(_Other._Value); } else if (_Has_value) { _Reinit_expected(_Unexpected, _Value, _STD move(_Other._Unexpected)); } else if (_Other._Has_value) { - _Reinit_expected(_Value, _Unexpected, _STD move(_Other._Value)); + _Reinit_expected(_Value, _Unexpected, static_cast<_Ty&&>(_Other._Value)); } else { _Unexpected = _STD move(_Other._Unexpected); } @@ -433,7 +433,7 @@ public: constexpr expected& operator=(_Uty&& _Other) noexcept( is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_assignable_v<_Ty&, _Uty>) /* strengthened */ { if (_Has_value) { - _Value = _STD forward<_Uty>(_Other); + static_cast<_Ty&>(_Value) = _STD forward<_Uty>(_Other); } else { _Reinit_expected(_Value, _Unexpected, _STD forward<_Uty>(_Other)); _Has_value = true; @@ -517,7 +517,7 @@ public: && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { if (_Has_value && _Other._Has_value) { - _Swap_adl(_Value, _Other._Value); + _STD _Swap_adl(static_cast<_Ty&>(_Value), static_cast<_Ty&>(_Other._Value)); } else if (_Has_value) { if constexpr (is_nothrow_move_constructible_v<_Err>) { _Err _Tmp(_STD move(_Other._Unexpected)); @@ -526,10 +526,10 @@ public: } if constexpr (is_nothrow_move_constructible_v<_Ty>) { - _STD construct_at(_STD addressof(_Other._Value), _STD move(_Value)); + _STD construct_at(_STD addressof(_Other._Value), static_cast<_Ty&&>(_Value)); } else { _GuardTy<_Err> _Guard{_STD addressof(_Other._Unexpected), _STD addressof(_Tmp)}; - _STD construct_at(_STD addressof(_Other._Value), _STD move(_Value)); + _STD construct_at(_STD addressof(_Other._Value), static_cast<_Ty&&>(_Value)); _Guard._Target = nullptr; } @@ -558,7 +558,7 @@ public: } else if (_Other._Has_value) { _Other.swap(*this); } else { - _Swap_adl(_Unexpected, _Other._Unexpected); + _STD _Swap_adl(_Unexpected, _Other._Unexpected); } } @@ -680,7 +680,7 @@ public: is_convertible_v<_Uty, _Ty>, "is_convertible_v must be true. (N4928 [expected.object.obs]/16)"); if (_Has_value) { - return _Value; + return static_cast(_Value); } else { return static_cast<_Ty>(_STD forward<_Uty>(_Other)); } @@ -694,7 +694,7 @@ public: is_convertible_v<_Uty, _Ty>, "is_convertible_v must be true. (N4928 [expected.object.obs]/18)"); if (_Has_value) { - return _STD move(_Value); + return static_cast<_Ty&&>(_Value); } else { return static_cast<_Ty>(_STD forward<_Uty>(_Other)); } @@ -744,7 +744,7 @@ public: "(N4928 [expected.object.monadic]/3)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _Value); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&>(_Value)); } else { return _Uty{unexpect, _Unexpected}; } @@ -763,7 +763,7 @@ public: "(N4928 [expected.object.monadic]/3)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _Value); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); } else { return _Uty{unexpect, _Unexpected}; } @@ -782,7 +782,7 @@ public: "(N4928 [expected.object.monadic]/7)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&&>(_Value)); } else { return _Uty{unexpect, _STD move(_Unexpected)}; } @@ -801,7 +801,7 @@ public: "(N4928 [expected.object.monadic]/7)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); } else { return _Uty{unexpect, _STD move(_Unexpected)}; } @@ -820,7 +820,7 @@ public: "(N4928 [expected.object.monadic]/11)"); if (_Has_value) { - return _Uty{in_place, _Value}; + return _Uty{in_place, static_cast<_Ty&>(_Value)}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected); } @@ -839,7 +839,7 @@ public: "(N4928 [expected.object.monadic]/11)"); if (_Has_value) { - return _Uty{in_place, _Value}; + return _Uty{in_place, static_cast(_Value)}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected); } @@ -858,7 +858,7 @@ public: "(N4928 [expected.object.monadic]/15)"); if (_Has_value) { - return _Uty{in_place, _STD move(_Value)}; + return _Uty{in_place, static_cast<_Ty&&>(_Value)}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected)); } @@ -877,7 +877,7 @@ public: "(N4928 [expected.object.monadic]/15)"); if (_Has_value) { - return _Uty{in_place, _STD move(_Value)}; + return _Uty{in_place, static_cast(_Value)}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected)); } @@ -899,11 +899,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), _Value); + _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&>(_Value)); return expected<_Uty, _Err>{}; } else { return expected<_Uty, _Err>{ - _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _Value}; + _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&>(_Value)}; } } else { return expected<_Uty, _Err>{unexpect, _Unexpected}; @@ -926,11 +926,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), _Value); + _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); return expected<_Uty, _Err>{}; } else { - return expected<_Uty, _Err>{ - _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _Value}; + return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), + static_cast(_Value)}; } } else { return expected<_Uty, _Err>{unexpect, _Unexpected}; @@ -953,11 +953,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); + _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&&>(_Value)); return expected<_Uty, _Err>{}; } else { return expected<_Uty, _Err>{ - _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(_Value)}; + _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&&>(_Value)}; } } else { return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)}; @@ -980,11 +980,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); + _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); return expected<_Uty, _Err>{}; } else { - return expected<_Uty, _Err>{ - _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(_Value)}; + return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), + static_cast(_Value)}; } } else { return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)}; @@ -1004,7 +1004,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, _Value}; + return expected<_Ty, _Uty>{in_place, static_cast<_Ty&>(_Value)}; } else { return expected<_Ty, _Uty>{ _Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected}; @@ -1025,7 +1025,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, _Value}; + return expected<_Ty, _Uty>{in_place, static_cast(_Value)}; } else { return expected<_Ty, _Uty>{ _Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected}; @@ -1045,7 +1045,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, _STD move(_Value)}; + return expected<_Ty, _Uty>{in_place, static_cast<_Ty&&>(_Value)}; } else { return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _STD move(_Unexpected)}; @@ -1066,7 +1066,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, _STD move(_Value)}; + return expected<_Ty, _Uty>{in_place, static_cast(_Value)}; } else { return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _STD move(_Unexpected)}; @@ -1077,12 +1077,12 @@ public: template requires (!is_void_v<_Uty>) _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept( - noexcept(_Fake_copy_init(_Left._Value == *_Right)) && noexcept( - _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { + noexcept(_STD _Fake_copy_init(static_cast(_Left._Value) == *_Right)) && noexcept( + _STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value != _Right.has_value()) { return false; } else if (_Left._Has_value) { - return _Left._Value == *_Right; + return static_cast(_Left._Value) == *_Right; } else { return _Left._Unexpected == _Right.error(); } @@ -1090,9 +1090,9 @@ public: template _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const _Uty& _Right) noexcept( - noexcept(static_cast(_Left._Value == _Right))) /* strengthened */ { + noexcept(static_cast(static_cast(_Left._Value) == _Right))) /* strengthened */ { if (_Left._Has_value) { - return static_cast(_Left._Value == _Right); + return static_cast(static_cast(_Left._Value) == _Right); } else { return false; } @@ -1140,7 +1140,7 @@ private: } union { - _Ty _Value; + remove_cv_t<_Ty> _Value; // per LWG-3891 _Err _Unexpected; }; bool _Has_value; diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 1f02f528726..a6abb3c6f06 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -2052,6 +2052,78 @@ struct Data { }; static_assert(((void) expected{unexpect, {1, 2, 3}}, true)); +struct CvAssignable { + CvAssignable() = default; + CvAssignable(const CvAssignable&) = default; + CvAssignable(CvAssignable&&) = default; + CvAssignable& operator=(const CvAssignable&) = default; + CvAssignable& operator=(CvAssignable&&) = default; + + template + CvAssignable(const volatile type_identity_t&) noexcept {} + template + CvAssignable(const volatile type_identity_t&&) noexcept {} + + template + constexpr CvAssignable& operator=(const volatile type_identity_t&) noexcept { + return *this; + } + template + constexpr CvAssignable& operator=(const volatile type_identity_t&&) noexcept { + return *this; + } + + template + constexpr const volatile CvAssignable& operator=(const volatile type_identity_t&) const volatile noexcept { + return *this; + } + template + constexpr const volatile CvAssignable& operator=(const volatile type_identity_t&&) const volatile noexcept { + return *this; + } +}; + +void test_lwg3891() { + { + expected oc{}; + oc.emplace(0); + static_assert(!is_copy_assignable_v); + static_assert(!is_move_assignable_v); + static_assert(!is_swappable_v); + + expected ov{}, ov2{}; + ov.emplace(0); + swap(ov, ov); + ov = ov2; + ov = move(ov2); + + expected ocv{}; + ocv.emplace(0); + static_assert(!is_copy_assignable_v); + static_assert(!is_move_assignable_v); + static_assert(!is_swappable_v); + } + { + expected oc{}, oc2{}; + oc.emplace(CvAssignable{}); + swap(oc, oc); + oc = oc2; + oc = move(oc2); + + expected ov{}, ov2{}; + ov.emplace(CvAssignable{}); + swap(ov, ov); + ov = ov2; + ov = move(ov2); + + expected ocv{}, ocv2{}; + ocv.emplace(CvAssignable{}); + swap(ocv, ocv); + ocv = ocv2; + ocv = move(ocv2); + } +} + int main() { test_unexpected::test_all(); static_assert(test_unexpected::test_all()); @@ -2067,4 +2139,5 @@ int main() { static_assert(is_convertible_v*, exception*>); test_reinit_regression(); + test_lwg3891(); } From eb874c2ffa9728d45f7468f3761780e57b4cac86 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 22 Feb 2023 00:28:35 +0800 Subject: [PATCH 19/40] `` etc.: speculatively implement LWG-3888 --- stl/inc/memory | 9 +- stl/inc/xmemory | 9 +- stl/inc/xutility | 6 +- .../test.cpp | 119 ++++++++++++++++-- 4 files changed, 125 insertions(+), 18 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index 98e4a8881f2..ee9126483b2 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -530,15 +530,14 @@ namespace ranges { // clang-format off template - requires requires(void* _Void_ptr, _Types&&... _Args) { - ::new (_Void_ptr) _Ty(static_cast<_Types&&>(_Args)...); + requires requires(_Ty* _Ptr, _Types&&... _Args) { + ::new (static_cast(_Ptr)) _Ty(static_cast<_Types&&>(_Args)...); // per LWG-3888 } constexpr _Ty* operator()(_Ty* _Location, _Types&&... _Args) const - noexcept(noexcept(::new (const_cast(static_cast(_Location))) + noexcept(noexcept(::new (static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { // clang-format on - _MSVC_CONSTEXPR return ::new (const_cast(static_cast(_Location))) - _Ty(_STD forward<_Types>(_Args)...); + _MSVC_CONSTEXPR return ::new (static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...); } }; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 17fad181c90..fd96203d0d5 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1619,9 +1619,12 @@ _CONSTEXPR20 _NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _In #ifdef __cpp_lib_concepts namespace ranges { template - concept _No_throw_input_iterator = input_iterator<_It> // - && is_lvalue_reference_v> // - && same_as>, iter_value_t<_It>>; + concept _No_throw_input_iterator = + input_iterator<_It> // + && is_lvalue_reference_v> // + && same_as>, remove_reference_t>> // per LWG-3888 + && same_as>, iter_value_t<_It>>; + template concept _No_throw_sentinel_for = sentinel_for<_Se, _It>; diff --git a/stl/inc/xutility b/stl/inc/xutility index 9ffb0f9c816..10c804f5c6e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -232,11 +232,13 @@ struct _Get_rebind_alias<_Ty, _Other, void_t()) _Ty(_STD declval<_Types>()...))>> + class = void_t(_STD declval<_Ty*>())) _Ty(_STD declval<_Types>()...))>> #else // ^^^ no workaround / workaround vvv +// per LWG-3888 _EXPORT_STD template ()) _Ty(_STD declval<_Types>()...))>* = nullptr> + void_t(_STD declval<_Ty*>())) _Ty(_STD declval<_Types>()...))>* = nullptr> #endif // TRANSITION, DevCom-1691516 constexpr _Ty* construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( noexcept(::new(static_cast(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 3cd2223a044..a036c3b2f61 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -74,7 +74,7 @@ constexpr bool destroy_at_noexcept() { static_assert(can_construct_at); static_assert(can_construct_at); static_assert(can_construct_at); -#if 0 // TRANSITION, construct_at is underconstrained for cv T* +// per LWG-3888 static_assert(!can_construct_at); static_assert(!can_construct_at); static_assert(!can_construct_at); @@ -84,7 +84,6 @@ static_assert(!can_construct_at); static_assert(!can_construct_at); static_assert(!can_construct_at); static_assert(!can_construct_at); -#endif // 0 struct X {}; @@ -102,11 +101,10 @@ struct indestructible { }; static_assert(can_construct_at); -#if 0 // TRANSITION, construct_at is underconstrained for cv T* +// per LWG-3888 static_assert(!can_construct_at); static_assert(!can_construct_at); static_assert(!can_construct_at); -#endif // 0 static_assert(can_construct_at); static_assert(can_construct_at); @@ -122,18 +120,16 @@ static_assert(!can_construct_at); // The following static_asserts test our strengthening of noexcept static_assert(construct_at_noexcept()); -#if 0 // TRANSITION, construct_at is underconstrained for cv T* +// per LWG-3888 static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); -#endif // 0 static_assert(!construct_at_noexcept()); -#if 0 // TRANSITION, construct_at is underconstrained for cv T* +// per LWG-3888 static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); static_assert(!construct_at_noexcept()); -#endif // 0 static_assert(destroy_at_noexcept()); static_assert(destroy_at_noexcept()); @@ -511,6 +507,113 @@ constexpr void test_compiletime_operators() { } static_assert((test_compiletime_operators(), true)); +// Also test LWG-3888 Most ranges uninitialized memory algorithms are underconstrained + +template +concept CanUninitilizedDefaultConstruct = requires(Rng& r) { ranges::uninitialized_default_construct(r); }; + +template +concept CanUninitilizedDefaultConstructN = + requires(It&& i) { ranges::uninitialized_default_construct_n(forward(i), iter_difference_t{}); }; + +template +concept CanUninitilizedValueConstruct = requires(Rng& r) { ranges::uninitialized_value_construct(r); }; + +template +concept CanUninitilizedValueConstructN = + requires(It&& i) { ranges::uninitialized_value_construct_n(forward(i), iter_difference_t{}); }; + +template +concept CanUninitilizedFill = requires(Rng& r, const T& t) { ranges::uninitialized_fill(r, t); }; + +template +concept CanUninitilizedFillN = + requires(It&& i, const T& t) { ranges::uninitialized_fill_n(forward(i), iter_difference_t{}, t); }; + +template +concept CanUninitilizedCopy = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_copy(ri, ro); }; + +template +concept CanUninitilizedCopyN = + requires(InIt&& ii, OutIt&& io, S&& s) { + ranges::uninitialized_copy_n(forward(ii), iter_difference_t{}, forward(io), forward(s)); + }; + +template +concept CanUninitilizedMove = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_move(ri, ro); }; + +template +concept CanUninitilizedMoveN = + requires(InIt&& ii, OutIt&& io, S&& s) { + ranges::uninitialized_move_n(forward(ii), iter_difference_t{}, forward(io), forward(s)); + }; + +template +concept CanDestroy = requires(Rng&& r) { ranges::destroy(forward(r)); }; + +template +concept CanDestroyN = requires(It&& i) { ranges::destroy_n(forward(i), iter_difference_t{}); }; + +static_assert(CanUninitilizedDefaultConstruct); +static_assert(!CanUninitilizedDefaultConstruct); +static_assert(!CanUninitilizedDefaultConstruct); +static_assert(!CanUninitilizedDefaultConstruct); + +static_assert(CanUninitilizedDefaultConstructN); +static_assert(!CanUninitilizedDefaultConstructN); +static_assert(!CanUninitilizedDefaultConstructN); +static_assert(!CanUninitilizedDefaultConstructN); + +static_assert(CanUninitilizedValueConstruct); +static_assert(!CanUninitilizedValueConstruct); +static_assert(!CanUninitilizedValueConstruct); +static_assert(!CanUninitilizedValueConstruct); + +static_assert(CanUninitilizedValueConstructN); +static_assert(!CanUninitilizedValueConstructN); +static_assert(!CanUninitilizedValueConstructN); +static_assert(!CanUninitilizedValueConstructN); + +static_assert(CanUninitilizedFill); +static_assert(!CanUninitilizedFill); +static_assert(!CanUninitilizedFill); +static_assert(!CanUninitilizedFill); + +static_assert(CanUninitilizedFillN); +static_assert(!CanUninitilizedFillN); +static_assert(!CanUninitilizedFillN); +static_assert(!CanUninitilizedFillN); + +static_assert(CanUninitilizedCopy); +static_assert(!CanUninitilizedCopy); +static_assert(!CanUninitilizedCopy); +static_assert(!CanUninitilizedCopy); + +static_assert(CanUninitilizedCopyN); +static_assert(!CanUninitilizedCopyN); +static_assert(!CanUninitilizedCopyN); +static_assert(!CanUninitilizedCopyN); + +static_assert(CanUninitilizedMove); +static_assert(!CanUninitilizedMove); +static_assert(!CanUninitilizedMove); +static_assert(!CanUninitilizedMove); + +static_assert(CanUninitilizedMoveN); +static_assert(!CanUninitilizedMoveN); +static_assert(!CanUninitilizedMoveN); +static_assert(!CanUninitilizedMoveN); + +static_assert(CanDestroy); +static_assert(!CanDestroy); +static_assert(!CanDestroy); +static_assert(!CanDestroy); + +static_assert(CanDestroyN); +static_assert(!CanDestroyN); +static_assert(!CanDestroyN); +static_assert(!CanDestroyN); + int main() { test_runtime(1234); test_runtime(string("hello world")); From f95959a09dba2edcb86ca134b935044cde83ad1f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 22 Feb 2023 00:38:21 +0800 Subject: [PATCH 20/40] Clang-format: restore mistakenly broken line --- stl/inc/expected | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/expected b/stl/inc/expected index f628c75cd3f..ed6afd94222 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -358,8 +358,7 @@ public: template static constexpr void _Reinit_expected(_First& _New_val, _Second& _Old_val, _Args&&... _Vals) noexcept( - is_nothrow_constructible_v<_First, _Args...>) - { + is_nothrow_constructible_v<_First, _Args...>) { if constexpr (is_nothrow_constructible_v<_First, _Args...>) { if constexpr (!is_trivially_destructible_v<_Second>) { _Old_val.~_Second(); From 486ebe9295416732846e04ffa8ac406af065ea73 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 22 Feb 2023 01:21:53 +0800 Subject: [PATCH 21/40] Fix tests and libcxx skip --- tests/libcxx/expected_results.txt | 1 + tests/libcxx/skipped_tests.txt | 1 + tests/std/tests/P0323R12_expected/test.cpp | 3 +++ .../test.cpp | 6 +++++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3d1a67f0831..681c8301e5b 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -127,6 +127,7 @@ std/strings/string.view/string.view.cons/from_string1.compile.fail.cpp FAIL std/strings/string.view/string.view.cons/from_string2.compile.fail.cpp FAIL # libc++ doesn't implement LWG-3870 +std/utilities/memory/specialized.algorithms/specialized.construct/ranges_construct_at.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp FAIL std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 7de059841b3..40141d77470 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -127,6 +127,7 @@ strings\string.view\string.view.cons\from_string1.compile.fail.cpp strings\string.view\string.view.cons\from_string2.compile.fail.cpp # libc++ doesn't implement LWG-3870 +utilities\memory\specialized.algorithms\specialized.construct\ranges_construct_at.pass.cpp utilities\memory\specialized.algorithms\uninitialized.construct.default\ranges_uninitialized_default_construct.pass.cpp utilities\memory\specialized.algorithms\uninitialized.construct.default\ranges_uninitialized_default_construct_n.pass.cpp utilities\memory\specialized.algorithms\uninitialized.construct.value\ranges_uninitialized_value_construct.pass.cpp diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index a6abb3c6f06..42b19080942 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -2083,6 +2083,8 @@ struct CvAssignable { } }; +#pragma warning(push) +#pragma warning(disable : 5216) // volatile qualified return type void test_lwg3891() { { expected oc{}; @@ -2123,6 +2125,7 @@ void test_lwg3891() { ocv = move(ocv2); } } +#pragma warning(pop) int main() { test_unexpected::test_all(); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index a036c3b2f61..b6470d8d8d4 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -62,7 +62,11 @@ inline constexpr bool can_construct_at = can_construct_at_impl constexpr bool construct_at_noexcept() { - return noexcept(construct_at(declval(), declval()...)); + if constexpr (can_construct_at) { + return noexcept(construct_at(declval(), declval()...)); + } else { + return false; + } } template From b37e73910cb7d1c1e1ab53381a21d4965cd5ebcb Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 22 Feb 2023 01:48:56 +0800 Subject: [PATCH 22/40] Furtherly fix tests --- tests/std/tests/P0323R12_expected/test.cpp | 9 +++++++++ .../test.cpp | 10 +++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 42b19080942..b6faa0d18be 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -2083,8 +2083,13 @@ struct CvAssignable { } }; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-volatile" // volatile qualified return type +#else // ^^^ Clang / MSVC vvv #pragma warning(push) #pragma warning(disable : 5216) // volatile qualified return type +#endif // ^^^ MSVC ^^^ void test_lwg3891() { { expected oc{}; @@ -2125,7 +2130,11 @@ void test_lwg3891() { ocv = move(ocv2); } } +#ifdef __clang__ +#pragma clang diagnostic pop +#else // ^^^ Clang / MSVC vvv #pragma warning(pop) +#endif // ^^^ MSVC ^^^ int main() { test_unexpected::test_all(); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index b6470d8d8d4..06a21eff78b 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -36,9 +36,13 @@ inline constexpr bool can_construct_at = [] { template constexpr bool construct_at_noexcept() { - constexpr bool result = noexcept(construct_at(declval(), declval()...)); - static_assert(noexcept(ranges::construct_at(declval(), declval()...)) == result); - return result; + if constexpr (can_construct_at) { + constexpr bool result = noexcept(construct_at(declval(), declval()...)); + static_assert(noexcept(ranges::construct_at(declval(), declval()...)) == result); + return result; + } else { + return false; + } } template From 17a09559065a3cd5d9cef4fbbc647e5f7705f14d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 22 Feb 2023 02:23:52 +0800 Subject: [PATCH 23/40] Fixes for Clang and EDG --- tests/std/tests/P0323R12_expected/test.cpp | 22 +++++++++++-------- .../test.cpp | 3 ++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index b6faa0d18be..9e8c49d9601 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -3,6 +3,11 @@ #define _CONTAINER_DEBUG_LEVEL 1 +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-volatile" // volatile qualified return type +#endif // __clang__ + #include #include #include @@ -11,6 +16,10 @@ #include #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + using namespace std; enum class IsDefaultConstructible : bool { Not, Yes }; @@ -2083,13 +2092,10 @@ struct CvAssignable { } }; -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-volatile" // volatile qualified return type -#else // ^^^ Clang / MSVC vvv +#ifndef __clang__ #pragma warning(push) #pragma warning(disable : 5216) // volatile qualified return type -#endif // ^^^ MSVC ^^^ +#endif // __clang__ void test_lwg3891() { { expected oc{}; @@ -2130,11 +2136,9 @@ void test_lwg3891() { ocv = move(ocv2); } } -#ifdef __clang__ -#pragma clang diagnostic pop -#else // ^^^ Clang / MSVC vvv +#ifndef __clang__ #pragma warning(pop) -#endif // ^^^ MSVC ^^^ +#endif // __clang__ int main() { test_unexpected::test_all(); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 06a21eff78b..c6dbf5043a6 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -515,8 +515,8 @@ constexpr void test_compiletime_operators() { } static_assert((test_compiletime_operators(), true)); +#ifdef __cpp_lib_concepts // Also test LWG-3888 Most ranges uninitialized memory algorithms are underconstrained - template concept CanUninitilizedDefaultConstruct = requires(Rng& r) { ranges::uninitialized_default_construct(r); }; @@ -621,6 +621,7 @@ static_assert(CanDestroyN); static_assert(!CanDestroyN); static_assert(!CanDestroyN); static_assert(!CanDestroyN); +#endif // __cpp_lib_concepts int main() { test_runtime(1234); From c6662ba6380ecb6d274c6fce7bbce3d19341954c Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 23 Feb 2023 07:15:00 +0800 Subject: [PATCH 24/40] Revert speculative implementation of LWG-3891 --- stl/inc/expected | 89 +++++++++++----------- tests/std/tests/P0323R12_expected/test.cpp | 89 ---------------------- 2 files changed, 45 insertions(+), 133 deletions(-) diff --git a/stl/inc/expected b/stl/inc/expected index ed6afd94222..9d4a583cfd0 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -209,7 +209,7 @@ public: && is_copy_constructible_v<_Ty> && is_copy_constructible_v<_Err>) : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), static_cast(_Other._Value)); + _STD construct_at(_STD addressof(_Value), _Other._Value); } else { _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected); } @@ -226,7 +226,7 @@ public: && is_move_constructible_v<_Ty> && is_move_constructible_v<_Err>) : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), static_cast<_Ty&&>(_Other._Value)); + _STD construct_at(_STD addressof(_Value), _STD move(_Other._Value)); } else { _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected)); } @@ -259,7 +259,7 @@ public: && is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), static_cast(_Other._Value)); + _STD construct_at(_STD addressof(_Value), _Other._Value); } else { _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected); } @@ -272,7 +272,7 @@ public: is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_constructible_v<_Err, _UErr>) // strengthened : _Has_value(_Other._Has_value) { if (_Has_value) { - _STD construct_at(_STD addressof(_Value), static_cast<_Uty&&>(_Other._Value)); + _STD construct_at(_STD addressof(_Value), _STD move(_Other._Value)); } else { _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected)); } @@ -358,7 +358,8 @@ public: template static constexpr void _Reinit_expected(_First& _New_val, _Second& _Old_val, _Args&&... _Vals) noexcept( - is_nothrow_constructible_v<_First, _Args...>) { + is_nothrow_constructible_v<_First, _Args...>) // strengthened + { if constexpr (is_nothrow_constructible_v<_First, _Args...>) { if constexpr (!is_trivially_destructible_v<_Second>) { _Old_val.~_Second(); @@ -390,11 +391,11 @@ public: && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { if (_Has_value && _Other._Has_value) { - static_cast<_Ty&>(_Value) = static_cast(_Other._Value); + _Value = _Other._Value; } else if (_Has_value) { _Reinit_expected(_Unexpected, _Value, _Other._Unexpected); } else if (_Other._Has_value) { - _Reinit_expected(_Value, _Unexpected, static_cast(_Other._Value)); + _Reinit_expected(_Value, _Unexpected, _Other._Value); } else { _Unexpected = _Other._Unexpected; } @@ -411,11 +412,11 @@ public: && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { if (_Has_value && _Other._Has_value) { - static_cast<_Ty&>(_Value) = static_cast<_Ty&&>(_Other._Value); + _Value = _STD move(_Other._Value); } else if (_Has_value) { _Reinit_expected(_Unexpected, _Value, _STD move(_Other._Unexpected)); } else if (_Other._Has_value) { - _Reinit_expected(_Value, _Unexpected, static_cast<_Ty&&>(_Other._Value)); + _Reinit_expected(_Value, _Unexpected, _STD move(_Other._Value)); } else { _Unexpected = _STD move(_Other._Unexpected); } @@ -432,7 +433,7 @@ public: constexpr expected& operator=(_Uty&& _Other) noexcept( is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_assignable_v<_Ty&, _Uty>) /* strengthened */ { if (_Has_value) { - static_cast<_Ty&>(_Value) = _STD forward<_Uty>(_Other); + _Value = _STD forward<_Uty>(_Other); } else { _Reinit_expected(_Value, _Unexpected, _STD forward<_Uty>(_Other)); _Has_value = true; @@ -516,7 +517,7 @@ public: && (is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) { if (_Has_value && _Other._Has_value) { - _STD _Swap_adl(static_cast<_Ty&>(_Value), static_cast<_Ty&>(_Other._Value)); + _Swap_adl(_Value, _Other._Value); } else if (_Has_value) { if constexpr (is_nothrow_move_constructible_v<_Err>) { _Err _Tmp(_STD move(_Other._Unexpected)); @@ -525,10 +526,10 @@ public: } if constexpr (is_nothrow_move_constructible_v<_Ty>) { - _STD construct_at(_STD addressof(_Other._Value), static_cast<_Ty&&>(_Value)); + _STD construct_at(_STD addressof(_Other._Value), _STD move(_Value)); } else { _GuardTy<_Err> _Guard{_STD addressof(_Other._Unexpected), _STD addressof(_Tmp)}; - _STD construct_at(_STD addressof(_Other._Value), static_cast<_Ty&&>(_Value)); + _STD construct_at(_STD addressof(_Other._Value), _STD move(_Value)); _Guard._Target = nullptr; } @@ -557,7 +558,7 @@ public: } else if (_Other._Has_value) { _Other.swap(*this); } else { - _STD _Swap_adl(_Unexpected, _Other._Unexpected); + _Swap_adl(_Unexpected, _Other._Unexpected); } } @@ -679,7 +680,7 @@ public: is_convertible_v<_Uty, _Ty>, "is_convertible_v must be true. (N4928 [expected.object.obs]/16)"); if (_Has_value) { - return static_cast(_Value); + return _Value; } else { return static_cast<_Ty>(_STD forward<_Uty>(_Other)); } @@ -693,7 +694,7 @@ public: is_convertible_v<_Uty, _Ty>, "is_convertible_v must be true. (N4928 [expected.object.obs]/18)"); if (_Has_value) { - return static_cast<_Ty&&>(_Value); + return _STD move(_Value); } else { return static_cast<_Ty>(_STD forward<_Uty>(_Other)); } @@ -743,7 +744,7 @@ public: "(N4928 [expected.object.monadic]/3)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&>(_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), _Value); } else { return _Uty{unexpect, _Unexpected}; } @@ -762,7 +763,7 @@ public: "(N4928 [expected.object.monadic]/3)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), _Value); } else { return _Uty{unexpect, _Unexpected}; } @@ -781,7 +782,7 @@ public: "(N4928 [expected.object.monadic]/7)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&&>(_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); } else { return _Uty{unexpect, _STD move(_Unexpected)}; } @@ -800,7 +801,7 @@ public: "(N4928 [expected.object.monadic]/7)"); if (_Has_value) { - return _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); + return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); } else { return _Uty{unexpect, _STD move(_Unexpected)}; } @@ -819,7 +820,7 @@ public: "(N4928 [expected.object.monadic]/11)"); if (_Has_value) { - return _Uty{in_place, static_cast<_Ty&>(_Value)}; + return _Uty{in_place, _Value}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected); } @@ -838,7 +839,7 @@ public: "(N4928 [expected.object.monadic]/11)"); if (_Has_value) { - return _Uty{in_place, static_cast(_Value)}; + return _Uty{in_place, _Value}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _Unexpected); } @@ -857,7 +858,7 @@ public: "(N4928 [expected.object.monadic]/15)"); if (_Has_value) { - return _Uty{in_place, static_cast<_Ty&&>(_Value)}; + return _Uty{in_place, _STD move(_Value)}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected)); } @@ -876,7 +877,7 @@ public: "(N4928 [expected.object.monadic]/15)"); if (_Has_value) { - return _Uty{in_place, static_cast(_Value)}; + return _Uty{in_place, _STD move(_Value)}; } else { return _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Unexpected)); } @@ -898,11 +899,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&>(_Value)); + _STD invoke(_STD forward<_Fn>(_Func), _Value); return expected<_Uty, _Err>{}; } else { return expected<_Uty, _Err>{ - _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&>(_Value)}; + _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _Value}; } } else { return expected<_Uty, _Err>{unexpect, _Unexpected}; @@ -925,11 +926,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); + _STD invoke(_STD forward<_Fn>(_Func), _Value); return expected<_Uty, _Err>{}; } else { - return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), - static_cast(_Value)}; + return expected<_Uty, _Err>{ + _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _Value}; } } else { return expected<_Uty, _Err>{unexpect, _Unexpected}; @@ -952,11 +953,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), static_cast<_Ty&&>(_Value)); + _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); return expected<_Uty, _Err>{}; } else { return expected<_Uty, _Err>{ - _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), static_cast<_Ty&&>(_Value)}; + _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(_Value)}; } } else { return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)}; @@ -979,11 +980,11 @@ public: if (_Has_value) { if constexpr (is_void_v<_Uty>) { - _STD invoke(_STD forward<_Fn>(_Func), static_cast(_Value)); + _STD invoke(_STD forward<_Fn>(_Func), _STD move(_Value)); return expected<_Uty, _Err>{}; } else { - return expected<_Uty, _Err>{_Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), - static_cast(_Value)}; + return expected<_Uty, _Err>{ + _Construct_expected_from_invoke_result_tag{}, _STD forward<_Fn>(_Func), _STD move(_Value)}; } } else { return expected<_Uty, _Err>{unexpect, _STD move(_Unexpected)}; @@ -1003,7 +1004,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, static_cast<_Ty&>(_Value)}; + return expected<_Ty, _Uty>{in_place, _Value}; } else { return expected<_Ty, _Uty>{ _Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected}; @@ -1024,7 +1025,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, static_cast(_Value)}; + return expected<_Ty, _Uty>{in_place, _Value}; } else { return expected<_Ty, _Uty>{ _Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _Unexpected}; @@ -1044,7 +1045,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, static_cast<_Ty&&>(_Value)}; + return expected<_Ty, _Uty>{in_place, _STD move(_Value)}; } else { return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _STD move(_Unexpected)}; @@ -1065,7 +1066,7 @@ public: static_assert(_Check_unexpected_argument<_Uty>::value); if (_Has_value) { - return expected<_Ty, _Uty>{in_place, static_cast(_Value)}; + return expected<_Ty, _Uty>{in_place, _STD move(_Value)}; } else { return expected<_Ty, _Uty>{_Construct_expected_from_invoke_result_tag{}, unexpect, _STD forward<_Fn>(_Func), _STD move(_Unexpected)}; @@ -1076,12 +1077,12 @@ public: template requires (!is_void_v<_Uty>) _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept( - noexcept(_STD _Fake_copy_init(static_cast(_Left._Value) == *_Right)) && noexcept( - _STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { + noexcept(_Fake_copy_init(_Left._Value == *_Right)) && noexcept( + _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value != _Right.has_value()) { return false; } else if (_Left._Has_value) { - return static_cast(_Left._Value) == *_Right; + return _Left._Value == *_Right; } else { return _Left._Unexpected == _Right.error(); } @@ -1089,9 +1090,9 @@ public: template _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const _Uty& _Right) noexcept( - noexcept(static_cast(static_cast(_Left._Value) == _Right))) /* strengthened */ { + noexcept(static_cast(_Left._Value == _Right))) /* strengthened */ { if (_Left._Has_value) { - return static_cast(static_cast(_Left._Value) == _Right); + return static_cast(_Left._Value == _Right); } else { return false; } @@ -1139,7 +1140,7 @@ private: } union { - remove_cv_t<_Ty> _Value; // per LWG-3891 + _Ty _Value; _Err _Unexpected; }; bool _Has_value; diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 9e8c49d9601..1f02f528726 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -3,11 +3,6 @@ #define _CONTAINER_DEBUG_LEVEL 1 -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-volatile" // volatile qualified return type -#endif // __clang__ - #include #include #include @@ -16,10 +11,6 @@ #include #include -#ifdef __clang__ -#pragma clang diagnostic pop -#endif // __clang__ - using namespace std; enum class IsDefaultConstructible : bool { Not, Yes }; @@ -2061,85 +2052,6 @@ struct Data { }; static_assert(((void) expected{unexpect, {1, 2, 3}}, true)); -struct CvAssignable { - CvAssignable() = default; - CvAssignable(const CvAssignable&) = default; - CvAssignable(CvAssignable&&) = default; - CvAssignable& operator=(const CvAssignable&) = default; - CvAssignable& operator=(CvAssignable&&) = default; - - template - CvAssignable(const volatile type_identity_t&) noexcept {} - template - CvAssignable(const volatile type_identity_t&&) noexcept {} - - template - constexpr CvAssignable& operator=(const volatile type_identity_t&) noexcept { - return *this; - } - template - constexpr CvAssignable& operator=(const volatile type_identity_t&&) noexcept { - return *this; - } - - template - constexpr const volatile CvAssignable& operator=(const volatile type_identity_t&) const volatile noexcept { - return *this; - } - template - constexpr const volatile CvAssignable& operator=(const volatile type_identity_t&&) const volatile noexcept { - return *this; - } -}; - -#ifndef __clang__ -#pragma warning(push) -#pragma warning(disable : 5216) // volatile qualified return type -#endif // __clang__ -void test_lwg3891() { - { - expected oc{}; - oc.emplace(0); - static_assert(!is_copy_assignable_v); - static_assert(!is_move_assignable_v); - static_assert(!is_swappable_v); - - expected ov{}, ov2{}; - ov.emplace(0); - swap(ov, ov); - ov = ov2; - ov = move(ov2); - - expected ocv{}; - ocv.emplace(0); - static_assert(!is_copy_assignable_v); - static_assert(!is_move_assignable_v); - static_assert(!is_swappable_v); - } - { - expected oc{}, oc2{}; - oc.emplace(CvAssignable{}); - swap(oc, oc); - oc = oc2; - oc = move(oc2); - - expected ov{}, ov2{}; - ov.emplace(CvAssignable{}); - swap(ov, ov); - ov = ov2; - ov = move(ov2); - - expected ocv{}, ocv2{}; - ocv.emplace(CvAssignable{}); - swap(ocv, ocv); - ocv = ocv2; - ocv = move(ocv2); - } -} -#ifndef __clang__ -#pragma warning(pop) -#endif // __clang__ - int main() { test_unexpected::test_all(); static_assert(test_unexpected::test_all()); @@ -2155,5 +2067,4 @@ int main() { static_assert(is_convertible_v*, exception*>); test_reinit_regression(); - test_lwg3891(); } From c7a72db31f8146b4508d1e36c364ed3c79f7922c Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 5 Mar 2023 20:06:51 +0800 Subject: [PATCH 25/40] Revert incorrect line addition --- stl/inc/ranges | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 3cdfd9805dd..10993f94d2c 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -4167,7 +4167,6 @@ namespace ranges { } else { _STL_INTERNAL_CHECK(_Inner_it._Contains == _Variantish_state::_Holds_second); - auto&& _Inner = _Get_inner(); if (_Inner_it._Get_second() != _RANGES end(_Get_inner())) { break; } From 1733c9f52c3bbed5a584259b9cc9d28c426448dc Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 5 Mar 2023 20:07:28 +0800 Subject: [PATCH 26/40] Skip the case for C++20 This may need an LWG issue. --- tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp b/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp index d981d148031..f7ea701ece3 100644 --- a/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp +++ b/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp @@ -1526,6 +1526,7 @@ namespace { pair_conversion_test>(); } +#if !_HAS_CXX20 // Test cv-qualified source type (LWG-3677) void lwg3677_test() { using PairType = std::pair; @@ -1545,6 +1546,7 @@ namespace { al.construct(static_cast(raw_ptr), mem_pair_conv{}); al.construct(static_cast(raw_ptr), mem_pair_conv{}); } +#endif // !_HAS_CXX20 } // namespace map_containers void test_gh3408() { @@ -1603,7 +1605,9 @@ int main() { map_containers::test(); +#if !_HAS_CXX20 map_containers::lwg3677_test(); +#endif // !_HAS_CXX20 test_gh3408(); } From ecb4077ec8b21ce4b24f6a63dc15e1ec29138a0e Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 12 Mar 2023 23:21:03 +0800 Subject: [PATCH 27/40] Address @strega-nil-ms's review comments --- stl/inc/memory | 34 +++++--------- stl/inc/ranges | 45 +++++++++++++------ tests/std/tests/P0896R4_views_single/test.cpp | 31 +++++++++++++ 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/stl/inc/memory b/stl/inc/memory index bcba723310a..b77b6ba6a28 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -937,17 +937,12 @@ namespace ranges { template _NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { if constexpr (is_pointer_v<_PtrTy>) { - return const_cast(static_cast(_Ptr)); + return _Ptr; } else { - return const_cast(static_cast(_STD addressof(*_Ptr))); + return _STD addressof(*_Ptr); } } -template -void _Construct_cv_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { - ::new (_STD _Voidify_unfancy(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); -} - #if _HAS_DEPRECATED_RAW_STORAGE_ITERATOR _EXPORT_STD template class _CXX17_DEPRECATE_RAW_STORAGE_ITERATOR raw_storage_iterator { // wrap stores to raw buffer as output iterator @@ -969,12 +964,12 @@ public: } raw_storage_iterator& operator=(const _Ty& _Val) { // construct value designated by stored iterator - _STD _Construct_cv_in_place(*_Next, _Val); + _STD _Construct_in_place(const_cast<_Remove_cvref_t&>(*_Next), _Val); return *this; } raw_storage_iterator& operator=(_Ty&& _Val) { // construct value designated by stored iterator - _STD _Construct_cv_in_place(*_Next, _STD move(_Val)); + _STD _Construct_in_place(const_cast<_Remove_cvref_t&>(*_Next), _STD move(_Val)); return *this; } @@ -2085,11 +2080,6 @@ _Dx* get_deleter(const shared_ptr<_Ty>&) noexcept = delete; // requires static R struct _For_overwrite_tag { explicit _For_overwrite_tag() = default; }; - -template -void _Default_construct_cv_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { - ::new (_STD _Voidify_unfancy(_STD addressof(_Obj))) _Ty; -} #endif // _HAS_CXX20 template @@ -2099,12 +2089,12 @@ public: explicit _Ref_count_obj2(_Types&&... _Args) : _Ref_count_base() { #if _HAS_CXX20 if constexpr (sizeof...(_Types) == 1 && (is_same_v<_For_overwrite_tag, remove_cvref_t<_Types>> && ...)) { - _STD _Default_construct_cv_in_place(_Storage._Value); + _STD _Default_construct_in_place(_Storage._Value); ((void) _Args, ...); } else #endif // _HAS_CXX20 { - _STD _Construct_cv_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); + _STD _Construct_in_place(_Storage._Value, _STD forward<_Types>(_Args)...); } } @@ -2117,7 +2107,7 @@ public: } union { - _Wrap<_Ty> _Storage; + _Wrap> _Storage; }; private: @@ -2219,12 +2209,12 @@ struct _NODISCARD _Uninitialized_rev_destroying_backout { template void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment - _STD _Construct_cv_in_place(*_Last, _STD forward<_Types>(_Vals)...); + _STD _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } void _Emplace_back_for_overwrite() { - _STD _Default_construct_cv_in_place(*_Last); + _STD _Default_construct_in_place(*_Last); ++_Last; } @@ -2368,7 +2358,7 @@ public: private: union { - _Wrap<_Element_type> _Storage; // flexible array must be last member + _Wrap> _Storage; // flexible array must be last member }; ~_Ref_count_unbounded_array() noexcept override { // TRANSITION, should be non-virtual @@ -2416,7 +2406,7 @@ private: size_t _Size; union { - _Wrap<_Element_type> _Storage; // flexible array must be last member + _Wrap> _Storage; // flexible array must be last member }; ~_Ref_count_unbounded_array() noexcept override { // TRANSITION, should be non-virtual @@ -2453,7 +2443,7 @@ public: } union { - _Wrap<_Ty> _Storage; + _Wrap> _Storage; }; private: diff --git a/stl/inc/ranges b/stl/inc/ranges index 7b0573a5bbd..3c503802a76 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -442,31 +442,48 @@ namespace ranges { is_nothrow_constructible_v<_Ty, _Types...>) // strengthened : _Val(_STD forward<_Types>(_Args)...) {} - _Movable_box(const _Movable_box&) = default; - _Movable_box(_Movable_box&&) = default; + // clang-format off + _Movable_box(const _Movable_box&) requires is_trivially_copy_constructible_v<_Ty> = default; + _Movable_box(_Movable_box&&) requires is_trivially_move_constructible_v<_Ty> = default; + // clang-format on + + _Movable_box(const _Movable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>) + : _Val(static_cast(_That._Val)) {} + + _Movable_box(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) + : _Val(static_cast<_Ty&&>(_That._Val)) {} // clang-format off - _Movable_box& operator=(const _Movable_box&) requires copyable<_Ty> = default; - _Movable_box& operator=(_Movable_box&&) requires movable<_Ty> = default; + _Movable_box& operator=(const _Movable_box&) + requires copyable<_Ty> && is_trivially_copy_assignable_v<_Ty> = default; + _Movable_box& operator=(_Movable_box&&) requires movable<_Ty> && is_trivially_move_assignable_v<_Ty> = default; // clang-format on - constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept + constexpr _Movable_box& operator=(const _Movable_box& _That) noexcept( + is_nothrow_copy_assignable_v<_Ty> || !copyable<_Ty>) // strengthened requires copy_constructible<_Ty> { - if (_STD addressof(_That) != this) { - _Val.~_Ty(); - _STD _Construct_in_place(_Val, static_cast(_That._Val)); + if constexpr (copyable<_Ty>) { + static_cast<_Ty&>(_Val) = static_cast(_That._Val); + } else { + if (_STD addressof(_That) != this) { + _Val.~_Ty(); + _STD _Construct_in_place(_Val, static_cast(_That._Val)); + } } - return *this; } - constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept { - if (_STD addressof(_That) != this) { - _Val.~_Ty(); - _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); + constexpr _Movable_box& operator=(_Movable_box&& _That) noexcept( + is_nothrow_move_assignable_v<_Ty> || !movable<_Ty>) /* strengthened */ { + if constexpr (movable<_Ty>) { + static_cast<_Ty&>(_Val) = static_cast<_Ty&&>(_That._Val); + } else { + if (_STD addressof(_That) != this) { + _Val.~_Ty(); + _STD _Construct_in_place(_Val, static_cast<_Ty&&>(_That._Val)); + } } - return *this; } diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index d4037cdb3cf..a2e2c0ccd9b 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -166,6 +166,26 @@ struct VolatileConstructible { constexpr VolatileConstructible(const volatile type_identity_t&&) noexcept {} }; +struct ConstSelection { + ConstSelection() = default; + ConstSelection(const ConstSelection&) = default; + ConstSelection(ConstSelection&&) = default; + ConstSelection& operator=(const ConstSelection&) = default; + ConstSelection& operator=(ConstSelection&&) = default; + + explicit constexpr ConstSelection(int x) noexcept : value{x} {} + + template + constexpr const ConstSelection& operator=(const type_identity_t&) const noexcept { + return *this; + } + + int value = 0; +}; + +static_assert(is_trivially_copy_assignable_v>); +static_assert(!is_trivially_copy_assignable_v>); + constexpr bool test_cv() { { ranges::single_view sv{}, sv2{}; @@ -180,6 +200,17 @@ constexpr bool test_cv() { [[maybe_unused]] ranges::single_view svc{}; [[maybe_unused]] ranges::single_view svcv{}; + { + ranges::single_view svx{in_place, 0}, svy{in_place, 42}; + svy = svx; + assert(svy.front().value == 0); + } + { + ranges::single_view scvx{in_place, 0}, scvy{in_place, 42}; + scvy = scvx; + assert(scvy.front().value == 42); + } + return true; } From 3ddb6941b55eaaddb3d91a9fbbd63234161f0011 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sun, 12 Mar 2023 23:59:42 +0800 Subject: [PATCH 28/40] Fix constraints and constexpr --- stl/inc/ranges | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 3c503802a76..0d0e5d61b61 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -429,6 +429,9 @@ namespace ranges { // is_nothrow_move_constructible_v is true. : movable<_Ty> || is_nothrow_move_constructible_v<_Ty>); + template + concept _Copy_constructible_for_box = is_copy_constructible_v<_Ty>; + template <_Valid_movable_box_object _Ty> requires _Use_simple_movable_box_wrapper<_Ty> class _Movable_box<_Ty> { // provide the same API more efficiently when we can avoid the disengaged state @@ -443,14 +446,16 @@ namespace ranges { : _Val(_STD forward<_Types>(_Args)...) {} // clang-format off - _Movable_box(const _Movable_box&) requires is_trivially_copy_constructible_v<_Ty> = default; + _Movable_box(const _Movable_box&) + requires _Copy_constructible_for_box<_Ty> && is_trivially_copy_constructible_v<_Ty> = default; _Movable_box(_Movable_box&&) requires is_trivially_move_constructible_v<_Ty> = default; // clang-format on - _Movable_box(const _Movable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>) + constexpr _Movable_box(const _Movable_box& _That) noexcept(is_nothrow_copy_constructible_v<_Ty>) + requires _Copy_constructible_for_box<_Ty> : _Val(static_cast(_That._Val)) {} - _Movable_box(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) + constexpr _Movable_box(_Movable_box&& _That) noexcept(is_nothrow_move_constructible_v<_Ty>) : _Val(static_cast<_Ty&&>(_That._Val)) {} // clang-format off From 215a0060ba6a3ca2944acfd980b1e3b042a917b9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 17:48:17 -0700 Subject: [PATCH 29/40] `explicit constexpr` => `constexpr explicit` --- tests/std/tests/P0896R4_common_iterator/test.cpp | 2 +- tests/std/tests/P0896R4_views_single/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index 748e99da5e5..ded0c00400f 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -345,7 +345,7 @@ struct VolatileSentinel { VolatileSentinel& operator=(const VolatileSentinel&) = default; VolatileSentinel& operator=(VolatileSentinel&&) = default; - explicit constexpr VolatileSentinel(const char* p) noexcept : ptr_{p} {} + constexpr explicit VolatileSentinel(const char* p) noexcept : ptr_{p} {} template constexpr VolatileSentinel(const volatile type_identity_t& other) noexcept : ptr_{other.ptr_} {} diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index b6f636d8950..51444174508 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -190,7 +190,7 @@ struct ConstSelection { ConstSelection& operator=(const ConstSelection&) = default; ConstSelection& operator=(ConstSelection&&) = default; - explicit constexpr ConstSelection(int x) noexcept : value{x} {} + constexpr explicit ConstSelection(int x) noexcept : value{x} {} template constexpr const ConstSelection& operator=(const type_identity_t&) const noexcept { From 2d11a16033ed44d718b314bfbe854b3ba2f232d9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 17:49:44 -0700 Subject: [PATCH 30/40] `Uninitilized` => `Uninitialized` --- .../test.cpp | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 8c567cfa896..f79d24527f1 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -522,40 +522,40 @@ static_assert((test_compiletime_operators(), true)); #ifdef __cpp_lib_concepts // Also test LWG-3888 Most ranges uninitialized memory algorithms are underconstrained template -concept CanUninitilizedDefaultConstruct = requires(Rng& r) { ranges::uninitialized_default_construct(r); }; +concept CanUninitializedDefaultConstruct = requires(Rng& r) { ranges::uninitialized_default_construct(r); }; template -concept CanUninitilizedDefaultConstructN = +concept CanUninitializedDefaultConstructN = requires(It&& i) { ranges::uninitialized_default_construct_n(forward(i), iter_difference_t{}); }; template -concept CanUninitilizedValueConstruct = requires(Rng& r) { ranges::uninitialized_value_construct(r); }; +concept CanUninitializedValueConstruct = requires(Rng& r) { ranges::uninitialized_value_construct(r); }; template -concept CanUninitilizedValueConstructN = +concept CanUninitializedValueConstructN = requires(It&& i) { ranges::uninitialized_value_construct_n(forward(i), iter_difference_t{}); }; template -concept CanUninitilizedFill = requires(Rng& r, const T& t) { ranges::uninitialized_fill(r, t); }; +concept CanUninitializedFill = requires(Rng& r, const T& t) { ranges::uninitialized_fill(r, t); }; template -concept CanUninitilizedFillN = +concept CanUninitializedFillN = requires(It&& i, const T& t) { ranges::uninitialized_fill_n(forward(i), iter_difference_t{}, t); }; template -concept CanUninitilizedCopy = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_copy(ri, ro); }; +concept CanUninitializedCopy = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_copy(ri, ro); }; template -concept CanUninitilizedCopyN = +concept CanUninitializedCopyN = requires(InIt&& ii, OutIt&& io, S&& s) { ranges::uninitialized_copy_n(forward(ii), iter_difference_t{}, forward(io), forward(s)); }; template -concept CanUninitilizedMove = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_move(ri, ro); }; +concept CanUninitializedMove = requires(InRng& ri, OutRng& ro) { ranges::uninitialized_move(ri, ro); }; template -concept CanUninitilizedMoveN = +concept CanUninitializedMoveN = requires(InIt&& ii, OutIt&& io, S&& s) { ranges::uninitialized_move_n(forward(ii), iter_difference_t{}, forward(io), forward(s)); }; @@ -566,55 +566,55 @@ concept CanDestroy = requires(Rng&& r) { ranges::destroy(forward(r)); }; template concept CanDestroyN = requires(It&& i) { ranges::destroy_n(forward(i), iter_difference_t{}); }; -static_assert(CanUninitilizedDefaultConstruct); -static_assert(!CanUninitilizedDefaultConstruct); -static_assert(!CanUninitilizedDefaultConstruct); -static_assert(!CanUninitilizedDefaultConstruct); - -static_assert(CanUninitilizedDefaultConstructN); -static_assert(!CanUninitilizedDefaultConstructN); -static_assert(!CanUninitilizedDefaultConstructN); -static_assert(!CanUninitilizedDefaultConstructN); - -static_assert(CanUninitilizedValueConstruct); -static_assert(!CanUninitilizedValueConstruct); -static_assert(!CanUninitilizedValueConstruct); -static_assert(!CanUninitilizedValueConstruct); - -static_assert(CanUninitilizedValueConstructN); -static_assert(!CanUninitilizedValueConstructN); -static_assert(!CanUninitilizedValueConstructN); -static_assert(!CanUninitilizedValueConstructN); - -static_assert(CanUninitilizedFill); -static_assert(!CanUninitilizedFill); -static_assert(!CanUninitilizedFill); -static_assert(!CanUninitilizedFill); - -static_assert(CanUninitilizedFillN); -static_assert(!CanUninitilizedFillN); -static_assert(!CanUninitilizedFillN); -static_assert(!CanUninitilizedFillN); - -static_assert(CanUninitilizedCopy); -static_assert(!CanUninitilizedCopy); -static_assert(!CanUninitilizedCopy); -static_assert(!CanUninitilizedCopy); - -static_assert(CanUninitilizedCopyN); -static_assert(!CanUninitilizedCopyN); -static_assert(!CanUninitilizedCopyN); -static_assert(!CanUninitilizedCopyN); - -static_assert(CanUninitilizedMove); -static_assert(!CanUninitilizedMove); -static_assert(!CanUninitilizedMove); -static_assert(!CanUninitilizedMove); - -static_assert(CanUninitilizedMoveN); -static_assert(!CanUninitilizedMoveN); -static_assert(!CanUninitilizedMoveN); -static_assert(!CanUninitilizedMoveN); +static_assert(CanUninitializedDefaultConstruct); +static_assert(!CanUninitializedDefaultConstruct); +static_assert(!CanUninitializedDefaultConstruct); +static_assert(!CanUninitializedDefaultConstruct); + +static_assert(CanUninitializedDefaultConstructN); +static_assert(!CanUninitializedDefaultConstructN); +static_assert(!CanUninitializedDefaultConstructN); +static_assert(!CanUninitializedDefaultConstructN); + +static_assert(CanUninitializedValueConstruct); +static_assert(!CanUninitializedValueConstruct); +static_assert(!CanUninitializedValueConstruct); +static_assert(!CanUninitializedValueConstruct); + +static_assert(CanUninitializedValueConstructN); +static_assert(!CanUninitializedValueConstructN); +static_assert(!CanUninitializedValueConstructN); +static_assert(!CanUninitializedValueConstructN); + +static_assert(CanUninitializedFill); +static_assert(!CanUninitializedFill); +static_assert(!CanUninitializedFill); +static_assert(!CanUninitializedFill); + +static_assert(CanUninitializedFillN); +static_assert(!CanUninitializedFillN); +static_assert(!CanUninitializedFillN); +static_assert(!CanUninitializedFillN); + +static_assert(CanUninitializedCopy); +static_assert(!CanUninitializedCopy); +static_assert(!CanUninitializedCopy); +static_assert(!CanUninitializedCopy); + +static_assert(CanUninitializedCopyN); +static_assert(!CanUninitializedCopyN); +static_assert(!CanUninitializedCopyN); +static_assert(!CanUninitializedCopyN); + +static_assert(CanUninitializedMove); +static_assert(!CanUninitializedMove); +static_assert(!CanUninitializedMove); +static_assert(!CanUninitializedMove); + +static_assert(CanUninitializedMoveN); +static_assert(!CanUninitializedMoveN); +static_assert(!CanUninitializedMoveN); +static_assert(!CanUninitializedMoveN); static_assert(CanDestroy); static_assert(!CanDestroy); From e9ea2db4bf97403cfcec242d93c4f893e26c5316 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 17:51:27 -0700 Subject: [PATCH 31/40] `ci` => `CommonIt` --- tests/std/tests/P0896R4_common_iterator/test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P0896R4_common_iterator/test.cpp b/tests/std/tests/P0896R4_common_iterator/test.cpp index ded0c00400f..ac88a54358b 100644 --- a/tests/std/tests/P0896R4_common_iterator/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator/test.cpp @@ -402,10 +402,10 @@ struct VolatileSentinel { // constexpr-incompatible void test_volatile() { using std::swap; - using ci = common_iterator; + using CommonIt = common_iterator; - ci it{static_cast(nullptr)}; - ci se{VolatileSentinel{static_cast(nullptr)}}; + CommonIt it{static_cast(nullptr)}; + CommonIt se{VolatileSentinel{static_cast(nullptr)}}; assert(it == se); assert(it - se == 0); From 226fba810ff5427cffb4451b18781124b6028c00 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 17:52:03 -0700 Subject: [PATCH 32/40] Avoid adding extra newline. --- stl/inc/xmemory | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 919cd159319..6f2a28fb780 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1637,7 +1637,6 @@ namespace ranges { && same_as>, remove_reference_t>> // per LWG-3888 && same_as>, iter_value_t<_It>>; - template concept _No_throw_sentinel_for = sentinel_for<_Se, _It>; From ccda2b13e22fecdf47bc9847cb34ea62a4b72963 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 17:58:26 -0700 Subject: [PATCH 33/40] Avoid defining multiple variables on a single line (pre-existing). --- tests/std/tests/P0088R3_variant/test.cpp | 3 ++- .../test.compile.pass.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index afff726fc50..7c3490a43c9 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -7193,7 +7193,8 @@ namespace msvc { using std::variant::variant; }; - my_variant v1{42}, v2{3.14}; + my_variant v1{42}; + my_variant v2{3.14}; auto visitor1 = [](auto&& x) { return static_cast(x); }; assert(std::visit(visitor1, v1) == 42.0); assert(std::visit(visitor1, v2) == 3.14); diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp index 0e6909d701f..e48746e4e1d 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp @@ -1274,7 +1274,8 @@ template void regex_token_iterator_test_impl() { using it_type = typename RegexTokenIterator::value_type::iterator; int submatches[10] = {0}; - it_type start{}, finish{}; + it_type start{}; + it_type finish{}; typename RegexTokenIterator::regex_type rgx{}; RegexTokenIterator rti0(start, finish, rgx, submatches); } From 39150b7842a640226e9a5f48b588c7271cd184fe Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 17:59:07 -0700 Subject: [PATCH 34/40] Avoid defining multiple variables on a single line. --- tests/std/tests/P0088R3_variant/test.cpp | 12 ++++++++---- tests/std/tests/P0220R1_optional/test.cpp | 12 ++++++++---- tests/std/tests/P0896R4_views_single/test.cpp | 12 ++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index 7c3490a43c9..7471255c69c 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -7900,7 +7900,8 @@ namespace msvc { STATIC_ASSERT(!std::is_move_assignable_v); STATIC_ASSERT(!std::is_swappable_v); - std::variant ov{}, ov2{}; + std::variant ov{}; + std::variant ov2{}; ov.emplace<0>(0); swap(ov, ov); ov = ov2; @@ -7913,19 +7914,22 @@ namespace msvc { STATIC_ASSERT(!std::is_swappable_v); } { - std::variant oc{}, oc2{}; + std::variant oc{}; + std::variant oc2{}; oc.emplace<0>(CvAssignable{}); swap(oc, oc); oc = oc2; oc = std::move(oc2); - std::variant ov{}, ov2{}; + std::variant ov{}; + std::variant ov2{}; ov.emplace<0>(CvAssignable{}); swap(ov, ov); ov = ov2; ov = std::move(ov2); - std::variant ocv{}, ocv2{}; + std::variant ocv{}; + std::variant ocv2{}; ocv.emplace<0>(CvAssignable{}); swap(ocv, ocv); ocv = ocv2; diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index 4459da9eb1f..fc6537f9ff9 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -8286,7 +8286,8 @@ namespace msvc { STATIC_ASSERT(!std::is_move_assignable_v); STATIC_ASSERT(!std::is_swappable_v); - std::optional ov{}, ov2{}; + std::optional ov{}; + std::optional ov2{}; ov.emplace(0); swap(ov, ov); ov = ov2; @@ -8299,19 +8300,22 @@ namespace msvc { STATIC_ASSERT(!std::is_swappable_v); } { - std::optional oc{}, oc2{}; + std::optional oc{}; + std::optional oc2{}; oc.emplace(CvAssignable{}); swap(oc, oc); oc = oc2; oc = std::move(oc2); - std::optional ov{}, ov2{}; + std::optional ov{}; + std::optional ov2{}; ov.emplace(CvAssignable{}); swap(ov, ov); ov = ov2; ov = std::move(ov2); - std::optional ocv{}, ocv2{}; + std::optional ocv{}; + std::optional ocv2{}; ocv.emplace(CvAssignable{}); swap(ocv, ocv); ocv = ocv2; diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index 51444174508..a0744731920 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -205,12 +205,14 @@ static_assert(!is_trivially_copy_assignable_v sv{}, sv2{}; + ranges::single_view sv{}; + ranges::single_view sv2{}; sv = sv2; sv = move(sv2); } { - ranges::single_view svv{}, svv2{}; + ranges::single_view svv{}; + ranges::single_view svv2{}; svv = svv2; svv = move(svv2); } @@ -218,12 +220,14 @@ constexpr bool test_cv() { [[maybe_unused]] ranges::single_view svcv{}; { - ranges::single_view svx{in_place, 0}, svy{in_place, 42}; + ranges::single_view svx{in_place, 0}; + ranges::single_view svy{in_place, 42}; svy = svx; assert(svy.front().value == 0); } { - ranges::single_view scvx{in_place, 0}, scvy{in_place, 42}; + ranges::single_view scvx{in_place, 0}; + ranges::single_view scvy{in_place, 42}; scvy = scvx; assert(scvy.front().value == 42); } From e02056ab0a67901a2dd412389564e45172de87fd Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 18:00:30 -0700 Subject: [PATCH 35/40] Add scope to avoid pollution. --- tests/std/tests/P0896R4_views_single/test.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P0896R4_views_single/test.cpp b/tests/std/tests/P0896R4_views_single/test.cpp index a0744731920..2c2ad638519 100644 --- a/tests/std/tests/P0896R4_views_single/test.cpp +++ b/tests/std/tests/P0896R4_views_single/test.cpp @@ -216,9 +216,10 @@ constexpr bool test_cv() { svv = svv2; svv = move(svv2); } - [[maybe_unused]] ranges::single_view svc{}; - [[maybe_unused]] ranges::single_view svcv{}; - + { + [[maybe_unused]] ranges::single_view svc{}; + [[maybe_unused]] ranges::single_view svcv{}; + } { ranges::single_view svx{in_place, 0}; ranges::single_view svy{in_place, 42}; From b2b8e40bd5ed8adada96a1ee089c01046807f4e5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 18:01:35 -0700 Subject: [PATCH 36/40] Guard `_Voidify_unfancy` with `_HAS_CXX20`. --- stl/inc/memory | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/memory b/stl/inc/memory index b77b6ba6a28..9ba2b098c14 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -934,6 +934,7 @@ namespace ranges { #endif // __cpp_lib_concepts #endif // _HAS_CXX17 +#if _HAS_CXX20 template _NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { if constexpr (is_pointer_v<_PtrTy>) { @@ -942,6 +943,7 @@ _NODISCARD void* _Voidify_unfancy(_PtrTy _Ptr) noexcept { return _STD addressof(*_Ptr); } } +#endif // _HAS_CXX20 #if _HAS_DEPRECATED_RAW_STORAGE_ITERATOR _EXPORT_STD template From 850600976688fd5541ac63a73734878916ca9dc6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 18 Mar 2023 18:03:21 -0700 Subject: [PATCH 37/40] Fix typo bug! --- stl/inc/iterator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/iterator b/stl/inc/iterator index 22ef3be1e3e..6884d506bd5 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -783,7 +783,7 @@ public: _RANGES swap(_Left._Get_first(), _Right._Get_first()); break; case _Variantish_state::_Holds_second: - _RANGES swap(_Left._Get_first(), _Right._Get_second()); + _RANGES swap(_Left._Get_second(), _Right._Get_second()); break; case _Variantish_state::_Nothing: break; From ab3e92b7f9f97256cd1e1a8c20fee3386cd136ca Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 23 Mar 2023 15:07:44 +0800 Subject: [PATCH 38/40] Restore support of `polymorphic_allocator::construct`... for cv-qualified types. --- stl/inc/xpolymorphic_allocator.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 5957f4333d0..43ba46e9542 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -279,7 +279,13 @@ namespace pmr { void construct(_Uty* const _Ptr, _Types&&... _Args) { // propagate allocator *this if uses_allocator_v, polymorphic_allocator> #if _HAS_CXX20 - _STD uninitialized_construct_using_allocator(_Ptr, *this, _STD forward<_Types>(_Args)...); + // equivalent to calling uninitialized_construct_using_allocator except for handling of cv-qualification + _STD apply( + [_Ptr](auto&&... _Construct_args) { + return ::new (const_cast(static_cast(_Ptr))) + _Uty(_STD forward(_Construct_args)...); + }, + _STD uses_allocator_construction_args<_Ty>(*this, _STD forward<_Types>(_Args)...)); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv allocator _Al{}; if constexpr (_Is_cv_pair<_Uty>) { From e720aa8be90ad061e512dc46601ebe3e8d425460 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 23 Mar 2023 15:25:13 +0800 Subject: [PATCH 39/40] Fix copy-pasta --- stl/inc/xpolymorphic_allocator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 43ba46e9542..44ae61c4bd6 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -285,7 +285,7 @@ namespace pmr { return ::new (const_cast(static_cast(_Ptr))) _Uty(_STD forward(_Construct_args)...); }, - _STD uses_allocator_construction_args<_Ty>(*this, _STD forward<_Types>(_Args)...)); + _STD uses_allocator_construction_args<_Uty>(*this, _STD forward<_Types>(_Args)...)); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv allocator _Al{}; if constexpr (_Is_cv_pair<_Uty>) { From bbcbcf017d0c6f24cddee0b4f34ecfed48ba0081 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 23 Mar 2023 16:00:56 +0800 Subject: [PATCH 40/40] Restore test coverage Reverting commit 1733c9f52c3bbed5a584259b9cc9d28c426448dc. --- tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp b/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp index f7ea701ece3..d981d148031 100644 --- a/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp +++ b/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp @@ -1526,7 +1526,6 @@ namespace { pair_conversion_test>(); } -#if !_HAS_CXX20 // Test cv-qualified source type (LWG-3677) void lwg3677_test() { using PairType = std::pair; @@ -1546,7 +1545,6 @@ namespace { al.construct(static_cast(raw_ptr), mem_pair_conv{}); al.construct(static_cast(raw_ptr), mem_pair_conv{}); } -#endif // !_HAS_CXX20 } // namespace map_containers void test_gh3408() { @@ -1605,9 +1603,7 @@ int main() { map_containers::test(); -#if !_HAS_CXX20 map_containers::lwg3677_test(); -#endif // !_HAS_CXX20 test_gh3408(); }