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

source code of libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp