diff --git a/libcxx/docs/Status/ZipProjects.csv b/libcxx/docs/Status/ZipProjects.csv --- a/libcxx/docs/Status/ZipProjects.csv +++ b/libcxx/docs/Status/ZipProjects.csv @@ -1,27 +1,27 @@ Section,Description,Dependencies,Assignee,Complete | `[tuple.syn] `_, "`[tuple] basic_common_reference, common_type `_", None, Nikolas Klauser, |Complete| -| `[tuple.tuple] `_, "`[tuple] constructor, assignment and swap overloads `_", None, Nikolas Klauser, |In Progress| +| `[tuple.tuple] `_, "`[tuple] constructor, assignment and swap overloads `_", None, Hui Xie, |Complete| | `[utility.syn] `_, "[pair] basic_common_reference, common_type", None, Nikolas Klauser, |Complete| -| `[pairs.pair] `_, "[pair] constructor, assignment and swap overloads", None, Nikolas Klauser, |Not Started| +| `[pairs.pair] `_, "`[pair] constructor, assignment and swap overloads `_", None, Hui Xie, |Complete| "| `[memory.syn] `_ -| `[allocator.uses.construction] `_", "[pair] uses_allocator_construction_args overloads", None, Unassigned, |Not Started| -| `[vector.bool] `_, "[vector::reference] add const operator= overload", None, Nikolas Klauser, |Not Started| -| `[iterator.concept.winc] `_, "Update weakly_comparable", None, Unassigned, |Not Started| +| `[allocator.uses.construction] `_", "[pair] uses_allocator_construction_args overloads", "P0591R4", Hui Xie, |Not Started| +| `[vector.bool] `_, "[vector::reference] add const operator= overload", None, Hui Xie, |Not Started| +| `[iterator.concept.winc] `_, "Update weakly_comparable", None, Hui Xie, |Not Started| | `[range.zip] `_, "`zip_view `_", "| `zip_view::iterator` | `zip_view::sentinel`", Hui Xie, |Complete| | `[range.zip.iterator] `_, "`zip_view::iterator `_", None, Hui Xie, |Complete| | `[range.zip.sentinel] `_, "`zip_view::sentinel `_", None, Hui Xie, |Complete| | `[range.zip.transform.view] `_, "zip_transform_view", "| `zip_transform_view::iterator` -| `zip_transform_view::sentinel`", Unassigned, |Not Started| -| `[range.zip.transform.iterator] `_, "zip_transform_view::iterator", None, Unassigned, |Not Started| -| `[range.zip.transform.sentinel] `_, "zip_transform_view::sentinel", None, Unassigned, |Not Started| +| `zip_transform_view::sentinel`", Hui Xie, |Not Started| +| `[range.zip.transform.iterator] `_, "zip_transform_view::iterator", None, Hui Xie, |Not Started| +| `[range.zip.transform.sentinel] `_, "zip_transform_view::sentinel", None, Hui Xie, |Not Started| | `[range.adjacent.view] `_, "adjacent_view", "| `adjacent_view::iterator` -| `adjacent_view::sentinel`", Unassigned, |Not Started| -| `[range.adjacent.iterator] `_, "adjacent_view::iterator", None, Unassigned, |Not Started| -| `[range.adjacent.sentinel] `_, "adjacent_view::sentinel", None, Unassigned, |Not Started| +| `adjacent_view::sentinel`", Hui Xie, |Not Started| +| `[range.adjacent.iterator] `_, "adjacent_view::iterator", None, unassigned, |Not Started| +| `[range.adjacent.sentinel] `_, "adjacent_view::sentinel", None, unassigned, |Not Started| | `[range.adjacent.transform.view] `_, "adjacent_transform_view", "| `adjacent_transform_view::iterator`, -| `adjacent_transform_view::sentinel`", Unassigned, |Not Started| -| `[range.adjacent.transform.iterator] `_, "adjacent_transform_view::iterator", None, Unassigned, |Not Started| -| `[range.adjacent.transform.sentinel] `_, "adjacent_transform_view::sentinel", None, Unassigned, |Not Started| +| `adjacent_transform_view::sentinel`", Hui Xie, |Not Started| +| `[range.adjacent.transform.iterator] `_, "adjacent_transform_view::iterator", None, Hui Xie, |Not Started| +| `[range.adjacent.transform.sentinel] `_, "adjacent_transform_view::sentinel", None, Hui Xie, |Not Started| | `[ranges.syn] `_, "enable_borrowed_range zip_view and adjacent_view", "| `zip_view` -| `adjacent_view`", Unassigned, |Not Started| +| `adjacent_view`", Hui Xie, |Not Started| diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -88,20 +88,26 @@ } template - static constexpr bool __enable_explicit() { + static constexpr bool __is_pair_constructible() { return is_constructible::value - && is_constructible::value - && (!is_convertible<_U1, first_type>::value - || !is_convertible<_U2, second_type>::value); + && is_constructible::value; } template - static constexpr bool __enable_implicit() { - return is_constructible::value - && is_constructible::value - && is_convertible<_U1, first_type>::value + static constexpr bool __is_implicit() { + return is_convertible<_U1, first_type>::value && is_convertible<_U2, second_type>::value; } + + template + static constexpr bool __enable_explicit() { + return __is_pair_constructible<_U1, _U2>() && !__is_implicit<_U1, _U2>(); + } + + template + static constexpr bool __enable_implicit() { + return __is_pair_constructible<_U1, _U2>() && __is_implicit<_U1, _U2>(); + } }; template @@ -196,6 +202,17 @@ is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {} +#if _LIBCPP_STD_VER > 20 + template() + >* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_CheckArgs::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>& __p) + noexcept((is_nothrow_constructible::value && + is_nothrow_constructible::value)) + : first(__p.first), second(__p.second) {} +#endif + template() >::type* = nullptr> @@ -232,6 +249,18 @@ is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__p.first)), second(_VSTD::forward<_U2>(__p.second)) {} +#if _LIBCPP_STD_VER > 20 + template() + >* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_CheckArgs::template __is_implicit()) + pair(const pair<_U1, _U2>&& __p) + noexcept((is_nothrow_constructible::value && + is_nothrow_constructible::value)) + : first(std::move(__p.first)), second(std::move(__p.second)) {} +#endif + template::template __enable_explicit<_Tuple>() >::type* = nullptr> @@ -284,6 +313,50 @@ return *this; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + const pair& operator=(pair const& __p) const + noexcept(is_nothrow_copy_assignable_v && + is_nothrow_copy_assignable_v) + requires (is_copy_assignable_v && + is_copy_assignable_v){ + first = __p.first; + second = __p.second; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr + const pair& operator=(pair&& __p) const + noexcept(is_nothrow_assignable_v && + is_nothrow_assignable_v) + requires (is_assignable_v && + is_assignable_v){ + first = std::forward(__p.first); + second = std::forward(__p.second); + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr + const pair& operator=(const pair<_U1, _U2>& __p) const + requires (is_assignable_v && + is_assignable_v){ + first = __p.first; + second = __p.second; + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr + const pair& operator=(pair<_U1, _U2>&& __p) const + requires (is_assignable_v && + is_assignable_v){ + first = std::forward<_U1>(__p.first); + second = std::forward<_U2>(__p.second); + return *this; + } +#endif // _LIBCPP_STD_VER > 20 + template ::template __enable_assign<_Tuple>() >::type* = nullptr> @@ -304,6 +377,18 @@ swap(first, __p.first); swap(second, __p.second); } + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const pair& __p) const + _NOEXCEPT_(__is_nothrow_swappable::value && + __is_nothrow_swappable::value) + { + using std::swap; + swap(first, __p.first); + swap(second, __p.second); + } +#endif private: #ifndef _LIBCPP_CXX03_LANG @@ -420,6 +505,19 @@ __x.swap(__y); } +#if _LIBCPP_STD_VER > 20 +template + requires (__is_swappable::value && + __is_swappable::value) +_LIBCPP_HIDE_FROM_ABI constexpr +void swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + _NOEXCEPT_(__is_nothrow_swappable::value && + __is_nothrow_swappable::value) +{ + __x.swap(__y); +} +#endif + #ifndef _LIBCPP_CXX03_LANG template diff --git a/libcxx/include/utility b/libcxx/include/utility --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -80,19 +80,29 @@ explicit(see-below) constexpr pair(); explicit(see-below) pair(const T1& x, const T2& y); // constexpr in C++14 template explicit(see-below) pair(U&&, V&&); // constexpr in C++14 + template constexpr explicit(see below) pair(pair&); // since C++23 template explicit(see-below) pair(const pair& p); // constexpr in C++14 template explicit(see-below) pair(pair&& p); // constexpr in C++14 + template + constexpr explicit(see below) pair(const pair&&); // since C++23 template pair(piecewise_construct_t, tuple first_args, tuple second_args); // constexpr in C++20 + constexpr const pair& operator=(const pair& p) const; // since C++23 template pair& operator=(const pair& p); // constexpr in C++20 + template + constexpr const pair& operator=(const pair& p) const; // since C++23 pair& operator=(pair&& p) noexcept(is_nothrow_move_assignable::value && is_nothrow_move_assignable::value); // constexpr in C++20 + constexpr const pair& operator=(pair&& p) const; // since C++23 template pair& operator=(pair&& p); // constexpr in C++20 + template + constexpr const pair& operator=(pair&& p) const; // since C++23 void swap(pair& p) noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v); // constexpr in C++20 + constexpr void swap(const pair& p) const noexcept(see below); // since C++23 }; template class TQual, template class UQual> @@ -119,6 +129,9 @@ void swap(pair& x, pair& y) noexcept(noexcept(x.swap(y))); // constexpr in C++20 +template +constexpr void swap(const pair& x, const pair& y) noexcept(noexcept(x.swap(y))); // since C++23 + struct piecewise_construct_t { explicit piecewise_construct_t() = default; }; inline constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t(); diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_copy_convert.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_copy_convert.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_copy_convert.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template struct pair +// template constexpr +// const pair& operator=(const pair& p) const; + +#include +#include + +#include "test_macros.h" +#include "../../../tuple/tuple.tuple/tuple.assign/types.h" + +// Constraints: +// is_assignable_v is true, and +// is_assignable_v is true. + +// clang-format off +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&, + const std::pair&>); + +static_assert(std::is_assignable_v< + const std::pair, AssignableFrom>&, + const std::pair&>); +static_assert(!std::is_assignable_v< + const std::pair, AssignableFrom>&, + const std::pair&>); + +// clang-format on + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + long j1 = 3; + long j2 = 4; + const std::pair p1{i1, i2}; + const std::pair p2{j1, j2}; + p2 = p1; + assert(p2.first == 1); + assert(p2.second == 2); + } + + // user defined const copy assignment + { + const std::pair p1{1, 2}; + const std::pair, AssignableFrom> p2{3, 4}; + p2 = p1; + assert(p2.first.v.val == 1); + assert(p2.second.v.val == 2); + } + + // The correct assignment operator of the underlying type is used + { + std::pair t1{}; + const std::pair, AssignableFrom> t2{}; + t2 = t1; + assert(t2.first.v.constCopyAssign == 1); + assert(t2.second.v.constCopyAssign == 1); + } + + return true; +} + +int main(int, const char**) { + test(); +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_copy_pair.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_copy_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_copy_pair.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template struct pair +// constexpr const pair& operator=(const pair& p) const; + +#include +#include + +#include "test_macros.h" +#include "../../../tuple/tuple.tuple/tuple.assign/types.h" + +// Constraints: +// is_copy_assignable is true and +// is_copy_assignable is true. + +// clang-format off +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&, + const std::pair&>); + +static_assert(std::is_assignable_v&, + const std::pair&>); +static_assert(!std::is_assignable_v&, + const std::pair&>); + +// clang-format on + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + double d1 = 3.0; + double d2 = 5.0; + const std::pair p1{i1, d1}; + const std::pair p2{i2, d2}; + p2 = p1; + assert(p2.first == 1); + assert(p2.second == 3.0); + } + + // user defined const copy assignment + { + const std::pair p1{1, 2}; + const std::pair p2{3, 4}; + p2 = p1; + assert(p2.first.val == 1); + assert(p2.second.val == 2); + } + + // The correct assignment operator of the underlying type is used + { + std::pair t1{}; + const std::pair t2{}; + t2 = t1; + assert(t2.first.constCopyAssign == 1); + assert(t2.second.constCopyAssign == 1); + } + + return true; +} + +int main(int, const char**) { + test(); +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_move_convert.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_move_convert.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_move_convert.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template struct pair +// template +// constexpr const pair& operator=(pair&& p) const; + +#include +#include + +#include "test_macros.h" +#include "../../../tuple/tuple.tuple/tuple.assign/types.h" + +// Constraints: +// is_assignable is true and +// is_assignable is true. + +// clang-format off +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&, + std::pair&&>); + +static_assert(std::is_assignable_v< + const std::pair, AssignableFrom>&, + std::pair&&>); +static_assert(!std::is_assignable_v< + const std::pair, AssignableFrom>&, + std::pair&&>); + +// clang-format on + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + long j1 = 3; + long j2 = 4; + std::pair p1{std::move(i1), std::move(i2)}; + const std::pair p2{std::move(j1), std::move(j2)}; + p2 = std::move(p1); + assert(p2.first == 1); + assert(p2.second == 2); + } + + // user defined const move assignment + { + std::pair p1{1, 2}; + const std::pair, AssignableFrom> p2{3, 4}; + p2 = std::move(p1); + assert(p2.first.v.val == 1); + assert(p2.second.v.val == 2); + } + + // The correct assignment operator of the underlying type is used + { + std::pair t1{}; + const std::pair, AssignableFrom> t2{}; + t2 = std::move(t1); + assert(t2.first.v.constMoveAssign == 1); + assert(t2.second.v.constMoveAssign == 1); + } + + return true; +} + +int main(int, const char**) { + test(); +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_move_pair.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_move_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_move_pair.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template struct pair +// constexpr const pair& operator=(pair&& p) const; + +#include +#include + +#include "test_macros.h" +#include "../../../tuple/tuple.tuple/tuple.assign/types.h" + +// Constraints: +// is_assignable is true and +// is_assignable is true. + +// clang-format off +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&, + std::pair&&>); + +static_assert(std::is_assignable_v&, + std::pair&&>); +static_assert(!std::is_assignable_v&, + std::pair&&>); + +// clang-format on + +constexpr bool test() { + // reference types + { + int i1 = 1; + int i2 = 2; + double d1 = 3.0; + double d2 = 5.0; + std::pair p1{std::move(i1), std::move(d1)}; + const std::pair p2{std::move(i2), std::move(d2)}; + p2 = std::move(p1); + assert(p2.first == 1); + assert(p2.second == 3.0); + } + + // user defined const move assignment + { + std::pair p1{1, 2}; + const std::pair p2{3, 4}; + p2 = std::move(p1); + assert(p2.first.val == 1); + assert(p2.second.val == 2); + } + + // The correct assignment operator of the underlying type is used + { + std::pair t1{}; + const std::pair t2{}; + t2 = std::move(t1); + assert(t2.first.constMoveAssign == 1); + assert(t2.second.constCopyAssign == 1); + } + + return true; +} + +int main(int, const char**) { + test(); +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor_pair_U_V_const_move.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor_pair_U_V_const_move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor_pair_U_V_const_move.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template struct pair +// template +// constexpr explicit(see below) pair(const pair&& p); + +#include +#include + +#include "../../../tuple/tuple.tuple/tuple.cnstr/convert_types.h" +#include "test_macros.h" + +// Constraints: +// is_constructible_v(FWD(p)))> is true and +// is_constructible_v(FWD(p)))> is true. +struct X {}; +struct Y {}; +struct NotConvertibleToXorY {}; + +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, const std::pair&&>); + +// The expression inside explicit is equivalent to: +// !is_convertible_v(FWD(p))), first_type> || +// !is_convertible_v(FWD(p))), second_type>. +static_assert(std::is_convertible_v&&, std::pair, ConvertibleFrom>>); +static_assert( + !std::is_convertible_v&&, std::pair, ExplicitConstructibleFrom>>); +static_assert( + !std::is_convertible_v&&, std::pair, ConvertibleFrom>>); +static_assert(!std::is_convertible_v&&, + std::pair, ExplicitConstructibleFrom>>); + +constexpr bool test() { + // simple case: init pair from const pair&& + { + const std::pair p1{1, 2}; + std::pair p2{std::move(p1)}; + assert(&(p2.first) == &(p1.first)); + assert(&(p2.second) == &(p1.second)); + } + + // test implicit conversions. + { + const std::pair p1{1, 2}; + std::pair, ConvertibleFrom> p2 = std::move(p1); + assert(p2.first.v.val == 1); + assert(p2.second.v == 2); + } + + // test explicit conversions. + { + const std::pair p1{1, 2}; + std::pair, ExplicitConstructibleFrom> p2{std::move(p1)}; + assert(p2.first.v.val == 1); + assert(p2.second.v == 2); + } + + // test correct constructors of underlying types are called + { + const std::pair p1{}; + std::pair, ConvertibleFrom> p2{std::move(p1)}; + assert(constMoveCtrCalled(p2.first.v)); + assert(constMoveCtrCalled(p2.second.v)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor_pair_U_V_ref.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor_pair_U_V_ref.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor_pair_U_V_ref.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template struct pair +// template +// constexpr explicit(see below) pair(pair& p); + +#include +#include + +#include "../../../tuple/tuple.tuple/tuple.cnstr/convert_types.h" +#include "test_macros.h" + +// Constraints: +// is_constructible_v(FWD(p)))> is true and +// is_constructible_v(FWD(p)))> is true. +struct X {}; +struct Y {}; +struct NotConvertibleToXorY {}; + +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::pair&>); + +// The expression inside explicit is equivalent to: +// !is_convertible_v(FWD(p))), first_type> || +// !is_convertible_v(FWD(p))), second_type>. +static_assert(std::is_convertible_v&, std::pair, ConvertibleFrom>>); +static_assert(!std::is_convertible_v&, std::pair, ExplicitConstructibleFrom>>); +static_assert(!std::is_convertible_v&, std::pair, ConvertibleFrom>>); +static_assert( + !std::is_convertible_v&, std::pair, ExplicitConstructibleFrom>>); + +constexpr bool test() { + // use case in zip. Init pair from pair& + { + std::pair p1{1, 2}; + std::pair p2{p1}; + assert(&(p2.first) == &(p1.first)); + assert(&(p2.second) == &(p1.second)); + } + + // test implicit conversions. + { + std::pair p1{1, 2}; + std::pair, ConvertibleFrom> p2 = p1; + assert(p2.first.v.val == 1); + assert(p2.second.v == 2); + } + + // test explicit conversions. + { + std::pair p1{1, 2}; + std::pair, ExplicitConstructibleFrom> p2{p1}; + assert(p2.first.v.val == 1); + assert(p2.second.v == 2); + } + + // test correct constructors of underlying types are called + { + std::pair p1{}; + std::pair, ConvertibleFrom> p2{p1}; + assert(nonConstCopyCtrCalled(p2.first.v)); + assert(nonConstCopyCtrCalled(p2.second.v)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/swap_member_const.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/swap_member_const.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/swap_member_const.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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 struct pair +// void swap(const pair& p) const; + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "test_macros.h" + +// Remarks: The expression inside noexcept is equivalent to +// is_nothrow_swappable_v && is_nothrow_swappable_v for the second overload. +template +concept MemberSwapNoexcept = + requires(T t1, T t2) { + { t1.swap(t2) } noexcept; + }; + +template +struct SwapMayThrow {}; + +template +void swap(const SwapMayThrow&, const SwapMayThrow&) noexcept(!canThrow); + +static_assert(MemberSwapNoexcept, SwapMayThrow>>); +static_assert(!MemberSwapNoexcept, SwapMayThrow>>); +static_assert(!MemberSwapNoexcept, SwapMayThrow>>); +static_assert(!MemberSwapNoexcept, SwapMayThrow>>); + +struct ConstSwappable { + mutable int i; + friend constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); } +}; + +constexpr bool test() { + // user defined const swap + { + using P = std::pair; + const P p1(ConstSwappable{0}, ConstSwappable{1}); + const P p2(ConstSwappable{2}, ConstSwappable{3}); + p1.swap(p2); + assert(p1.first.i == 2); + assert(p1.second.i == 3); + assert(p2.first.i == 0); + assert(p2.second.i == 1); + } + + // pair of references + { + int i1 = 0, i2 = 1, i3 = 2, i4 = 3; + const std::pair p1{i1, i2}; + const std::pair p2{i3, i4}; + p1.swap(p2); + assert(p1.first == 2); + assert(p1.second == 3); + assert(p2.first == 0); + assert(p2.second == 1); + } + return true; +} + +int main(int, char**) { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif + + return 0; +} \ No newline at end of file diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.spec/non_member_const_swap.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.spec/non_member_const_swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.spec/non_member_const_swap.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 +// void swap(const pair& x, const pair& y) const noexcept(noexcept(x.swap(y)));; + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "test_macros.h" + +// Constraints: +// For the second overload, is_swappable_v is true and is_swappable_v is true. +struct NonConstSwappable { + friend constexpr void swap(NonConstSwappable&, NonConstSwappable&); +}; + +struct ConstSwappable { + mutable int i; + friend constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); } +}; + +static_assert(std::is_swappable_v>); +static_assert(!std::is_swappable_v>); +static_assert(!std::is_swappable_v>); +static_assert(!std::is_swappable_v>); + +// noexcept(noexcept(x.swap(y))); +template +concept NonMemberSwapNoexcept = + requires(T t1, T t2) { + { swap(t1, t2) } noexcept; + }; + +template +struct SwapMayThrow {}; + +template +void swap(const SwapMayThrow&, const SwapMayThrow&) noexcept(!canThrow); + +static_assert(NonMemberSwapNoexcept, SwapMayThrow>>); +static_assert(!NonMemberSwapNoexcept, SwapMayThrow>>); +static_assert(!NonMemberSwapNoexcept, SwapMayThrow>>); +static_assert(!NonMemberSwapNoexcept, SwapMayThrow>>); + +constexpr bool test() { + // user defined const swap + { + using P = std::pair; + const P p1(ConstSwappable{0}, ConstSwappable{1}); + const P p2(ConstSwappable{2}, ConstSwappable{3}); + using std::swap; + swap(p1, p2); + assert(p1.first.i == 2); + assert(p1.second.i == 3); + assert(p2.first.i == 0); + assert(p2.second.i == 1); + } + + // pair of references + { + int i1 = 0, i2 = 1, i3 = 2, i4 = 3; + const std::pair p1{i1, i2}; + const std::pair p2{i3, i4}; + using std::swap; + swap(p1, p2); + assert(p1.first == 2); + assert(p1.second == 3); + assert(p2.first == 0); + assert(p2.second == 1); + } + return true; +} + +int main(int, char**) { + test(); + +// gcc cannot have mutable member in constant expression +#if !defined(TEST_COMPILER_GCC) + static_assert(test()); +#endif + + return 0; +} \ No newline at end of file