blob: 05b58c16f3d8a876f7a143773e8830eb74b44b6d [file] [log] [blame]
Eric Fiselier80e66ac2016-11-23 01:02:51 +00001// -*- 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
Mehdi Aminie9c66ad2017-05-04 17:08:54 +000013// 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
Eric Fiselier80e66ac2016-11-23 01:02:51 +000020// <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
35enum CallType : unsigned {
36 CT_None,
37 CT_NonConst = 1,
38 CT_Const = 2,
39 CT_LValue = 4,
40 CT_RValue = 8
41};
42
43inline constexpr CallType operator|(CallType LHS, CallType RHS) {
44 return static_cast<CallType>(static_cast<unsigned>(LHS) |
45 static_cast<unsigned>(RHS));
46}
47
48struct ForwardingCallObject {
49
50 template <class... Args> bool operator()(Args &&...) & {
51 set_call<Args &&...>(CT_NonConst | CT_LValue);
52 return true;
53 }
54
55 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.
61 template <class... Args> bool operator()(Args &&...) && {
62 set_call<Args &&...>(CT_NonConst | CT_RValue);
63 return true;
64 }
65
66 template <class... Args> bool operator()(Args &&...) const && {
67 set_call<Args &&...>(CT_Const | CT_RValue);
68 return true;
69 }
70
71 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
78 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;
Eric Fiselier0d3d8de2016-12-02 23:00:05 +000087 static const TypeID *last_call_args;
Eric Fiselier80e66ac2016-11-23 01:02:51 +000088};
89
90CallType ForwardingCallObject::last_call_type = CT_None;
Eric Fiselier0d3d8de2016-12-02 23:00:05 +000091const TypeID *ForwardingCallObject::last_call_args = nullptr;
Eric Fiselier80e66ac2016-11-23 01:02:51 +000092
93void test_call_operator_forwarding() {
94 using Fn = ForwardingCallObject;
95 Fn obj{};
Eric Fiselier0d3d8de2016-12-02 23:00:05 +000096 const Fn &cobj = obj;
Eric Fiselier80e66ac2016-11-23 01:02:51 +000097 { // test call operator forwarding - single variant, single arg
98 using V = std::variant<int>;
99 V v(42);
100 std::visit(obj, v);
101 assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
102 std::visit(cobj, v);
103 assert(Fn::check_call<int &>(CT_Const | CT_LValue));
104 std::visit(std::move(obj), v);
105 assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
106 std::visit(std::move(cobj), v);
107 assert(Fn::check_call<int &>(CT_Const | CT_RValue));
108 }
109 { // test call operator forwarding - single variant, multi arg
110 using V = std::variant<int, long, double>;
111 V v(42l);
112 std::visit(obj, v);
113 assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
114 std::visit(cobj, v);
115 assert(Fn::check_call<long &>(CT_Const | CT_LValue));
116 std::visit(std::move(obj), v);
117 assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
118 std::visit(std::move(cobj), v);
119 assert(Fn::check_call<long &>(CT_Const | CT_RValue));
120 }
121 { // test call operator forwarding - multi variant, multi arg
122 using V = std::variant<int, long, double>;
123 using V2 = std::variant<int *, std::string>;
124 V v(42l);
125 V2 v2("hello");
126 std::visit(obj, v, v2);
127 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
128 std::visit(cobj, v, v2);
129 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
130 std::visit(std::move(obj), v, v2);
131 assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
132 std::visit(std::move(cobj), v, v2);
133 assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
134 }
135}
136
137void test_argument_forwarding() {
138 using Fn = ForwardingCallObject;
139 Fn obj{};
140 const auto Val = CT_LValue | CT_NonConst;
141 { // single argument - value type
142 using V = std::variant<int>;
143 V v(42);
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000144 const V &cv = v;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000145 std::visit(obj, v);
146 assert(Fn::check_call<int &>(Val));
147 std::visit(obj, cv);
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000148 assert(Fn::check_call<const int &>(Val));
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000149 std::visit(obj, std::move(v));
150 assert(Fn::check_call<int &&>(Val));
151 std::visit(obj, std::move(cv));
152 assert(Fn::check_call<const int &&>(Val));
153 }
154#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
155 { // single argument - lvalue reference
156 using V = std::variant<int &>;
157 int x = 42;
158 V v(x);
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000159 const V &cv = v;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000160 std::visit(obj, v);
161 assert(Fn::check_call<int &>(Val));
162 std::visit(obj, cv);
163 assert(Fn::check_call<int &>(Val));
164 std::visit(obj, std::move(v));
165 assert(Fn::check_call<int &>(Val));
166 std::visit(obj, std::move(cv));
167 assert(Fn::check_call<int &>(Val));
168 }
169 { // single argument - rvalue reference
170 using V = std::variant<int &&>;
171 int x = 42;
172 V v(std::move(x));
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000173 const V &cv = v;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000174 std::visit(obj, v);
175 assert(Fn::check_call<int &>(Val));
176 std::visit(obj, cv);
177 assert(Fn::check_call<int &>(Val));
178 std::visit(obj, std::move(v));
179 assert(Fn::check_call<int &&>(Val));
180 std::visit(obj, std::move(cv));
181 assert(Fn::check_call<int &&>(Val));
182 }
183 { // multi argument - multi variant
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000184 using S = const std::string &;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000185 using V = std::variant<int, S, long &&>;
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000186 const std::string str = "hello";
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000187 long l = 43;
188 V v1(42);
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000189 const V &cv1 = v1;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000190 V v2(str);
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000191 const V &cv2 = v2;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000192 V v3(std::move(l));
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000193 const V &cv3 = v3;
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000194 std::visit(obj, v1, v2, v3);
195 assert((Fn::check_call<int &, S, long &>(Val)));
196 std::visit(obj, cv1, cv2, std::move(v3));
197 assert((Fn::check_call<const int &, S, long &&>(Val)));
198 }
199#endif
200}
201
202struct ReturnFirst {
203 template <class... Args> constexpr int operator()(int f, Args &&...) const {
204 return f;
205 }
206};
207
208struct ReturnArity {
209 template <class... Args> constexpr int operator()(Args &&...) const {
210 return sizeof...(Args);
211 }
212};
213
214void test_constexpr() {
215 constexpr ReturnFirst obj{};
216 constexpr ReturnArity aobj{};
217 {
218 using V = std::variant<int>;
219 constexpr V v(42);
220 static_assert(std::visit(obj, v) == 42, "");
221 }
222 {
223 using V = std::variant<short, long, char>;
224 constexpr V v(42l);
225 static_assert(std::visit(obj, v) == 42, "");
226 }
227 {
228 using V1 = std::variant<int>;
229 using V2 = std::variant<int, char *, long long>;
230 using V3 = std::variant<bool, int, int>;
231 constexpr V1 v1;
232 constexpr V2 v2(nullptr);
233 constexpr V3 v3;
234 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
235 }
236 {
237 using V1 = std::variant<int>;
238 using V2 = std::variant<int, char *, long long>;
239 using V3 = std::variant<void *, int, int>;
240 constexpr V1 v1;
241 constexpr V2 v2(nullptr);
242 constexpr V3 v3;
243 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
244 }
245}
246
247void test_exceptions() {
248#ifndef TEST_HAS_NO_EXCEPTIONS
249 ReturnArity obj{};
250 auto test = [&](auto &&... args) {
251 try {
252 std::visit(obj, args...);
Eric Fiselier0d3d8de2016-12-02 23:00:05 +0000253 } catch (const std::bad_variant_access &) {
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000254 return true;
255 } catch (...) {
256 }
257 return false;
258 };
259 {
260 using V = std::variant<int, MakeEmptyT>;
261 V v;
262 makeEmpty(v);
263 assert(test(v));
264 }
265 {
266 using V = std::variant<int, MakeEmptyT>;
267 using V2 = std::variant<long, std::string, void *>;
268 V v;
269 makeEmpty(v);
270 V2 v2("hello");
271 assert(test(v, v2));
272 }
273 {
274 using V = std::variant<int, MakeEmptyT>;
275 using V2 = std::variant<long, std::string, void *>;
276 V v;
277 makeEmpty(v);
278 V2 v2("hello");
279 assert(test(v2, v));
280 }
281 {
282 using V = std::variant<int, MakeEmptyT>;
283 using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
284 V v;
285 makeEmpty(v);
286 V2 v2;
287 makeEmpty(v2);
288 assert(test(v, v2));
289 }
290#endif
291}
292
Eric Fiseliera18ef6f2017-02-09 19:01:22 +0000293// See http://llvm.org/PR31916
294void test_caller_accepts_nonconst() {
295 struct A {};
296 struct Visitor {
297 void operator()(A&) {}
298 };
299 std::variant<A> v;
300 std::visit(Visitor{}, v);
301}
302
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000303int main() {
304 test_call_operator_forwarding();
305 test_argument_forwarding();
306 test_constexpr();
307 test_exceptions();
Eric Fiseliera18ef6f2017-02-09 19:01:22 +0000308 test_caller_accepts_nonconst();
Eric Fiselier80e66ac2016-11-23 01:02:51 +0000309}