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