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: use_system_cxx_lib && x86_64-apple-macosx10.12 && !no-exceptions
14 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.11 && !no-exceptions
15 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.10 && !no-exceptions
16 // XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.9 && !no-exceptions
17 
18 // <variant>
19 // template <class Visitor, class... Variants>
20 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
21 
22 #include <cassert>
23 #include <memory>
24 #include <string>
25 #include <type_traits>
26 #include <utility>
27 #include <variant>
28 
29 #include "test_macros.h"
30 #include "variant_test_helpers.h"
31 
32 void test_call_operator_forwarding() {
33   using Fn = ForwardingCallObject;
34   Fn obj{};
35   const Fn &cobj = obj;
36   { // test call operator forwarding - no variant
37     std::visit(obj);
38     assert(Fn::check_call<>(CT_NonConst | CT_LValue));
39     std::visit(cobj);
40     assert(Fn::check_call<>(CT_Const | CT_LValue));
41     std::visit(std::move(obj));
42     assert(Fn::check_call<>(CT_NonConst | CT_RValue));
43     std::visit(std::move(cobj));
44     assert(Fn::check_call<>(CT_Const | CT_RValue));
45   }
46   { // test call operator forwarding - single variant, single arg
47     using V = std::variant<int>;
48     V v(42);
49     std::visit(obj, v);
50     assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
51     std::visit(cobj, v);
52     assert(Fn::check_call<int &>(CT_Const | CT_LValue));
53     std::visit(std::move(obj), v);
54     assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
55     std::visit(std::move(cobj), v);
56     assert(Fn::check_call<int &>(CT_Const | CT_RValue));
57   }
58   { // test call operator forwarding - single variant, multi arg
59     using V = std::variant<int, long, double>;
60     V v(42l);
61     std::visit(obj, v);
62     assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
63     std::visit(cobj, v);
64     assert(Fn::check_call<long &>(CT_Const | CT_LValue));
65     std::visit(std::move(obj), v);
66     assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
67     std::visit(std::move(cobj), v);
68     assert(Fn::check_call<long &>(CT_Const | CT_RValue));
69   }
70   { // test call operator forwarding - multi variant, multi arg
71     using V = std::variant<int, long, double>;
72     using V2 = std::variant<int *, std::string>;
73     V v(42l);
74     V2 v2("hello");
75     std::visit(obj, v, v2);
76     assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
77     std::visit(cobj, v, v2);
78     assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
79     std::visit(std::move(obj), v, v2);
80     assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
81     std::visit(std::move(cobj), v, v2);
82     assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
83   }
84   {
85     using V = std::variant<int, long, double, std::string>;
86     V v1(42l), v2("hello"), v3(101), v4(1.1);
87     std::visit(obj, v1, v2, v3, v4);
88     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
89     std::visit(cobj, v1, v2, v3, v4);
90     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
91     std::visit(std::move(obj), v1, v2, v3, v4);
92     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
93     std::visit(std::move(cobj), v1, v2, v3, v4);
94     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));
95   }
96   {
97     using V = std::variant<int, long, double, int*, std::string>;
98     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
99     std::visit(obj, v1, v2, v3, v4);
100     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
101     std::visit(cobj, v1, v2, v3, v4);
102     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
103     std::visit(std::move(obj), v1, v2, v3, v4);
104     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
105     std::visit(std::move(cobj), v1, v2, v3, v4);
106     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
107   }
108 }
109 
110 void test_argument_forwarding() {
111   using Fn = ForwardingCallObject;
112   Fn obj{};
113   const auto Val = CT_LValue | CT_NonConst;
114   { // single argument - value type
115     using V = std::variant<int>;
116     V v(42);
117     const V &cv = v;
118     std::visit(obj, v);
119     assert(Fn::check_call<int &>(Val));
120     std::visit(obj, cv);
121     assert(Fn::check_call<const int &>(Val));
122     std::visit(obj, std::move(v));
123     assert(Fn::check_call<int &&>(Val));
124     std::visit(obj, std::move(cv));
125     assert(Fn::check_call<const int &&>(Val));
126   }
127 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
128   { // single argument - lvalue reference
129     using V = std::variant<int &>;
130     int x = 42;
131     V v(x);
132     const V &cv = v;
133     std::visit(obj, v);
134     assert(Fn::check_call<int &>(Val));
135     std::visit(obj, cv);
136     assert(Fn::check_call<int &>(Val));
137     std::visit(obj, std::move(v));
138     assert(Fn::check_call<int &>(Val));
139     std::visit(obj, std::move(cv));
140     assert(Fn::check_call<int &>(Val));
141   }
142   { // single argument - rvalue reference
143     using V = std::variant<int &&>;
144     int x = 42;
145     V v(std::move(x));
146     const V &cv = v;
147     std::visit(obj, v);
148     assert(Fn::check_call<int &>(Val));
149     std::visit(obj, cv);
150     assert(Fn::check_call<int &>(Val));
151     std::visit(obj, std::move(v));
152     assert(Fn::check_call<int &&>(Val));
153     std::visit(obj, std::move(cv));
154     assert(Fn::check_call<int &&>(Val));
155   }
156 #endif
157   { // multi argument - multi variant
158     using V = std::variant<int, std::string, long>;
159     V v1(42), v2("hello"), v3(43l);
160     std::visit(obj, v1, v2, v3);
161     assert((Fn::check_call<int &, std::string &, long &>(Val)));
162     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
163     assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));
164   }
165   {
166     using V = std::variant<int, long, double, std::string>;
167     V v1(42l), v2("hello"), v3(101), v4(1.1);
168     std::visit(obj, v1, v2, v3, v4);
169     assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
170     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
171     assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val)));
172   }
173   {
174     using V = std::variant<int, long, double, int*, std::string>;
175     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
176     std::visit(obj, v1, v2, v3, v4);
177     assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
178     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
179     assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));
180   }
181 }
182 
183 void test_return_type() {
184   using Fn = ForwardingCallObject;
185   Fn obj{};
186   const Fn &cobj = obj;
187   { // test call operator forwarding - no variant
188     static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
189     static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
190     static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
191     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
192   }
193   { // test call operator forwarding - single variant, single arg
194     using V = std::variant<int>;
195     V v(42);
196     static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
197     static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
198     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
199     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
200   }
201   { // test call operator forwarding - single variant, multi arg
202     using V = std::variant<int, long, double>;
203     V v(42l);
204     static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
205     static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
206     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
207     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
208   }
209   { // test call operator forwarding - multi variant, multi arg
210     using V = std::variant<int, long, double>;
211     using V2 = std::variant<int *, std::string>;
212     V v(42l);
213     V2 v2("hello");
214     static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
215     static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
216     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
217     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
218   }
219   {
220     using V = std::variant<int, long, double, std::string>;
221     V v1(42l), v2("hello"), v3(101), v4(1.1);
222     static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
223     static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
224     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
225     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
226   }
227   {
228     using V = std::variant<int, long, double, int*, std::string>;
229     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
230     static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
231     static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
232     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
233     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
234   }
235 }
236 
237 void test_constexpr() {
238   constexpr ReturnFirst obj{};
239   constexpr ReturnArity aobj{};
240   {
241     using V = std::variant<int>;
242     constexpr V v(42);
243     static_assert(std::visit(obj, v) == 42, "");
244   }
245   {
246     using V = std::variant<short, long, char>;
247     constexpr V v(42l);
248     static_assert(std::visit(obj, v) == 42, "");
249   }
250   {
251     using V1 = std::variant<int>;
252     using V2 = std::variant<int, char *, long long>;
253     using V3 = std::variant<bool, int, int>;
254     constexpr V1 v1;
255     constexpr V2 v2(nullptr);
256     constexpr V3 v3;
257     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
258   }
259   {
260     using V1 = std::variant<int>;
261     using V2 = std::variant<int, char *, long long>;
262     using V3 = std::variant<void *, int, int>;
263     constexpr V1 v1;
264     constexpr V2 v2(nullptr);
265     constexpr V3 v3;
266     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
267   }
268   {
269     using V = std::variant<int, long, double, int *>;
270     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
271     static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
272   }
273   {
274     using V = std::variant<int, long, double, long long, int *>;
275     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
276     static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
277   }
278 }
279 
280 void test_exceptions() {
281 #ifndef TEST_HAS_NO_EXCEPTIONS
282   ReturnArity obj{};
283   auto test = [&](auto &&... args) {
284     try {
285       std::visit(obj, args...);
286     } catch (const std::bad_variant_access &) {
287       return true;
288     } catch (...) {
289     }
290     return false;
291   };
292   {
293     using V = std::variant<int, MakeEmptyT>;
294     V v;
295     makeEmpty(v);
296     assert(test(v));
297   }
298   {
299     using V = std::variant<int, MakeEmptyT>;
300     using V2 = std::variant<long, std::string, void *>;
301     V v;
302     makeEmpty(v);
303     V2 v2("hello");
304     assert(test(v, v2));
305   }
306   {
307     using V = std::variant<int, MakeEmptyT>;
308     using V2 = std::variant<long, std::string, void *>;
309     V v;
310     makeEmpty(v);
311     V2 v2("hello");
312     assert(test(v2, v));
313   }
314   {
315     using V = std::variant<int, MakeEmptyT>;
316     using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
317     V v;
318     makeEmpty(v);
319     V2 v2;
320     makeEmpty(v2);
321     assert(test(v, v2));
322   }
323   {
324     using V = std::variant<int, long, double, MakeEmptyT>;
325     V v1(42l), v2(101), v3(202), v4(1.1);
326     makeEmpty(v1);
327     assert(test(v1, v2, v3, v4));
328   }
329   {
330     using V = std::variant<int, long, double, long long, MakeEmptyT>;
331     V v1(42l), v2(101), v3(202), v4(1.1);
332     makeEmpty(v1);
333     makeEmpty(v2);
334     makeEmpty(v3);
335     makeEmpty(v4);
336     assert(test(v1, v2, v3, v4));
337   }
338 #endif
339 }
340 
341 // See https://llvm.org/PR31916
342 void test_caller_accepts_nonconst() {
343   struct A {};
344   struct Visitor {
345     void operator()(A&) {}
346   };
347   std::variant<A> v;
348   std::visit(Visitor{}, v);
349 }
350 
351 struct MyVariant : std::variant<short, long, float> {};
352 
353 namespace std {
354 template <size_t Index>
355 void get(const MyVariant&) {
356   assert(false);
357 }
358 } // namespace std
359 
360 void test_derived_from_variant() {
361   auto v1 = MyVariant{42};
362   const auto cv1 = MyVariant{142};
363   std::visit([](auto x) { assert(x == 42); }, v1);
364   std::visit([](auto x) { assert(x == 142); }, cv1);
365   std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f});
366   std::visit([](auto x) { assert(x == 42); }, std::move(v1));
367   std::visit([](auto x) { assert(x == 142); }, std::move(cv1));
368 
369   // Check that visit does not take index nor valueless_by_exception members from the base class.
370   struct EvilVariantBase {
371     int index;
372     char valueless_by_exception;
373   };
374 
375   struct EvilVariant1 : std::variant<int, long, double>,
376                         std::tuple<int>,
377                         EvilVariantBase {
378     using std::variant<int, long, double>::variant;
379   };
380 
381   std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12});
382   std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3});
383 
384   // Check that visit unambiguously picks the variant, even if the other base has __impl member.
385   struct ImplVariantBase {
386     struct Callable {
387       bool operator()();
388     };
389 
390     Callable __impl;
391   };
392 
393   struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase {
394     using std::variant<int, long, double>::variant;
395   };
396 
397   std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12});
398   std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3});
399 }
400 
401 struct any_visitor {
402   template <typename T>
403   void operator()(const T&) const {}
404 };
405 
406 template <typename T, typename = decltype(std::visit(
407                           std::declval<any_visitor&>(), std::declval<T>()))>
408 constexpr bool has_visit(int) {
409   return true;
410 }
411 
412 template <typename T>
413 constexpr bool has_visit(...) {
414   return false;
415 }
416 
417 void test_sfinae() {
418   struct BadVariant : std::variant<short>, std::variant<long, float> {};
419   struct BadVariant2 : private std::variant<long, float> {};
420   struct GoodVariant : std::variant<long, float> {};
421   struct GoodVariant2 : GoodVariant {};
422 
423   static_assert(!has_visit<int>(0));
424   static_assert(!has_visit<BadVariant>(0));
425   static_assert(!has_visit<BadVariant2>(0));
426   static_assert(has_visit<std::variant<int>>(0));
427   static_assert(has_visit<GoodVariant>(0));
428   static_assert(has_visit<GoodVariant2>(0));
429 }
430 
431 int main(int, char**) {
432   test_call_operator_forwarding();
433   test_argument_forwarding();
434   test_return_type();
435   test_constexpr();
436   test_exceptions();
437   test_caller_accepts_nonconst();
438   test_derived_from_variant();
439   test_sfinae();
440 
441   return 0;
442 }
443