1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14
11 // XFAIL: availability-bad_variant_access-missing && !no-exceptions
15 // template <class ...Types> class variant;
17 // constexpr variant(variant&&) noexcept(see below);
21 #include <type_traits>
24 #include "test_macros.h"
25 #include "test_workarounds.h"
28 ThrowsMove(ThrowsMove
&&) noexcept(false) {}
32 NoCopy(const NoCopy
&) = delete;
37 MoveOnly(int v
) : value(v
) {}
38 MoveOnly(const MoveOnly
&) = delete;
39 MoveOnly(MoveOnly
&&) = default;
44 MoveOnlyNT(int v
) : value(v
) {}
45 MoveOnlyNT(const MoveOnlyNT
&) = delete;
46 MoveOnlyNT(MoveOnlyNT
&&other
) : value(other
.value
) { other
.value
= -1; }
50 constexpr NTMove(int v
) : value(v
) {}
51 NTMove(const NTMove
&) = delete;
52 NTMove(NTMove
&&that
) : value(that
.value
) { that
.value
= -1; }
56 static_assert(!std::is_trivially_move_constructible
<NTMove
>::value
, "");
57 static_assert(std::is_move_constructible
<NTMove
>::value
, "");
60 constexpr TMove(int v
) : value(v
) {}
61 TMove(const TMove
&) = delete;
62 TMove(TMove
&&) = default;
66 static_assert(std::is_trivially_move_constructible
<TMove
>::value
, "");
69 constexpr TMoveNTCopy(int v
) : value(v
) {}
70 TMoveNTCopy(const TMoveNTCopy
& that
) : value(that
.value
) {}
71 TMoveNTCopy(TMoveNTCopy
&&) = default;
75 static_assert(std::is_trivially_move_constructible
<TMoveNTCopy
>::value
, "");
77 #ifndef TEST_HAS_NO_EXCEPTIONS
80 MakeEmptyT() { ++alive
; }
81 MakeEmptyT(const MakeEmptyT
&) {
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
>);
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).
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
))};
218 constexpr auto result
= test();
219 static_assert(result
.index
== 0, "");
220 static_assert(result
.value
== 42, "");
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
))};
230 constexpr auto result
= test();
231 static_assert(result
.index
== 1, "");
232 static_assert(result
.value
== 42, "");
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
))};
242 constexpr auto result
= test();
243 static_assert(result
.index
== 0, "");
244 static_assert(result
.value
.value
== 42, "");
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
))};
254 constexpr auto result
= test();
255 static_assert(result
.index
== 1, "");
256 static_assert(result
.value
.value
== 42, "");
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
))};
266 constexpr auto result
= test();
267 static_assert(result
.index
== 0, "");
268 static_assert(result
.value
.value
== 42, "");
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
))};
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
>;
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
) {
297 auto v2
= std::move(copy
);
298 return v2
.index() == v
.index() &&
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();