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 // template <class Visitor, class... Variants>
23 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
24
25 #include <cassert>
26 #include <memory>
27 #include <string>
28 #include <type_traits>
29 #include <utility>
30 #include <variant>
31
32 #include "test_macros.h"
33 #include "type_id.h"
34 #include "variant_test_helpers.hpp"
35
36 enum CallType : unsigned {
37 CT_None,
38 CT_NonConst = 1,
39 CT_Const = 2,
40 CT_LValue = 4,
41 CT_RValue = 8
42 };
43
operator |(CallType LHS,CallType RHS)44 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
45 return static_cast<CallType>(static_cast<unsigned>(LHS) |
46 static_cast<unsigned>(RHS));
47 }
48
49 struct ForwardingCallObject {
50
operator ()ForwardingCallObject51 template <class... Args> bool operator()(Args &&...) & {
52 set_call<Args &&...>(CT_NonConst | CT_LValue);
53 return true;
54 }
55
operator ()ForwardingCallObject56 template <class... Args> bool operator()(Args &&...) const & {
57 set_call<Args &&...>(CT_Const | CT_LValue);
58 return true;
59 }
60
61 // Don't allow the call operator to be invoked as an rvalue.
operator ()ForwardingCallObject62 template <class... Args> bool operator()(Args &&...) && {
63 set_call<Args &&...>(CT_NonConst | CT_RValue);
64 return true;
65 }
66
operator ()ForwardingCallObject67 template <class... Args> bool operator()(Args &&...) const && {
68 set_call<Args &&...>(CT_Const | CT_RValue);
69 return true;
70 }
71
set_callForwardingCallObject72 template <class... Args> static void set_call(CallType type) {
73 assert(last_call_type == CT_None);
74 assert(last_call_args == nullptr);
75 last_call_type = type;
76 last_call_args = std::addressof(makeArgumentID<Args...>());
77 }
78
check_callForwardingCallObject79 template <class... Args> static bool check_call(CallType type) {
80 bool result = last_call_type == type && last_call_args &&
81 *last_call_args == makeArgumentID<Args...>();
82 last_call_type = CT_None;
83 last_call_args = nullptr;
84 return result;
85 }
86
87 static CallType last_call_type;
88 static const TypeID *last_call_args;
89 };
90
91 CallType ForwardingCallObject::last_call_type = CT_None;
92 const TypeID *ForwardingCallObject::last_call_args = nullptr;
93
test_call_operator_forwarding()94 void test_call_operator_forwarding() {
95 using Fn = ForwardingCallObject;
96 Fn obj{};
97 const Fn &cobj = obj;
98 { // test call operator forwarding - no variant
99 std::visit(obj);
100 assert(Fn::check_call<>(CT_NonConst | CT_LValue));
101 std::visit(cobj);
102 assert(Fn::check_call<>(CT_Const | CT_LValue));
103 std::visit(std::move(obj));
104 assert(Fn::check_call<>(CT_NonConst | CT_RValue));
105 std::visit(std::move(cobj));
106 assert(Fn::check_call<>(CT_Const | CT_RValue));
107 }
108 { // test call operator forwarding - single variant, single arg
109 using V = std::variant<int>;
110 V v(42);
111 std::visit(obj, v);
112 assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
113 std::visit(cobj, v);
114 assert(Fn::check_call<int &>(CT_Const | CT_LValue));
115 std::visit(std::move(obj), v);
116 assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
117 std::visit(std::move(cobj), v);
118 assert(Fn::check_call<int &>(CT_Const | CT_RValue));
119 }
120 { // test call operator forwarding - single variant, multi arg
121 using V = std::variant<int, long, double>;
122 V v(42l);
123 std::visit(obj, v);
124 assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
125 std::visit(cobj, v);
126 assert(Fn::check_call<long &>(CT_Const | CT_LValue));
127 std::visit(std::move(obj), v);
128 assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
129 std::visit(std::move(cobj), v);
130 assert(Fn::check_call<long &>(CT_Const | CT_RValue));
131 }
132 { // test call operator forwarding - multi variant, multi arg
133 using V = std::variant<int, long, double>;
134 using V2 = std::variant<int *, std::string>;
135 V v(42l);
136 V2 v2("hello");
137 std::visit(obj, v, v2);
138 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
139 std::visit(cobj, v, v2);
140 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
141 std::visit(std::move(obj), v, v2);
142 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
143 std::visit(std::move(cobj), v, v2);
144 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
145 }
146 }
147
test_argument_forwarding()148 void test_argument_forwarding() {
149 using Fn = ForwardingCallObject;
150 Fn obj{};
151 const auto Val = CT_LValue | CT_NonConst;
152 { // single argument - value type
153 using V = std::variant<int>;
154 V v(42);
155 const V &cv = v;
156 std::visit(obj, v);
157 assert(Fn::check_call<int &>(Val));
158 std::visit(obj, cv);
159 assert(Fn::check_call<const int &>(Val));
160 std::visit(obj, std::move(v));
161 assert(Fn::check_call<int &&>(Val));
162 std::visit(obj, std::move(cv));
163 assert(Fn::check_call<const int &&>(Val));
164 }
165 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
166 { // single argument - lvalue reference
167 using V = std::variant<int &>;
168 int x = 42;
169 V v(x);
170 const V &cv = v;
171 std::visit(obj, v);
172 assert(Fn::check_call<int &>(Val));
173 std::visit(obj, cv);
174 assert(Fn::check_call<int &>(Val));
175 std::visit(obj, std::move(v));
176 assert(Fn::check_call<int &>(Val));
177 std::visit(obj, std::move(cv));
178 assert(Fn::check_call<int &>(Val));
179 }
180 { // single argument - rvalue reference
181 using V = std::variant<int &&>;
182 int x = 42;
183 V v(std::move(x));
184 const V &cv = v;
185 std::visit(obj, v);
186 assert(Fn::check_call<int &>(Val));
187 std::visit(obj, cv);
188 assert(Fn::check_call<int &>(Val));
189 std::visit(obj, std::move(v));
190 assert(Fn::check_call<int &&>(Val));
191 std::visit(obj, std::move(cv));
192 assert(Fn::check_call<int &&>(Val));
193 }
194 { // multi argument - multi variant
195 using S = const std::string &;
196 using V = std::variant<int, S, long &&>;
197 const std::string str = "hello";
198 long l = 43;
199 V v1(42);
200 const V &cv1 = v1;
201 V v2(str);
202 const V &cv2 = v2;
203 V v3(std::move(l));
204 const V &cv3 = v3;
205 std::visit(obj, v1, v2, v3);
206 assert((Fn::check_call<int &, S, long &>(Val)));
207 std::visit(obj, cv1, cv2, std::move(v3));
208 assert((Fn::check_call<const int &, S, long &&>(Val)));
209 }
210 #endif
211 }
212
213 struct ReturnFirst {
operator ()ReturnFirst214 template <class... Args> constexpr int operator()(int f, Args &&...) const {
215 return f;
216 }
217 };
218
219 struct ReturnArity {
operator ()ReturnArity220 template <class... Args> constexpr int operator()(Args &&...) const {
221 return sizeof...(Args);
222 }
223 };
224
test_constexpr()225 void test_constexpr() {
226 constexpr ReturnFirst obj{};
227 constexpr ReturnArity aobj{};
228 {
229 using V = std::variant<int>;
230 constexpr V v(42);
231 static_assert(std::visit(obj, v) == 42, "");
232 }
233 {
234 using V = std::variant<short, long, char>;
235 constexpr V v(42l);
236 static_assert(std::visit(obj, v) == 42, "");
237 }
238 {
239 using V1 = std::variant<int>;
240 using V2 = std::variant<int, char *, long long>;
241 using V3 = std::variant<bool, int, int>;
242 constexpr V1 v1;
243 constexpr V2 v2(nullptr);
244 constexpr V3 v3;
245 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
246 }
247 {
248 using V1 = std::variant<int>;
249 using V2 = std::variant<int, char *, long long>;
250 using V3 = std::variant<void *, int, int>;
251 constexpr V1 v1;
252 constexpr V2 v2(nullptr);
253 constexpr V3 v3;
254 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
255 }
256 }
257
test_exceptions()258 void test_exceptions() {
259 #ifndef TEST_HAS_NO_EXCEPTIONS
260 ReturnArity obj{};
261 auto test = [&](auto &&... args) {
262 try {
263 std::visit(obj, args...);
264 } catch (const std::bad_variant_access &) {
265 return true;
266 } catch (...) {
267 }
268 return false;
269 };
270 {
271 using V = std::variant<int, MakeEmptyT>;
272 V v;
273 makeEmpty(v);
274 assert(test(v));
275 }
276 {
277 using V = std::variant<int, MakeEmptyT>;
278 using V2 = std::variant<long, std::string, void *>;
279 V v;
280 makeEmpty(v);
281 V2 v2("hello");
282 assert(test(v, v2));
283 }
284 {
285 using V = std::variant<int, MakeEmptyT>;
286 using V2 = std::variant<long, std::string, void *>;
287 V v;
288 makeEmpty(v);
289 V2 v2("hello");
290 assert(test(v2, v));
291 }
292 {
293 using V = std::variant<int, MakeEmptyT>;
294 using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
295 V v;
296 makeEmpty(v);
297 V2 v2;
298 makeEmpty(v2);
299 assert(test(v, v2));
300 }
301 #endif
302 }
303
304 // See https://bugs.llvm.org/show_bug.cgi?id=31916
test_caller_accepts_nonconst()305 void test_caller_accepts_nonconst() {
306 struct A {};
307 struct Visitor {
308 void operator()(A&) {}
309 };
310 std::variant<A> v;
311 std::visit(Visitor{}, v);
312 }
313
main()314 int main() {
315 test_call_operator_forwarding();
316 test_argument_forwarding();
317 test_constexpr();
318 test_exceptions();
319 test_caller_accepts_nonconst();
320 }
321