xref: /llvm-project/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair_U_V.pass.cpp (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03
10 
11 // <utility>
12 
13 // template <class T1, class T2> struct pair
14 
15 // template<class U, class V> pair& operator=(pair<U, V>&& p);
16 
17 #include <utility>
18 #include <memory>
19 #include <cassert>
20 
21 #include "test_macros.h"
22 #include "archetypes.h"
23 
24 struct Derived : ConstexprTestTypes::MoveOnly {
25   Derived() = default;
DerivedDerived26   TEST_CONSTEXPR_CXX20 Derived(ConstexprTestTypes::MoveOnly&&) {}
27 };
28 struct CountAssign {
29   int copied = 0;
30   int moved = 0;
31   TEST_CONSTEXPR_CXX20 CountAssign() = default;
CountAssignCountAssign32   TEST_CONSTEXPR_CXX20 CountAssign(const int) {}
operator =CountAssign33   TEST_CONSTEXPR_CXX20 CountAssign& operator=(CountAssign const&) {
34     ++copied;
35     return *this;
36   }
operator =CountAssign37   TEST_CONSTEXPR_CXX20 CountAssign& operator=(CountAssign&&) {
38     ++moved;
39     return *this;
40   }
41 };
42 
43 struct CopyAssignableInt {
operator =CopyAssignableInt44   CopyAssignableInt& operator=(int&) { return *this; }
45 };
46 
47 struct NotAssignable {
48   NotAssignable& operator=(NotAssignable const&) = delete;
49   NotAssignable& operator=(NotAssignable&&) = delete;
50 };
51 
52 struct MoveAssignable {
53   MoveAssignable& operator=(MoveAssignable const&) = delete;
54   MoveAssignable& operator=(MoveAssignable&&) = default;
55 };
56 
57 struct CopyAssignable {
58   CopyAssignable& operator=(CopyAssignable const&) = default;
59   CopyAssignable& operator=(CopyAssignable&&) = delete;
60 };
61 
test()62 TEST_CONSTEXPR_CXX20 bool test() {
63   {
64     typedef std::pair<Derived, short> P1;
65     typedef std::pair<ConstexprTestTypes::MoveOnly, long> P2;
66     P1 p1(Derived(), static_cast<short>(4));
67     P2 p2;
68     p2 = std::move(p1);
69     assert(p2.second == 4);
70   }
71   {
72     using P = std::pair<int, CountAssign>;
73     using T = std::pair<long, CountAssign>;
74     T t(42, -42);
75     P p(101, 101);
76     p = std::move(t);
77     assert(p.first == 42);
78     assert(p.second.moved == 1);
79     assert(p.second.copied == 0);
80     assert(t.second.moved == 0);
81     assert(t.second.copied == 0);
82   }
83   { // test const requirement
84     using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
85     using P = std::pair<int, int>;
86     static_assert(!std::is_assignable<T&, P&&>::value, "");
87     static_assert(!std::is_assignable<P&, T&&>::value, "");
88   }
89   {
90     // Make sure we can't move-assign from a pair containing a reference
91     // if that type isn't copy-constructible (since otherwise we'd be
92     // stealing the object through the reference).
93     using P1 = std::pair<MoveAssignable, long>;
94     using P2 = std::pair<MoveAssignable&, int>;
95     static_assert(!std::is_assignable<P1&, P2&&>::value, "");
96 
97     // ... but this should work since we're going to steal out of the
98     // incoming rvalue reference.
99     using P3 = std::pair<MoveAssignable, long>;
100     using P4 = std::pair<MoveAssignable&&, int>;
101     static_assert(std::is_assignable<P3&, P4&&>::value, "");
102   }
103   {
104     // We assign through the reference and don't move out of the incoming ref,
105     // so this doesn't work (but would if the type were CopyAssignable).
106     {
107       using P1 = std::pair<MoveAssignable&, long>;
108       using P2 = std::pair<MoveAssignable&, int>;
109       static_assert(!std::is_assignable<P1&, P2&&>::value, "");
110     }
111 
112     // ... works if it's CopyAssignable
113     {
114       using P1 = std::pair<CopyAssignable&, long>;
115       using P2 = std::pair<CopyAssignable&, int>;
116       static_assert(std::is_assignable<P1&, P2&&>::value, "");
117     }
118 
119     // For rvalue-references, we can move-assign if the type is MoveAssignable,
120     // or CopyAssignable (since in the worst case the move will decay into a copy).
121     {
122       using P1 = std::pair<MoveAssignable&&, long>;
123       using P2 = std::pair<MoveAssignable&&, int>;
124       static_assert(std::is_assignable<P1&, P2&&>::value, "");
125 
126       using P3 = std::pair<CopyAssignable&&, long>;
127       using P4 = std::pair<CopyAssignable&&, int>;
128       static_assert(std::is_assignable<P3&, P4&&>::value, "");
129     }
130 
131     // In all cases, we can't move-assign if the types are not assignable,
132     // since we assign through the reference.
133     {
134       using P1 = std::pair<NotAssignable&, long>;
135       using P2 = std::pair<NotAssignable&, int>;
136       static_assert(!std::is_assignable<P1&, P2&&>::value, "");
137 
138       using P3 = std::pair<NotAssignable&&, long>;
139       using P4 = std::pair<NotAssignable&&, int>;
140       static_assert(!std::is_assignable<P3&, P4&&>::value, "");
141     }
142   }
143   return true;
144 }
145 
main(int,char **)146 int main(int, char**) {
147   test();
148 #if TEST_STD_VER >= 20
149   static_assert(test());
150 #endif
151 
152   return 0;
153 }
154