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