• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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