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 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 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; 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 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 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 { 213 template <class... Args> constexpr int operator()(int f, Args &&...) const { 214 return f; 215 } 216 }; 217 218 struct ReturnArity { 219 template <class... Args> constexpr int operator()(Args &&...) const { 220 return sizeof...(Args); 221 } 222 }; 223 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 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 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 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