xref: /llvm-project/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp (revision a8b057483be7f3aa185e0fc9a3fc38c55c28f34f)
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 
35 namespace MetaHelpers {
36 
37 struct Dummy {
38   Dummy() = default;
39 };
40 
41 struct ThrowsCtorT {
42   ThrowsCtorT(int) noexcept(false) {}
43   ThrowsCtorT &operator=(int) noexcept { return *this; }
44 };
45 
46 struct ThrowsAssignT {
47   ThrowsAssignT(int) noexcept {}
48   ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
49 };
50 
51 struct NoThrowT {
52   NoThrowT(int) noexcept {}
53   NoThrowT &operator=(int) noexcept { return *this; }
54 };
55 
56 } // namespace MetaHelpers
57 
58 namespace RuntimeHelpers {
59 #ifndef TEST_HAS_NO_EXCEPTIONS
60 
61 struct 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 
71 struct 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 
82 struct 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 
93 struct 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 
100 struct 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 
113 void 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 
129 void 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 
154 void 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 
191 void 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 
215 void 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 
257 int 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