2 //===----------------------------------------------------------------------===//
4 // The LLVM Compiler Infrastructure
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++98, c++03, c++11, c++14
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
22 // template <class Visitor, class... Variants>
23 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
28 #include <type_traits>
32 #include "test_macros.h"
34 #include "variant_test_helpers.hpp"
36 enum CallType : unsigned {
44 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
45 return static_cast<CallType>(static_cast<unsigned>(LHS) |
46 static_cast<unsigned>(RHS));
49 struct ForwardingCallObject {
51 template <class... Args> bool operator()(Args &&...) & {
52 set_call<Args &&...>(CT_NonConst | CT_LValue);
56 template <class... Args> bool operator()(Args &&...) const & {
57 set_call<Args &&...>(CT_Const | CT_LValue);
61 // Don't allow the call operator to be invoked as an rvalue.
62 template <class... Args> bool operator()(Args &&...) && {
63 set_call<Args &&...>(CT_NonConst | CT_RValue);
67 template <class... Args> bool operator()(Args &&...) const && {
68 set_call<Args &&...>(CT_Const | CT_RValue);
72 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...>());
79 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;
87 static CallType last_call_type;
88 static const TypeID *last_call_args;
91 CallType ForwardingCallObject::last_call_type = CT_None;
92 const TypeID *ForwardingCallObject::last_call_args = nullptr;
94 void test_call_operator_forwarding() {
95 using Fn = ForwardingCallObject;
98 { // test call operator forwarding - no variant
100 assert(Fn::check_call<>(CT_NonConst | CT_LValue));
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));
108 { // test call operator forwarding - single variant, single arg
109 using V = std::variant<int>;
112 assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
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));
120 { // test call operator forwarding - single variant, multi arg
121 using V = std::variant<int, long, double>;
124 assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
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));
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>;
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)));
148 void test_argument_forwarding() {
149 using Fn = ForwardingCallObject;
151 const auto Val = CT_LValue | CT_NonConst;
152 { // single argument - value type
153 using V = std::variant<int>;
157 assert(Fn::check_call<int &>(Val));
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));
165 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
166 { // single argument - lvalue reference
167 using V = std::variant<int &>;
172 assert(Fn::check_call<int &>(Val));
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));
180 { // single argument - rvalue reference
181 using V = std::variant<int &&>;
186 assert(Fn::check_call<int &>(Val));
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));
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";
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)));
214 template <class... Args> constexpr int operator()(int f, Args &&...) const {
220 template <class... Args> constexpr int operator()(Args &&...) const {
221 return sizeof...(Args);
225 void test_constexpr() {
226 constexpr ReturnFirst obj{};
227 constexpr ReturnArity aobj{};
229 using V = std::variant<int>;
231 static_assert(std::visit(obj, v) == 42, "");
234 using V = std::variant<short, long, char>;
236 static_assert(std::visit(obj, v) == 42, "");
239 using V1 = std::variant<int>;
240 using V2 = std::variant<int, char *, long long>;
241 using V3 = std::variant<bool, int, int>;
243 constexpr V2 v2(nullptr);
245 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
248 using V1 = std::variant<int>;
249 using V2 = std::variant<int, char *, long long>;
250 using V3 = std::variant<void *, int, int>;
252 constexpr V2 v2(nullptr);
254 static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
258 void test_exceptions() {
259 #ifndef TEST_HAS_NO_EXCEPTIONS
261 auto test = [&](auto &&... args) {
263 std::visit(obj, args...);
264 } catch (const std::bad_variant_access &) {
271 using V = std::variant<int, MakeEmptyT>;
277 using V = std::variant<int, MakeEmptyT>;
278 using V2 = std::variant<long, std::string, void *>;
285 using V = std::variant<int, MakeEmptyT>;
286 using V2 = std::variant<long, std::string, void *>;
293 using V = std::variant<int, MakeEmptyT>;
294 using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
304 // See https://bugs.llvm.org/show_bug.cgi?id=31916
305 void test_caller_accepts_nonconst() {
308 void operator()(A&) {}
311 std::visit(Visitor{}, v);
315 test_call_operator_forwarding();
316 test_argument_forwarding();
319 test_caller_accepts_nonconst();