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