xref: /llvm-project/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp (revision 52271a5c11f6abde1fa1221db304212b5eb8ec7c)
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 
24 struct NonT {
NonTNonT25   constexpr NonT(int v) : value(v) {}
NonTNonT26   constexpr NonT(const NonT& o) : value(o.value) {}
27   int value;
28 };
29 static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
30 
31 struct NoCopy {
32   NoCopy(const NoCopy&) = delete;
33 };
34 
35 struct MoveOnly {
36   MoveOnly(const MoveOnly&) = delete;
37   MoveOnly(MoveOnly&&)      = default;
38 };
39 
40 struct MoveOnlyNT {
41   MoveOnlyNT(const MoveOnlyNT&) = delete;
MoveOnlyNTMoveOnlyNT42   MoveOnlyNT(MoveOnlyNT&&) {}
43 };
44 
45 struct NTCopy {
NTCopyNTCopy46   constexpr NTCopy(int v) : value(v) {}
NTCopyNTCopy47   NTCopy(const NTCopy& that) : value(that.value) {}
48   NTCopy(NTCopy&&) = delete;
49   int value;
50 };
51 
52 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
53 static_assert(std::is_copy_constructible<NTCopy>::value, "");
54 
55 struct TCopy {
TCopyTCopy56   constexpr TCopy(int v) : value(v) {}
57   TCopy(TCopy const&) = default;
58   TCopy(TCopy&&)      = delete;
59   int value;
60 };
61 
62 static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
63 
64 struct TCopyNTMove {
TCopyNTMoveTCopyNTMove65   constexpr TCopyNTMove(int v) : value(v) {}
66   TCopyNTMove(const TCopyNTMove&) = default;
TCopyNTMoveTCopyNTMove67   TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
68   int value;
69 };
70 
71 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
72 
73 #ifndef TEST_HAS_NO_EXCEPTIONS
74 struct MakeEmptyT {
75   static int alive;
MakeEmptyTMakeEmptyT76   MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT77   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   }
MakeEmptyTMakeEmptyT82   MakeEmptyT(MakeEmptyT&&) { throw 42; }
operator =MakeEmptyT83   MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }
operator =MakeEmptyT84   MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
~MakeEmptyTMakeEmptyT85   ~MakeEmptyT() { --alive; }
86 };
87 
88 int MakeEmptyT::alive = 0;
89 
90 template <class Variant>
makeEmpty(Variant & v)91 void 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 
test_copy_ctor_sfinae()102 constexpr 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 
test_copy_ctor_basic()140 TEST_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>(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>(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>(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>(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>(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>(v2).value == 42, "");
210   }
211 }
212 
test_copy_ctor_valueless_by_exception()213 void test_copy_ctor_valueless_by_exception() {
214 #ifndef TEST_HAS_NO_EXCEPTIONS
215   using V = std::variant<int, MakeEmptyT>;
216   V v1;
217   makeEmpty(v1);
218   const V& cv1 = v1;
219   V v(cv1);
220   assert(v.valueless_by_exception());
221 #endif // TEST_HAS_NO_EXCEPTIONS
222 }
223 
224 template <std::size_t Idx, class T>
test_constexpr_copy_ctor_imp(const T & v)225 constexpr 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 
test_constexpr_copy_ctor_trivial()232 constexpr 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(42l));
246   test_constexpr_copy_ctor_imp<1>(V(nullptr));
247   test_constexpr_copy_ctor_imp<2>(V(101));
248 }
249 
250 struct NonTrivialCopyCtor {
251   int i = 0;
NonTrivialCopyCtorNonTrivialCopyCtor252   constexpr NonTrivialCopyCtor(int ii) : i(ii) {}
NonTrivialCopyCtorNonTrivialCopyCtor253   constexpr NonTrivialCopyCtor(const NonTrivialCopyCtor& other) : i(other.i) {}
254   constexpr NonTrivialCopyCtor(NonTrivialCopyCtor&& other) = default;
255   TEST_CONSTEXPR_CXX20 ~NonTrivialCopyCtor()               = default;
operator ==(const NonTrivialCopyCtor & x,const NonTrivialCopyCtor & y)256   friend constexpr bool operator==(const NonTrivialCopyCtor& x, const NonTrivialCopyCtor& y) { return x.i == y.i; }
257 };
258 
test_constexpr_copy_ctor_non_trivial()259 TEST_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(42l));
264   test_constexpr_copy_ctor_imp<1>(V(NonTrivialCopyCtor(5)));
265   test_constexpr_copy_ctor_imp<2>(V(nullptr));
266 }
267 
non_constexpr_test()268 void non_constexpr_test() { test_copy_ctor_valueless_by_exception(); }
269 
cxx17_constexpr_test()270 constexpr bool cxx17_constexpr_test() {
271   test_copy_ctor_sfinae();
272   test_constexpr_copy_ctor_trivial();
273 
274   return true;
275 }
276 
cxx20_constexpr_test()277 TEST_CONSTEXPR_CXX20 bool cxx20_constexpr_test() {
278   test_copy_ctor_basic();
279   test_constexpr_copy_ctor_non_trivial();
280 
281   return true;
282 }
283 
main(int,char **)284 int 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