1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // The LLVM Compiler Infrastructure
5 //
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10
11 // UNSUPPORTED: c++98, c++03, c++11, c++14
12
13 // <variant>
14
15 // template <class ...Types> class variant;
16
17 // variant(variant&&) noexcept(see below);
18
19 #include <cassert>
20 #include <string>
21 #include <type_traits>
22 #include <variant>
23
24 #include "test_macros.h"
25
26 struct ThrowsMove {
ThrowsMoveThrowsMove27 ThrowsMove(ThrowsMove &&) noexcept(false) {}
28 };
29
30 struct NoCopy {
31 NoCopy(const NoCopy &) = delete;
32 };
33
34 struct MoveOnly {
35 int value;
MoveOnlyMoveOnly36 MoveOnly(int v) : value(v) {}
37 MoveOnly(const MoveOnly &) = delete;
38 MoveOnly(MoveOnly &&) = default;
39 };
40
41 struct MoveOnlyNT {
42 int value;
MoveOnlyNTMoveOnlyNT43 MoveOnlyNT(int v) : value(v) {}
44 MoveOnlyNT(const MoveOnlyNT &) = delete;
MoveOnlyNTMoveOnlyNT45 MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
46 };
47
48 #ifndef TEST_HAS_NO_EXCEPTIONS
49 struct MakeEmptyT {
50 static int alive;
MakeEmptyTMakeEmptyT51 MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT52 MakeEmptyT(const MakeEmptyT &) {
53 ++alive;
54 // Don't throw from the copy constructor since variant's assignment
55 // operator performs a copy before committing to the assignment.
56 }
MakeEmptyTMakeEmptyT57 MakeEmptyT(MakeEmptyT &&) { throw 42; }
operator =MakeEmptyT58 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
operator =MakeEmptyT59 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
~MakeEmptyTMakeEmptyT60 ~MakeEmptyT() { --alive; }
61 };
62
63 int MakeEmptyT::alive = 0;
64
makeEmpty(Variant & v)65 template <class Variant> void makeEmpty(Variant &v) {
66 Variant v2(std::in_place_type<MakeEmptyT>);
67 try {
68 v = v2;
69 assert(false);
70 } catch (...) {
71 assert(v.valueless_by_exception());
72 }
73 }
74 #endif // TEST_HAS_NO_EXCEPTIONS
75
test_move_noexcept()76 void test_move_noexcept() {
77 {
78 using V = std::variant<int, long>;
79 static_assert(std::is_nothrow_move_constructible<V>::value, "");
80 }
81 {
82 using V = std::variant<int, MoveOnly>;
83 static_assert(std::is_nothrow_move_constructible<V>::value, "");
84 }
85 {
86 using V = std::variant<int, MoveOnlyNT>;
87 static_assert(!std::is_nothrow_move_constructible<V>::value, "");
88 }
89 {
90 using V = std::variant<int, ThrowsMove>;
91 static_assert(!std::is_nothrow_move_constructible<V>::value, "");
92 }
93 }
94
test_move_ctor_sfinae()95 void test_move_ctor_sfinae() {
96 {
97 using V = std::variant<int, long>;
98 static_assert(std::is_move_constructible<V>::value, "");
99 }
100 {
101 using V = std::variant<int, MoveOnly>;
102 static_assert(std::is_move_constructible<V>::value, "");
103 }
104 {
105 using V = std::variant<int, MoveOnlyNT>;
106 static_assert(std::is_move_constructible<V>::value, "");
107 }
108 {
109 using V = std::variant<int, NoCopy>;
110 static_assert(!std::is_move_constructible<V>::value, "");
111 }
112 }
113
test_move_ctor_basic()114 void test_move_ctor_basic() {
115 {
116 std::variant<int> v(std::in_place_index<0>, 42);
117 std::variant<int> v2 = std::move(v);
118 assert(v2.index() == 0);
119 assert(std::get<0>(v2) == 42);
120 }
121 {
122 std::variant<int, long> v(std::in_place_index<1>, 42);
123 std::variant<int, long> v2 = std::move(v);
124 assert(v2.index() == 1);
125 assert(std::get<1>(v2) == 42);
126 }
127 {
128 std::variant<MoveOnly> v(std::in_place_index<0>, 42);
129 assert(v.index() == 0);
130 std::variant<MoveOnly> v2(std::move(v));
131 assert(v2.index() == 0);
132 assert(std::get<0>(v2).value == 42);
133 }
134 {
135 std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
136 assert(v.index() == 1);
137 std::variant<int, MoveOnly> v2(std::move(v));
138 assert(v2.index() == 1);
139 assert(std::get<1>(v2).value == 42);
140 }
141 {
142 std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
143 assert(v.index() == 0);
144 std::variant<MoveOnlyNT> v2(std::move(v));
145 assert(v2.index() == 0);
146 assert(std::get<0>(v).value == -1);
147 assert(std::get<0>(v2).value == 42);
148 }
149 {
150 std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
151 assert(v.index() == 1);
152 std::variant<int, MoveOnlyNT> v2(std::move(v));
153 assert(v2.index() == 1);
154 assert(std::get<1>(v).value == -1);
155 assert(std::get<1>(v2).value == 42);
156 }
157 }
158
test_move_ctor_valueless_by_exception()159 void test_move_ctor_valueless_by_exception() {
160 #ifndef TEST_HAS_NO_EXCEPTIONS
161 using V = std::variant<int, MakeEmptyT>;
162 V v1;
163 makeEmpty(v1);
164 V v(std::move(v1));
165 assert(v.valueless_by_exception());
166 #endif
167 }
168
169 template <size_t Idx>
test_constexpr_ctor_extension_imp(std::variant<long,void *,const int> const & v)170 constexpr bool test_constexpr_ctor_extension_imp(
171 std::variant<long, void*, const int> const& v)
172 {
173 auto copy = v;
174 auto v2 = std::move(copy);
175 return v2.index() == v.index() &&
176 v2.index() == Idx &&
177 std::get<Idx>(v2) == std::get<Idx>(v);
178 }
179
test_constexpr_move_ctor_extension()180 void test_constexpr_move_ctor_extension() {
181 #ifdef _LIBCPP_VERSION
182 using V = std::variant<long, void*, const int>;
183 static_assert(std::is_trivially_copyable<V>::value, "");
184 static_assert(std::is_trivially_move_constructible<V>::value, "");
185 static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), "");
186 static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), "");
187 static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), "");
188 #endif
189 }
190
main()191 int main() {
192 test_move_ctor_basic();
193 test_move_ctor_valueless_by_exception();
194 test_move_noexcept();
195 test_move_ctor_sfinae();
196 test_constexpr_move_ctor_extension();
197 }
198