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