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 // XFAIL: availability=macosx10.13
14 // XFAIL: availability=macosx10.12
15 // XFAIL: availability=macosx10.11
16 // XFAIL: availability=macosx10.10
17 // XFAIL: availability=macosx10.9
18 // XFAIL: availability=macosx10.8
19 // XFAIL: availability=macosx10.7
20
21 // <variant>
22
23 // template <class ...Types> class variant;
24
25 // variant(variant const&); // constexpr in C++20
26
27 #include <cassert>
28 #include <type_traits>
29 #include <variant>
30
31 #include "test_macros.h"
32 #include "test_workarounds.h"
33
34 struct NonT {
NonTNonT35 NonT(int v) : value(v) {}
NonTNonT36 NonT(const NonT &o) : value(o.value) {}
37 int value;
38 };
39 static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
40
41 struct NoCopy {
42 NoCopy(const NoCopy &) = delete;
43 };
44
45 struct MoveOnly {
46 MoveOnly(const MoveOnly &) = delete;
47 MoveOnly(MoveOnly &&) = default;
48 };
49
50 struct MoveOnlyNT {
51 MoveOnlyNT(const MoveOnlyNT &) = delete;
MoveOnlyNTMoveOnlyNT52 MoveOnlyNT(MoveOnlyNT &&) {}
53 };
54
55 struct NTCopy {
NTCopyNTCopy56 constexpr NTCopy(int v) : value(v) {}
NTCopyNTCopy57 NTCopy(const NTCopy &that) : value(that.value) {}
58 NTCopy(NTCopy &&) = delete;
59 int value;
60 };
61
62 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
63 static_assert(std::is_copy_constructible<NTCopy>::value, "");
64
65 struct TCopy {
TCopyTCopy66 constexpr TCopy(int v) : value(v) {}
67 TCopy(TCopy const &) = default;
68 TCopy(TCopy &&) = delete;
69 int value;
70 };
71
72 static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
73
74 struct TCopyNTMove {
TCopyNTMoveTCopyNTMove75 constexpr TCopyNTMove(int v) : value(v) {}
76 TCopyNTMove(const TCopyNTMove&) = default;
TCopyNTMoveTCopyNTMove77 TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
78 int value;
79 };
80
81 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
82
83 #ifndef TEST_HAS_NO_EXCEPTIONS
84 struct MakeEmptyT {
85 static int alive;
MakeEmptyTMakeEmptyT86 MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT87 MakeEmptyT(const MakeEmptyT &) {
88 ++alive;
89 // Don't throw from the copy constructor since variant's assignment
90 // operator performs a copy before committing to the assignment.
91 }
MakeEmptyTMakeEmptyT92 MakeEmptyT(MakeEmptyT &&) { throw 42; }
operator =MakeEmptyT93 MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
operator =MakeEmptyT94 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
~MakeEmptyTMakeEmptyT95 ~MakeEmptyT() { --alive; }
96 };
97
98 int MakeEmptyT::alive = 0;
99
makeEmpty(Variant & v)100 template <class Variant> void makeEmpty(Variant &v) {
101 Variant v2(std::in_place_type<MakeEmptyT>);
102 try {
103 v = std::move(v2);
104 assert(false);
105 } catch (...) {
106 assert(v.valueless_by_exception());
107 }
108 }
109 #endif // TEST_HAS_NO_EXCEPTIONS
110
test_copy_ctor_sfinae()111 void test_copy_ctor_sfinae() {
112 {
113 using V = std::variant<int, long>;
114 static_assert(std::is_copy_constructible<V>::value, "");
115 }
116 {
117 using V = std::variant<int, NoCopy>;
118 static_assert(!std::is_copy_constructible<V>::value, "");
119 }
120 {
121 using V = std::variant<int, MoveOnly>;
122 static_assert(!std::is_copy_constructible<V>::value, "");
123 }
124 {
125 using V = std::variant<int, MoveOnlyNT>;
126 static_assert(!std::is_copy_constructible<V>::value, "");
127 }
128
129 // Make sure we properly propagate triviality (see P0602R4).
130 #if TEST_STD_VER > 17
131 {
132 using V = std::variant<int, long>;
133 static_assert(std::is_trivially_copy_constructible<V>::value, "");
134 }
135 {
136 using V = std::variant<int, NTCopy>;
137 static_assert(!std::is_trivially_copy_constructible<V>::value, "");
138 static_assert(std::is_copy_constructible<V>::value, "");
139 }
140 {
141 using V = std::variant<int, TCopy>;
142 static_assert(std::is_trivially_copy_constructible<V>::value, "");
143 }
144 {
145 using V = std::variant<int, TCopyNTMove>;
146 static_assert(std::is_trivially_copy_constructible<V>::value, "");
147 }
148 #endif // > C++17
149 }
150
test_copy_ctor_basic()151 void test_copy_ctor_basic() {
152 {
153 std::variant<int> v(std::in_place_index<0>, 42);
154 std::variant<int> v2 = v;
155 assert(v2.index() == 0);
156 assert(std::get<0>(v2) == 42);
157 }
158 {
159 std::variant<int, long> v(std::in_place_index<1>, 42);
160 std::variant<int, long> v2 = v;
161 assert(v2.index() == 1);
162 assert(std::get<1>(v2) == 42);
163 }
164 {
165 std::variant<NonT> v(std::in_place_index<0>, 42);
166 assert(v.index() == 0);
167 std::variant<NonT> v2(v);
168 assert(v2.index() == 0);
169 assert(std::get<0>(v2).value == 42);
170 }
171 {
172 std::variant<int, NonT> v(std::in_place_index<1>, 42);
173 assert(v.index() == 1);
174 std::variant<int, NonT> v2(v);
175 assert(v2.index() == 1);
176 assert(std::get<1>(v2).value == 42);
177 }
178
179 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
180 #if TEST_STD_VER > 17
181 {
182 constexpr std::variant<int> v(std::in_place_index<0>, 42);
183 static_assert(v.index() == 0, "");
184 constexpr std::variant<int> v2 = v;
185 static_assert(v2.index() == 0, "");
186 static_assert(std::get<0>(v2) == 42, "");
187 }
188 {
189 constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
190 static_assert(v.index() == 1, "");
191 constexpr std::variant<int, long> v2 = v;
192 static_assert(v2.index() == 1, "");
193 static_assert(std::get<1>(v2) == 42, "");
194 }
195 {
196 constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
197 static_assert(v.index() == 0, "");
198 constexpr std::variant<TCopy> v2(v);
199 static_assert(v2.index() == 0, "");
200 static_assert(std::get<0>(v2).value == 42, "");
201 }
202 {
203 constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
204 static_assert(v.index() == 1, "");
205 constexpr std::variant<int, TCopy> v2(v);
206 static_assert(v2.index() == 1, "");
207 static_assert(std::get<1>(v2).value == 42, "");
208 }
209 {
210 constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
211 static_assert(v.index() == 0, "");
212 constexpr std::variant<TCopyNTMove> v2(v);
213 static_assert(v2.index() == 0, "");
214 static_assert(std::get<0>(v2).value == 42, "");
215 }
216 {
217 constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
218 static_assert(v.index() == 1, "");
219 constexpr std::variant<int, TCopyNTMove> v2(v);
220 static_assert(v2.index() == 1, "");
221 static_assert(std::get<1>(v2).value == 42, "");
222 }
223 #endif // > C++17
224 }
225
test_copy_ctor_valueless_by_exception()226 void test_copy_ctor_valueless_by_exception() {
227 #ifndef TEST_HAS_NO_EXCEPTIONS
228 using V = std::variant<int, MakeEmptyT>;
229 V v1;
230 makeEmpty(v1);
231 const V &cv1 = v1;
232 V v(cv1);
233 assert(v.valueless_by_exception());
234 #endif // TEST_HAS_NO_EXCEPTIONS
235 }
236
237 template <size_t Idx>
test_constexpr_copy_ctor_imp(std::variant<long,void *,const int> const & v)238 constexpr bool test_constexpr_copy_ctor_imp(std::variant<long, void*, const int> const& v) {
239 auto v2 = v;
240 return v2.index() == v.index() &&
241 v2.index() == Idx &&
242 std::get<Idx>(v2) == std::get<Idx>(v);
243 }
244
test_constexpr_copy_ctor()245 void test_constexpr_copy_ctor() {
246 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
247 #if TEST_STD_VER > 17
248 using V = std::variant<long, void*, const int>;
249 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
250 static_assert(std::is_trivially_destructible<V>::value, "");
251 static_assert(std::is_trivially_copy_constructible<V>::value, "");
252 static_assert(std::is_trivially_move_constructible<V>::value, "");
253 static_assert(!std::is_copy_assignable<V>::value, "");
254 static_assert(!std::is_move_assignable<V>::value, "");
255 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
256 static_assert(std::is_trivially_copyable<V>::value, "");
257 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
258 static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), "");
259 static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), "");
260 static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), "");
261 #endif // > C++17
262 }
263
main()264 int main() {
265 test_copy_ctor_basic();
266 test_copy_ctor_valueless_by_exception();
267 test_copy_ctor_sfinae();
268 test_constexpr_copy_ctor();
269 #if 0
270 // disable this for the moment; it fails on older compilers.
271 // Need to figure out which compilers will support it.
272 { // This is the motivating example from P0739R0
273 std::variant<int, double> v1(3);
274 std::variant v2 = v1;
275 (void) v2;
276 }
277 #endif
278 }
279