diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -25,14 +25,24 @@ explicit(see-below) tuple(U&&...); // constexpr in C++14 tuple(const tuple&) = default; tuple(tuple&&) = default; + + template + constexpr explicit(see below) tuple(tuple&); // C++23 template explicit(see-below) tuple(const tuple&); // constexpr in C++14 template explicit(see-below) tuple(tuple&&); // constexpr in C++14 + template + constexpr explicit(see below) tuple(const tuple&&); // C++23 + + template + constexpr explicit(see below) tuple(pair&); // iff sizeof...(Types) == 2 // C++23 template explicit(see-below) tuple(const pair&); // iff sizeof...(T) == 2 // constexpr in C++14 template explicit(see-below) tuple(pair&&); // iff sizeof...(T) == 2 // constexpr in C++14 + template + constexpr explicit(see below) tuple(const pair&&); // iff sizeof...(Types) == 2 // C++23 // allocator-extended constructors template @@ -45,25 +55,47 @@ tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 + template + constexpr explicit(see below) + tuple(allocator_arg_t, const Alloc& a, tuple&); // C++23 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 + template + constexpr explicit(see below) + tuple(allocator_arg_t, const Alloc& a, const tuple&&); // C++23 + template + constexpr explicit(see below) + tuple(allocator_arg_t, const Alloc& a, pair&); // C++23 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const pair&); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, pair&&); // constexpr in C++20 + template + constexpr explicit(see below) + tuple(allocator_arg_t, const Alloc& a, const pair&&); // C++23 tuple& operator=(const tuple&); // constexpr in C++20 + constexpr const tuple& operator=(const tuple&) const; // C++23 tuple& operator=(tuple&&) noexcept(is_nothrow_move_assignable_v && ...); // constexpr in C++20 + constexpr const tuple& operator=(tuple&&) const; // C++23 template tuple& operator=(const tuple&); // constexpr in C++20 + template + constexpr const tuple& operator=(const tuple&) const; // C++23 template tuple& operator=(tuple&&); // constexpr in C++20 + template + constexpr const tuple& operator=(tuple&&) const; // C++23 template tuple& operator=(const pair&); // iff sizeof...(T) == 2 // constexpr in C++20 + template + constexpr const tuple& operator=(const pair&) const; // iff sizeof...(Types) == 2 // C++23 template tuple& operator=(pair&&); // iff sizeof...(T) == 2 // constexpr in C++20 + template + constexpr const tuple& operator=(pair&&) const; // iff sizeof...(Types) == 2 // C++23 template tuple& operator=(array const&) // iff sizeof...(T) == N, EXTENSION @@ -71,6 +103,7 @@ tuple& operator=(array&&) // iff sizeof...(T) == N, EXTENSION void swap(tuple&) noexcept(AND(swap(declval(), declval())...)); // constexpr in C++20 + constexpr void swap(const tuple&) const noexcept(see below); // C++23 }; @@ -161,6 +194,9 @@ void swap(tuple& x, tuple& y) noexcept(noexcept(x.swap(y))); +template + constexpr void swap(const tuple& x, const tuple& y) noexcept(see below); // C++23 + } // std */ @@ -219,6 +255,13 @@ swap(__x.get(), __y.get()); } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +void swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x, const __tuple_leaf<_Ip, _Hp, _Ep>& __y) + _NOEXCEPT_(__is_nothrow_swappable::value) { + swap(__x.get(), __y.get()); +} + template class __tuple_leaf { @@ -307,6 +350,12 @@ return 0; } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + int swap(const __tuple_leaf& __t) const _NOEXCEPT_(__is_nothrow_swappable::value) { + _VSTD::swap(*this, __t); + return 0; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return __value_;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return __value_;} }; @@ -373,6 +422,12 @@ return 0; } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + int swap(const __tuple_leaf& __rhs) const _NOEXCEPT_(__is_nothrow_swappable::value) { + _VSTD::swap(*this, __rhs); + return 0; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return static_cast<_Hp&>(*this);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return static_cast(*this);} }; @@ -463,6 +518,13 @@ { _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t))...); } + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + void swap(const __tuple_impl& __t) const + _NOEXCEPT_(__all<__is_nothrow_swappable::value...>::value) + { + _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast&>(__t))...); + } }; template @@ -698,6 +760,7 @@ template class _And = _And, __enable_if_t< _And...>::value , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple(allocator_arg_t, const _Alloc& __alloc, const tuple& __t) : __base_(allocator_arg_t(), __alloc, __t) { } @@ -705,30 +768,37 @@ template class _And = _And, __enable_if_t< _And...>::value , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple(allocator_arg_t, const _Alloc& __alloc, tuple&& __t) : __base_(allocator_arg_t(), __alloc, _VSTD::move(__t)) { } // tuple(const tuple&) constructors (including allocator_arg_t variants) - template - struct _EnableCopyFromOtherTuple : _And< - _Not, tuple<_Up...> > >, - _Lazy<_Or, - _BoolConstant, + + template , class = void> + struct _EnableCtrFromUTypesTuple : false_type {}; + + template + struct _EnableCtrFromUTypesTuple<_OtherTuple, tuple<_Up...>, + // the length of the packs needs to checked first otherwise the 2 packs cannot be expanded simultaneously below + typename enable_if::type> : _And< + _Not >, // not in spec, but to keep previous libcxx behaviour + _Not >, // not in spec, but to keep previous libcxx behaviour + is_constructible<_Tp, __copy_cvref_t<_OtherTuple, _Up> >..., + _Or<_BoolConstant, // _Tp and _Up are 1-element packs - the pack expansions look // weird to avoid tripping up the type traits in degenerate cases - _Lazy<_And, - _Not&, _Tp> >..., - _Not&> >... + _And< + _Not >..., + _Lazy<_Not, is_convertible<_OtherTuple, _Tp> >..., + _Lazy<_Not, is_constructible<_Tp, _OtherTuple> >... > - >, - is_constructible<_Tp, const _Up&>... - > { }; + > + > {}; template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&>, is_convertible... // explicit check >::value , int> = 0> @@ -740,8 +810,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&>, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -753,8 +822,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&>, is_convertible... // explicit check >::value , int> = 0> @@ -765,8 +833,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&>, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -775,26 +842,27 @@ : __base_(allocator_arg_t(), __a, __t) { } +#if _LIBCPP_STD_VER > 20 + // tuple(tuple&) constructors (including allocator_arg_t variants) + + template &>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<_Up&, _Tp> && ...)) + tuple(tuple<_Up...>& __t) : __base_(__t) {} + + template &>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<_Up&, _Tp> && ...)) + tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t) : __base_(allocator_arg_t(), __alloc, __t) {} +#endif // _LIBCPP_STD_VER > 20 + // tuple(tuple&&) constructors (including allocator_arg_t variants) - template - struct _EnableMoveFromOtherTuple : _And< - _Not, tuple<_Up...> > >, - _Lazy<_Or, - _BoolConstant, - // _Tp and _Up are 1-element packs - the pack expansions look - // weird to avoid tripping up the type traits in degenerate cases - _Lazy<_And, - _Not, _Tp> >..., - _Not > >... - > - >, - is_constructible<_Tp, _Up>... - > { }; template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&&>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -806,8 +874,7 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&&>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -819,8 +886,7 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&&>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -831,8 +897,7 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtrFromUTypesTuple&&>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -841,27 +906,47 @@ : __base_(allocator_arg_t(), __a, _VSTD::move(__t)) { } +#if _LIBCPP_STD_VER > 20 + // tuple(const tuple&&) constructors (including allocator_arg_t variants) + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v && ...)) + tuple(const tuple<_Up...>&& __t) : __base_(std::move(__t)) {} + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v && ...)) + tuple(allocator_arg_t, const _Alloc& __alloc, const tuple<_Up...>&& __t) + : __base_(allocator_arg_t(), __alloc, std::move(__t)) {} +#endif // _LIBCPP_STD_VER > 20 + // tuple(const pair&) constructors (including allocator_arg_t variants) - template - struct _EnableImplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - is_convertible >, // explicit check - is_convertible > - > { }; - template - struct _EnableExplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - _Not > >, // explicit check - _Not > > - > { }; + template , class _Tuple = tuple> + struct _EnableCtrFromPair : false_type{}; + + template + struct _EnableCtrFromPair<_Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2>> : _And< + is_constructible<_Tp1, __copy_cvref_t<_Pair, _Up1> >, + is_constructible<_Tp2, __copy_cvref_t<_Pair, _Up2> > + > {}; + + template , class _Tuple = tuple> + struct _BothImplicitlyConvertible : false_type{}; + + template + struct _BothImplicitlyConvertible<_Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2>> : _And< + is_convertible<__copy_cvref_t<_Pair, _Up1>, _Tp1>, + is_convertible<__copy_cvref_t<_Pair, _Up2>, _Tp2> + > {}; template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&>, + _BothImplicitlyConvertible&> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -875,8 +960,8 @@ template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&>, + _Not<_BothImplicitlyConvertible&> > >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -890,8 +975,8 @@ template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&>, + _BothImplicitlyConvertible&> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -901,8 +986,8 @@ template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&>, + _Not<_BothImplicitlyConvertible&> > >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -910,27 +995,28 @@ : __base_(allocator_arg_t(), __a, __p) { } - // tuple(pair&&) constructors (including allocator_arg_t variants) - template - struct _EnableImplicitMoveFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, _Up1>, - is_constructible<_SecondType<_DependentTp...>, _Up2>, - is_convertible<_Up1, _FirstType<_DependentTp...> >, // explicit check - is_convertible<_Up2, _SecondType<_DependentTp...> > - > { }; +#if _LIBCPP_STD_VER > 20 + // tuple(pair&) constructors (including allocator_arg_t variants) + + template &>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible&>::value) + tuple(pair<_U1, _U2>& __p) : __base_(__p) {} + + template &>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible&>::value) + tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p) : __base_(allocator_arg_t(), __alloc, __p) {} +#endif - template - struct _EnableExplicitMoveFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, _Up1>, - is_constructible<_SecondType<_DependentTp...>, _Up2>, - _Not > >, // explicit check - _Not > > - > { }; + // tuple(pair&&) constructors (including allocator_arg_t variants) template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&&>, + _BothImplicitlyConvertible&&> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -944,8 +1030,8 @@ template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&&>, + _Not<_BothImplicitlyConvertible&&> > >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -959,8 +1045,8 @@ template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&&>, + _BothImplicitlyConvertible&&> >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -970,8 +1056,8 @@ template class _And = _And, __enable_if_t< _And< - _BoolConstant, - _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtrFromPair&&>, + _Not<_BothImplicitlyConvertible&&> > >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -979,6 +1065,23 @@ : __base_(allocator_arg_t(), __a, _VSTD::move(__p)) { } +#if _LIBCPP_STD_VER > 20 + // tuple(const pair&&) constructors (including allocator_arg_t variants) + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible&&>::value) + tuple(const pair<_U1, _U2>&& __p) : __base_(std::move(__p)) {} + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible&&>::value) + tuple(allocator_arg_t, const _Alloc& __alloc, const pair<_U1, _U2>&& __p) + : __base_(allocator_arg_t(), __alloc, std::move(__p)) {} +#endif // _LIBCPP_STD_VER > 20 + // [tuple.assign] _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(_If<_And...>::value, tuple, __nat> const& __tuple) @@ -989,6 +1092,23 @@ return *this; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(_If<_And...>::value, tuple, __nat> const& __tuple) const { + std::__memberwise_copy_assign(*this, __tuple, typename __make_tuple_indices::type()); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(_If<_And...>::value, tuple, __nat>&& __tuple) const { + std::__memberwise_forward_assign(*this, + std::move(__tuple), + __tuple_types<_Tp...>(), + typename __make_tuple_indices::type()); + return *this; + } +#endif // _LIBCPP_STD_VER > 20 + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(_If<_And...>::value, tuple, __nat>&& __tuple) _NOEXCEPT_((_And...>::value)) @@ -1030,6 +1150,59 @@ return *this; } + +#if _LIBCPP_STD_VER > 20 + template , + is_assignable...>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(const tuple<_UTypes...>& __u) const { + std::__memberwise_copy_assign(*this, + __u, + typename __make_tuple_indices::type()); + return *this; + } + + template , + is_assignable...>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(tuple<_UTypes...>&& __u) const { + std::__memberwise_forward_assign(*this, + __u, + __tuple_types<_UTypes...>(), + typename __make_tuple_indices::type()); + return *this; + } + + template , class _Tuple = tuple> + struct _EnableAssignFromPair : false_type {}; + + template + struct _EnableAssignFromPair<_Const, _Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2>> : + _And&, __copy_cvref_t<_Pair, _Up1>>, + is_assignable<__maybe_const<_Const, _Tp2>&, __copy_cvref_t<_Pair, _Up2>> + > {}; + + template &>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(const pair<_U1, _U2>& __pair) const { + std::get<0>(*this) = __pair.first; + std::get<1>(*this) = __pair.second; + return *this; + } + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(pair<_U1, _U2>&& __pair) const { + std::get<0>(*this) = std::move(__pair.first); + std::get<1>(*this) = std::move(__pair.second); + return *this; + } +#endif // _LIBCPP_STD_VER > 20 + template, @@ -1105,6 +1278,13 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(tuple& __t) _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) {__base_.swap(__t.__base_);} + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const tuple& __t) const noexcept(__all...>::value) { + __base_.swap(__t.__base_); + } +#endif // _LIBCPP_STD_VER > 20 }; template <> @@ -1127,6 +1307,9 @@ tuple(allocator_arg_t, const _Alloc&, array<_Up, 0>) _NOEXCEPT {} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(tuple&) _NOEXCEPT {} +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr void swap(const tuple&) const noexcept {} +#endif // _LIBCPP_STD_VER > 20 }; #if _LIBCPP_STD_VER > 20 @@ -1167,6 +1350,16 @@ _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) {__t.swap(__u);} +#if _LIBCPP_STD_VER > 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr +enable_if_t<__all...>::value, void> +swap(const tuple<_Tp...>& __lhs, const tuple<_Tp...>& __rhs) + noexcept(__all...>::value) { + __lhs.swap(__rhs); +} +#endif // _LIBCPP_STD_VER > 20 + // get template diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -2297,7 +2297,6 @@ template using common_type_t = typename common_type<_Tp...>::type; #endif -#if _LIBCPP_STD_VER > 11 // Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's // top-level cv-qualifiers. template @@ -2309,19 +2308,19 @@ template struct __copy_cv { - using type = add_const_t<_To>; + using type = typename add_const<_To>::type; }; template struct __copy_cv { - using type = add_volatile_t<_To>; + using type = typename add_volatile<_To>::type; }; template struct __copy_cv { - using type = add_cv_t<_To>; + using type = typename add_cv<_To>::type; }; template @@ -2336,19 +2335,18 @@ template struct __copy_cvref<_From&, _To> { - using type = add_lvalue_reference_t<__copy_cv_t<_From, _To>>; + using type = typename add_lvalue_reference<__copy_cv_t<_From, _To> >::type; }; template struct __copy_cvref<_From&&, _To> { - using type = add_rvalue_reference_t<__copy_cv_t<_From, _To>>; + using type = typename add_rvalue_reference<__copy_cv_t<_From, _To> >::type; }; template using __copy_cvref_t = typename __copy_cvref<_From, _To>::type; -#endif // _LIBCPP_STD_VER > 11 // common_reference #if _LIBCPP_STD_VER > 17 diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/range.concept.compile.pass.cpp @@ -165,15 +165,11 @@ int buffer2[3] = {1, 2, 3}; int buffer3[4] = {1, 2, 3, 4}; - // TODO: uncomment all the static_asserts once [tuple.tuple] section in P2321R2 is implemented - // This is because convertible_to&, tuple> is false without - // the above implementation, thus the zip iterator does not model indirectly_readable - { std::ranges::zip_view v{ContiguousCommonView{buffer1}, ContiguousCommonView{buffer2}, ContiguousCommonView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::random_access_range); + static_assert(std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); static_assert(std::ranges::common_range); static_assert(std::ranges::sized_range); @@ -183,7 +179,7 @@ std::ranges::zip_view v{ContiguousNonCommonView{buffer1}, ContiguousNonCommonView{buffer2}, ContiguousNonCommonView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::random_access_range); + static_assert(std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); static_assert(!std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -193,7 +189,7 @@ std::ranges::zip_view v{ContiguousNonCommonSized{buffer1}, ContiguousNonCommonSized{buffer2}, ContiguousNonCommonSized{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::random_access_range); + static_assert(std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); static_assert(std::ranges::common_range); static_assert(std::ranges::sized_range); @@ -203,7 +199,7 @@ std::ranges::zip_view v{SizedRandomAccessView{buffer1}, ContiguousCommonView{buffer2}, ContiguousCommonView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::random_access_range); + static_assert(std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); static_assert(std::ranges::common_range); static_assert(std::ranges::sized_range); @@ -213,7 +209,7 @@ std::ranges::zip_view v{SizedRandomAccessView{buffer1}, SizedRandomAccessView{buffer2}, SizedRandomAccessView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::random_access_range); + static_assert(std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); static_assert(std::ranges::common_range); static_assert(std::ranges::sized_range); @@ -223,7 +219,7 @@ std::ranges::zip_view v{NonSizedRandomAccessView{buffer1}, NonSizedRandomAccessView{buffer2}, NonSizedRandomAccessView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::random_access_range); + static_assert(std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); static_assert(!std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -232,7 +228,7 @@ { std::ranges::zip_view v{BidiCommonView{buffer1}, SizedRandomAccessView{buffer2}, SizedRandomAccessView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::bidirectional_range); + static_assert(std::ranges::bidirectional_range); static_assert(!std::ranges::random_access_range); static_assert(!std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -241,7 +237,7 @@ { std::ranges::zip_view v{BidiCommonView{buffer1}, BidiCommonView{buffer2}, BidiCommonView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::bidirectional_range); + static_assert(std::ranges::bidirectional_range); static_assert(!std::ranges::random_access_range); static_assert(!std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -250,7 +246,7 @@ { std::ranges::zip_view v{BidiCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::forward_range); + static_assert(std::ranges::forward_range); static_assert(!std::ranges::bidirectional_range); static_assert(std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -259,7 +255,7 @@ { std::ranges::zip_view v{BidiNonCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::forward_range); + static_assert(std::ranges::forward_range); static_assert(!std::ranges::bidirectional_range); static_assert(!std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -268,7 +264,7 @@ { std::ranges::zip_view v{ForwardSizedView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::forward_range); + static_assert(std::ranges::forward_range); static_assert(!std::ranges::bidirectional_range); static_assert(std::ranges::common_range); static_assert(std::ranges::sized_range); @@ -277,7 +273,7 @@ { std::ranges::zip_view v{ForwardSizedNonCommon{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::forward_range); + static_assert(std::ranges::forward_range); static_assert(!std::ranges::bidirectional_range); static_assert(!std::ranges::common_range); static_assert(std::ranges::sized_range); @@ -286,7 +282,7 @@ { std::ranges::zip_view v{InputCommonView{buffer1}, ForwardSizedView{buffer2}, ForwardSizedView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::input_range); + static_assert(std::ranges::input_range); static_assert(!std::ranges::forward_range); static_assert(std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -295,7 +291,7 @@ { std::ranges::zip_view v{InputCommonView{buffer1}, InputCommonView{buffer2}, InputCommonView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::input_range); + static_assert(std::ranges::input_range); static_assert(!std::ranges::forward_range); static_assert(std::ranges::common_range); static_assert(!std::ranges::sized_range); @@ -304,7 +300,7 @@ { std::ranges::zip_view v{InputNonCommonView{buffer1}, InputCommonView{buffer2}, InputCommonView{buffer3}}; using View = decltype(v); - // static_assert(std::ranges::input_range); + static_assert(std::ranges::input_range); static_assert(!std::ranges::forward_range); static_assert(!std::ranges::common_range); static_assert(!std::ranges::sized_range); diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_convert_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_convert_copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_convert_copy.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// constexpr const tuple& operator=(const tuple& u) const; +// +// Constraints: +// - sizeof...(Types) equals sizeof...(UTypes) and +// - (is_assignable_v && ...) is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "types.h" + +// test constraints + +// sizeof...(Types) equals sizeof...(UTypes) +static_assert(std::is_assignable_v&, const std::tuple&>); +static_assert(!std::is_assignable_v&, const std::tuple&>); +static_assert(!std::is_assignable_v&, const std::tuple&>); + +// (is_assignable_v && ...) is true +static_assert( + std::is_assignable_v>&, const std::tuple&>); + +static_assert(std::is_assignable_v, ConstCopyAssign>&, + const std::tuple&>); + +static_assert(!std::is_assignable_v, CopyAssign>&, + const std::tuple&>); + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + long j1 = 3; + long j2 = 4; + const std::tuple t1{i1, i2}; + const std::tuple t2{j1, j2}; + t2 = t1; + assert(std::get<0>(t2) == 1); + assert(std::get<1>(t2) == 2); + } + + // user defined const copy assignment + { + const std::tuple t1{1}; + const std::tuple> t2{2}; + t2 = t1; + assert(std::get<0>(t2).v.val == 1); + } + + // correct overload should be selected + { + std::tuple t1{}; + const std::tuple> t2{}; + t2 = t1; + assert(std::get<0>(t2).v.constCopyAssign == 1); + } + + return true; +} + +int main() { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(__GNUG__) || defined(__clang__) + static_assert(test()); +#endif + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_convert_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_convert_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_convert_move.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// constexpr const tuple& operator=(tuple&& u) const; +// +// Constraints: +// - sizeof...(Types) equals sizeof...(UTypes) and +// - (is_assignable_v && ...) is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "types.h" + +// test constraints + +// sizeof...(Types) equals sizeof...(UTypes) +static_assert(std::is_assignable_v&, std::tuple&&>); +static_assert(!std::is_assignable_v&, std::tuple&&>); +static_assert(!std::is_assignable_v&, std::tuple&&>); + +// (is_assignable_v && ...) is true +static_assert(std::is_assignable_v>&, std::tuple&&>); + +static_assert(std::is_assignable_v, ConstMoveAssign>&, + std::tuple&&>); + +static_assert(!std::is_assignable_v, AssignableFrom>&, + std::tuple&&>); + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + long j1 = 3; + long j2 = 4; + std::tuple t1{i1, i2}; + const std::tuple t2{j1, j2}; + t2 = std::move(t1); + assert(std::get<0>(t2) == 1); + assert(std::get<1>(t2) == 2); + } + + // user defined const copy assignment + { + std::tuple t1{1}; + const std::tuple> t2{2}; + t2 = std::move(t1); + assert(std::get<0>(t2).v.val == 1); + } + + // correct overload should be selected + { + std::tuple t1{}; + const std::tuple> t2{}; + t2 = std::move(t1); + assert(std::get<0>(t2).v.constMoveAssign == 1); + } + + return true; +} + +int main() { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(__GNUG__) || defined(__clang__) + static_assert(test()); +#endif + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_copy.pass.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// constexpr const tuple& operator=(const tuple&) const; +// +// Constraints: (is_copy_assignable_v && ...) is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// test constraints + +#include +#include +#include + +#include "types.h" + +static_assert(!std::is_assignable_v&, const std::tuple&>); +static_assert(std::is_assignable_v&, const std::tuple&>); +static_assert(std::is_assignable_v&, const std::tuple&>); +static_assert(!std::is_assignable_v&, const std::tuple&>); +static_assert(std::is_assignable_v&, const std::tuple&>); +static_assert(!std::is_assignable_v&, const std::tuple&>); +static_assert(!std::is_assignable_v&, const std::tuple&>); +static_assert(!std::is_assignable_v&, const std::tuple&>); + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + double d1 = 3.0; + double d2 = 5.0; + const std::tuple t1{i1, d1}; + const std::tuple t2{i2, d2}; + t2 = t1; + assert(std::get<0>(t2) == 1); + assert(std::get<1>(t2) == 3.0); + } + + // user defined const copy assignment + { + const std::tuple t1{1}; + const std::tuple t2{2}; + t2 = t1; + assert(std::get<0>(t2).val == 1); + } + + // correct overload should be selected + { + std::tuple t1{}; + const std::tuple t2{}; + t2 = t1; + assert(std::get<0>(t2).constCopyAssign == 1); + assert(std::get<1>(t2).constCopyAssign == 1); + } + + return true; +} + +int main() { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(__GNUG__) || defined(__clang__) + static_assert(test()); +#endif + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_move.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// constexpr const tuple& operator=(tuple&&) const; +// +// Constraints: (is_assignable_v && ...) is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// test constraints + +#include +#include +#include + +#include "types.h" + +static_assert(!std::is_assignable_v&, std::tuple&&>); +static_assert(std::is_assignable_v&, std::tuple&&>); +static_assert(std::is_assignable_v&, std::tuple&&>); +static_assert(!std::is_assignable_v&, std::tuple&&>); + +// this is fallback to tuple's const copy assignment +static_assert(std::is_assignable_v&, std::tuple&&>); + +static_assert(!std::is_assignable_v&, std::tuple&&>); +static_assert(std::is_assignable_v&, std::tuple&&>); +static_assert(!std::is_assignable_v&, std::tuple&&>); + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + double d1 = 3.0; + double d2 = 5.0; + std::tuple t1{i1, d1}; + const std::tuple t2{i2, d2}; + t2 = std::move(t1); + assert(std::get<0>(t2) == 1); + assert(std::get<1>(t2) == 3.0); + } + + // user defined const move assignment + { + std::tuple t1{1}; + const std::tuple t2{2}; + t2 = std::move(t1); + assert(std::get<0>(t2).val == 1); + } + + // correct overload should be selected + { + std::tuple t1{}; + const std::tuple t2{}; + t2 = std::move(t1); + assert(std::get<0>(t2).constMoveAssign == 1); + assert(std::get<1>(t2).constCopyAssign == 1); + } + + return true; +} + +int main() { + test(); +// gcc cannot have mutable member in constant expression +#if !defined(__GNUG__) || defined(__clang__) + static_assert(test()); +#endif + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair_copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair_copy.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// constexpr const tuple& operator=(const pair& u) const; +// +// - sizeof...(Types) is 2, +// - is_assignable_v is true, and +// - is_assignable_v is true + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include + +#include "types.h" + +// test constraints + +// sizeof...(Types) != 2, +static_assert(std::is_assignable_v&, const std::pair&>); +static_assert(!std::is_assignable_v&, const std::pair&>); +static_assert(!std::is_assignable_v&, const std::pair&>); + +static_assert(std::is_assignable_v, ConstCopyAssign>&, + const std::pair&>); + +// is_assignable_v is false +static_assert(!std::is_assignable_v, ConstCopyAssign>&, + const std::pair&>); + +// - is_assignable_v is false +static_assert(!std::is_assignable_v, AssignableFrom>&, + const std::tuple&>); + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + long j1 = 3; + long j2 = 4; + const std::pair t1{i1, i2}; + const std::tuple t2{j1, j2}; + t2 = t1; + assert(std::get<0>(t2) == 1); + assert(std::get<1>(t2) == 2); + } + + // user defined const copy assignment + { + const std::pair t1{1, 2}; + const std::tuple, ConstCopyAssign> t2{3, 4}; + t2 = t1; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2).val == 2); + } + + // correct overload should be selected + { + std::pair t1{}; + const std::tuple, AssignableFrom> t2{}; + t2 = t1; + assert(std::get<0>(t2).v.constCopyAssign == 1); + assert(std::get<1>(t2).v.constCopyAssign == 1); + } + + return true; +} + +int main() { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(__GNUG__) || defined(__clang__) + static_assert(test()); +#endif + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/const_pair_move.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// constexpr const tuple& operator=(pair&& u) const; +// +// - sizeof...(Types) is 2, +// - is_assignable_v is true, and +// - is_assignable_v is true + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include +#include + +#include "types.h" + +// test constraints + +// sizeof...(Types) != 2, +static_assert(std::is_assignable_v&, std::pair&&>); +static_assert(!std::is_assignable_v&, std::pair&&>); +static_assert(!std::is_assignable_v&, std::pair&&>); + +static_assert(std::is_assignable_v, ConstMoveAssign>&, + std::pair&&>); + +// is_assignable_v is false +static_assert(!std::is_assignable_v, ConstMoveAssign>&, + std::pair&&>); + +// - is_assignable_v is false +static_assert(!std::is_assignable_v, AssignableFrom>&, + std::tuple&&>); + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + long j1 = 3; + long j2 = 4; + std::pair t1{i1, i2}; + const std::tuple t2{j1, j2}; + t2 = std::move(t1); + assert(std::get<0>(t2) == 1); + assert(std::get<1>(t2) == 2); + } + + // user defined const copy assignment + { + std::pair t1{1, 2}; + const std::tuple, ConstMoveAssign> t2{3, 4}; + t2 = std::move(t1); + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2).val == 2); + } + + // correct overload should be selected + { + std::pair t1{}; + const std::tuple, AssignableFrom> t2{}; + t2 = std::move(t1); + assert(std::get<0>(t2).v.constMoveAssign == 1); + assert(std::get<1>(t2).v.constMoveAssign == 1); + } + + return true; +} + +int main() { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(__GNUG__) || defined(__clang__) + static_assert(test()); +#endif + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/types.h b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/types.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/types.h @@ -0,0 +1,131 @@ +#ifndef __TEST_TUPLE_ASSIGN_TYPES_H +#define __TEST_TUPLE_ASSIGN_TYPES_H + +#include "test_allocator.h" +#include + +struct CopyAssign { + int val; + + constexpr CopyAssign() = default; + constexpr CopyAssign(int v) : val(v) {} + + constexpr CopyAssign& operator=(const CopyAssign&) = default; + + constexpr const CopyAssign& operator=(const CopyAssign&) const = delete; + constexpr CopyAssign& operator=(CopyAssign&&) = delete; + constexpr const CopyAssign& operator=(CopyAssign&&) const = delete; +}; + +struct ConstCopyAssign { + mutable int val; + + constexpr ConstCopyAssign() = default; + constexpr ConstCopyAssign(int v) : val(v) {} + + constexpr const ConstCopyAssign& operator=(const ConstCopyAssign& other) const { + val = other.val; + return *this; + } + + constexpr ConstCopyAssign& operator=(const ConstCopyAssign&) = delete; + constexpr ConstCopyAssign& operator=(ConstCopyAssign&&) = delete; + constexpr const ConstCopyAssign& operator=(ConstCopyAssign&&) const = delete; +}; + +struct MoveAssign { + int val; + + constexpr MoveAssign() = default; + constexpr MoveAssign(int v) : val(v) {} + + constexpr MoveAssign& operator=(MoveAssign&&) = default; + + constexpr MoveAssign& operator=(const MoveAssign&) = delete; + constexpr const MoveAssign& operator=(const MoveAssign&) const = delete; + constexpr const MoveAssign& operator=(MoveAssign&&) const = delete; +}; + +struct ConstMoveAssign { + mutable int val; + + constexpr ConstMoveAssign() = default; + constexpr ConstMoveAssign(int v) : val(v) {} + + constexpr const ConstMoveAssign& operator=(ConstMoveAssign&& other) const { + val = other.val; + return *this; + } + + constexpr ConstMoveAssign& operator=(const ConstMoveAssign&) = delete; + constexpr const ConstMoveAssign& operator=(const ConstMoveAssign&) const = delete; + constexpr ConstMoveAssign& operator=(ConstMoveAssign&&) = delete; +}; + +template +struct AssignableFrom { + T v; + + constexpr AssignableFrom() = default; + + template + constexpr AssignableFrom(U&& u) + requires std::is_constructible_v + : v(std::forward(u)) {} + + constexpr AssignableFrom& operator=(const T& t) + requires std::is_copy_assignable_v + { + v = t; + return *this; + } + + constexpr AssignableFrom& operator=(T&& t) + requires std::is_move_assignable_v + { + v = std::move(t); + return *this; + } + + constexpr const AssignableFrom& operator=(const T& t) const + requires std::is_assignable_v + { + v = t; + return *this; + } + + constexpr const AssignableFrom& operator=(T&& t) const + requires std::is_assignable_v + { + v = std::move(t); + return *this; + } +}; + +struct TracedAssignment { + int copyAssign = 0; + mutable int constCopyAssign = 0; + int moveAssign = 0; + mutable int constMoveAssign = 0; + + constexpr TracedAssignment() = default; + + constexpr TracedAssignment& operator=(const TracedAssignment&) { + copyAssign++; + return *this; + } + constexpr const TracedAssignment& operator=(const TracedAssignment&) const { + constCopyAssign++; + return *this; + } + constexpr TracedAssignment& operator=(TracedAssignment&&) { + moveAssign++; + return *this; + } + constexpr const TracedAssignment& operator=(TracedAssignment&&) const { + constMoveAssign++; + return *this; + } +}; + +#endif \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_move_pair.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_move_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_move_pair.pass.cpp @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) +// tuple::tuple(allocator_arg_t, const Alloc& a, const pair&& u); + +// Constraints: +// - sizeof...(Types) is 2 and +// - is_constructible_v(FWD(u)))> is true and +// - is_constructible_v(FWD(u)))> is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "convert_types.h" +#include "test_allocator.h" + +// test constraints +// sizeof...(Types) == 2 +static_assert(std::is_constructible_v, std::allocator_arg_t, test_allocator, + const std::pair&&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, test_allocator, + const std::pair&&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, test_allocator, + const std::pair&&>); + +// test constraints +// is_constructible_v(FWD(u)))> is true and +// is_constructible_v(FWD(u)))> is true. +static_assert(std::is_constructible_v, std::allocator_arg_t, test_allocator, + const std::pair&&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + test_allocator, const std::pair&&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + test_allocator, const std::pair&&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + test_allocator, const std::pair&&>); + +// test: The expression inside explicit is equivalent to: +// !is_convertible_v(FWD(u))), T0> || +// !is_convertible_v(FWD(u))), T1> +static_assert( + ImplicitlyConstructible< std::tuple, ConvertibleFrom>, std::allocator_arg_t, + test_allocator, const std::pair&&>); + +static_assert( + !ImplicitlyConstructible, ExplicitConstructibleFrom>, + std::allocator_arg_t, test_allocator, const std::pair&&>); + +static_assert( + !ImplicitlyConstructible, ConvertibleFrom>, + std::allocator_arg_t, test_allocator, const std::pair&&>); + +constexpr bool test() { + // test implicit conversions. + { + const std::pair p{1, 2}; + std::tuple, ConvertibleFrom> t = {std::allocator_arg, test_allocator{}, + std::move(p)}; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + assert(std::get<0>(t).alloc_constructed); + assert(std::get<1>(t).alloc_constructed); + } + + // test explicit conversions. + { + const std::pair p{1, 2}; + std::tuple, ExplicitConstructibleFrom> t{ + std::allocator_arg, test_allocator{}, std::move(p)}; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + assert(std::get<0>(t).alloc_constructed); + assert(std::get<1>(t).alloc_constructed); + } + + // non const overload should be called + { + const std::pair p; + std::tuple, TracedCopyMove> t = {std::allocator_arg, test_allocator{}, + std::move(p)}; + assert(constMoveCtrCalled(std::get<0>(t).v)); + assert(constMoveCtrCalled(std::get<1>(t))); + assert(std::get<0>(t).alloc_constructed); + assert(std::get<1>(t).alloc_constructed); + } + + return true; +} + +int main() { + test(); + static_assert(test()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_const_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_const_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_const_move.pass.cpp @@ -0,0 +1,155 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) +// tuple::tuple(allocator_arg_t, const Alloc& a, +// const tuple&&); +// +// Constraints: +// sizeof...(Types) equals sizeof...(UTypes) && +// (is_constructible_v(FWD(u)))> && ...) is true && +// ( +// sizeof...(Types) is not 1 || +// ( +// !is_convertible_v && +// !is_constructible_v && +// !is_same_v +// ) +// ) + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "convert_types.h" +#include "test_allocator.h" + +// test: The expression inside explicit is equivalent to: +// !(is_convertible_v(FWD(u))), Types> && ...) +static_assert(ImplicitlyConstructible< std::tuple>, std::allocator_arg_t, + const test_allocator&, const std::tuple&&>); + +static_assert( + ImplicitlyConstructible< std::tuple, ConvertibleFrom>, std::allocator_arg_t, + const test_allocator&, const std::tuple&&>); + +static_assert(!ImplicitlyConstructible>, std::allocator_arg_t, + const test_allocator&, const std::tuple&&>); + +static_assert(!ImplicitlyConstructible, ConvertibleFrom>, + std::allocator_arg_t, const test_allocator&, + const std::tuple&&>); + +constexpr bool test() { + // test implicit conversions. + // sizeof...(Types) == 1 + { + const std::tuple t1{1}; + std::tuple> t2 = {std::allocator_arg, test_allocator{}, std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<0>(t2).alloc_constructed); + } + + // test implicit conversions. + // sizeof...(Types) > 1 + { + const std::tuple t1{1, 2}; + std::tuple, int> t2 = {std::allocator_arg_t{}, test_allocator{}, std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + assert(std::get<0>(t2).alloc_constructed); + } + + // test explicit conversions. + // sizeof...(Types) == 1 + { + const std::tuple t1{1}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<0>(t2).alloc_constructed); + } + + // test explicit conversions. + // sizeof...(Types) > 1 + { + const std::tuple t1{1, 2}; + std::tuple, int> t2{std::allocator_arg_t{}, test_allocator{}, + std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + assert(std::get<0>(t2).alloc_constructed); + } + + // test constraints + + // sizeof...(Types) != sizeof...(UTypes) + static_assert(!std::is_constructible_v, std::allocator_arg_t, const test_allocator&, + const std::tuple&&>); + static_assert(!std::is_constructible_v, std::allocator_arg_t, const test_allocator&, + const std::tuple&&>); + + // !(is_constructible_v(FWD(u)))> && ...) + static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + const test_allocator&, const std::tuple&&>); + + // sizeof...(Types) == 1 && other branch of "||" satisfied + { + const std::tuple t1{}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, std::move(t1)}; + assert(constMoveCtrCalled(std::get<0>(t2).v)); + assert(std::get<0>(t2).alloc_constructed); + } + + // sizeof...(Types) == 1 && is_same_v + { + const std::tuple t1{}; + std::tuple t2{std::allocator_arg_t{}, test_allocator{}, std::move(t1)}; + assert(!constMoveCtrCalled(std::get<0>(t2))); + assert(std::get<0>(t2).alloc_constructed); + } + + // sizeof...(Types) != 1 + { + const std::tuple t1{}; + std::tuple t2{std::allocator_arg_t{}, test_allocator{}, std::move(t1)}; + assert(constMoveCtrCalled(std::get<0>(std::move(t2)))); + assert(std::get<0>(t2).alloc_constructed); + } + + // These two test points cause gcc to ICE +#if !defined(__GNUG__) || defined(__clang__) + // sizeof...(Types) == 1 && is_convertible_v + { + const std::tuple t1{}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, std::move(t1)}; + assert(!constMoveCtrCalled(std::get<0>(t2).v)); + assert(std::get<0>(t2).alloc_constructed); + } + + // sizeof...(Types) == 1 && is_constructible_v + { + const std::tuple t1{}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, + std::move(t1)}; + assert(!constMoveCtrCalled(std::get<0>(t2).v)); + assert(std::get<0>(t2).alloc_constructed); + } +#endif + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp @@ -11,6 +11,7 @@ // template class tuple; // template +// constexpr // since c++20 // tuple(allocator_arg_t, const Alloc& a, const tuple&); // UNSUPPORTED: c++03 @@ -21,6 +22,7 @@ #include "test_macros.h" #include "allocators.h" +#include "test_allocator.h" #include "../alloc_first.h" #include "../alloc_last.h" @@ -34,6 +36,15 @@ Implicit(int x) : value(x) {} }; +#if _LIBCPP_STD_VER > 17 +constexpr bool alloc_copy_constructor_is_constexpr() { + const std::tuple t1 = 1; + std::tuple t2 = {std::allocator_arg, test_allocator{}, t1}; + assert(std::get<0>(t2) == 1); + return true; +} +#endif + int main(int, char**) { { @@ -95,5 +106,8 @@ std::tuple t0(derived, A1(), from); } +#if _LIBCPP_STD_VER > 17 + static_assert(alloc_copy_constructor_is_constexpr()); +#endif return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp @@ -22,6 +22,7 @@ #include "test_macros.h" #include "allocators.h" +#include "test_allocator.h" #include "../alloc_first.h" #include "../alloc_last.h" @@ -50,6 +51,15 @@ Implicit(int x) : value(x) {} }; +#if _LIBCPP_STD_VER > 17 +constexpr bool alloc_move_constructor_is_constexpr() { + std::tuple t1 = 1; + std::tuple t2 = {std::allocator_arg, test_allocator{}, std::move(t1)}; + assert(std::get<0>(t2) == 1); + return true; +} +#endif + int main(int, char**) { { @@ -109,5 +119,9 @@ std::tuple t0(derived, A1(), std::move(from)); } +#if _LIBCPP_STD_VER > 17 + static_assert(alloc_move_constructor_is_constexpr()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_non_const_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_non_const_copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_non_const_copy.pass.cpp @@ -0,0 +1,153 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) +// tuple::tuple(allocator_arg_t, const Alloc& a, +// tuple&); +// +// Constraints: +// sizeof...(Types) equals sizeof...(UTypes) && +// (is_constructible_v(FWD(u)))> && ...) is true && +// ( +// sizeof...(Types) is not 1 || +// ( +// !is_convertible_v && +// !is_constructible_v && +// !is_same_v +// ) +// ) + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "convert_types.h" +#include "test_allocator.h" + +// test: The expression inside explicit is equivalent to: +// !(is_convertible_v(FWD(u))), Types> && ...) +static_assert(ImplicitlyConstructible< std::tuple>, std::allocator_arg_t, + const test_allocator&, std::tuple&>); + +static_assert( + ImplicitlyConstructible< std::tuple, ConvertibleFrom>, + std::allocator_arg_t, const test_allocator&, std::tuple&>); + +static_assert(!ImplicitlyConstructible>, std::allocator_arg_t, + const test_allocator&, std::tuple&>); + +static_assert( + !ImplicitlyConstructible, ConvertibleFrom>, + std::allocator_arg_t, const test_allocator&, std::tuple&>); + +constexpr bool test() { + // test implicit conversions. + // sizeof...(Types) == 1 + { + std::tuple t1{1}; + std::tuple> t2 = {std::allocator_arg, test_allocator{}, t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<0>(t2).alloc_constructed); + } + + // test implicit conversions. + // sizeof...(Types) > 1 + { + std::tuple t1{1, 2}; + std::tuple, int> t2 = {std::allocator_arg_t{}, test_allocator{}, t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + assert(std::get<0>(t2).alloc_constructed); + } + + // test explicit conversions. + // sizeof...(Types) == 1 + { + std::tuple t1{1}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<0>(t2).alloc_constructed); + } + + // test explicit conversions. + // sizeof...(Types) > 1 + { + std::tuple t1{1, 2}; + std::tuple, int> t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + assert(std::get<0>(t2).alloc_constructed); + } + + // test constraints + + // sizeof...(Types) != sizeof...(UTypes) + static_assert(!std::is_constructible_v, std::allocator_arg_t, const test_allocator&, + std::tuple&>); + static_assert(!std::is_constructible_v, std::allocator_arg_t, const test_allocator&, + std::tuple&>); + + // !(is_constructible_v(FWD(u)))> && ...) + static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + const test_allocator&, std::tuple&>); + + // sizeof...(Types) == 1 && other branch of "||" satisfied + { + std::tuple t1{}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(nonConstCopyCtrCalled(std::get<0>(t2).v)); + assert(std::get<0>(t2).alloc_constructed); + } + + // sizeof...(Types) == 1 && is_same_v + { + std::tuple t1{}; + std::tuple t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(!nonConstCopyCtrCalled(std::get<0>(t2))); + assert(std::get<0>(t2).alloc_constructed); + } + + // sizeof...(Types) != 1 + { + std::tuple t1{}; + std::tuple t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(nonConstCopyCtrCalled(std::get<0>(t2))); + assert(std::get<0>(t2).alloc_constructed); + } + + // These two test points cause gcc to ICE +#if !defined(__GNUG__) || defined(__clang__) + // sizeof...(Types) == 1 && is_convertible_v + { + std::tuple t1{}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(!nonConstCopyCtrCalled(std::get<0>(t2).v)); + assert(std::get<0>(t2).alloc_constructed); + } + + // sizeof...(Types) == 1 && is_constructible_v + { + std::tuple t1{}; + std::tuple> t2{std::allocator_arg_t{}, test_allocator{}, t1}; + assert(!nonConstCopyCtrCalled(std::get<0>(t2).v)); + assert(std::get<0>(t2).alloc_constructed); + } +#endif + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_non_const_pair.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_non_const_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_non_const_pair.pass.cpp @@ -0,0 +1,111 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) +// tuple::tuple(allocator_arg_t, const Alloc& a, pair& +// u); + +// Constraints: +// - sizeof...(Types) is 2 and +// - is_constructible_v(FWD(u)))> is true and +// - is_constructible_v(FWD(u)))> is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "convert_types.h" +#include "test_allocator.h" + +// test constraints +// sizeof...(Types) == 2 +static_assert(std::is_constructible_v, std::allocator_arg_t, test_allocator, + std::pair&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, test_allocator, + std::pair&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, test_allocator, + std::pair&>); + +// test constraints +// is_constructible_v(FWD(u)))> is true and +// is_constructible_v(FWD(u)))> is true. +static_assert( + std::is_constructible_v, std::allocator_arg_t, test_allocator, std::pair&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + test_allocator, std::pair&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + test_allocator, std::pair&>); + +static_assert(!std::is_constructible_v< std::tuple, std::allocator_arg_t, + test_allocator, std::pair&>); + +// test: The expression inside explicit is equivalent to: +// !is_convertible_v(FWD(u))), T0> || +// !is_convertible_v(FWD(u))), T1> +static_assert(ImplicitlyConstructible, ConvertibleFrom>, + std::allocator_arg_t, test_allocator, std::pair&>); + +static_assert( + !ImplicitlyConstructible, ExplicitConstructibleFrom>, + std::allocator_arg_t, test_allocator, std::pair&>); + +static_assert( + !ImplicitlyConstructible, ConvertibleFrom>, + std::allocator_arg_t, test_allocator, std::pair&>); + +constexpr bool test() { + // test implicit conversions. + { + std::pair p{1, 2}; + std::tuple, ConvertibleFrom> t = {std::allocator_arg, test_allocator{}, p}; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + assert(std::get<0>(t).alloc_constructed); + assert(std::get<1>(t).alloc_constructed); + } + + // test explicit conversions. + { + std::pair p{1, 2}; + std::tuple, ExplicitConstructibleFrom> t{std::allocator_arg, + test_allocator{}, p}; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + assert(std::get<0>(t).alloc_constructed); + assert(std::get<1>(t).alloc_constructed); + } + + // non const overload should be called + { + std::pair p; + std::tuple, TracedCopyMove> t = {std::allocator_arg, test_allocator{}, p}; + assert(nonConstCopyCtrCalled(std::get<0>(t).v)); + assert(nonConstCopyCtrCalled(std::get<1>(t))); + assert(std::get<0>(t).alloc_constructed); + assert(std::get<1>(t).alloc_constructed); + } + + return true; +} + +int main() { + test(); + static_assert(test()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_move_pair.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_move_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_move_pair.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) tuple::tuple(const pair&& u); + +// Constraints: +// - sizeof...(Types) is 2 and +// - is_constructible_v(FWD(u)))> is true and +// - is_constructible_v(FWD(u)))> is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "convert_types.h" + +// test constraints +// sizeof...(Types) == 2 +static_assert(std::is_constructible_v, const std::pair&&>); + +static_assert(!std::is_constructible_v, const std::pair&&>); + +static_assert(!std::is_constructible_v, const std::pair&&>); + +// test constraints +// is_constructible_v(FWD(u)))> is true and +// is_constructible_v(FWD(u)))> is true. +static_assert(std::is_constructible_v, const std::pair&&>); + +static_assert(!std::is_constructible_v, const std::pair&&>); + +static_assert(!std::is_constructible_v, const std::pair&&>); + +static_assert( + !std::is_constructible_v< std::tuple, const std::pair&&>); + +// test: The expression inside explicit is equivalent to: +// !is_convertible_v(FWD(u))), T0> || +// !is_convertible_v(FWD(u))), T1> +static_assert(std::is_convertible_v&&, + std::tuple, ConvertibleFrom>>); + +static_assert(!std::is_convertible_v&&, + std::tuple, ConvertibleFrom>>); + +static_assert(!std::is_convertible_v&&, + std::tuple, ExplicitConstructibleFrom>>); + +constexpr bool test() { + // test implicit conversions. + { + const std::pair p{1, 2}; + std::tuple, ConvertibleFrom> t = std::move(p); + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + } + + // test explicit conversions. + { + const std::pair p{1, 2}; + std::tuple, ExplicitConstructibleFrom> t{std::move(p)}; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + } + + // non const overload should be called + { + const std::pair p; + std::tuple, TracedCopyMove> t = std::move(p); + assert(constMoveCtrCalled(std::get<0>(t).v)); + assert(constMoveCtrCalled(std::get<1>(t))); + } + + return true; +} + +int main() { + test(); + static_assert(test()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) tuple::tuple(const +// tuple&&); +// +// Constraints: +// sizeof...(Types) equals sizeof...(UTypes) && +// (is_constructible_v(FWD(u)))> && ...) is true && +// ( +// sizeof...(Types) is not 1 || +// ( +// !is_convertible_v && +// !is_constructible_v && +// !is_same_v +// ) +// ) + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "convert_types.h" + +// test: The expression inside explicit is equivalent to: +// !(is_convertible_v(FWD(u))), Types> && ...) +static_assert(std::is_convertible_v&&, std::tuple>>); + +static_assert(std::is_convertible_v&&, + std::tuple, ConvertibleFrom>>); + +static_assert( + !std::is_convertible_v&&, std::tuple>>); + +static_assert(!std::is_convertible_v&&, + std::tuple, ExplicitConstructibleFrom>>); + +constexpr bool test() { + // test implicit conversions. + // sizeof...(Types) == 1 + { + const std::tuple t1{1}; + std::tuple> t2 = std::move(t1); + assert(std::get<0>(t2).v.val == 1); + } + + // test implicit conversions. + // sizeof...(Types) > 1 + { + const std::tuple t1{1, 2}; + std::tuple, int> t2 = std::move(t1); + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + } + + // test explicit conversions. + // sizeof...(Types) == 1 + { + const std::tuple t1{1}; + std::tuple> t2{std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + } + + // test explicit conversions. + // sizeof...(Types) > 1 + { + const std::tuple t1{1, 2}; + std::tuple, int> t2{std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + } + + // test constraints + + // sizeof...(Types) != sizeof...(UTypes) + static_assert(!std::is_constructible_v, const std::tuple&&>); + static_assert(!std::is_constructible_v, const std::tuple&&>); + + // !(is_constructible_v(FWD(u)))> && ...) + static_assert(!std::is_constructible_v, const std::tuple&&>); + + // sizeof...(Types) == 1 && other branch of "||" satisfied + { + const std::tuple t1{}; + std::tuple> t2{std::move(t1)}; + assert(constMoveCtrCalled(std::get<0>(t2).v)); + } + + // sizeof...(Types) == 1 && is_same_v + { + const std::tuple t1{}; + std::tuple t2{t1}; + assert(!constMoveCtrCalled(std::get<0>(t2))); + } + + // sizeof...(Types) != 1 + { + const std::tuple t1{}; + std::tuple t2{std::move(t1)}; + assert(constMoveCtrCalled(std::get<0>(t2))); + } + + // These two test points cause gcc to ICE +#if !defined(__GNUG__) || defined(__clang__) + // sizeof...(Types) == 1 && is_convertible_v + { + const std::tuple t1{}; + std::tuple> t2{std::move(t1)}; + assert(!constMoveCtrCalled(std::get<0>(t2).v)); + } + + // sizeof...(Types) == 1 && is_constructible_v + { + const std::tuple t1{}; + std::tuple> t2{std::move(t1)}; + assert(!constMoveCtrCalled(std::get<0>(t2).v)); + } +#endif + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_non_const_copy.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_non_const_copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_non_const_copy.pass.cpp @@ -0,0 +1,135 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) tuple::tuple(tuple&); +// +// Constraints: +// sizeof...(Types) equals sizeof...(UTypes) && +// (is_constructible_v(FWD(u)))> && ...) is true && +// ( +// sizeof...(Types) is not 1 || +// ( +// !is_convertible_v && +// !is_constructible_v && +// !is_same_v +// ) +// ) + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "convert_types.h" + +// test: The expression inside explicit is equivalent to: +// !(is_convertible_v(FWD(u))), Types> && ...) +static_assert(std::is_convertible_v&, std::tuple>>); + +static_assert(std::is_convertible_v&, + std::tuple, ConvertibleFrom>>); + +static_assert(!std::is_convertible_v&, std::tuple>>); + +static_assert(!std::is_convertible_v&, + std::tuple, ExplicitConstructibleFrom>>); + +constexpr bool test() { + // test implicit conversions. + // sizeof...(Types) == 1 + { + std::tuple t1{1}; + std::tuple> t2 = t1; + assert(std::get<0>(t2).v.val == 1); + } + + // test implicit conversions. + // sizeof...(Types) > 1 + { + std::tuple t1{1, 2}; + std::tuple, int> t2 = t1; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + } + + // test explicit conversions. + // sizeof...(Types) == 1 + { + std::tuple t1{1}; + std::tuple> t2{t1}; + assert(std::get<0>(t2).v.val == 1); + } + + // test explicit conversions. + // sizeof...(Types) > 1 + { + std::tuple t1{1, 2}; + std::tuple, int> t2{t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); + } + + // test constraints + + // sizeof...(Types) != sizeof...(UTypes) + static_assert(!std::is_constructible_v, std::tuple&>); + static_assert(!std::is_constructible_v, std::tuple&>); + static_assert(!std::is_constructible_v, std::tuple&>); + + // !(is_constructible_v(FWD(u)))> && ...) + static_assert(!std::is_constructible_v, std::tuple&>); + + // sizeof...(Types) == 1 && other branch of "||" satisfied + { + std::tuple t1{}; + std::tuple> t2{t1}; + assert(nonConstCopyCtrCalled(std::get<0>(t2).v)); + } + + // sizeof...(Types) == 1 && is_same_v + { + std::tuple t1{}; + std::tuple t2{t1}; + assert(!nonConstCopyCtrCalled(std::get<0>(t2))); + } + + // sizeof...(Types) != 1 + { + std::tuple t1{}; + std::tuple t2{t1}; + assert(nonConstCopyCtrCalled(std::get<0>(t2))); + } + + // These two test points cause gcc to ICE +#if !defined(__GNUG__) || defined(__clang__) + // sizeof...(Types) == 1 && is_convertible_v + { + std::tuple t1{}; + std::tuple> t2{t1}; + assert(!nonConstCopyCtrCalled(std::get<0>(t2).v)); + } + + // sizeof...(Types) == 1 && is_constructible_v + { + std::tuple t1{}; + std::tuple> t2{t1}; + assert(!nonConstCopyCtrCalled(std::get<0>(t2).v)); + } +#endif + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_types.h b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_types.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_types.h @@ -0,0 +1,211 @@ +#ifndef __TEST_TUPLE_CNSTR_TYPES_H +#define __TEST_TUPLE_CNSTR_TYPES_H + +#include "test_allocator.h" +#include + +struct MutableCopy { + int val; + bool alloc_constructed{false}; + + constexpr MutableCopy() = default; + constexpr MutableCopy(int _val) : val(_val) {} + constexpr MutableCopy(MutableCopy&) = default; + constexpr MutableCopy(const MutableCopy&) = delete; + + constexpr MutableCopy(std::allocator_arg_t, const test_allocator&, MutableCopy& o) + : val(o.val), alloc_constructed(true) {} +}; + +template <> +struct std::uses_allocator> : std::true_type {}; + +struct ConstCopy { + int val; + bool alloc_constructed{false}; + + constexpr ConstCopy() = default; + constexpr ConstCopy(int _val) : val(_val) {} + constexpr ConstCopy(const ConstCopy&) = default; + constexpr ConstCopy(ConstCopy&) = delete; + + constexpr ConstCopy(std::allocator_arg_t, const test_allocator&, const ConstCopy& o) + : val(o.val), alloc_constructed(true) {} +}; + +template <> +struct std::uses_allocator> : std::true_type {}; + +struct MutableMove { + int val; + bool alloc_constructed{false}; + + constexpr MutableMove() = default; + constexpr MutableMove(int _val) : val(_val) {} + constexpr MutableMove(MutableMove&&) = default; + constexpr MutableMove(const MutableMove&&) = delete; + + constexpr MutableMove(std::allocator_arg_t, const test_allocator&, MutableMove&& o) + : val(o.val), alloc_constructed(true) {} +}; + +template <> +struct std::uses_allocator> : std::true_type {}; + +struct ConstMove { + int val; + bool alloc_constructed{false}; + + constexpr ConstMove() = default; + constexpr ConstMove(int _val) : val(_val) {} + constexpr ConstMove(const ConstMove&& o) : val(o.val) {} + constexpr ConstMove(ConstMove&&) = delete; + + constexpr ConstMove(std::allocator_arg_t, const test_allocator&, const ConstMove&& o) + : val(o.val), alloc_constructed(true) {} +}; + +template <> +struct std::uses_allocator> : std::true_type {}; + +template +struct ConvertibleFrom { + T v; + bool alloc_constructed{false}; + + constexpr ConvertibleFrom() = default; + constexpr ConvertibleFrom(T& _v) + requires(std::is_constructible_v) + : v(_v) {} + constexpr ConvertibleFrom(const T& _v) + requires(std::is_constructible_v && !std::is_const_v) + : v(_v) {} + constexpr ConvertibleFrom(T&& _v) + requires(std::is_constructible_v) + : v(std::move(_v)) {} + constexpr ConvertibleFrom(const T&& _v) + requires(std::is_constructible_v && !std::is_const_v) + : v(std::move(_v)) {} + + template + requires std::is_constructible_v + constexpr ConvertibleFrom(std::allocator_arg_t, const test_allocator&, U&& _u) + : ConvertibleFrom{std::forward(_u)} { + alloc_constructed = true; + } +}; + +template +struct std::uses_allocator, test_allocator> : std::true_type {}; + +template +struct ExplicitConstructibleFrom { + T v; + bool alloc_constructed{false}; + + constexpr explicit ExplicitConstructibleFrom() = default; + constexpr explicit ExplicitConstructibleFrom(T& _v) + requires(std::is_constructible_v) + : v(_v) {} + constexpr explicit ExplicitConstructibleFrom(const T& _v) + requires(std::is_constructible_v && !std::is_const_v) + : v(_v) {} + constexpr explicit ExplicitConstructibleFrom(T&& _v) + requires(std::is_constructible_v) + : v(std::move(_v)) {} + constexpr explicit ExplicitConstructibleFrom(const T&& _v) + requires(std::is_constructible_v && !std::is_const_v) + : v(std::move(_v)) {} + + template + requires std::is_constructible_v + constexpr ExplicitConstructibleFrom(std::allocator_arg_t, const test_allocator&, U&& _u) + : ExplicitConstructibleFrom{std::forward(_u)} { + alloc_constructed = true; + } +}; + +template +struct std::uses_allocator, test_allocator> : std::true_type {}; + +struct TracedCopyMove { + int nonConstCopy = 0; + int constCopy = 0; + int nonConstMove = 0; + int constMove = 0; + bool alloc_constructed = false; + + constexpr TracedCopyMove() = default; + constexpr TracedCopyMove(const TracedCopyMove& other) + : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy + 1), nonConstMove(other.nonConstMove), + constMove(other.constMove) {} + constexpr TracedCopyMove(TracedCopyMove& other) + : nonConstCopy(other.nonConstCopy + 1), constCopy(other.constCopy), nonConstMove(other.nonConstMove), + constMove(other.constMove) {} + + constexpr TracedCopyMove(TracedCopyMove&& other) + : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove + 1), + constMove(other.constMove) {} + + constexpr TracedCopyMove(const TracedCopyMove&& other) + : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove), + constMove(other.constMove + 1) {} + + template + requires std::is_constructible_v + constexpr TracedCopyMove(std::allocator_arg_t, const test_allocator&, U&& _u) + : TracedCopyMove{std::forward(_u)} { + alloc_constructed = true; + } +}; + +template <> +struct std::uses_allocator> : std::true_type {}; + +// If the constructor tuple(tuple&) is not available, +// the fallback call to `tuple(const tuple&) = default;` or any other +// constructor that takes const ref would increment the constCopy. +inline constexpr bool nonConstCopyCtrCalled(const TracedCopyMove& obj) { + return obj.nonConstCopy == 1 && obj.constCopy == 0 && obj.constMove == 0 && obj.nonConstMove == 0; +} + +// If the constructor tuple(const tuple&&) is not available, +// the fallback call to `tuple(const tuple&) = default;` or any other +// constructor that takes const ref would increment the constCopy. +inline constexpr bool constMoveCtrCalled(const TracedCopyMove& obj) { + return obj.nonConstMove == 0 && obj.constMove == 1 && obj.constCopy == 0 && obj.nonConstCopy == 0; +} + +struct NoConstructorFromInt {}; + +struct CvtFromTupleRef : TracedCopyMove { + constexpr CvtFromTupleRef() = default; + constexpr CvtFromTupleRef(std::tuple& other) + : TracedCopyMove(static_cast(std::get<0>(other))) {} +}; + +struct ExplicitCtrFromTupleRef : TracedCopyMove { + constexpr explicit ExplicitCtrFromTupleRef() = default; + constexpr explicit ExplicitCtrFromTupleRef(std::tuple& other) + : TracedCopyMove(static_cast(std::get<0>(other))) {} +}; + +struct CvtFromConstTupleRefRef : TracedCopyMove { + constexpr CvtFromConstTupleRefRef() = default; + constexpr CvtFromConstTupleRefRef(const std::tuple&& other) + : TracedCopyMove(static_cast(std::get<0>(other))) {} +}; + +struct ExplicitCtrFromConstTupleRefRef : TracedCopyMove { + constexpr explicit ExplicitCtrFromConstTupleRefRef() = default; + constexpr explicit ExplicitCtrFromConstTupleRefRef(std::tuple&& other) + : TracedCopyMove(static_cast(std::get<0>(other))) {} +}; + +template +void conversion_test(T); + +template +concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; + +#endif \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/non_const_pair.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/non_const_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/non_const_pair.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// template +// constexpr explicit(see below) tuple::tuple(pair& u); + +// Constraints: +// - sizeof...(Types) is 2 and +// - is_constructible_v(FWD(u)))> is true and +// - is_constructible_v(FWD(u)))> is true. + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +#include "convert_types.h" + +// test constraints +// sizeof...(Types) == 2 +static_assert(std::is_constructible_v, std::pair&>); + +static_assert(!std::is_constructible_v, std::pair&>); + +static_assert(!std::is_constructible_v, std::pair&>); + +// test constraints +// is_constructible_v(FWD(u)))> is true and +// is_constructible_v(FWD(u)))> is true. +static_assert(std::is_constructible_v, std::pair&>); + +static_assert(!std::is_constructible_v, std::pair&>); + +static_assert(!std::is_constructible_v, std::pair&>); + +static_assert(!std::is_constructible_v< std::tuple, std::pair&>); + +// test: The expression inside explicit is equivalent to: +// !is_convertible_v(FWD(u))), T0> || +// !is_convertible_v(FWD(u))), T1> +static_assert(std::is_convertible_v&, + std::tuple, ConvertibleFrom>>); + +static_assert(!std::is_convertible_v&, + std::tuple, ConvertibleFrom>>); + +static_assert(!std::is_convertible_v&, + std::tuple, ExplicitConstructibleFrom>>); + +constexpr bool test() { + // test implicit conversions. + { + std::pair p{1, 2}; + std::tuple, ConvertibleFrom> t = p; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + } + + // test explicit conversions. + { + std::pair p{1, 2}; + std::tuple, ExplicitConstructibleFrom> t{p}; + assert(std::get<0>(t).v.val == 1); + assert(std::get<1>(t).v == 2); + } + + // non const overload should be called + { + std::pair p; + std::tuple, TracedCopyMove> t = p; + assert(nonConstCopyCtrCalled(std::get<0>(t).v)); + assert(nonConstCopyCtrCalled(std::get<1>(t))); + } + + return true; +} + +int main() { + test(); + static_assert(test()); + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.special/non_member_swap_const.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.special/non_member_swap_const.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.special/non_member_swap_const.pass.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// void swap(const tuple& x, const tuple& y); + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +struct S { + int* calls; + friend constexpr void swap(S& a, S& b) { + *a.calls += 1; + *b.calls += 1; + } +}; +struct CS { + int* calls; + friend constexpr void swap(const CS& a, const CS& b) { + *a.calls += 1; + *b.calls += 1; + } +}; + +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(!std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(std::is_swappable_v>); +static_assert(!std::is_swappable_v>); +static_assert(std::is_swappable_v>); + +constexpr bool test() { + int cs_calls = 0; + int s_calls = 0; + S s1{&s_calls}; + S s2{&s_calls}; + const std::tuple t1 = {CS{&cs_calls}, s1}; + const std::tuple t2 = {CS{&cs_calls}, s2}; + swap(t1, t2); + assert(cs_calls == 2); + assert(s_calls == 2); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap.pass.cpp @@ -65,7 +65,7 @@ int main(int, char**) { test(); -#if TEST_STD_VER >= 20 +#if TEST_STD_VER > 17 static_assert(test()); #endif diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap_const.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap_const.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.swap/member_swap_const.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// void swap(const tuple& rhs); + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: gcc + +#include +#include +#include + +#include "test_macros.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +class SwapThrower { + void swap(SwapThrower&) = delete; + void swap(const SwapThrower&) const = delete; +}; + +void swap(const SwapThrower&, const SwapThrower&) { throw 0.f; } + +static_assert(std::is_swappable_v); +static_assert(std::is_swappable_with_v); + +void test_noexcept() { + const std::tuple t1; + const std::tuple t2; + + try { + t1.swap(t2); + std::swap(t1, t2); + assert(false); + } catch (float) { + } + + try { + std::swap(std::as_const(t1), std::as_const(t2)); + assert(false); + } catch (float) { + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +struct ConstSwappable { + mutable int i; +}; + +constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); } + +constexpr bool test() { + { + typedef std::tuple T; + const T t0({0}); + T t1({1}); + t0.swap(t1); + assert(std::get<0>(t0).i == 1); + assert(std::get<0>(t1).i == 0); + } + { + typedef std::tuple T; + const T t0({0}, {1}); + const T t1({2}, {3}); + t0.swap(t1); + assert(std::get<0>(t0).i == 2); + assert(std::get<1>(t0).i == 3); + assert(std::get<0>(t1).i == 0); + assert(std::get<1>(t1).i == 1); + } + { + typedef std::tuple T; + const T t0({0}, {1}, {2}); + const T t1({3}, {4}, {5}); + t0.swap(t1); + assert(std::get<0>(t0).i == 3); + assert(std::get<1>(t0).i == 4); + assert(std::get<2>(t0).i == 5); + assert(std::get<0>(t1).i == 0); + assert(std::get<1>(t1).i == 1); + assert(std::get<2>(t1).i == 2); + } + return true; +} + +int main(int, char**) { +#ifndef TEST_HAS_NO_EXCEPTIONS + test_noexcept(); +#endif + test(); + static_assert(test()); + + return 0; +}