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