• 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 // <variant>
14 
15 // template <class ...Types> class variant;
16 
17 // template <class T>
18 // variant& operator=(T&&) noexcept(see below);
19 
20 #include <cassert>
21 #include <string>
22 #include <type_traits>
23 #include <variant>
24 
25 #include "test_macros.h"
26 #include "variant_test_helpers.hpp"
27 
28 namespace MetaHelpers {
29 
30 struct Dummy {
31   Dummy() = default;
32 };
33 
34 struct ThrowsCtorT {
ThrowsCtorTMetaHelpers::ThrowsCtorT35   ThrowsCtorT(int) noexcept(false) {}
operator =MetaHelpers::ThrowsCtorT36   ThrowsCtorT &operator=(int) noexcept { return *this; }
37 };
38 
39 struct ThrowsAssignT {
ThrowsAssignTMetaHelpers::ThrowsAssignT40   ThrowsAssignT(int) noexcept {}
operator =MetaHelpers::ThrowsAssignT41   ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
42 };
43 
44 struct NoThrowT {
NoThrowTMetaHelpers::NoThrowT45   NoThrowT(int) noexcept {}
operator =MetaHelpers::NoThrowT46   NoThrowT &operator=(int) noexcept { return *this; }
47 };
48 
49 } // namespace MetaHelpers
50 
51 namespace RuntimeHelpers {
52 #ifndef TEST_HAS_NO_EXCEPTIONS
53 
54 struct ThrowsCtorT {
55   int value;
ThrowsCtorTRuntimeHelpers::ThrowsCtorT56   ThrowsCtorT() : value(0) {}
ThrowsCtorTRuntimeHelpers::ThrowsCtorT57   ThrowsCtorT(int) noexcept(false) { throw 42; }
operator =RuntimeHelpers::ThrowsCtorT58   ThrowsCtorT &operator=(int v) noexcept {
59     value = v;
60     return *this;
61   }
62 };
63 
64 struct ThrowsAssignT {
65   int value;
ThrowsAssignTRuntimeHelpers::ThrowsAssignT66   ThrowsAssignT() : value(0) {}
ThrowsAssignTRuntimeHelpers::ThrowsAssignT67   ThrowsAssignT(int v) noexcept : value(v) {}
operator =RuntimeHelpers::ThrowsAssignT68   ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
69 };
70 
71 struct NoThrowT {
72   int value;
NoThrowTRuntimeHelpers::NoThrowT73   NoThrowT() : value(0) {}
NoThrowTRuntimeHelpers::NoThrowT74   NoThrowT(int v) noexcept : value(v) {}
operator =RuntimeHelpers::NoThrowT75   NoThrowT &operator=(int v) noexcept {
76     value = v;
77     return *this;
78   }
79 };
80 
81 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
82 } // namespace RuntimeHelpers
83 
test_T_assignment_noexcept()84 void test_T_assignment_noexcept() {
85   using namespace MetaHelpers;
86   {
87     using V = std::variant<Dummy, NoThrowT>;
88     static_assert(std::is_nothrow_assignable<V, int>::value, "");
89   }
90   {
91     using V = std::variant<Dummy, ThrowsCtorT>;
92     static_assert(!std::is_nothrow_assignable<V, int>::value, "");
93   }
94   {
95     using V = std::variant<Dummy, ThrowsAssignT>;
96     static_assert(!std::is_nothrow_assignable<V, int>::value, "");
97   }
98 }
99 
test_T_assignment_sfinae()100 void test_T_assignment_sfinae() {
101   {
102     using V = std::variant<long, unsigned>;
103     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
104   }
105   {
106     using V = std::variant<std::string, std::string>;
107     static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
108   }
109   {
110     using V = std::variant<std::string, void *>;
111     static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
112   }
113 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
114   {
115     using V = std::variant<int, int &&>;
116     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
117   }
118   {
119     using V = std::variant<int, const int &>;
120     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
121   }
122 #endif
123 }
124 
test_T_assignment_basic()125 void test_T_assignment_basic() {
126   {
127     std::variant<int> v(43);
128     v = 42;
129     assert(v.index() == 0);
130     assert(std::get<0>(v) == 42);
131   }
132   {
133     std::variant<int, long> v(43l);
134     v = 42;
135     assert(v.index() == 0);
136     assert(std::get<0>(v) == 42);
137     v = 43l;
138     assert(v.index() == 1);
139     assert(std::get<1>(v) == 43);
140   }
141 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
142   {
143     using V = std::variant<int &, int &&, long>;
144     int x = 42;
145     V v(43l);
146     v = x;
147     assert(v.index() == 0);
148     assert(&std::get<0>(v) == &x);
149     v = std::move(x);
150     assert(v.index() == 1);
151     assert(&std::get<1>(v) == &x);
152     // 'long' is selected by FUN(const int &) since 'const int &' cannot bind
153     // to 'int&'.
154     const int &cx = x;
155     v = cx;
156     assert(v.index() == 2);
157     assert(std::get<2>(v) == 42);
158   }
159 #endif
160 }
161 
test_T_assignment_performs_construction()162 void test_T_assignment_performs_construction() {
163   using namespace RuntimeHelpers;
164 #ifndef TEST_HAS_NO_EXCEPTIONS
165   {
166     using V = std::variant<std::string, ThrowsCtorT>;
167     V v(std::in_place_type<std::string>, "hello");
168     try {
169       v = 42;
170     } catch (...) { /* ... */
171     }
172     assert(v.valueless_by_exception());
173   }
174   {
175     using V = std::variant<ThrowsAssignT, std::string>;
176     V v(std::in_place_type<std::string>, "hello");
177     v = 42;
178     assert(v.index() == 0);
179     assert(std::get<0>(v).value == 42);
180   }
181 #endif
182 }
183 
test_T_assignment_performs_assignment()184 void test_T_assignment_performs_assignment() {
185   using namespace RuntimeHelpers;
186 #ifndef TEST_HAS_NO_EXCEPTIONS
187   {
188     using V = std::variant<ThrowsCtorT>;
189     V v;
190     v = 42;
191     assert(v.index() == 0);
192     assert(std::get<0>(v).value == 42);
193   }
194   {
195     using V = std::variant<ThrowsCtorT, std::string>;
196     V v;
197     v = 42;
198     assert(v.index() == 0);
199     assert(std::get<0>(v).value == 42);
200   }
201   {
202     using V = std::variant<ThrowsAssignT>;
203     V v(100);
204     try {
205       v = 42;
206       assert(false);
207     } catch (...) { /* ... */
208     }
209     assert(v.index() == 0);
210     assert(std::get<0>(v).value == 100);
211   }
212   {
213     using V = std::variant<std::string, ThrowsAssignT>;
214     V v(100);
215     try {
216       v = 42;
217       assert(false);
218     } catch (...) { /* ... */
219     }
220     assert(v.index() == 1);
221     assert(std::get<1>(v).value == 100);
222   }
223 #endif
224 }
225 
main()226 int main() {
227   test_T_assignment_basic();
228   test_T_assignment_performs_construction();
229   test_T_assignment_performs_assignment();
230   test_T_assignment_noexcept();
231   test_T_assignment_sfinae();
232 }
233