• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++03, c++11, c++14
11 
12 // Throwing bad_variant_access is supported starting in macosx10.13
13 // XFAIL: with_system_cxx_lib=macosx10.12 && !no-exceptions
14 // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions
15 // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions
16 // XFAIL: with_system_cxx_lib=macosx10.9 && !no-exceptions
17 
18 // <variant>
19 
20 // template <class ...Types> class variant;
21 
22 // template <class T>
23 // variant& operator=(T&&) noexcept(see below);
24 
25 #include <cassert>
26 #include <string>
27 #include <type_traits>
28 #include <variant>
29 #include <memory>
30 
31 #include "test_macros.h"
32 #include "variant_test_helpers.h"
33 
34 namespace MetaHelpers {
35 
36 struct Dummy {
37   Dummy() = default;
38 };
39 
40 struct ThrowsCtorT {
ThrowsCtorTMetaHelpers::ThrowsCtorT41   ThrowsCtorT(int) noexcept(false) {}
operator =MetaHelpers::ThrowsCtorT42   ThrowsCtorT &operator=(int) noexcept { return *this; }
43 };
44 
45 struct ThrowsAssignT {
ThrowsAssignTMetaHelpers::ThrowsAssignT46   ThrowsAssignT(int) noexcept {}
operator =MetaHelpers::ThrowsAssignT47   ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
48 };
49 
50 struct NoThrowT {
NoThrowTMetaHelpers::NoThrowT51   NoThrowT(int) noexcept {}
operator =MetaHelpers::NoThrowT52   NoThrowT &operator=(int) noexcept { return *this; }
53 };
54 
55 } // namespace MetaHelpers
56 
57 namespace RuntimeHelpers {
58 #ifndef TEST_HAS_NO_EXCEPTIONS
59 
60 struct ThrowsCtorT {
61   int value;
ThrowsCtorTRuntimeHelpers::ThrowsCtorT62   ThrowsCtorT() : value(0) {}
ThrowsCtorTRuntimeHelpers::ThrowsCtorT63   ThrowsCtorT(int) noexcept(false) { throw 42; }
operator =RuntimeHelpers::ThrowsCtorT64   ThrowsCtorT &operator=(int v) noexcept {
65     value = v;
66     return *this;
67   }
68 };
69 
70 struct MoveCrashes {
71   int value;
MoveCrashesRuntimeHelpers::MoveCrashes72   MoveCrashes(int v = 0) noexcept : value{v} {}
MoveCrashesRuntimeHelpers::MoveCrashes73   MoveCrashes(MoveCrashes &&) noexcept { assert(false); }
operator =RuntimeHelpers::MoveCrashes74   MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; }
operator =RuntimeHelpers::MoveCrashes75   MoveCrashes &operator=(int v) noexcept {
76     value = v;
77     return *this;
78   }
79 };
80 
81 struct ThrowsCtorTandMove {
82   int value;
ThrowsCtorTandMoveRuntimeHelpers::ThrowsCtorTandMove83   ThrowsCtorTandMove() : value(0) {}
ThrowsCtorTandMoveRuntimeHelpers::ThrowsCtorTandMove84   ThrowsCtorTandMove(int) noexcept(false) { throw 42; }
ThrowsCtorTandMoveRuntimeHelpers::ThrowsCtorTandMove85   ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); }
operator =RuntimeHelpers::ThrowsCtorTandMove86   ThrowsCtorTandMove &operator=(int v) noexcept {
87     value = v;
88     return *this;
89   }
90 };
91 
92 struct ThrowsAssignT {
93   int value;
ThrowsAssignTRuntimeHelpers::ThrowsAssignT94   ThrowsAssignT() : value(0) {}
ThrowsAssignTRuntimeHelpers::ThrowsAssignT95   ThrowsAssignT(int v) noexcept : value(v) {}
operator =RuntimeHelpers::ThrowsAssignT96   ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
97 };
98 
99 struct NoThrowT {
100   int value;
NoThrowTRuntimeHelpers::NoThrowT101   NoThrowT() : value(0) {}
NoThrowTRuntimeHelpers::NoThrowT102   NoThrowT(int v) noexcept : value(v) {}
operator =RuntimeHelpers::NoThrowT103   NoThrowT &operator=(int v) noexcept {
104     value = v;
105     return *this;
106   }
107 };
108 
109 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
110 } // namespace RuntimeHelpers
111 
test_T_assignment_noexcept()112 void test_T_assignment_noexcept() {
113   using namespace MetaHelpers;
114   {
115     using V = std::variant<Dummy, NoThrowT>;
116     static_assert(std::is_nothrow_assignable<V, int>::value, "");
117   }
118   {
119     using V = std::variant<Dummy, ThrowsCtorT>;
120     static_assert(!std::is_nothrow_assignable<V, int>::value, "");
121   }
122   {
123     using V = std::variant<Dummy, ThrowsAssignT>;
124     static_assert(!std::is_nothrow_assignable<V, int>::value, "");
125   }
126 }
127 
test_T_assignment_sfinae()128 void test_T_assignment_sfinae() {
129   {
130     using V = std::variant<long, long long>;
131     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
132   }
133   {
134     using V = std::variant<std::string, std::string>;
135     static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
136   }
137   {
138     using V = std::variant<std::string, void *>;
139     static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
140   }
141   {
142     using V = std::variant<std::string, float>;
143     static_assert(std::is_assignable<V, int>::value == VariantAllowsNarrowingConversions,
144     "no matching operator=");
145   }
146   {
147     using V = std::variant<std::unique_ptr<int>, bool>;
148     static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value,
149                   "no explicit bool in operator=");
150     struct X {
151       operator void*();
152     };
153     static_assert(!std::is_assignable<V, X>::value,
154                   "no boolean conversion in operator=");
155     static_assert(!std::is_assignable<V, std::false_type>::value,
156                   "no converted to bool in operator=");
157   }
158   {
159     struct X {};
160     struct Y {
161       operator X();
162     };
163     using V = std::variant<X>;
164     static_assert(std::is_assignable<V, Y>::value,
165                   "regression on user-defined conversions in operator=");
166   }
167 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
168   {
169     using V = std::variant<int, int &&>;
170     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
171   }
172   {
173     using V = std::variant<int, const int &>;
174     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
175   }
176 #endif // TEST_VARIANT_HAS_NO_REFERENCES
177 }
178 
test_T_assignment_basic()179 void test_T_assignment_basic() {
180   {
181     std::variant<int> v(43);
182     v = 42;
183     assert(v.index() == 0);
184     assert(std::get<0>(v) == 42);
185   }
186   {
187     std::variant<int, long> v(43l);
188     v = 42;
189     assert(v.index() == 0);
190     assert(std::get<0>(v) == 42);
191     v = 43l;
192     assert(v.index() == 1);
193     assert(std::get<1>(v) == 43);
194   }
195 #ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
196   {
197     std::variant<unsigned, long> v;
198     v = 42;
199     assert(v.index() == 1);
200     assert(std::get<1>(v) == 42);
201     v = 43u;
202     assert(v.index() == 0);
203     assert(std::get<0>(v) == 43);
204   }
205 #endif
206   {
207     std::variant<std::string, bool> v = true;
208     v = "bar";
209     assert(v.index() == 0);
210     assert(std::get<0>(v) == "bar");
211   }
212   {
213     std::variant<bool, std::unique_ptr<int>> v;
214     v = nullptr;
215     assert(v.index() == 1);
216     assert(std::get<1>(v) == nullptr);
217   }
218   {
219     std::variant<bool volatile, int> v = 42;
220     v = false;
221     assert(v.index() == 0);
222     assert(!std::get<0>(v));
223     bool lvt = true;
224     v = lvt;
225     assert(v.index() == 0);
226     assert(std::get<0>(v));
227   }
228 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
229   {
230     using V = std::variant<int &, int &&, long>;
231     int x = 42;
232     V v(43l);
233     v = x;
234     assert(v.index() == 0);
235     assert(&std::get<0>(v) == &x);
236     v = std::move(x);
237     assert(v.index() == 1);
238     assert(&std::get<1>(v) == &x);
239     // 'long' is selected by FUN(const int &) since 'const int &' cannot bind
240     // to 'int&'.
241     const int &cx = x;
242     v = cx;
243     assert(v.index() == 2);
244     assert(std::get<2>(v) == 42);
245   }
246 #endif // TEST_VARIANT_HAS_NO_REFERENCES
247 }
248 
test_T_assignment_performs_construction()249 void test_T_assignment_performs_construction() {
250   using namespace RuntimeHelpers;
251 #ifndef TEST_HAS_NO_EXCEPTIONS
252   {
253     using V = std::variant<std::string, ThrowsCtorT>;
254     V v(std::in_place_type<std::string>, "hello");
255     try {
256       v = 42;
257       assert(false);
258     } catch (...) { /* ... */
259     }
260     assert(v.index() == 0);
261     assert(std::get<0>(v) == "hello");
262   }
263   {
264     using V = std::variant<ThrowsAssignT, std::string>;
265     V v(std::in_place_type<std::string>, "hello");
266     v = 42;
267     assert(v.index() == 0);
268     assert(std::get<0>(v).value == 42);
269   }
270 #endif // TEST_HAS_NO_EXCEPTIONS
271 }
272 
test_T_assignment_performs_assignment()273 void test_T_assignment_performs_assignment() {
274   using namespace RuntimeHelpers;
275 #ifndef TEST_HAS_NO_EXCEPTIONS
276   {
277     using V = std::variant<ThrowsCtorT>;
278     V v;
279     v = 42;
280     assert(v.index() == 0);
281     assert(std::get<0>(v).value == 42);
282   }
283   {
284     using V = std::variant<ThrowsCtorT, std::string>;
285     V v;
286     v = 42;
287     assert(v.index() == 0);
288     assert(std::get<0>(v).value == 42);
289   }
290   {
291     using V = std::variant<ThrowsAssignT>;
292     V v(100);
293     try {
294       v = 42;
295       assert(false);
296     } catch (...) { /* ... */
297     }
298     assert(v.index() == 0);
299     assert(std::get<0>(v).value == 100);
300   }
301   {
302     using V = std::variant<std::string, ThrowsAssignT>;
303     V v(100);
304     try {
305       v = 42;
306       assert(false);
307     } catch (...) { /* ... */
308     }
309     assert(v.index() == 1);
310     assert(std::get<1>(v).value == 100);
311   }
312 #endif // TEST_HAS_NO_EXCEPTIONS
313 }
314 
main(int,char **)315 int main(int, char**) {
316   test_T_assignment_basic();
317   test_T_assignment_performs_construction();
318   test_T_assignment_performs_assignment();
319   test_T_assignment_noexcept();
320   test_T_assignment_sfinae();
321 
322   return 0;
323 }
324