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