diff --git a/stl/inc/tuple b/stl/inc/tuple index 49492bda9..bc2948eb0 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -91,6 +91,12 @@ template _INLINE_VAR constexpr bool _Tuple_assignable_v0, _Srcs...> = conjunction_v...>; // note _Dests& instead of _Dests +#if _HAS_CXX23 +template +inline constexpr bool _Tuple_assignable_v0, _Srcs...> = + conjunction_v...>; +#endif // _HAS_CXX23 + template _INLINE_VAR constexpr bool _Tuple_assignable_v = _Tuple_assignable_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; @@ -105,27 +111,24 @@ template _INLINE_VAR constexpr bool _Tuple_nothrow_assignable_v0, _Srcs...> = conjunction_v...>; // note _Dests& instead of _Dests +#if _HAS_CXX23 +template +inline constexpr bool _Tuple_nothrow_assignable_v0, _Srcs...> = + conjunction_v...>; +#endif // _HAS_CXX23 + template _INLINE_VAR constexpr bool _Tuple_nothrow_assignable_v = _Tuple_nothrow_assignable_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; -// Constrain tuple's copy converting constructor (LWG-2549) -template -struct _Tuple_convert_copy_val : true_type {}; +// Constrain tuple's converting constructors +template +struct _Tuple_convert_val : true_type {}; -template -struct _Tuple_convert_copy_val, _Uty> - : bool_constant, is_constructible<_This, const tuple<_Uty>&>, - is_convertible&, _This>>> {}; - -// Constrain tuple's move converting constructor (LWG-2549) -template -struct _Tuple_convert_move_val : true_type {}; - -template -struct _Tuple_convert_move_val, _Uty> - : bool_constant, is_constructible<_This, tuple<_Uty>>, - is_convertible, _This>>> {}; +template +struct _Tuple_convert_val, _OtherTuple, _Uty> + : bool_constant, is_constructible<_This, _OtherTuple>, + is_convertible<_OtherTuple, _This>>> {}; // Constrain tuple's perfect forwarding constructor (LWG-3121) template @@ -225,8 +228,16 @@ public: constexpr tuple(_Tag, const _Alloc&) noexcept /* strengthened */ {} constexpr tuple& operator=(const tuple&) = default; +#if _HAS_CXX23 + constexpr const tuple& operator=(const tuple&) const noexcept /* strengthened */ { + return *this; + } +#endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple&) noexcept {} +#if _HAS_CXX23 + constexpr void swap(const tuple&) const noexcept {} +#endif // _HAS_CXX23 constexpr bool _Equals(const tuple&) const noexcept { return true; @@ -355,9 +366,18 @@ public: tuple(const tuple&) = default; tuple(tuple&&) = default; +#if _HAS_CXX23 + template , + _STD _Tuple_convert_val&, _Other...>>, + int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened + : tuple(_Unpack_tuple_t{}, _Right) {} +#endif // _HAS_CXX23 + #if _HAS_CONDITIONAL_EXPLICIT template , - _STD _Tuple_convert_copy_val>, + _STD _Tuple_convert_val&, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>& _Right) noexcept( @@ -365,14 +385,14 @@ public: : tuple(_Unpack_tuple_t{}, _Right) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template , - _Tuple_convert_copy_val>, + _Tuple_convert_val&, _Other...>>, int> = 0> constexpr tuple(const tuple<_Other...>& _Right) noexcept( _Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} template , - _Tuple_convert_copy_val>, + _Tuple_convert_val&, _Other...>>, int> = 0> constexpr explicit tuple(const tuple<_Other...>& _Right) noexcept( _Tuple_nothrow_constructible_v) // strengthened @@ -381,27 +401,43 @@ public: #if _HAS_CONDITIONAL_EXPLICIT template , - _STD _Tuple_convert_move_val>, + _STD _Tuple_convert_val, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv - template , _Tuple_convert_move_val>, - int> = 0> + template , + _Tuple_convert_val, _Other...>>, + int> = 0> constexpr tuple(tuple<_Other...>&& _Right) noexcept( _Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} - template , _Tuple_convert_move_val>, - int> = 0> + template , + _Tuple_convert_val, _Other...>>, + int> = 0> constexpr explicit tuple(tuple<_Other...>&& _Right) noexcept( _Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ +#if _HAS_CXX23 + template , + _STD _Tuple_convert_val, _Other...>>, + int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(const tuple<_Other...>&& _Right) noexcept( + _Tuple_nothrow_constructible_v) // strengthened + : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} + + template , int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(pair<_First, _Second>& _Right) noexcept( + _Tuple_nothrow_constructible_v) // strengthened + : tuple(_Unpack_tuple_t{}, _Right) {} +#endif // _HAS_CXX23 + #if _HAS_CONDITIONAL_EXPLICIT template , int> = 0> @@ -440,6 +476,15 @@ public: : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ +#if _HAS_CXX23 + template , int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(const pair<_First, _Second>&& _Right) noexcept( + _Tuple_nothrow_constructible_v) // strengthened + : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} +#endif // _HAS_CXX23 + #if _HAS_CONDITIONAL_EXPLICIT template , _STD is_default_constructible<_Rest>...>, @@ -516,25 +561,35 @@ public: _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, tuple&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} +#if _HAS_CXX23 + template , + _STD _Tuple_convert_val&, _Other...>>, + int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} +#endif // _HAS_CXX23 + #if _HAS_CONDITIONAL_EXPLICIT template , - _STD _Tuple_convert_copy_val>, + _STD _Tuple_convert_val&, _Other...>>, int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template , _Tuple_convert_copy_val>, + enable_if_t, + _Tuple_convert_val&, _Other...>>, int> = 0> _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template , _Tuple_convert_copy_val>, + enable_if_t, + _Tuple_convert_val&, _Other...>>, int> = 0> _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} @@ -543,25 +598,43 @@ public: #if _HAS_CONDITIONAL_EXPLICIT template , - _STD _Tuple_convert_move_val>, + _STD _Tuple_convert_val, _Other...>>, int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template , _Tuple_convert_move_val>, + enable_if_t, + _Tuple_convert_val, _Other...>>, int> = 0> _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} template , _Tuple_convert_move_val>, + enable_if_t, + _Tuple_convert_val, _Other...>>, int> = 0> _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ +#if _HAS_CXX23 + template , + _STD _Tuple_convert_val, _Other...>>, + int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>&& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} + + template , int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} +#endif // _HAS_CXX23 + #if _HAS_CONDITIONAL_EXPLICIT template , int> = 0> @@ -598,6 +671,14 @@ public: : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ +#if _HAS_CXX23 + template , int> = 0> + constexpr explicit(_Tuple_conditional_explicit_v) + tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>&& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} +#endif // _HAS_CXX23 + tuple& operator=(const volatile tuple&) = delete; template , + _STD _Is_copy_assignable_no_precondition_check...>, + int> = 0> + constexpr const tuple& operator=(_Identity_t _Right) const + noexcept(conjunction_v, + is_nothrow_copy_assignable...>) /* strengthened */ { + _Myfirst._Val = _Right._Myfirst._Val; + _Get_rest() = _Right._Get_rest(); + return *this; + } +#endif // _HAS_CXX23 + template , _STD _Is_move_assignable_no_precondition_check<_Rest>...>, @@ -622,6 +717,20 @@ public: return *this; } +#if _HAS_CXX23 + template , + _STD _Is_assignable_no_precondition_check...>, + int> = 0> + constexpr const tuple& operator=(_Identity_t<_Myself&&> _Right) const + noexcept(conjunction_v, + is_nothrow_assignable...>) /* strengthened */ { + _Myfirst._Val = _STD forward<_This>(_Right._Myfirst._Val); + _Get_rest() = _STD forward<_Mybase>(_Right._Get_rest()); + return *this; + } +#endif // _HAS_CXX23 + template >>, _STD _Tuple_assignable_val>, int> = 0> @@ -632,6 +741,18 @@ public: return *this; } +#if _HAS_CXX23 + template >>, + _STD _Tuple_assignable_val>, + int> = 0> + constexpr const tuple& operator=(const tuple<_Other...>& _Right) const + noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { + _Myfirst._Val = _Right._Myfirst._Val; + _Get_rest() = _Right._Get_rest(); + return *this; + } +#endif // _HAS_CXX23 + template >>, _STD _Tuple_assignable_val>, int> = 0> @@ -642,6 +763,18 @@ public: return *this; } +#if _HAS_CXX23 + template >>, + _STD _Tuple_assignable_val>, + int> = 0> + constexpr const tuple& operator=(tuple<_Other...>&& _Right) const + noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { + _Myfirst._Val = _STD forward::_This_type>(_Right._Myfirst._Val); + _Get_rest() = _STD forward::_Mybase>(_Right._Get_rest()); + return *this; + } +#endif // _HAS_CXX23 + template , int> = 0> _CONSTEXPR20 tuple& operator=(const pair<_First, _Second>& _Right) noexcept( @@ -651,6 +784,17 @@ public: return *this; } +#if _HAS_CXX23 + template , int> = 0> + constexpr const tuple& operator=(const pair<_First, _Second>& _Right) const + noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { + _Myfirst._Val = _Right.first; + _Get_rest()._Myfirst._Val = _Right.second; + return *this; + } +#endif // _HAS_CXX23 + template , int> = 0> _CONSTEXPR20 tuple& operator=(pair<_First, _Second>&& _Right) noexcept( _Tuple_nothrow_assignable_v) /* strengthened */ { @@ -659,12 +803,30 @@ public: return *this; } +#if _HAS_CXX23 + template , int> = 0> + constexpr const tuple& operator=(pair<_First, _Second>&& _Right) const + noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { + _Myfirst._Val = _STD forward<_First>(_Right.first); + _Get_rest()._Myfirst._Val = _STD forward<_Second>(_Right.second); + return *this; + } +#endif // _HAS_CXX23 + _CONSTEXPR20 void swap(tuple& _Right) noexcept( conjunction_v<_Is_nothrow_swappable<_This>, _Is_nothrow_swappable<_Rest>...>) { _Swap_adl(_Myfirst._Val, _Right._Myfirst._Val); _Mybase::swap(_Right._Get_rest()); } +#if _HAS_CXX23 + constexpr void swap(const tuple& _Right) const + noexcept(conjunction_v, is_nothrow_swappable...>) { + _Swap_adl(_Myfirst._Val, _Right._Myfirst._Val); + _Mybase::swap(_Right._Get_rest()); + } +#endif // _HAS_CXX23 + constexpr _Mybase& _Get_rest() noexcept { // get reference to rest of elements return *this; } @@ -786,11 +948,19 @@ _NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple } #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ -template ...>, int> = 0> +template ...>, int> = 0> _CONSTEXPR20 void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { return _Left.swap(_Right); } +#if _HAS_CXX23 +template ...>, int> = 0> +constexpr void swap(const tuple<_Types...>& _Left, const tuple<_Types...>& _Right) noexcept( + noexcept(_Left.swap(_Right))) { + return _Left.swap(_Right); +} +#endif // _HAS_CXX23 + template struct _Tuple_element {}; // backstop _Tuple_element definition @@ -1007,6 +1177,24 @@ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) { // construct _Ty from template struct uses_allocator, _Alloc> : true_type {}; // true_type if container allocator enabled +#ifdef __cpp_lib_concepts +template class _TQual, template class _UQual> + requires requires { + typename tuple, _UQual<_UTypes>>...>; + } +struct basic_common_reference, tuple<_UTypes...>, _TQual, _UQual> { + using type = tuple, _UQual<_UTypes>>...>; +}; + +template + requires requires { + typename tuple...>; + } +struct common_type, tuple<_UTypes...>> { + using type = tuple...>; +}; +#endif // __cpp_lib_concepts + #if _HAS_TR1_NAMESPACE namespace _DEPRECATE_TR1_NAMESPACE tr1 { using _STD get; diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 28c7ba06f..678c8c6b6 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -682,6 +682,14 @@ struct is_assignable : bool_constant<__is_assignable(_To, _From)> {}; // determi template _INLINE_VAR constexpr bool is_assignable_v = __is_assignable(_To, _From); +#if defined(_IS_ASSIGNABLE_NOCHECK_SUPPORTED) && !defined(__CUDACC__) +template +struct _Is_assignable_no_precondition_check : bool_constant<__is_assignable_no_precondition_check(_To, _From)> {}; +#else // ^^^ Use intrinsic / intrinsic not supported vvv +template +using _Is_assignable_no_precondition_check = is_assignable<_To, _From>; +#endif // defined(_IS_ASSIGNABLE_NOCHECK_SUPPORTED) && !defined(__CUDACC__) + template struct is_copy_assignable : bool_constant<__is_assignable(add_lvalue_reference_t<_Ty>, add_lvalue_reference_t)> { diff --git a/stl/inc/utility b/stl/inc/utility index 2f438e316..6b9bbb5cf 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -225,6 +225,15 @@ struct pair { // store a pair of values pair(const pair&) = default; pair(pair&&) = default; +#if _HAS_CXX23 + template , is_constructible<_Ty2, _Other2&>>, int> = 0> + constexpr explicit(!conjunction_v, is_convertible<_Other2&, _Ty2>>) + pair(pair<_Other1, _Other2>& _Right) noexcept( + is_nothrow_constructible_v<_Ty1, _Other1&>&& is_nothrow_constructible_v<_Ty2, _Other2&>) // strengthened + : first(_Right.first), second(_Right.second) {} +#endif // _HAS_CXX23 + #if _HAS_CONDITIONAL_EXPLICIT template , is_constructible<_Ty2, const _Other2&>>, @@ -278,6 +287,16 @@ struct pair { // store a pair of values : first(_STD forward<_Other1>(_Right.first)), second(_STD forward<_Other2>(_Right.second)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ +#if _HAS_CXX23 + template , is_constructible<_Ty2, const _Other2>>, int> = + 0> + constexpr explicit(!conjunction_v, is_convertible>) + pair(const pair<_Other1, _Other2>&& _Right) noexcept(is_nothrow_constructible_v<_Ty1, const _Other1>&& + is_nothrow_constructible_v<_Ty2, const _Other2>) // strengthened + : first(_STD forward(_Right.first)), second(_STD forward(_Right.second)) {} +#endif // _HAS_CXX23 + template constexpr pair(_Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indexes1...>, index_sequence<_Indexes2...>) : first(_Tuple_get<_Indexes1>(_STD move(_Val1))...), second(_Tuple_get<_Indexes2>(_STD move(_Val2))...) {} @@ -299,6 +318,20 @@ struct pair { // store a pair of values return *this; } +#if _HAS_CXX23 + template , + _Is_copy_assignable_no_precondition_check>, + int> = 0> + constexpr const pair& operator=(_Identity_t _Right) const + noexcept(conjunction_v, + is_nothrow_copy_assignable>) /* strengthened */ { + first = _Right.first; + second = _Right.second; + return *this; + } +#endif // _HAS_CXX23 + template , _Is_move_assignable_no_precondition_check>, @@ -310,6 +343,20 @@ struct pair { // store a pair of values return *this; } +#if _HAS_CXX23 + template , + _Is_assignable_no_precondition_check>, + int> = 0> + constexpr const pair& operator=(_Identity_t<_Myself&&> _Right) const + noexcept(conjunction_v, + is_nothrow_assignable>) /* strengthened */ { + first = _STD forward<_Ty1>(_Right.first); + second = _STD forward<_Ty2>(_Right.second); + return *this; + } +#endif // _HAS_CXX23 + template >>, is_assignable<_Ty1&, const _Other1&>, is_assignable<_Ty2&, const _Other2&>>, @@ -322,6 +369,20 @@ struct pair { // store a pair of values return *this; } +#if _HAS_CXX23 + template >>, + is_assignable, is_assignable>, + int> = 0> + constexpr const pair& operator=(const pair<_Other1, _Other2>& _Right) const + noexcept(is_nothrow_assignable_v&& + is_nothrow_assignable_v) /* strengthened */ { + first = _Right.first; + second = _Right.second; + return *this; + } +#endif // _HAS_CXX23 + template >>, is_assignable<_Ty1&, _Other1>, is_assignable<_Ty2&, _Other2>>, @@ -333,6 +394,20 @@ struct pair { // store a pair of values return *this; } +#if _HAS_CXX23 + template >>, is_assignable, + is_assignable>, + int> = 0> + constexpr const pair& operator=(pair<_Other1, _Other2>&& _Right) const + noexcept(is_nothrow_assignable_v&& + is_nothrow_assignable_v) /* strengthened */ { + first = _STD forward<_Other1>(_Right.first); + second = _STD forward<_Other2>(_Right.second); + return *this; + } +#endif // _HAS_CXX23 + _CONSTEXPR20 void swap(pair& _Right) noexcept( _Is_nothrow_swappable<_Ty1>::value&& _Is_nothrow_swappable<_Ty2>::value) { if (this != _STD addressof(_Right)) { @@ -341,6 +416,16 @@ struct pair { // store a pair of values } } +#if _HAS_CXX23 + constexpr void swap(const pair& _Right) const + noexcept(is_nothrow_swappable_v&& is_nothrow_swappable_v) { + if (this != _STD addressof(_Right)) { + _Swap_adl(first, _Right.first); + _Swap_adl(second, _Right.second); + } + } +#endif // _HAS_CXX23 + _Ty1 first; // the first stored value _Ty2 second; // the second stored value }; @@ -355,6 +440,14 @@ _CONSTEXPR20 void swap(pair<_Ty1, _Ty2>& _Left, pair<_Ty1, _Ty2>& _Right) noexce _Left.swap(_Right); } +#if _HAS_CXX23 +template && is_swappable_v, int> = 0> +constexpr void swap(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) noexcept( + noexcept(_Left.swap(_Right))) { + _Left.swap(_Right); +} +#endif // _HAS_CXX23 + template _NODISCARD constexpr bool operator==(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) { return _Left.first == _Right.first && _Left.second == _Right.second; @@ -398,6 +491,25 @@ _NODISCARD constexpr bool operator>=(const pair<_Ty1, _Ty2>& _Left, const pair<_ } #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ +#ifdef __cpp_lib_concepts +template class _TQual, + template class _UQual> + requires requires { + typename pair, _UQual<_Uty1>>, common_reference_t<_TQual<_Ty2>, _UQual<_Uty2>>>; + } +struct basic_common_reference, pair<_Uty1, _Uty2>, _TQual, _UQual> { + using type = pair, _UQual<_Uty1>>, common_reference_t<_TQual<_Ty2>, _UQual<_Uty2>>>; +}; + +template + requires requires { + typename pair, common_type_t<_Ty2, _Uty2>>; + } +struct common_type, pair<_Uty1, _Uty2>> { + using type = pair, common_type_t<_Ty2, _Uty2>>; +}; +#endif // __cpp_lib_concepts + template struct _Unrefwrap_helper { // leave unchanged if not a reference_wrapper using type = _Ty; diff --git a/stl/inc/vector b/stl/inc/vector index 29e592a75..429375882 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -2274,6 +2274,18 @@ public: return *this; } +#if _HAS_CXX23 + constexpr const _Vb_reference& operator=(bool _Val) const noexcept { + if (_Val) { + *const_cast<_Vbase*>(_Getptr()) |= _Mask(); + } else { + *const_cast<_Vbase*>(_Getptr()) &= ~_Mask(); + } + + return *this; + } +#endif // _HAS_CXX23 + _CONSTEXPR20 void flip() noexcept { *const_cast<_Vbase*>(_Getptr()) ^= _Mask(); } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 7619ead6e..c65ccedac 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2119,12 +2119,23 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al) no template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty1&& _Val1, _Uty2&& _Val2) noexcept; +#if _HAS_CXX23 +template , int> = 0> +_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>& _Pair) noexcept; +#endif // _HAS_CXX23 + template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, const pair<_Uty1, _Uty2>& _Pair) noexcept; template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>&& _Pair) noexcept; +#if _HAS_CXX23 +template , int> = 0> +_NODISCARD constexpr auto uses_allocator_construction_args( + const _Alloc& _Al, const pair<_Uty1, _Uty2>&& _Pair) noexcept; +#endif // _HAS_CXX23 + template && !_Is_deducible_as_pair<_Uty&>, int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept; @@ -2165,6 +2176,18 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _U _STD uses_allocator_construction_args(_Al, _STD forward<_Uty2>(_Val2))); } +#if _HAS_CXX23 +template , int>> +_NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>& _Pair) noexcept { + // equivalent to + // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(_Pair.first), _STD forward_as_tuple(_Pair.second)); + return _STD make_tuple(piecewise_construct, + _STD uses_allocator_construction_args(_Al, _Pair.first), + _STD uses_allocator_construction_args(_Al, _Pair.second)); +} +#endif // _HAS_CXX23 + template , int>> _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, const pair<_Uty1, _Uty2>& _Pair) noexcept { @@ -2186,6 +2209,19 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pa _STD uses_allocator_construction_args(_Al, _STD get<1>(_STD move(_Pair)))); } +#if _HAS_CXX23 +template , int>> +_NODISCARD constexpr auto uses_allocator_construction_args( + const _Alloc& _Al, const pair<_Uty1, _Uty2>&& _Pair) noexcept { + // equivalent to + // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(_STD get<0>(_STD move(_Pair)), _STD forward_as_tuple(_STD get<1>(_STD move(_Pair))); + return _STD make_tuple(piecewise_construct, + _STD uses_allocator_construction_args(_Al, _STD get<0>(_STD move(_Pair))), + _STD uses_allocator_construction_args(_Al, _STD get<1>(_STD move(_Pair)))); +} +#endif // _HAS_CXX23 + template && !_Is_deducible_as_pair<_Uty&>, int>> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 6cea1f60c..0fee42f44 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -302,6 +302,8 @@ // P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr // P2186R2 Removing Garbage Collection Support // P2273R3 constexpr unique_ptr +// P2321R2 zip +// (changes to pair, tuple, and vector::reference only) // P2443R1 views::chunk_by // Parallel Algorithms Notes diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 2d593cbcc..8ccf16fbf 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -86,6 +86,9 @@ std/utilities/format/format.functions/vformat_to.pass.cpp FAIL std/utilities/format/format.functions/vformat.locale.pass.cpp FAIL std/utilities/format/format.functions/vformat.pass.cpp FAIL +# libc++ doesn't implement P2321R2's changes to vector::reference +std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp FAIL + # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" @@ -230,8 +233,6 @@ std/utilities/meta/meta.unary/meta.unary.prop/is_literal_type.deprecated.fail.cp # P2321R2 zip std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp FAIL std/language.support/support.limits/support.limits.general/utility.version.pass.cpp FAIL -std/utilities/meta/meta.trans/meta.trans.other/common_reference.compile.pass.cpp FAIL -std/utilities/meta/meta.trans/meta.trans.other/common_type.pass.cpp FAIL # P1328R1 constexpr type_info::operator==() std/language.support/support.limits/support.limits.general/typeinfo.version.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index a7d2ec064..5c931e01b 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -86,6 +86,9 @@ utilities\format\format.functions\vformat_to.pass.cpp utilities\format\format.functions\vformat.locale.pass.cpp utilities\format\format.functions\vformat.pass.cpp +# libc++ doesn't implement P2321R2's changes to vector::reference +containers\sequences\vector.bool\iterator_concept_conformance.compile.pass.cpp + # *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX *** # Tracked by VSO-593630 " Enable libcxx filesystem tests" @@ -230,8 +233,6 @@ utilities\meta\meta.unary\meta.unary.prop\is_literal_type.deprecated.fail.cpp # P2321R2 zip language.support\support.limits\support.limits.general\tuple.version.pass.cpp language.support\support.limits\support.limits.general\utility.version.pass.cpp -utilities\meta\meta.trans\meta.trans.other\common_reference.compile.pass.cpp -utilities\meta\meta.trans\meta.trans.other\common_type.pass.cpp # P1328R1 constexpr type_info::operator==() language.support\support.limits\support.limits.general\typeinfo.version.pass.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 03b63583b..f36dffa2e 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -470,6 +470,7 @@ tests\P2136R3_invoke_r tests\P2162R2_std_visit_for_derived_classes_from_variant tests\P2231R1_complete_constexpr_optional_variant tests\P2273R3_constexpr_unique_ptr +tests\P2321R2_proxy_reference tests\P2401R0_conditional_noexcept_for_exchange tests\P2415R2_owning_view tests\P2443R1_views_chunk_by diff --git a/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp b/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp index bece898ad..912c20613 100644 --- a/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp +++ b/tests/std/tests/Dev10_500860_overloaded_address_of/test.cpp @@ -42,6 +42,12 @@ namespace Meow { constexpr Evil() noexcept : data(1701) {} + template + const Evil& operator=(const Evil&) const { + // provide an Evil operator= for std::tuple::swap + return *this; + } + int func() const { return 1729; } 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 395159736..542948c01 100644 --- a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp +++ b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp @@ -74,9 +74,13 @@ constexpr bool test_P0591R4() { using ConstAllocatorConstructArgs = tuple&>; using MovedAllocatorArgConstructArgs = tuple&, int&&>; using MovedAllocatorConstructArgs = tuple&>; - using OnlyAllocatorArgConstructArgs = tuple&>; - using OnlyAllocatorConstructArgs = tuple&>; - using DefaultConstructArgs = tuple<>; +#if _HAS_CXX23 + using MovedConstAllocatorArgConstructArgs = tuple&, const int&&>; + using MovedConstAllocatorConstructArgs = tuple&>; +#endif // _HAS_CXX23 + using OnlyAllocatorArgConstructArgs = tuple&>; + using OnlyAllocatorConstructArgs = tuple&>; + using DefaultConstructArgs = tuple<>; { // non-pair overload auto tuple1 = uses_allocator_construction_args(alloc, i); @@ -121,12 +125,31 @@ constexpr bool test_P0591R4() { static_assert(is_same_v>>); } - { // pair(const pair&) overload + { // pair(const pair&) overload before C++23; pair(pair&) overload since C++23 auto tuple10 = uses_allocator_construction_args>(alloc, p); +#if _HAS_CXX23 + static_assert( + is_same_v, AllocatorArgConstructArgs>>); +#else // _HAS_CXX23 + static_assert(is_same_v, ConstAllocatorArgConstructArgs>>); +#endif // _HAS_CXX23 + + auto tuple11 = uses_allocator_construction_args>(alloc, p); +#if _HAS_CXX23 + static_assert(is_same_v>>); +#else // _HAS_CXX23 + static_assert( + is_same_v>>); +#endif // _HAS_CXX23 + } + + { // pair(const pair&) overload + auto tuple10 = uses_allocator_construction_args>(alloc, as_const(p)); static_assert(is_same_v, ConstAllocatorArgConstructArgs>>); - auto tuple11 = uses_allocator_construction_args>(alloc, p); + auto tuple11 = uses_allocator_construction_args>(alloc, as_const(p)); static_assert( is_same_v>>); } @@ -141,6 +164,18 @@ constexpr bool test_P0591R4() { is_same_v>>); } +#if _HAS_CXX23 + { // pair(const pair&&) overload + auto tuple12 = uses_allocator_construction_args>(alloc, move(as_const(p))); + static_assert(is_same_v, MovedConstAllocatorArgConstructArgs>>); + + auto tuple13 = uses_allocator_construction_args>(alloc, move(as_const(p))); + static_assert(is_same_v>>); + } +#endif // _HAS_CXX23 + { auto obj1 = make_obj_using_allocator(alloc, i); static_assert(is_same_v); diff --git a/tests/std/tests/P2321R2_proxy_reference/env.lst b/tests/std/tests/P2321R2_proxy_reference/env.lst new file mode 100644 index 000000000..642f530ff --- /dev/null +++ b/tests/std/tests/P2321R2_proxy_reference/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2321R2_proxy_reference/test.cpp b/tests/std/tests/P2321R2_proxy_reference/test.cpp new file mode 100644 index 000000000..594664904 --- /dev/null +++ b/tests/std/tests/P2321R2_proxy_reference/test.cpp @@ -0,0 +1,295 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +using namespace std; + +enum class State { + none, + copy_construct, + copy_construct_from_const, + move_construct, + move_construct_from_const, + copy_assign, + copy_assign_to_const, + move_assign, + move_assign_to_const, + swap, + swap_const, +}; + +struct Meow { + Meow() = default; + constexpr Meow(Meow&) : state(State::copy_construct) {} + constexpr Meow(const Meow&) : state(State::copy_construct_from_const) {} + constexpr Meow(Meow&&) : state(State::move_construct) {} + constexpr Meow(const Meow&&) : state(State::move_construct_from_const) {} + + constexpr Meow& operator=(Meow&) = delete; + constexpr const Meow& operator=(Meow&) const = delete; + + constexpr Meow& operator=(const Meow&) { + state = State::copy_assign; + return *this; + } + constexpr const Meow& operator=(const Meow&) const { + state = State::copy_assign_to_const; + return *this; + } + constexpr Meow& operator=(Meow&&) { + state = State::move_assign; + return *this; + } + constexpr const Meow& operator=(Meow&&) const { + state = State::move_assign_to_const; + return *this; + } + + constexpr Meow& operator=(const Meow&&) = delete; + constexpr const Meow& operator=(const Meow&&) const = delete; + + friend constexpr void swap(Meow& left, Meow&) { + left.state = State::swap; + } + friend constexpr void swap(const Meow& left, const Meow&) { + left.state = State::swap_const; + } + + mutable State state; +}; + +constexpr bool test() { + { // Test pair and tuple + int val = 0; + + pair pris{val, Meow{}}; + + // Test pair construction + pair pris2 = pris; + pair pris3 = as_const(pris); + pair pris4 = move(pris); + pair pris5 = move(as_const(pris)); + + pair prcis1 = pris; + pair prcis2 = as_const(pris); + pair prcis3 = move(pris); + pair prcis4 = move(as_const(pris)); + + assert(pris2.second.state == State::copy_construct); + assert(pris3.second.state == State::copy_construct_from_const); + assert(pris4.second.state == State::move_construct); + assert(pris5.second.state == State::move_construct_from_const); + assert(prcis1.second.state == State::copy_construct); + assert(prcis2.second.state == State::copy_construct_from_const); + assert(prcis3.second.state == State::move_construct); + assert(prcis4.second.state == State::move_construct_from_const); + + // Test pair assignment from lvalue + pris2 = pris4; + as_const(pris3) = pris5; + pris4 = prcis1; + as_const(pris5) = prcis2; + + assert(pris2.second.state == State::copy_assign); + assert(pris3.second.state == State::copy_assign_to_const); + assert(pris4.second.state == State::copy_assign); + assert(pris5.second.state == State::copy_assign_to_const); + + // Test pair assignment from rvalue + pris2 = move(pris4); + as_const(pris3) = move(pris5); + pris4 = move(prcis1); + as_const(pris5) = move(prcis2); + + assert(pris2.second.state == State::move_assign); + assert(pris3.second.state == State::move_assign_to_const); + assert(pris4.second.state == State::move_assign); + assert(pris5.second.state == State::move_assign_to_const); + + // Test pair member swap + pris.swap(pris2); + as_const(pris2).swap(as_const(pris3)); + + assert(pris.second.state == State::swap); + assert(pris2.second.state == State::swap_const); + + // Test pair non-member swap + swap(pris3, pris5); + swap(as_const(pris4), as_const(pris5)); + assert(pris3.second.state == State::swap); + assert(pris4.second.state == State::swap_const); + static_assert(is_nothrow_swappable_v>); + static_assert(is_nothrow_swappable_v>); + static_assert(!is_nothrow_swappable_v>); + static_assert(!is_nothrow_swappable_v>); + +#ifdef __cpp_lib_concepts + // Test basic_common_reference and common_type specializations for pair + static_assert(is_same_v, pair>, pair>); + static_assert(is_same_v, pair>, + pair>); + static_assert(is_same_v, pair>, pair>); +#endif // __cpp_lib_concepts + + tuple tris{val, Meow{}}; + + // Test tuple construction (from tuple or pair) + tuple tris2 = tris; + tuple tris3 = as_const(tris); + tuple tris4 = move(tris); + tuple tris5 = move(as_const(tris)); + tuple tris6 = pris; + tuple tris7 = as_const(pris); + tuple tris8 = move(pris); + tuple tris9 = move(as_const(pris)); + + tuple trcis1 = tris; + tuple trcis2 = as_const(tris); + tuple trcis3 = move(tris); + tuple trcis4 = move(as_const(tris)); + tuple trcis5 = pris; + tuple trcis6 = as_const(pris); + tuple trcis7 = move(pris); + tuple trcis8 = move(as_const(pris)); + + assert(get<1>(tris2).state == State::copy_construct); + assert(get<1>(tris3).state == State::copy_construct_from_const); + assert(get<1>(tris4).state == State::move_construct); + assert(get<1>(tris5).state == State::move_construct_from_const); + assert(get<1>(tris6).state == State::copy_construct); + assert(get<1>(tris7).state == State::copy_construct_from_const); + assert(get<1>(tris8).state == State::move_construct); + assert(get<1>(tris9).state == State::move_construct_from_const); + assert(get<1>(trcis1).state == State::copy_construct); + assert(get<1>(trcis2).state == State::copy_construct_from_const); + assert(get<1>(trcis3).state == State::move_construct); + assert(get<1>(trcis4).state == State::move_construct_from_const); + assert(get<1>(trcis5).state == State::copy_construct); + assert(get<1>(trcis6).state == State::copy_construct_from_const); + assert(get<1>(trcis7).state == State::move_construct); + assert(get<1>(trcis8).state == State::move_construct_from_const); + + // Test tuple uses-allocator construction + tuple tris10{allocator_arg, allocator{}, tris}; + tuple tris11{allocator_arg, allocator{}, as_const(tris)}; + tuple tris12{allocator_arg, allocator{}, move(tris)}; + tuple tris13{allocator_arg, allocator{}, move(as_const(tris))}; + tuple tris14{allocator_arg, allocator{}, pris}; + tuple tris15{allocator_arg, allocator{}, as_const(pris)}; + tuple tris16{allocator_arg, allocator{}, move(pris)}; + tuple tris17{allocator_arg, allocator{}, move(as_const(pris))}; + + tuple trcis9{allocator_arg, allocator{}, tris}; + tuple trcis10{allocator_arg, allocator{}, as_const(tris)}; + tuple trcis11{allocator_arg, allocator{}, move(tris)}; + tuple trcis12{allocator_arg, allocator{}, move(as_const(tris))}; + tuple trcis13{allocator_arg, allocator{}, pris}; + tuple trcis14{allocator_arg, allocator{}, as_const(pris)}; + tuple trcis15{allocator_arg, allocator{}, move(pris)}; + tuple trcis16{allocator_arg, allocator{}, move(as_const(pris))}; + + assert(get<1>(tris10).state == State::copy_construct); + assert(get<1>(tris11).state == State::copy_construct_from_const); + assert(get<1>(tris12).state == State::move_construct); + assert(get<1>(tris13).state == State::move_construct_from_const); + assert(get<1>(tris14).state == State::copy_construct); + assert(get<1>(tris15).state == State::copy_construct_from_const); + assert(get<1>(tris16).state == State::move_construct); + assert(get<1>(tris17).state == State::move_construct_from_const); + assert(get<1>(trcis9).state == State::copy_construct); + assert(get<1>(trcis10).state == State::copy_construct_from_const); + assert(get<1>(trcis11).state == State::move_construct); + assert(get<1>(trcis12).state == State::move_construct_from_const); + assert(get<1>(trcis13).state == State::copy_construct); + assert(get<1>(trcis14).state == State::copy_construct_from_const); + assert(get<1>(trcis15).state == State::move_construct); + assert(get<1>(trcis16).state == State::move_construct_from_const); + + // Test tuple assignment from tuple lvalue + tris2 = tris; + as_const(tris3) = tris; + tris4 = trcis1; + as_const(tris5) = trcis2; + + assert(get<1>(tris2).state == State::copy_assign); + assert(get<1>(tris3).state == State::copy_assign_to_const); + assert(get<1>(tris4).state == State::copy_assign); + assert(get<1>(tris5).state == State::copy_assign_to_const); + + // Test tuple assignment from tuple rvalue + tris2 = move(tris); + as_const(tris3) = move(tris); + tris4 = move(trcis1); + as_const(tris5) = move(trcis2); + + assert(get<1>(tris2).state == State::move_assign); + assert(get<1>(tris3).state == State::move_assign_to_const); + assert(get<1>(tris4).state == State::move_assign); + assert(get<1>(tris5).state == State::move_assign_to_const); + + // Test tuple assignment from pair + tris2 = pris; + as_const(tris3) = pris; + tris4 = move(pris); + as_const(tris5) = move(pris); + + assert(get<1>(tris2).state == State::copy_assign); + assert(get<1>(tris3).state == State::copy_assign_to_const); + assert(get<1>(tris4).state == State::move_assign); + assert(get<1>(tris5).state == State::move_assign_to_const); + + // Test tuple member swap + tris2.swap(tris); + as_const(tris3).swap(tris); + + assert(get<1>(tris2).state == State::swap); + assert(get<1>(tris3).state == State::swap_const); + + // Test tuple non-member swap + swap(tris4, tris); + swap(as_const(tris5), as_const(tris)); + + assert(get<1>(tris4).state == State::swap); + assert(get<1>(tris5).state == State::swap_const); + + static_assert(is_nothrow_swappable_v>); + static_assert(is_nothrow_swappable_v>); + static_assert(!is_nothrow_swappable_v>); + static_assert(!is_nothrow_swappable_v>); + +#ifdef __cpp_lib_concepts + // Test basic_common_reference and common_type specializations for tuple + static_assert( + is_same_v, tuple>, tuple>); + static_assert(is_same_v, tuple>, + tuple>); + static_assert(is_same_v, tuple>, tuple>); +#endif // __cpp_lib_concepts + } + + { // Test vector::reference + static_assert(is_assignable_v::reference, bool>); +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1274387, VSO-1273296 + if (!is_constant_evaluated()) +#endif // defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 + { + vector vb{false}; + const vector::reference r = vb[0]; + + r = true; + assert(vb.front()); + } + } + + return true; +} + +int main() { + test(); + static_assert(test()); +}