From b94c77e002e0c7941e8aeee549e58df026be7382 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 28 Feb 2023 01:09:56 +0800 Subject: [PATCH 1/5] Implement LWG-3821 --- stl/inc/xmemory | 82 ++++++++++++------- .../test.cpp | 38 +++++++++ 2 files changed, 90 insertions(+), 30 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 4ab17c0a8e..f83d6f13dc 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2304,8 +2304,13 @@ _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, const pair<_Uty1, _Uty2>&& _Pair) noexcept; #endif // _HAS_CXX23 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +_EXPORT_STD template + requires _Is_cv_pair<_Ty> && (_Pair_like<_Uty> || !_Is_deducible_as_pair<_Uty&>) +#else // ^^^ C++23 with concepts / C++20 or no concepts vvv _EXPORT_STD template && !_Is_deducible_as_pair<_Uty&>, int> = 0> +#endif // ^^^ C++20 or no concepts ^^^ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept; _EXPORT_STD template , int> = 0> @@ -2390,41 +2395,58 @@ _NODISCARD constexpr auto uses_allocator_construction_args( } #endif // _HAS_CXX23 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +_EXPORT_STD template + requires _Is_cv_pair<_Ty> && (_Pair_like<_Uty> || !_Is_deducible_as_pair<_Uty&>) +#else // ^^^ C++23 with concepts / C++20 or no concepts vvv _EXPORT_STD template && !_Is_deducible_as_pair<_Uty&>, int>> +#endif // ^^^ C++20 or no concepts ^^^ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept { - struct _Pair_remaker { - const _Alloc& _Al; - _Uty& _Ux; - - constexpr operator remove_cv_t<_Ty>() const { - using _Pair_t = remove_cv_t<_Ty>; - static_assert(_Is_normally_bindable<_Pair_t, _Uty>, - "The argument must be bindable to a reference to the std::pair type."); - - using _Pair_first_t = typename _Pair_t::first_type; - using _Pair_second_t = typename _Pair_t::second_type; - using _Pair_ref_t = _Normally_bound_ref<_Pair_t, _Uty>; - _Pair_ref_t _Pair_ref = _STD forward<_Uty>(_Ux); - if constexpr (is_same_v<_Pair_ref_t, const _Pair_t&>) { - // equivalent to - // return _STD make_obj_using_allocator<_Pair_t>(_Al, _Pair_ref); - return _Pair_t{piecewise_construct, - _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _Pair_ref.first), - _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _Pair_ref.second)}; - } else { - // equivalent to - // return _STD make_obj_using_allocator<_Pair_t>(_Al, _STD move(_Pair_ref)); - return _Pair_t{piecewise_construct, - _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _STD get<0>(_STD move(_Pair_ref))), - _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _STD get<1>(_STD move(_Pair_ref)))}; +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + if constexpr (_Pair_like<_Uty> && !_Is_subrange_v>) { + // equivalent to + // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(_STD get<0>(_STD move(_Ux)), _STD forward_as_tuple(_STD get<1>(_STD move(_Ux))); + return _STD make_tuple(piecewise_construct, + _STD uses_allocator_construction_args(_Al, _STD get<0>(_STD move(_Ux))), + _STD uses_allocator_construction_args(_Al, _STD get<1>(_STD move(_Ux)))); + } else +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + { + struct _Pair_remaker { + const _Alloc& _Al; + _Uty& _Ux; + + constexpr operator remove_cv_t<_Ty>() const { + using _Pair_t = remove_cv_t<_Ty>; + static_assert(_Is_normally_bindable<_Pair_t, _Uty>, + "The argument must be bindable to a reference to the std::pair type."); + + using _Pair_first_t = typename _Pair_t::first_type; + using _Pair_second_t = typename _Pair_t::second_type; + using _Pair_ref_t = _Normally_bound_ref<_Pair_t, _Uty>; + _Pair_ref_t _Pair_ref = _STD forward<_Uty>(_Ux); + if constexpr (is_same_v<_Pair_ref_t, const _Pair_t&>) { + // equivalent to + // return _STD make_obj_using_allocator<_Pair_t>(_Al, _Pair_ref); + return _Pair_t{piecewise_construct, + _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _Pair_ref.first), + _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _Pair_ref.second)}; + } else { + // equivalent to + // return _STD make_obj_using_allocator<_Pair_t>(_Al, _STD move(_Pair_ref)); + return _Pair_t{piecewise_construct, + _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _STD get<0>(_STD move(_Pair_ref))), + _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _STD get<1>(_STD move(_Pair_ref)))}; + } } - } - }; + }; - // equivalent to - // return _STD make_tuple(_Pair_remaker{_Al, _Ux}); - return tuple<_Pair_remaker>({_Al, _Ux}); + // equivalent to + // return _STD make_tuple(_Pair_remaker{_Al, _Ux}); + return tuple<_Pair_remaker>({_Al, _Ux}); + } } _EXPORT_STD template diff --git a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp index 351fa0edbb..af84186d0b 100644 --- a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp +++ b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp @@ -177,6 +177,44 @@ constexpr bool test_P0591R4() { } #endif // _HAS_CXX23 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 + { // pair(PairLike&&) overload + tuple tpl(i, i); + auto tuple14 = uses_allocator_construction_args>(alloc, tpl); + static_assert( + is_same_v, MovedAllocatorArgConstructArgs>>); + + auto tuple15 = uses_allocator_construction_args>(alloc, tpl); + static_assert( + is_same_v>>); + + auto tuple16 = uses_allocator_construction_args>(alloc, move(tpl)); + static_assert( + is_same_v, MovedAllocatorArgConstructArgs>>); + + auto tuple17 = uses_allocator_construction_args>(alloc, move(tpl)); + static_assert( + is_same_v>>); + + auto tuple18 = uses_allocator_construction_args>(alloc, as_const(tpl)); + static_assert(is_same_v, MovedConstAllocatorArgConstructArgs>>); + + auto tuple19 = uses_allocator_construction_args>(alloc, as_const(tpl)); + static_assert(is_same_v>>); + + auto tuple20 = + uses_allocator_construction_args>(alloc, move(as_const(tpl))); + static_assert(is_same_v, MovedConstAllocatorArgConstructArgs>>); + + auto tuple21 = uses_allocator_construction_args>(alloc, move(as_const(tpl))); + static_assert(is_same_v>>); + } +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + { auto obj1 = make_obj_using_allocator(alloc, i); static_assert(is_same_v); From e6a602db31cbc1c88c534b16185ab492af5d5b64 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 28 Feb 2023 09:43:28 +0800 Subject: [PATCH 2/5] Missing changes (thanks to @StephanTLavavej) --- stl/inc/utility | 9 +++++---- stl/inc/xmemory | 8 +++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 1ad3d703bc..44cf2c0651 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -208,9 +208,9 @@ concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v> == 2; #ifdef __clang__ // TRANSITION, LLVM-59827 template -concept _Can_construct_from_pair_like = - _Pair_like<_PairLike> && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))> - && is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>; +concept _Can_construct_from_pair_like = _Pair_like<_PairLike> && (!_Is_subrange_v>) + && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))> + && is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>; #endif // __clang__ #endif // _HAS_CXX23 #endif // __cpp_lib_concepts @@ -289,7 +289,8 @@ struct pair { // store a pair of values #else // ^^^ workaround / no workaround vvv template <_Pair_like _Other> requires conjunction_v(_STD declval<_Other>()))>, - is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>> + is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>, + bool_constant>>> #endif // __clang__ constexpr explicit(!conjunction_v(_STD declval<_Other>())), _Ty1>, is_convertible(_STD declval<_Other>())), _Ty2>>) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index f83d6f13dc..bec5145b41 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2407,10 +2407,12 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _U if constexpr (_Pair_like<_Uty> && !_Is_subrange_v>) { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, - // _STD forward_as_tuple(_STD get<0>(_STD move(_Ux)), _STD forward_as_tuple(_STD get<1>(_STD move(_Ux))); + // _STD forward_as_tuple(_STD get<0>(_STD forward<_Uty>(_Ux)), + // _STD forward_as_tuple(_STD get<1>(_STD forward<_Uty>(_Ux))); return _STD make_tuple(piecewise_construct, - _STD uses_allocator_construction_args(_Al, _STD get<0>(_STD move(_Ux))), - _STD uses_allocator_construction_args(_Al, _STD get<1>(_STD move(_Ux)))); + _STD uses_allocator_construction_args(_Al, _STD get<0>(_STD forward<_Uty>(_Ux))), + _STD uses_allocator_construction_args( + _Al, _STD get<1>(_STD forward<_Uty>(_Ux)))); } else #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) { From 1872df08ab7380079687c15a16de621d7cf00404 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 28 Feb 2023 09:49:23 +0800 Subject: [PATCH 3/5] Fix a severe typo! --- stl/inc/xmemory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index bec5145b41..c809f772e9 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2404,7 +2404,7 @@ _EXPORT_STD template && !_Is_subrange_v>) { + if constexpr (_Pair_like<_Uty> && !_Is_subrange_v>) { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, // _STD forward_as_tuple(_STD get<0>(_STD forward<_Uty>(_Ux)), From 5f669cb51fdbbfe002d3254b59fb1d941073ae4a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 28 Feb 2023 10:35:34 +0800 Subject: [PATCH 4/5] Fix test cases for `tuple` lvalues --- .../test.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp index af84186d0b..352327d2a4 100644 --- a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp +++ b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp @@ -182,11 +182,10 @@ constexpr bool test_P0591R4() { tuple tpl(i, i); auto tuple14 = uses_allocator_construction_args>(alloc, tpl); static_assert( - is_same_v, MovedAllocatorArgConstructArgs>>); + is_same_v, AllocatorArgConstructArgs>>); auto tuple15 = uses_allocator_construction_args>(alloc, tpl); - static_assert( - is_same_v>>); + static_assert(is_same_v>>); auto tuple16 = uses_allocator_construction_args>(alloc, move(tpl)); static_assert( @@ -198,11 +197,11 @@ constexpr bool test_P0591R4() { auto tuple18 = uses_allocator_construction_args>(alloc, as_const(tpl)); static_assert(is_same_v, MovedConstAllocatorArgConstructArgs>>); + tuple, ConstAllocatorArgConstructArgs>>); auto tuple19 = uses_allocator_construction_args>(alloc, as_const(tpl)); - static_assert(is_same_v>>); + static_assert( + is_same_v>>); auto tuple20 = uses_allocator_construction_args>(alloc, move(as_const(tpl))); From b7110b348d0b7284cfef03487719299cee84dacf Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Tue, 28 Feb 2023 14:47:53 -0800 Subject: [PATCH 5/5] reorder conjunction --- stl/inc/utility | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/utility b/stl/inc/utility index 44cf2c0651..f3bfe433fe 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -288,9 +288,9 @@ struct pair { // store a pair of values template , int> = 0> #else // ^^^ workaround / no workaround vvv template <_Pair_like _Other> - requires conjunction_v(_STD declval<_Other>()))>, - is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>, - bool_constant>>> + requires conjunction_v>>, + is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>, + is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>> #endif // __clang__ constexpr explicit(!conjunction_v(_STD declval<_Other>())), _Ty1>, is_convertible(_STD declval<_Other>())), _Ty2>>)