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: with_system_cxx_lib=macosx10.12 && !no-exceptions
14 // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions
15 // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions
16 // XFAIL: with_system_cxx_lib=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 "type_id.h"
31 #include "variant_test_helpers.h"
32 
33 enum CallType : unsigned {
34   CT_None,
35   CT_NonConst = 1,
36   CT_Const = 2,
37   CT_LValue = 4,
38   CT_RValue = 8
39 };
40 
operator |(CallType LHS,CallType RHS)41 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
42   return static_cast<CallType>(static_cast<unsigned>(LHS) |
43                                static_cast<unsigned>(RHS));
44 }
45 
46 struct ForwardingCallObject {
47 
48   template <class... Args>
operator ()ForwardingCallObject49   ForwardingCallObject& operator()(Args&&...) & {
50     set_call<Args &&...>(CT_NonConst | CT_LValue);
51     return *this;
52   }
53 
54   template <class... Args>
operator ()ForwardingCallObject55   const ForwardingCallObject& operator()(Args&&...) const & {
56     set_call<Args &&...>(CT_Const | CT_LValue);
57     return *this;
58   }
59 
60   template <class... Args>
operator ()ForwardingCallObject61   ForwardingCallObject&& operator()(Args&&...) && {
62     set_call<Args &&...>(CT_NonConst | CT_RValue);
63     return std::move(*this);
64   }
65 
66   template <class... Args>
operator ()ForwardingCallObject67   const ForwardingCallObject&& operator()(Args&&...) const && {
68     set_call<Args &&...>(CT_Const | CT_RValue);
69     return std::move(*this);
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     using V = std::variant<int, long, double, std::string>;
148     V v1(42l), v2("hello"), v3(101), v4(1.1);
149     std::visit(obj, v1, v2, v3, v4);
150     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
151     std::visit(cobj, v1, v2, v3, v4);
152     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
153     std::visit(std::move(obj), v1, v2, v3, v4);
154     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
155     std::visit(std::move(cobj), v1, v2, v3, v4);
156     assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));
157   }
158   {
159     using V = std::variant<int, long, double, int*, std::string>;
160     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
161     std::visit(obj, v1, v2, v3, v4);
162     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
163     std::visit(cobj, v1, v2, v3, v4);
164     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
165     std::visit(std::move(obj), v1, v2, v3, v4);
166     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
167     std::visit(std::move(cobj), v1, v2, v3, v4);
168     assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
169   }
170 }
171 
test_argument_forwarding()172 void test_argument_forwarding() {
173   using Fn = ForwardingCallObject;
174   Fn obj{};
175   const auto Val = CT_LValue | CT_NonConst;
176   { // single argument - value type
177     using V = std::variant<int>;
178     V v(42);
179     const V &cv = v;
180     std::visit(obj, v);
181     assert(Fn::check_call<int &>(Val));
182     std::visit(obj, cv);
183     assert(Fn::check_call<const int &>(Val));
184     std::visit(obj, std::move(v));
185     assert(Fn::check_call<int &&>(Val));
186     std::visit(obj, std::move(cv));
187     assert(Fn::check_call<const int &&>(Val));
188   }
189 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
190   { // single argument - lvalue reference
191     using V = std::variant<int &>;
192     int x = 42;
193     V v(x);
194     const V &cv = v;
195     std::visit(obj, v);
196     assert(Fn::check_call<int &>(Val));
197     std::visit(obj, cv);
198     assert(Fn::check_call<int &>(Val));
199     std::visit(obj, std::move(v));
200     assert(Fn::check_call<int &>(Val));
201     std::visit(obj, std::move(cv));
202     assert(Fn::check_call<int &>(Val));
203   }
204   { // single argument - rvalue reference
205     using V = std::variant<int &&>;
206     int x = 42;
207     V v(std::move(x));
208     const V &cv = v;
209     std::visit(obj, v);
210     assert(Fn::check_call<int &>(Val));
211     std::visit(obj, cv);
212     assert(Fn::check_call<int &>(Val));
213     std::visit(obj, std::move(v));
214     assert(Fn::check_call<int &&>(Val));
215     std::visit(obj, std::move(cv));
216     assert(Fn::check_call<int &&>(Val));
217   }
218 #endif
219   { // multi argument - multi variant
220     using V = std::variant<int, std::string, long>;
221     V v1(42), v2("hello"), v3(43l);
222     std::visit(obj, v1, v2, v3);
223     assert((Fn::check_call<int &, std::string &, long &>(Val)));
224     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
225     assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));
226   }
227   {
228     using V = std::variant<int, long, double, std::string>;
229     V v1(42l), v2("hello"), v3(101), v4(1.1);
230     std::visit(obj, v1, v2, v3, v4);
231     assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
232     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
233     assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val)));
234   }
235   {
236     using V = std::variant<int, long, double, int*, std::string>;
237     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
238     std::visit(obj, v1, v2, v3, v4);
239     assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
240     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
241     assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));
242   }
243 }
244 
test_return_type()245 void test_return_type() {
246   using Fn = ForwardingCallObject;
247   Fn obj{};
248   const Fn &cobj = obj;
249   { // test call operator forwarding - no variant
250     static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
251     static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
252     static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
253     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
254   }
255   { // test call operator forwarding - single variant, single arg
256     using V = std::variant<int>;
257     V v(42);
258     static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
259     static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
260     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
261     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
262   }
263   { // test call operator forwarding - single variant, multi arg
264     using V = std::variant<int, long, double>;
265     V v(42l);
266     static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
267     static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
268     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
269     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
270   }
271   { // test call operator forwarding - multi variant, multi arg
272     using V = std::variant<int, long, double>;
273     using V2 = std::variant<int *, std::string>;
274     V v(42l);
275     V2 v2("hello");
276     static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
277     static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
278     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
279     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
280   }
281   {
282     using V = std::variant<int, long, double, std::string>;
283     V v1(42l), v2("hello"), v3(101), v4(1.1);
284     static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
285     static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
286     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
287     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
288   }
289   {
290     using V = std::variant<int, long, double, int*, std::string>;
291     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
292     static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
293     static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
294     static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
295     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
296   }
297 }
298 
299 struct ReturnFirst {
operator ()ReturnFirst300   template <class... Args> constexpr int operator()(int f, Args &&...) const {
301     return f;
302   }
303 };
304 
305 struct ReturnArity {
operator ()ReturnArity306   template <class... Args> constexpr int operator()(Args &&...) const {
307     return sizeof...(Args);
308   }
309 };
310 
test_constexpr()311 void test_constexpr() {
312   constexpr ReturnFirst obj{};
313   constexpr ReturnArity aobj{};
314   {
315     using V = std::variant<int>;
316     constexpr V v(42);
317     static_assert(std::visit(obj, v) == 42, "");
318   }
319   {
320     using V = std::variant<short, long, char>;
321     constexpr V v(42l);
322     static_assert(std::visit(obj, v) == 42, "");
323   }
324   {
325     using V1 = std::variant<int>;
326     using V2 = std::variant<int, char *, long long>;
327     using V3 = std::variant<bool, int, int>;
328     constexpr V1 v1;
329     constexpr V2 v2(nullptr);
330     constexpr V3 v3;
331     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
332   }
333   {
334     using V1 = std::variant<int>;
335     using V2 = std::variant<int, char *, long long>;
336     using V3 = std::variant<void *, int, int>;
337     constexpr V1 v1;
338     constexpr V2 v2(nullptr);
339     constexpr V3 v3;
340     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
341   }
342   {
343     using V = std::variant<int, long, double, int *>;
344     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
345     static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
346   }
347   {
348     using V = std::variant<int, long, double, long long, int *>;
349     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
350     static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, "");
351   }
352 }
353 
test_exceptions()354 void test_exceptions() {
355 #ifndef TEST_HAS_NO_EXCEPTIONS
356   ReturnArity obj{};
357   auto test = [&](auto &&... args) {
358     try {
359       std::visit(obj, args...);
360     } catch (const std::bad_variant_access &) {
361       return true;
362     } catch (...) {
363     }
364     return false;
365   };
366   {
367     using V = std::variant<int, MakeEmptyT>;
368     V v;
369     makeEmpty(v);
370     assert(test(v));
371   }
372   {
373     using V = std::variant<int, MakeEmptyT>;
374     using V2 = std::variant<long, std::string, void *>;
375     V v;
376     makeEmpty(v);
377     V2 v2("hello");
378     assert(test(v, v2));
379   }
380   {
381     using V = std::variant<int, MakeEmptyT>;
382     using V2 = std::variant<long, std::string, void *>;
383     V v;
384     makeEmpty(v);
385     V2 v2("hello");
386     assert(test(v2, v));
387   }
388   {
389     using V = std::variant<int, MakeEmptyT>;
390     using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
391     V v;
392     makeEmpty(v);
393     V2 v2;
394     makeEmpty(v2);
395     assert(test(v, v2));
396   }
397   {
398     using V = std::variant<int, long, double, MakeEmptyT>;
399     V v1(42l), v2(101), v3(202), v4(1.1);
400     makeEmpty(v1);
401     assert(test(v1, v2, v3, v4));
402   }
403   {
404     using V = std::variant<int, long, double, long long, MakeEmptyT>;
405     V v1(42l), v2(101), v3(202), v4(1.1);
406     makeEmpty(v1);
407     makeEmpty(v2);
408     makeEmpty(v3);
409     makeEmpty(v4);
410     assert(test(v1, v2, v3, v4));
411   }
412 #endif
413 }
414 
415 // See https://bugs.llvm.org/show_bug.cgi?id=31916
test_caller_accepts_nonconst()416 void test_caller_accepts_nonconst() {
417   struct A {};
418   struct Visitor {
419     void operator()(A&) {}
420   };
421   std::variant<A> v;
422   std::visit(Visitor{}, v);
423 }
424 
main(int,char **)425 int main(int, char**) {
426   test_call_operator_forwarding();
427   test_argument_forwarding();
428   test_return_type();
429   test_constexpr();
430   test_exceptions();
431   test_caller_accepts_nonconst();
432 
433   return 0;
434 }
435