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