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