Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / std / utilities / variant / variant.variant / variant.ctor / move.pass.cpp
blob308461e93f78d16d0d64f193d3ac6a2b59774b18
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 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
11 // XFAIL: availability-bad_variant_access-missing && !no-exceptions
13 // <variant>
15 // template <class ...Types> class variant;
17 // constexpr variant(variant&&) noexcept(see below);
19 #include <cassert>
20 #include <string>
21 #include <type_traits>
22 #include <variant>
24 #include "test_macros.h"
25 #include "test_workarounds.h"
27 struct ThrowsMove {
28 ThrowsMove(ThrowsMove &&) noexcept(false) {}
31 struct NoCopy {
32 NoCopy(const NoCopy &) = delete;
35 struct MoveOnly {
36 int value;
37 MoveOnly(int v) : value(v) {}
38 MoveOnly(const MoveOnly &) = delete;
39 MoveOnly(MoveOnly &&) = default;
42 struct MoveOnlyNT {
43 int value;
44 MoveOnlyNT(int v) : value(v) {}
45 MoveOnlyNT(const MoveOnlyNT &) = delete;
46 MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
49 struct NTMove {
50 constexpr NTMove(int v) : value(v) {}
51 NTMove(const NTMove &) = delete;
52 NTMove(NTMove &&that) : value(that.value) { that.value = -1; }
53 int value;
56 static_assert(!std::is_trivially_move_constructible<NTMove>::value, "");
57 static_assert(std::is_move_constructible<NTMove>::value, "");
59 struct TMove {
60 constexpr TMove(int v) : value(v) {}
61 TMove(const TMove &) = delete;
62 TMove(TMove &&) = default;
63 int value;
66 static_assert(std::is_trivially_move_constructible<TMove>::value, "");
68 struct TMoveNTCopy {
69 constexpr TMoveNTCopy(int v) : value(v) {}
70 TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {}
71 TMoveNTCopy(TMoveNTCopy&&) = default;
72 int value;
75 static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");
77 #ifndef TEST_HAS_NO_EXCEPTIONS
78 struct MakeEmptyT {
79 static int alive;
80 MakeEmptyT() { ++alive; }
81 MakeEmptyT(const MakeEmptyT &) {
82 ++alive;
83 // Don't throw from the copy constructor since variant's assignment
84 // operator performs a copy before committing to the assignment.
86 MakeEmptyT(MakeEmptyT &&) { throw 42; }
87 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
88 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
89 ~MakeEmptyT() { --alive; }
92 int MakeEmptyT::alive = 0;
94 template <class Variant> void makeEmpty(Variant &v) {
95 Variant v2(std::in_place_type<MakeEmptyT>);
96 try {
97 v = std::move(v2);
98 assert(false);
99 } catch (...) {
100 assert(v.valueless_by_exception());
103 #endif // TEST_HAS_NO_EXCEPTIONS
105 void test_move_noexcept() {
107 using V = std::variant<int, long>;
108 static_assert(std::is_nothrow_move_constructible<V>::value, "");
111 using V = std::variant<int, MoveOnly>;
112 static_assert(std::is_nothrow_move_constructible<V>::value, "");
115 using V = std::variant<int, MoveOnlyNT>;
116 static_assert(!std::is_nothrow_move_constructible<V>::value, "");
119 using V = std::variant<int, ThrowsMove>;
120 static_assert(!std::is_nothrow_move_constructible<V>::value, "");
124 void test_move_ctor_sfinae() {
126 using V = std::variant<int, long>;
127 static_assert(std::is_move_constructible<V>::value, "");
130 using V = std::variant<int, MoveOnly>;
131 static_assert(std::is_move_constructible<V>::value, "");
134 using V = std::variant<int, MoveOnlyNT>;
135 static_assert(std::is_move_constructible<V>::value, "");
138 using V = std::variant<int, NoCopy>;
139 static_assert(!std::is_move_constructible<V>::value, "");
142 // Make sure we properly propagate triviality (see P0602R4).
144 using V = std::variant<int, long>;
145 static_assert(std::is_trivially_move_constructible<V>::value, "");
148 using V = std::variant<int, NTMove>;
149 static_assert(!std::is_trivially_move_constructible<V>::value, "");
150 static_assert(std::is_move_constructible<V>::value, "");
153 using V = std::variant<int, TMove>;
154 static_assert(std::is_trivially_move_constructible<V>::value, "");
157 using V = std::variant<int, TMoveNTCopy>;
158 static_assert(std::is_trivially_move_constructible<V>::value, "");
162 template <typename T>
163 struct Result { std::size_t index; T value; };
165 void test_move_ctor_basic() {
167 std::variant<int> v(std::in_place_index<0>, 42);
168 std::variant<int> v2 = std::move(v);
169 assert(v2.index() == 0);
170 assert(std::get<0>(v2) == 42);
173 std::variant<int, long> v(std::in_place_index<1>, 42);
174 std::variant<int, long> v2 = std::move(v);
175 assert(v2.index() == 1);
176 assert(std::get<1>(v2) == 42);
179 std::variant<MoveOnly> v(std::in_place_index<0>, 42);
180 assert(v.index() == 0);
181 std::variant<MoveOnly> v2(std::move(v));
182 assert(v2.index() == 0);
183 assert(std::get<0>(v2).value == 42);
186 std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
187 assert(v.index() == 1);
188 std::variant<int, MoveOnly> v2(std::move(v));
189 assert(v2.index() == 1);
190 assert(std::get<1>(v2).value == 42);
193 std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
194 assert(v.index() == 0);
195 std::variant<MoveOnlyNT> v2(std::move(v));
196 assert(v2.index() == 0);
197 assert(std::get<0>(v).value == -1);
198 assert(std::get<0>(v2).value == 42);
201 std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
202 assert(v.index() == 1);
203 std::variant<int, MoveOnlyNT> v2(std::move(v));
204 assert(v2.index() == 1);
205 assert(std::get<1>(v).value == -1);
206 assert(std::get<1>(v2).value == 42);
209 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
211 struct {
212 constexpr Result<int> operator()() const {
213 std::variant<int> v(std::in_place_index<0>, 42);
214 std::variant<int> v2 = std::move(v);
215 return {v2.index(), std::get<0>(std::move(v2))};
217 } test;
218 constexpr auto result = test();
219 static_assert(result.index == 0, "");
220 static_assert(result.value == 42, "");
223 struct {
224 constexpr Result<long> operator()() const {
225 std::variant<int, long> v(std::in_place_index<1>, 42);
226 std::variant<int, long> v2 = std::move(v);
227 return {v2.index(), std::get<1>(std::move(v2))};
229 } test;
230 constexpr auto result = test();
231 static_assert(result.index == 1, "");
232 static_assert(result.value == 42, "");
235 struct {
236 constexpr Result<TMove> operator()() const {
237 std::variant<TMove> v(std::in_place_index<0>, 42);
238 std::variant<TMove> v2(std::move(v));
239 return {v2.index(), std::get<0>(std::move(v2))};
241 } test;
242 constexpr auto result = test();
243 static_assert(result.index == 0, "");
244 static_assert(result.value.value == 42, "");
247 struct {
248 constexpr Result<TMove> operator()() const {
249 std::variant<int, TMove> v(std::in_place_index<1>, 42);
250 std::variant<int, TMove> v2(std::move(v));
251 return {v2.index(), std::get<1>(std::move(v2))};
253 } test;
254 constexpr auto result = test();
255 static_assert(result.index == 1, "");
256 static_assert(result.value.value == 42, "");
259 struct {
260 constexpr Result<TMoveNTCopy> operator()() const {
261 std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42);
262 std::variant<TMoveNTCopy> v2(std::move(v));
263 return {v2.index(), std::get<0>(std::move(v2))};
265 } test;
266 constexpr auto result = test();
267 static_assert(result.index == 0, "");
268 static_assert(result.value.value == 42, "");
271 struct {
272 constexpr Result<TMoveNTCopy> operator()() const {
273 std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42);
274 std::variant<int, TMoveNTCopy> v2(std::move(v));
275 return {v2.index(), std::get<1>(std::move(v2))};
277 } test;
278 constexpr auto result = test();
279 static_assert(result.index == 1, "");
280 static_assert(result.value.value == 42, "");
284 void test_move_ctor_valueless_by_exception() {
285 #ifndef TEST_HAS_NO_EXCEPTIONS
286 using V = std::variant<int, MakeEmptyT>;
287 V v1;
288 makeEmpty(v1);
289 V v(std::move(v1));
290 assert(v.valueless_by_exception());
291 #endif // TEST_HAS_NO_EXCEPTIONS
294 template <std::size_t Idx>
295 constexpr bool test_constexpr_ctor_imp(std::variant<long, void*, const int> const& v) {
296 auto copy = v;
297 auto v2 = std::move(copy);
298 return v2.index() == v.index() &&
299 v2.index() == Idx &&
300 std::get<Idx>(v2) == std::get<Idx>(v);
303 void test_constexpr_move_ctor() {
304 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
305 using V = std::variant<long, void*, const int>;
306 #ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
307 static_assert(std::is_trivially_destructible<V>::value, "");
308 static_assert(std::is_trivially_copy_constructible<V>::value, "");
309 static_assert(std::is_trivially_move_constructible<V>::value, "");
310 static_assert(!std::is_copy_assignable<V>::value, "");
311 static_assert(!std::is_move_assignable<V>::value, "");
312 #else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
313 static_assert(std::is_trivially_copyable<V>::value, "");
314 #endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
315 static_assert(std::is_trivially_move_constructible<V>::value, "");
316 static_assert(test_constexpr_ctor_imp<0>(V(42l)), "");
317 static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), "");
318 static_assert(test_constexpr_ctor_imp<2>(V(101)), "");
321 int main(int, char**) {
322 test_move_ctor_basic();
323 test_move_ctor_valueless_by_exception();
324 test_move_noexcept();
325 test_move_ctor_sfinae();
326 test_constexpr_move_ctor();
328 return 0;