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 NonT(int v) : value(v) {}
26 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> void makeEmpty(Variant &v) {
91 Variant v2(std::in_place_type<MakeEmptyT>);
92 try {
93 v = std::move(v2);
94 assert(false);
95 } catch (...) {
96 assert(v.valueless_by_exception());
97 }
98}
99#endif // TEST_HAS_NO_EXCEPTIONS
100
101void test_copy_ctor_sfinae() {
102 {
103 using V = std::variant<int, long>;
104 static_assert(std::is_copy_constructible<V>::value, "");
105 }
106 {
107 using V = std::variant<int, NoCopy>;
108 static_assert(!std::is_copy_constructible<V>::value, "");
109 }
110 {
111 using V = std::variant<int, MoveOnly>;
112 static_assert(!std::is_copy_constructible<V>::value, "");
113 }
114 {
115 using V = std::variant<int, MoveOnlyNT>;
116 static_assert(!std::is_copy_constructible<V>::value, "");
117 }
118
119 // Make sure we properly propagate triviality (see P0602R4).
120 {
121 using V = std::variant<int, long>;
122 static_assert(std::is_trivially_copy_constructible<V>::value, "");
123 }
124 {
125 using V = std::variant<int, NTCopy>;
126 static_assert(!std::is_trivially_copy_constructible<V>::value, "");
127 static_assert(std::is_copy_constructible<V>::value, "");
128 }
129 {
130 using V = std::variant<int, TCopy>;
131 static_assert(std::is_trivially_copy_constructible<V>::value, "");
132 }
133 {
134 using V = std::variant<int, TCopyNTMove>;
135 static_assert(std::is_trivially_copy_constructible<V>::value, "");
136 }
137}
138
139void test_copy_ctor_basic() {
140 {
141 std::variant<int> v(std::in_place_index<0>, 42);
142 std::variant<int> v2 = v;
143 assert(v2.index() == 0);
144 assert(std::get<0>(v2) == 42);
145 }
146 {
147 std::variant<int, long> v(std::in_place_index<1>, 42);
148 std::variant<int, long> v2 = v;
149 assert(v2.index() == 1);
150 assert(std::get<1>(v2) == 42);
151 }
152 {
153 std::variant<NonT> v(std::in_place_index<0>, 42);
154 assert(v.index() == 0);
155 std::variant<NonT> v2(v);
156 assert(v2.index() == 0);
157 assert(std::get<0>(v2).value == 42);
158 }
159 {
160 std::variant<int, NonT> v(std::in_place_index<1>, 42);
161 assert(v.index() == 1);
162 std::variant<int, NonT> v2(v);
163 assert(v2.index() == 1);
164 assert(std::get<1>(v2).value == 42);
165 }
166
167 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
168 {
169 constexpr std::variant<int> v(std::in_place_index<0>, 42);
170 static_assert(v.index() == 0, "");
171 constexpr std::variant<int> v2 = v;
172 static_assert(v2.index() == 0, "");
173 static_assert(std::get<0>(v: v2) == 42, "");
174 }
175 {
176 constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
177 static_assert(v.index() == 1, "");
178 constexpr std::variant<int, long> v2 = v;
179 static_assert(v2.index() == 1, "");
180 static_assert(std::get<1>(v: v2) == 42, "");
181 }
182 {
183 constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
184 static_assert(v.index() == 0, "");
185 constexpr std::variant<TCopy> v2(v);
186 static_assert(v2.index() == 0, "");
187 static_assert(std::get<0>(v: v2).value == 42, "");
188 }
189 {
190 constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
191 static_assert(v.index() == 1, "");
192 constexpr std::variant<int, TCopy> v2(v);
193 static_assert(v2.index() == 1, "");
194 static_assert(std::get<1>(v: v2).value == 42, "");
195 }
196 {
197 constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
198 static_assert(v.index() == 0, "");
199 constexpr std::variant<TCopyNTMove> v2(v);
200 static_assert(v2.index() == 0, "");
201 static_assert(std::get<0>(v: v2).value == 42, "");
202 }
203 {
204 constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
205 static_assert(v.index() == 1, "");
206 constexpr std::variant<int, TCopyNTMove> v2(v);
207 static_assert(v2.index() == 1, "");
208 static_assert(std::get<1>(v: v2).value == 42, "");
209 }
210}
211
212void test_copy_ctor_valueless_by_exception() {
213#ifndef TEST_HAS_NO_EXCEPTIONS
214 using V = std::variant<int, MakeEmptyT>;
215 V v1;
216 makeEmpty(v&: v1);
217 const V &cv1 = v1;
218 V v(cv1);
219 assert(v.valueless_by_exception());
220#endif // TEST_HAS_NO_EXCEPTIONS
221}
222
223template <std::size_t Idx>
224constexpr bool test_constexpr_copy_ctor_imp(std::variant<long, void*, const int> const& v) {
225 auto v2 = v;
226 return v2.index() == v.index() &&
227 v2.index() == Idx &&
228 std::get<Idx>(v2) == std::get<Idx>(v);
229}
230
231void test_constexpr_copy_ctor() {
232 // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
233 using V = std::variant<long, void*, const int>;
234#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
235 static_assert(std::is_trivially_destructible<V>::value, "");
236 static_assert(std::is_trivially_copy_constructible<V>::value, "");
237 static_assert(std::is_trivially_move_constructible<V>::value, "");
238 static_assert(!std::is_copy_assignable<V>::value, "");
239 static_assert(!std::is_move_assignable<V>::value, "");
240#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
241 static_assert(std::is_trivially_copyable<V>::value, "");
242#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
243 static_assert(test_constexpr_copy_ctor_imp<0>(v: V(42l)), "");
244 static_assert(test_constexpr_copy_ctor_imp<1>(v: V(nullptr)), "");
245 static_assert(test_constexpr_copy_ctor_imp<2>(v: V(101)), "");
246}
247
248int main(int, char**) {
249 test_copy_ctor_basic();
250 test_copy_ctor_valueless_by_exception();
251 test_copy_ctor_sfinae();
252 test_constexpr_copy_ctor();
253 return 0;
254}
255

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