• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: availability=macosx10.13
14 // XFAIL: availability=macosx10.12
15 // XFAIL: availability=macosx10.11
16 // XFAIL: availability=macosx10.10
17 // XFAIL: availability=macosx10.9
18 // XFAIL: availability=macosx10.8
19 // XFAIL: availability=macosx10.7
20 
21 // <variant>
22 // template <class Visitor, class... Variants>
23 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
24 
25 #include <cassert>
26 #include <memory>
27 #include <string>
28 #include <type_traits>
29 #include <utility>
30 #include <variant>
31 
32 #include "test_macros.h"
33 #include "type_id.h"
34 #include "variant_test_helpers.hpp"
35 
36 enum CallType : unsigned {
37   CT_None,
38   CT_NonConst = 1,
39   CT_Const = 2,
40   CT_LValue = 4,
41   CT_RValue = 8
42 };
43 
operator |(CallType LHS,CallType RHS)44 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
45   return static_cast<CallType>(static_cast<unsigned>(LHS) |
46                                static_cast<unsigned>(RHS));
47 }
48 
49 struct ForwardingCallObject {
50 
operator ()ForwardingCallObject51   template <class... Args> bool operator()(Args &&...) & {
52     set_call<Args &&...>(CT_NonConst | CT_LValue);
53     return true;
54   }
55 
operator ()ForwardingCallObject56   template <class... Args> bool operator()(Args &&...) const & {
57     set_call<Args &&...>(CT_Const | CT_LValue);
58     return true;
59   }
60 
61   // Don't allow the call operator to be invoked as an rvalue.
operator ()ForwardingCallObject62   template <class... Args> bool operator()(Args &&...) && {
63     set_call<Args &&...>(CT_NonConst | CT_RValue);
64     return true;
65   }
66 
operator ()ForwardingCallObject67   template <class... Args> bool operator()(Args &&...) const && {
68     set_call<Args &&...>(CT_Const | CT_RValue);
69     return true;
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 
test_argument_forwarding()148 void test_argument_forwarding() {
149   using Fn = ForwardingCallObject;
150   Fn obj{};
151   const auto Val = CT_LValue | CT_NonConst;
152   { // single argument - value type
153     using V = std::variant<int>;
154     V v(42);
155     const V &cv = v;
156     std::visit(obj, v);
157     assert(Fn::check_call<int &>(Val));
158     std::visit(obj, cv);
159     assert(Fn::check_call<const int &>(Val));
160     std::visit(obj, std::move(v));
161     assert(Fn::check_call<int &&>(Val));
162     std::visit(obj, std::move(cv));
163     assert(Fn::check_call<const int &&>(Val));
164   }
165 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
166   { // single argument - lvalue reference
167     using V = std::variant<int &>;
168     int x = 42;
169     V v(x);
170     const V &cv = v;
171     std::visit(obj, v);
172     assert(Fn::check_call<int &>(Val));
173     std::visit(obj, cv);
174     assert(Fn::check_call<int &>(Val));
175     std::visit(obj, std::move(v));
176     assert(Fn::check_call<int &>(Val));
177     std::visit(obj, std::move(cv));
178     assert(Fn::check_call<int &>(Val));
179   }
180   { // single argument - rvalue reference
181     using V = std::variant<int &&>;
182     int x = 42;
183     V v(std::move(x));
184     const V &cv = v;
185     std::visit(obj, v);
186     assert(Fn::check_call<int &>(Val));
187     std::visit(obj, cv);
188     assert(Fn::check_call<int &>(Val));
189     std::visit(obj, std::move(v));
190     assert(Fn::check_call<int &&>(Val));
191     std::visit(obj, std::move(cv));
192     assert(Fn::check_call<int &&>(Val));
193   }
194   { // multi argument - multi variant
195     using S = const std::string &;
196     using V = std::variant<int, S, long &&>;
197     const std::string str = "hello";
198     long l = 43;
199     V v1(42);
200     const V &cv1 = v1;
201     V v2(str);
202     const V &cv2 = v2;
203     V v3(std::move(l));
204     const V &cv3 = v3;
205     std::visit(obj, v1, v2, v3);
206     assert((Fn::check_call<int &, S, long &>(Val)));
207     std::visit(obj, cv1, cv2, std::move(v3));
208     assert((Fn::check_call<const int &, S, long &&>(Val)));
209   }
210 #endif
211 }
212 
213 struct ReturnFirst {
operator ()ReturnFirst214   template <class... Args> constexpr int operator()(int f, Args &&...) const {
215     return f;
216   }
217 };
218 
219 struct ReturnArity {
operator ()ReturnArity220   template <class... Args> constexpr int operator()(Args &&...) const {
221     return sizeof...(Args);
222   }
223 };
224 
test_constexpr()225 void test_constexpr() {
226   constexpr ReturnFirst obj{};
227   constexpr ReturnArity aobj{};
228   {
229     using V = std::variant<int>;
230     constexpr V v(42);
231     static_assert(std::visit(obj, v) == 42, "");
232   }
233   {
234     using V = std::variant<short, long, char>;
235     constexpr V v(42l);
236     static_assert(std::visit(obj, v) == 42, "");
237   }
238   {
239     using V1 = std::variant<int>;
240     using V2 = std::variant<int, char *, long long>;
241     using V3 = std::variant<bool, int, int>;
242     constexpr V1 v1;
243     constexpr V2 v2(nullptr);
244     constexpr V3 v3;
245     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
246   }
247   {
248     using V1 = std::variant<int>;
249     using V2 = std::variant<int, char *, long long>;
250     using V3 = std::variant<void *, 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 
test_exceptions()258 void test_exceptions() {
259 #ifndef TEST_HAS_NO_EXCEPTIONS
260   ReturnArity obj{};
261   auto test = [&](auto &&... args) {
262     try {
263       std::visit(obj, args...);
264     } catch (const std::bad_variant_access &) {
265       return true;
266     } catch (...) {
267     }
268     return false;
269   };
270   {
271     using V = std::variant<int, MakeEmptyT>;
272     V v;
273     makeEmpty(v);
274     assert(test(v));
275   }
276   {
277     using V = std::variant<int, MakeEmptyT>;
278     using V2 = std::variant<long, std::string, void *>;
279     V v;
280     makeEmpty(v);
281     V2 v2("hello");
282     assert(test(v, v2));
283   }
284   {
285     using V = std::variant<int, MakeEmptyT>;
286     using V2 = std::variant<long, std::string, void *>;
287     V v;
288     makeEmpty(v);
289     V2 v2("hello");
290     assert(test(v2, v));
291   }
292   {
293     using V = std::variant<int, MakeEmptyT>;
294     using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
295     V v;
296     makeEmpty(v);
297     V2 v2;
298     makeEmpty(v2);
299     assert(test(v, v2));
300   }
301 #endif
302 }
303 
304 // See https://bugs.llvm.org/show_bug.cgi?id=31916
test_caller_accepts_nonconst()305 void test_caller_accepts_nonconst() {
306   struct A {};
307   struct Visitor {
308     void operator()(A&) {}
309   };
310   std::variant<A> v;
311   std::visit(Visitor{}, v);
312 }
313 
main()314 int main() {
315   test_call_operator_forwarding();
316   test_argument_forwarding();
317   test_constexpr();
318   test_exceptions();
319   test_caller_accepts_nonconst();
320 }
321