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// template <class T>
25// variant& operator=(T&&) noexcept(see below);
26
27#include <cassert>
28#include <string>
29#include <type_traits>
30#include <variant>
31
32#include "test_macros.h"
33#include "variant_test_helpers.hpp"
34
35namespace MetaHelpers {
36
37struct Dummy {
38  Dummy() = default;
39};
40
41struct ThrowsCtorT {
42  ThrowsCtorT(int) noexcept(false) {}
43  ThrowsCtorT &operator=(int) noexcept { return *this; }
44};
45
46struct ThrowsAssignT {
47  ThrowsAssignT(int) noexcept {}
48  ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
49};
50
51struct NoThrowT {
52  NoThrowT(int) noexcept {}
53  NoThrowT &operator=(int) noexcept { return *this; }
54};
55
56} // namespace MetaHelpers
57
58namespace RuntimeHelpers {
59#ifndef TEST_HAS_NO_EXCEPTIONS
60
61struct ThrowsCtorT {
62  int value;
63  ThrowsCtorT() : value(0) {}
64  ThrowsCtorT(int) noexcept(false) { throw 42; }
65  ThrowsCtorT &operator=(int v) noexcept {
66    value = v;
67    return *this;
68  }
69};
70
71struct MoveCrashes {
72  int value;
73  MoveCrashes(int v = 0) noexcept : value{v} {}
74  MoveCrashes(MoveCrashes &&) noexcept { assert(false); }
75  MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; }
76  MoveCrashes &operator=(int v) noexcept {
77    value = v;
78    return *this;
79  }
80};
81
82struct ThrowsCtorTandMove {
83  int value;
84  ThrowsCtorTandMove() : value(0) {}
85  ThrowsCtorTandMove(int) noexcept(false) { throw 42; }
86  ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); }
87  ThrowsCtorTandMove &operator=(int v) noexcept {
88    value = v;
89    return *this;
90  }
91};
92
93struct ThrowsAssignT {
94  int value;
95  ThrowsAssignT() : value(0) {}
96  ThrowsAssignT(int v) noexcept : value(v) {}
97  ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
98};
99
100struct NoThrowT {
101  int value;
102  NoThrowT() : value(0) {}
103  NoThrowT(int v) noexcept : value(v) {}
104  NoThrowT &operator=(int v) noexcept {
105    value = v;
106    return *this;
107  }
108};
109
110#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
111} // namespace RuntimeHelpers
112
113void test_T_assignment_noexcept() {
114  using namespace MetaHelpers;
115  {
116    using V = std::variant<Dummy, NoThrowT>;
117    static_assert(std::is_nothrow_assignable<V, int>::value, "");
118  }
119  {
120    using V = std::variant<Dummy, ThrowsCtorT>;
121    static_assert(!std::is_nothrow_assignable<V, int>::value, "");
122  }
123  {
124    using V = std::variant<Dummy, ThrowsAssignT>;
125    static_assert(!std::is_nothrow_assignable<V, int>::value, "");
126  }
127}
128
129void test_T_assignment_sfinae() {
130  {
131    using V = std::variant<long, unsigned>;
132    static_assert(!std::is_assignable<V, int>::value, "ambiguous");
133  }
134  {
135    using V = std::variant<std::string, std::string>;
136    static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
137  }
138  {
139    using V = std::variant<std::string, void *>;
140    static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
141  }
142#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
143  {
144    using V = std::variant<int, int &&>;
145    static_assert(!std::is_assignable<V, int>::value, "ambiguous");
146  }
147  {
148    using V = std::variant<int, const int &>;
149    static_assert(!std::is_assignable<V, int>::value, "ambiguous");
150  }
151#endif // TEST_VARIANT_HAS_NO_REFERENCES
152}
153
154void test_T_assignment_basic() {
155  {
156    std::variant<int> v(43);
157    v = 42;
158    assert(v.index() == 0);
159    assert(std::get<0>(v) == 42);
160  }
161  {
162    std::variant<int, long> v(43l);
163    v = 42;
164    assert(v.index() == 0);
165    assert(std::get<0>(v) == 42);
166    v = 43l;
167    assert(v.index() == 1);
168    assert(std::get<1>(v) == 43);
169  }
170#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
171  {
172    using V = std::variant<int &, int &&, long>;
173    int x = 42;
174    V v(43l);
175    v = x;
176    assert(v.index() == 0);
177    assert(&std::get<0>(v) == &x);
178    v = std::move(x);
179    assert(v.index() == 1);
180    assert(&std::get<1>(v) == &x);
181    // 'long' is selected by FUN(const int &) since 'const int &' cannot bind
182    // to 'int&'.
183    const int &cx = x;
184    v = cx;
185    assert(v.index() == 2);
186    assert(std::get<2>(v) == 42);
187  }
188#endif // TEST_VARIANT_HAS_NO_REFERENCES
189}
190
191void test_T_assignment_performs_construction() {
192  using namespace RuntimeHelpers;
193#ifndef TEST_HAS_NO_EXCEPTIONS
194  {
195    using V = std::variant<std::string, ThrowsCtorT>;
196    V v(std::in_place_type<std::string>, "hello");
197    try {
198      v = 42;
199      assert(false);
200    } catch (...) { /* ... */
201    }
202    assert(v.index() == 0);
203    assert(std::get<0>(v) == "hello");
204  }
205  {
206    using V = std::variant<ThrowsAssignT, std::string>;
207    V v(std::in_place_type<std::string>, "hello");
208    v = 42;
209    assert(v.index() == 0);
210    assert(std::get<0>(v).value == 42);
211  }
212#endif // TEST_HAS_NO_EXCEPTIONS
213}
214
215void test_T_assignment_performs_assignment() {
216  using namespace RuntimeHelpers;
217#ifndef TEST_HAS_NO_EXCEPTIONS
218  {
219    using V = std::variant<ThrowsCtorT>;
220    V v;
221    v = 42;
222    assert(v.index() == 0);
223    assert(std::get<0>(v).value == 42);
224  }
225  {
226    using V = std::variant<ThrowsCtorT, std::string>;
227    V v;
228    v = 42;
229    assert(v.index() == 0);
230    assert(std::get<0>(v).value == 42);
231  }
232  {
233    using V = std::variant<ThrowsAssignT>;
234    V v(100);
235    try {
236      v = 42;
237      assert(false);
238    } catch (...) { /* ... */
239    }
240    assert(v.index() == 0);
241    assert(std::get<0>(v).value == 100);
242  }
243  {
244    using V = std::variant<std::string, ThrowsAssignT>;
245    V v(100);
246    try {
247      v = 42;
248      assert(false);
249    } catch (...) { /* ... */
250    }
251    assert(v.index() == 1);
252    assert(std::get<1>(v).value == 100);
253  }
254#endif // TEST_HAS_NO_EXCEPTIONS
255}
256
257int main() {
258  test_T_assignment_basic();
259  test_T_assignment_performs_construction();
260  test_T_assignment_performs_assignment();
261  test_T_assignment_noexcept();
262  test_T_assignment_sfinae();
263}
264