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