xref: /llvm-project/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.assign/move.pass.cpp (revision 06e2b737aa0347b42e8bf37cb00a053eab0a9393)
15a83710eSEric Fiselier //===----------------------------------------------------------------------===//
25a83710eSEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a83710eSEric Fiselier //
75a83710eSEric Fiselier //===----------------------------------------------------------------------===//
85a83710eSEric Fiselier 
95a83710eSEric Fiselier // <tuple>
105a83710eSEric Fiselier 
115a83710eSEric Fiselier // template <class... Types> class tuple;
125a83710eSEric Fiselier 
135a83710eSEric Fiselier // tuple& operator=(tuple&& u);
145a83710eSEric Fiselier 
1531cbe0f2SLouis Dionne // UNSUPPORTED: c++03
160a52cd79SEric Fiselier 
175a127cdcSMarshall Clow #include <memory>
185a83710eSEric Fiselier #include <tuple>
19e21582e7SMarshall Clow #include <utility>
205a83710eSEric Fiselier #include <cassert>
215a83710eSEric Fiselier 
227fc6a556SMarshall Clow #include "test_macros.h"
23949389c3SMarshall Clow #include "MoveOnly.h"
245a83710eSEric Fiselier 
25aedcbf89SEric Fiselier struct NonAssignable {
26aedcbf89SEric Fiselier   NonAssignable& operator=(NonAssignable const&) = delete;
27aedcbf89SEric Fiselier   NonAssignable& operator=(NonAssignable&&) = delete;
28aedcbf89SEric Fiselier };
29aedcbf89SEric Fiselier struct CopyAssignable {
30aedcbf89SEric Fiselier   CopyAssignable& operator=(CopyAssignable const&) = default;
31aedcbf89SEric Fiselier   CopyAssignable& operator=(CopyAssignable&&) = delete;
32aedcbf89SEric Fiselier };
33aedcbf89SEric Fiselier static_assert(std::is_copy_assignable<CopyAssignable>::value, "");
34aedcbf89SEric Fiselier struct MoveAssignable {
35aedcbf89SEric Fiselier   MoveAssignable& operator=(MoveAssignable const&) = delete;
36aedcbf89SEric Fiselier   MoveAssignable& operator=(MoveAssignable&&) = default;
37aedcbf89SEric Fiselier };
38a0839b14SLouis Dionne struct NothrowMoveAssignable {
operator =NothrowMoveAssignable39a0839b14SLouis Dionne   NothrowMoveAssignable& operator=(NothrowMoveAssignable&&) noexcept { return *this; }
40a0839b14SLouis Dionne };
41a0839b14SLouis Dionne struct PotentiallyThrowingMoveAssignable {
operator =PotentiallyThrowingMoveAssignable42a0839b14SLouis Dionne   PotentiallyThrowingMoveAssignable& operator=(PotentiallyThrowingMoveAssignable&&) { return *this; }
43a0839b14SLouis Dionne };
44aedcbf89SEric Fiselier 
45aedcbf89SEric Fiselier struct CountAssign {
46aedcbf89SEric Fiselier   static int copied;
47aedcbf89SEric Fiselier   static int moved;
resetCountAssign48aedcbf89SEric Fiselier   static void reset() { copied = moved = 0; }
49aedcbf89SEric Fiselier   CountAssign() = default;
operator =CountAssign50aedcbf89SEric Fiselier   CountAssign& operator=(CountAssign const&) { ++copied; return *this; }
operator =CountAssign51aedcbf89SEric Fiselier   CountAssign& operator=(CountAssign&&) { ++moved; return *this; }
52aedcbf89SEric Fiselier };
53aedcbf89SEric Fiselier int CountAssign::copied = 0;
54aedcbf89SEric Fiselier int CountAssign::moved = 0;
55aedcbf89SEric Fiselier 
56*06e2b737SArthur O'Dwyer TEST_CONSTEXPR_CXX20
test()57*06e2b737SArthur O'Dwyer bool test()
585a83710eSEric Fiselier {
595a83710eSEric Fiselier     {
605a83710eSEric Fiselier         typedef std::tuple<> T;
615a83710eSEric Fiselier         T t0;
625a83710eSEric Fiselier         T t;
635a83710eSEric Fiselier         t = std::move(t0);
645a83710eSEric Fiselier     }
655a83710eSEric Fiselier     {
665a83710eSEric Fiselier         typedef std::tuple<MoveOnly> T;
675a83710eSEric Fiselier         T t0(MoveOnly(0));
685a83710eSEric Fiselier         T t;
695a83710eSEric Fiselier         t = std::move(t0);
705a83710eSEric Fiselier         assert(std::get<0>(t) == 0);
715a83710eSEric Fiselier     }
725a83710eSEric Fiselier     {
735a83710eSEric Fiselier         typedef std::tuple<MoveOnly, MoveOnly> T;
745a83710eSEric Fiselier         T t0(MoveOnly(0), MoveOnly(1));
755a83710eSEric Fiselier         T t;
765a83710eSEric Fiselier         t = std::move(t0);
775a83710eSEric Fiselier         assert(std::get<0>(t) == 0);
785a83710eSEric Fiselier         assert(std::get<1>(t) == 1);
795a83710eSEric Fiselier     }
805a83710eSEric Fiselier     {
815a83710eSEric Fiselier         typedef std::tuple<MoveOnly, MoveOnly, MoveOnly> T;
825a83710eSEric Fiselier         T t0(MoveOnly(0), MoveOnly(1), MoveOnly(2));
835a83710eSEric Fiselier         T t;
845a83710eSEric Fiselier         t = std::move(t0);
855a83710eSEric Fiselier         assert(std::get<0>(t) == 0);
865a83710eSEric Fiselier         assert(std::get<1>(t) == 1);
875a83710eSEric Fiselier         assert(std::get<2>(t) == 2);
885a83710eSEric Fiselier     }
89aedcbf89SEric Fiselier     {
90aedcbf89SEric Fiselier         // test reference assignment.
91aedcbf89SEric Fiselier         using T = std::tuple<int&, int&&>;
92aedcbf89SEric Fiselier         int x = 42;
93aedcbf89SEric Fiselier         int y = 100;
94aedcbf89SEric Fiselier         int x2 = -1;
95aedcbf89SEric Fiselier         int y2 = 500;
96aedcbf89SEric Fiselier         T t(x, std::move(y));
97aedcbf89SEric Fiselier         T t2(x2, std::move(y2));
98aedcbf89SEric Fiselier         t = std::move(t2);
99aedcbf89SEric Fiselier         assert(std::get<0>(t) == x2);
100aedcbf89SEric Fiselier         assert(&std::get<0>(t) == &x);
101aedcbf89SEric Fiselier         assert(std::get<1>(t) == y2);
102aedcbf89SEric Fiselier         assert(&std::get<1>(t) == &y);
103aedcbf89SEric Fiselier     }
104*06e2b737SArthur O'Dwyer     return true;
105*06e2b737SArthur O'Dwyer }
106*06e2b737SArthur O'Dwyer 
main(int,char **)107*06e2b737SArthur O'Dwyer int main(int, char**)
108*06e2b737SArthur O'Dwyer {
109*06e2b737SArthur O'Dwyer     test();
110*06e2b737SArthur O'Dwyer #if TEST_STD_VER >= 20
111*06e2b737SArthur O'Dwyer     static_assert(test());
112*06e2b737SArthur O'Dwyer #endif
113*06e2b737SArthur O'Dwyer 
114aedcbf89SEric Fiselier     {
115aedcbf89SEric Fiselier         // test that the implicitly generated move assignment operator
116aedcbf89SEric Fiselier         // is properly deleted
117aedcbf89SEric Fiselier         using T = std::tuple<std::unique_ptr<int>>;
118aedcbf89SEric Fiselier         static_assert(std::is_move_assignable<T>::value, "");
119aedcbf89SEric Fiselier         static_assert(!std::is_copy_assignable<T>::value, "");
120aedcbf89SEric Fiselier     }
121aedcbf89SEric Fiselier     {
122aedcbf89SEric Fiselier         using T = std::tuple<int, NonAssignable>;
123aedcbf89SEric Fiselier         static_assert(!std::is_move_assignable<T>::value, "");
124aedcbf89SEric Fiselier     }
125aedcbf89SEric Fiselier     {
126aedcbf89SEric Fiselier         using T = std::tuple<int, MoveAssignable>;
127aedcbf89SEric Fiselier         static_assert(std::is_move_assignable<T>::value, "");
128aedcbf89SEric Fiselier     }
129aedcbf89SEric Fiselier     {
130aedcbf89SEric Fiselier         // The move should decay to a copy.
131aedcbf89SEric Fiselier         CountAssign::reset();
132aedcbf89SEric Fiselier         using T = std::tuple<CountAssign, CopyAssignable>;
133aedcbf89SEric Fiselier         static_assert(std::is_move_assignable<T>::value, "");
134aedcbf89SEric Fiselier         T t1;
135aedcbf89SEric Fiselier         T t2;
136aedcbf89SEric Fiselier         t1 = std::move(t2);
137aedcbf89SEric Fiselier         assert(CountAssign::copied == 1);
138aedcbf89SEric Fiselier         assert(CountAssign::moved == 0);
139aedcbf89SEric Fiselier     }
140a0839b14SLouis Dionne     {
141a0839b14SLouis Dionne         using T = std::tuple<int, NonAssignable>;
142a0839b14SLouis Dionne         static_assert(!std::is_move_assignable<T>::value, "");
143a0839b14SLouis Dionne     }
144a0839b14SLouis Dionne     {
145a0839b14SLouis Dionne         using T = std::tuple<int, MoveAssignable>;
146a0839b14SLouis Dionne         static_assert(std::is_move_assignable<T>::value, "");
147a0839b14SLouis Dionne     }
148a0839b14SLouis Dionne     {
149a0839b14SLouis Dionne         using T = std::tuple<NothrowMoveAssignable, int>;
150a0839b14SLouis Dionne         static_assert(std::is_nothrow_move_assignable<T>::value, "");
151a0839b14SLouis Dionne     }
152a0839b14SLouis Dionne     {
153a0839b14SLouis Dionne         using T = std::tuple<PotentiallyThrowingMoveAssignable, int>;
154a0839b14SLouis Dionne         static_assert(!std::is_nothrow_move_assignable<T>::value, "");
155a0839b14SLouis Dionne     }
156618862e8SLouis Dionne     {
157618862e8SLouis Dionne         // We assign through the reference and don't move out of the incoming ref,
158618862e8SLouis Dionne         // so this doesn't work (but would if the type were CopyAssignable).
159618862e8SLouis Dionne         using T1 = std::tuple<MoveAssignable&, int>;
160618862e8SLouis Dionne         static_assert(!std::is_move_assignable<T1>::value, "");
161618862e8SLouis Dionne 
162618862e8SLouis Dionne         // ... works if it's CopyAssignable
163618862e8SLouis Dionne         using T2 = std::tuple<CopyAssignable&, int>;
164618862e8SLouis Dionne         static_assert(std::is_move_assignable<T2>::value, "");
165618862e8SLouis Dionne 
166618862e8SLouis Dionne         // For rvalue-references, we can move-assign if the type is MoveAssignable
167618862e8SLouis Dionne         // or CopyAssignable (since in the worst case the move will decay into a copy).
168618862e8SLouis Dionne         using T3 = std::tuple<MoveAssignable&&, int>;
169618862e8SLouis Dionne         using T4 = std::tuple<CopyAssignable&&, int>;
170618862e8SLouis Dionne         static_assert(std::is_move_assignable<T3>::value, "");
171618862e8SLouis Dionne         static_assert(std::is_move_assignable<T4>::value, "");
172618862e8SLouis Dionne 
173618862e8SLouis Dionne         // In all cases, we can't move-assign if the types are not assignable,
174618862e8SLouis Dionne         // since we assign through the reference.
175618862e8SLouis Dionne         using T5 = std::tuple<NonAssignable&, int>;
176618862e8SLouis Dionne         using T6 = std::tuple<NonAssignable&&, int>;
177618862e8SLouis Dionne         static_assert(!std::is_move_assignable<T5>::value, "");
178618862e8SLouis Dionne         static_assert(!std::is_move_assignable<T6>::value, "");
179618862e8SLouis Dionne     }
1802df59c50SJF Bastien 
1812df59c50SJF Bastien     return 0;
1825a83710eSEric Fiselier }
183