diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -220,6 +220,15 @@ swap(__x.get(), __y.get()); } +#if _LIBCPP_STD_VER > 20 +template +inline _LIBCPP_HIDE_FROM_ABI constexpr void +swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x, + const __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(is_nothrow_swappable_v) { + swap(__x.get(), __y.get()); +} +#endif // _LIBCPP_STD_VER > 20 + template class __tuple_leaf { @@ -304,10 +313,18 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 int swap(__tuple_leaf& __t) _NOEXCEPT_(__is_nothrow_swappable<__tuple_leaf>::value) { - _VSTD::swap(*this, __t); + std::swap(*this, __t); return 0; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + int swap(const __tuple_leaf& __rhs) const noexcept(is_nothrow_swappable_v) { + std::swap(*this, __rhs); + return 0; + } +#endif // _LIBCPP_STD_VER > 20 + _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_;} }; @@ -374,6 +391,13 @@ return 0; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const __tuple_leaf& __rhs) const noexcept(is_nothrow_swappable_v) { + std::swap(*this, __rhs); + } +#endif // _LIBCPP_STD_VER > 20 + _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);} }; @@ -464,6 +488,14 @@ { _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t))...); } + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const __tuple_impl& __rhs) const noexcept((is_nothrow_swappable_v && ...)) { + (static_cast&>(*this).swap(static_cast&>(__rhs)), + ...); + } +#endif // _LIBCPP_STD_VER > 20 }; template @@ -711,7 +743,7 @@ { } // tuple(const tuple&) constructors (including allocator_arg_t variants) - template + template struct _EnableCopyFromOtherTuple : _And< _Not, tuple<_Up...> > >, _Lazy<_Or, @@ -719,17 +751,34 @@ // _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&> >... + _Not>&, _Tp> >..., + _Not>&> >... > >, - is_constructible<_Tp, const _Up&>... - > { }; + is_constructible<_Tp, __maybe_const<_Const, _Up>&>... + > {}; + +#if _LIBCPP_STD_VER > 20 + template , + _EnableCopyFromOtherTuple>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<_Up&, _Tp> && ...)) + tuple(tuple<_Up...>& __t) : __base_(__t) {} + + template , + _EnableCopyFromOtherTuple>::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 template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCopyFromOtherTuple, is_convertible... // explicit check >::value , int> = 0> @@ -742,7 +791,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCopyFromOtherTuple, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -755,7 +804,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCopyFromOtherTuple, is_convertible... // explicit check >::value , int> = 0> @@ -767,7 +816,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCopyFromOtherTuple, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -792,6 +841,24 @@ is_constructible<_Tp, _Up>... > { }; +#if _LIBCPP_STD_VER > 20 + template , + _EnableMoveFromOtherTuple<_Up...>>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v && ...)) + tuple(const tuple<_Up...>&& __t) : __base_(std::move(__t)) {} + + template , + _EnableMoveFromOtherTuple<_Up...>>::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 + template , @@ -843,21 +910,25 @@ { } // tuple(const pair&) constructors (including allocator_arg_t variants) + template + struct _EnableCopyFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, _U1>, + is_constructible<_SecondType<_DependentTp...>, _U2> + > {}; + template struct _EnableImplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, is_convertible >, // explicit check - is_convertible > - > { }; + is_convertible >, + _EnableCopyFromPair + > {}; template struct _EnableExplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - _Not > >, // explicit check - _Not > > - > { }; + _Or<_Not > >, // explicit check + _Not > > >, + _EnableCopyFromPair + > {}; template class _And = _And, __enable_if_t< _And< @@ -912,21 +983,64 @@ { } // tuple(pair&&) constructors (including allocator_arg_t variants) + template + struct _EnableMoveFromPair : _And< + is_constructible<_FirstType<_DependentTp...>, _Up1>, + is_constructible<_SecondType<_DependentTp...>, _Up2> + > {}; + 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...> > - > { }; + is_convertible<_Up1, _FirstType<_DependentTp...> >, + is_convertible<_Up2, _SecondType<_DependentTp...> >, + _EnableMoveFromPair<_Up1, _Up2, _DependentTp...> + > {}; template struct _EnableExplicitMoveFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, _Up1>, - is_constructible<_SecondType<_DependentTp...>, _Up2>, - _Not > >, // explicit check - _Not > > - > { }; + _Or<_Not > >, + _Not > > >, + _EnableMoveFromPair<_Up1, _Up2, _DependentTp...> + > {}; + +#if _LIBCPP_STD_VER > 20 + template , + _EnableCopyFromPair<_U1&, _U2&, _Tp...>>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!is_convertible_v<_U1&, _FirstType<_Tp...>> || !is_convertible_v<_U2&, _SecondType<_Tp...>>) + tuple(pair<_U1, _U2>& __p) : __base_(__p) {} + + template , + _EnableCopyFromPair<_U1&, _U2&, _Tp...>>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!is_convertible_v<_U1&, _FirstType<_Tp...>> || !is_convertible_v<_U2&, _SecondType<_Tp...>>) + tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p) : __base_(allocator_arg_t(), __alloc, __p) {} + + template , + _EnableMoveFromPair<_U1, _U2, _Tp...>>::value>* = nullptr> + requires (sizeof...(_Tp) == 2) + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!is_convertible_v> || !is_convertible_v>) + tuple(const pair<_U1, _U2>&& __p) : __base_(std::move(__p)) {} + + template , + _EnableMoveFromPair<_U1, _U2, _Tp...>>::value>* = nullptr> + requires (sizeof...(_Tp) == 2) + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!is_convertible_v> || !is_convertible_v>) + 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 template class _And = _And, __enable_if_t< _And< @@ -990,6 +1104,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)) @@ -1031,6 +1162,57 @@ 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, + __tuple_types<_UTypes...>(), + 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 , + is_assignable>&, const _U1&>, + is_assignable>&, const _U2&>>::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 , + is_assignable>&, _U1>, + is_assignable>&, _U2>>::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, @@ -1106,6 +1288,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& __rhs) const noexcept(__all...>::value) { + __base_.swap(__rhs.__base_); + } +#endif // _LIBCPP_STD_VER > 20 }; template <> @@ -1128,6 +1317,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 @@ -1168,6 +1360,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 @@ -467,6 +467,16 @@ typedef _LIBCPP_BOOL_CONSTANT(true) true_type; typedef _LIBCPP_BOOL_CONSTANT(false) false_type; +struct __nat +{ +#ifndef _LIBCPP_CXX03_LANG + __nat() = delete; + __nat(const __nat&) = delete; + __nat& operator=(const __nat&) = delete; + ~__nat() = delete; +#endif +}; + template using _BoolConstant _LIBCPP_NODEBUG = integral_constant; @@ -493,7 +503,12 @@ using _SelectApplyImpl _LIBCPP_NODEBUG = _SecondFn<_Args...>; template using _OrImpl _LIBCPP_NODEBUG = _Result; + template + using _FirstImpl = __nat; + template + using _SecondImpl = __nat; }; + template using _If _LIBCPP_NODEBUG = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>; template @@ -1820,16 +1835,6 @@ typedef _Tp _Tail; }; -struct __nat -{ -#ifndef _LIBCPP_CXX03_LANG - __nat() = delete; - __nat(const __nat&) = delete; - __nat& operator=(const __nat&) = delete; - ~__nat() = delete; -#endif -}; - template struct __align_type { @@ -4089,10 +4094,8 @@ template using __make_const_lvalue_ref = const typename remove_reference<_Tp>::type&; -#if _LIBCPP_STD_VER > 17 template -using __maybe_const = conditional_t<_Const, const _Tp, _Tp>; -#endif // _LIBCPP_STD_VER > 17 +using __maybe_const = typename conditional<_Const, const _Tp, _Tp>::type; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_cpp23.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_cpp23.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/convert_cpp23.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// 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 tuple(const tuple& u); + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: gcc + +#include +#include + +struct MutableCopy { + int val; + + constexpr MutableCopy() = default; + constexpr MutableCopy(int _val) : val(_val) {} + constexpr MutableCopy& operator=(const MutableCopy& o) { val = o.val; return *this; } +}; + +struct ConstCopy { + mutable int val; + + constexpr ConstCopy() = default; + constexpr ConstCopy(int _val) : val(_val) {} + constexpr ConstCopy(const ConstCopy&) = default; + constexpr const ConstCopy& operator=(const ConstCopy& o) const { val = o.val; return *this; } +}; + +struct MutableMove { + int val; + + constexpr MutableMove() = default; + constexpr MutableMove(int _val) : val(_val) {} + constexpr MutableMove& operator=(MutableMove&& o) { val = o.val; return *this; } +}; + +struct ConstMove { + mutable int val; + + constexpr ConstMove() = default; + constexpr ConstMove(int _val) : val(_val) {} + constexpr const ConstMove& operator=(ConstMove&& o) const { val = o.val; return *this; } + constexpr ConstMove& operator=(const ConstMove&) = delete; +}; + +static_assert(std::is_assignable_v); + +template +struct ConvertibleFrom { + T v; + constexpr ConvertibleFrom() = default; + constexpr ConvertibleFrom(T& _v) : v(_v) {} + constexpr ConvertibleFrom(T&& _v) : v(std::move(_v)) {} +}; + +template +struct ConstConvertibleFrom { + mutable T v; + constexpr ConstConvertibleFrom() = default; + constexpr ConstConvertibleFrom(T& _v) : v(_v) {} + constexpr ConstConvertibleFrom(T&& _v) : v(std::move(_v)) {} + constexpr ConstConvertibleFrom(const ConstConvertibleFrom&) = default; + constexpr const ConstConvertibleFrom& operator=(const ConstConvertibleFrom& o) const { v = o.v; return *this; } +}; + +constexpr bool test() { + { + using T = std::tuple; + + T t1{1}; + T t2; + t2 = t1; + assert(std::get<0>(t2).val == 1); + } + { + using T = std::tuple; + + T t1{1}; + const T t2; + t2 = t1; + assert(std::get<0>(t2).val == 1); + } + { + using T = std::tuple; + + T t1{1}; + T t2; + t2 = std::move(t1); + assert(std::get<0>(t2).val == 1); + } + { + using T = std::tuple; + + T t1{1}; + const T t2; + t2 = std::move(t1); + assert(std::get<0>(t2).val == 1); + } + + { + using T1 = std::pair; + using T2 = std::tuple; + + T1 t1{1, 2}; + T2 t2; + t2 = t1; + assert(std::get<0>(t2).val == 1); + } + { + using T1 = std::pair>; + using T2 = std::tuple>; + + T1 t1{1, 2}; + const T2 t2; + t2 = t1; + assert(std::get<0>(t2).val == 1); + } + { + using T1 = std::pair; + using T2 = std::tuple; + + T1 t1{1, 2}; + T2 t2; + t2 = std::move(t1); + assert(std::get<0>(t2).val == 1); + } + { + using T1 = std::pair>; + using T2 = std::tuple>; + + T1 t1{1, 2}; + const T2 t2; + t2 = std::move(t1); + assert(std::get<0>(t2).val == 1); + } + + 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_cpp23.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_cpp23.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_cpp23.pass.cpp @@ -0,0 +1,202 @@ +//===----------------------------------------------------------------------===// +// +// 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 tuple(const tuple& u); + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// XFAIL: gcc + +#include +#include + +#include "test_allocator.h" + +struct MutableCopy { + int val; + + constexpr MutableCopy() = default; + constexpr MutableCopy(int _val) : val(_val) {} + constexpr MutableCopy(MutableCopy& o) : val(o.val) {} + constexpr MutableCopy(const MutableCopy&) = delete; +}; + +struct ConstCopy { + mutable int val; + + constexpr ConstCopy() = default; + constexpr ConstCopy(int _val) : val(_val) {} + constexpr ConstCopy(const ConstCopy& o) : val(o.val) {} + constexpr ConstCopy(ConstCopy&) = delete; +}; + +struct MutableMove { + int val; + + constexpr MutableMove() = default; + constexpr MutableMove(int _val) : val(_val) {} + constexpr MutableMove(MutableMove&& o) : val(o.val) {} + constexpr MutableMove(const MutableMove&&) = delete; +}; + +struct ConstMove { + mutable int val; + + constexpr ConstMove() = default; + constexpr ConstMove(int _val) : val(_val) {} + constexpr ConstMove(const ConstMove&& o) : val(o.val) {} + constexpr ConstMove(ConstMove&&) = delete; +}; + +template +struct ConvertibleFrom { + T v; + constexpr ConvertibleFrom() = default; + constexpr ConvertibleFrom(T& _v) requires(std::is_constructible_v) : v(_v) {} + constexpr ConvertibleFrom(T&& _v) requires(std::is_constructible_v) : v(std::move(_v)) {} +}; + +template +struct ExplicitConstructibleFrom { + T v; + constexpr explicit ExplicitConstructibleFrom() = default; + constexpr explicit ExplicitConstructibleFrom(T& _v) requires(std::is_constructible_v) : v(_v) {} + constexpr explicit ExplicitConstructibleFrom(T&& _v) requires(std::is_constructible_v) : v(std::move(_v)) {} + + constexpr explicit ExplicitConstructibleFrom(std::remove_const& _v) requires(std::is_const_v) = delete; + constexpr explicit ExplicitConstructibleFrom(std::remove_const&& _v) requires(std::is_const_v) = delete; + constexpr explicit ExplicitConstructibleFrom(const T& _v) requires(!std::is_const_v) = delete; + constexpr explicit ExplicitConstructibleFrom(const T&& _v) requires(!std::is_const_v) = delete; +}; + +static_assert(!std::is_convertible_v&, std::tuple>>); +static_assert(!std::is_convertible_v&, const std::tuple>>); +static_assert(!std::is_convertible_v&&, std::tuple>>); +static_assert(!std::is_convertible_v&&, const std::tuple>>); + +template +constexpr void test_copy() { + T t1{1, 2}; + U t2 = t1; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_move() { + T t1{1, 2}; + U t2 = std::move(t1); + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_copy_allocator() { + test_allocator alloc; + + T t1{1, 2}; + U t2 = {std::allocator_arg_t{}, alloc, t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_move_allocator() { + test_allocator alloc; + + T t1{1, 2}; + U t2 = {std::allocator_arg_t{}, alloc, std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_copy_explicit() { + T t1{1, 2}; + U t2{t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_move_explicit() { + T t1{1, 2}; + U t2{std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_copy_allocator_explicit() { + test_allocator alloc; + + T t1{1, 2}; + U t2{std::allocator_arg_t{}, alloc, t1}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +template +constexpr void test_move_allocator_explicit() { + test_allocator alloc; + + T t1{1, 2}; + U t2{std::allocator_arg_t{}, alloc, std::move(t1)}; + assert(std::get<0>(t2).v.val == 1); + assert(std::get<1>(t2) == 2); +} + +constexpr bool test() { + // test implicit conversions + test_copy< std::tuple, std::tuple, int>>(); + test_copy, std::tuple, int>>(); + test_move< std::tuple, std::tuple, int>>(); + test_move, std::tuple, int>>(); + test_copy< std::pair , std::tuple, int>>(); + test_copy, std::tuple, int>>(); + test_move< std::pair , std::tuple, int>>(); + test_move, std::tuple, int>>(); + // test implicit conversions with allocator + test_copy_allocator< std::tuple, std::tuple, int>>(); + test_copy_allocator, std::tuple, int>>(); + test_move_allocator< std::tuple, std::tuple, int>>(); + test_move_allocator, std::tuple, int>>(); + test_copy_allocator< std::pair , std::tuple, int>>(); + test_copy_allocator, std::tuple, int>>(); + test_move_allocator< std::pair , std::tuple, int>>(); + test_move_allocator, std::tuple, int>>(); + // test explicit conversions + test_copy_explicit< std::tuple, std::tuple, int>>(); + test_copy_explicit, std::tuple, int>>(); + test_move_explicit< std::tuple, std::tuple, int>>(); + test_move_explicit, std::tuple, int>>(); + test_copy_explicit< std::pair , std::tuple, int>>(); + test_copy_explicit, std::tuple, int>>(); + test_move_explicit< std::pair , std::tuple, int>>(); + test_move_explicit, std::tuple, int>>(); + // test explicit conversions with allocator + test_copy_allocator_explicit< std::tuple, std::tuple, int>>(); + test_copy_allocator_explicit, std::tuple, int>>(); + test_move_allocator_explicit< std::tuple, std::tuple, int>>(); + test_move_allocator_explicit, std::tuple, int>>(); + test_copy_allocator_explicit< std::pair , std::tuple, int>>(); + test_copy_allocator_explicit, std::tuple, int>>(); + test_move_allocator_explicit< std::pair , std::tuple, int>>(); + test_move_allocator_explicit, std::tuple, int>>(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} 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,91 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +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) {} +} + +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**) { + test_noexcept(); + test(); + static_assert(test()); + + return 0; +}