13412bc76SHristo Hristov //===----------------------------------------------------------------------===// 23412bc76SHristo Hristov // 33412bc76SHristo Hristov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43412bc76SHristo Hristov // See https://llvm.org/LICENSE.txt for license information. 53412bc76SHristo Hristov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63412bc76SHristo Hristov // 73412bc76SHristo Hristov //===----------------------------------------------------------------------===// 83412bc76SHristo Hristov 93412bc76SHristo Hristov // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 103412bc76SHristo Hristov // The tested functionality needs deducing this. 113412bc76SHristo Hristov // XFAIL: apple-clang 123412bc76SHristo Hristov 133412bc76SHristo Hristov // <variant> 143412bc76SHristo Hristov 153412bc76SHristo Hristov // class variant; 163412bc76SHristo Hristov 173412bc76SHristo Hristov // template<class Self, class Visitor> 183412bc76SHristo Hristov // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 193412bc76SHristo Hristov 203412bc76SHristo Hristov #include <cassert> 213412bc76SHristo Hristov #include <memory> 223412bc76SHristo Hristov #include <string> 232a385514SNikolas Klauser #include <tuple> 243412bc76SHristo Hristov #include <type_traits> 253412bc76SHristo Hristov #include <utility> 263412bc76SHristo Hristov #include <variant> 273412bc76SHristo Hristov 283412bc76SHristo Hristov #include "test_macros.h" 293412bc76SHristo Hristov #include "variant_test_helpers.h" 303412bc76SHristo Hristov 313412bc76SHristo Hristov void test_call_operator_forwarding() { 323412bc76SHristo Hristov using Fn = ForwardingCallObject; 333412bc76SHristo Hristov Fn obj{}; 343412bc76SHristo Hristov const Fn& cobj = obj; 353412bc76SHristo Hristov 363412bc76SHristo Hristov { // test call operator forwarding - single variant, single arg 373412bc76SHristo Hristov using V = std::variant<int>; 383412bc76SHristo Hristov V v(42); 393412bc76SHristo Hristov 403412bc76SHristo Hristov v.visit(obj); 413412bc76SHristo Hristov assert(Fn::check_call<int&>(CT_NonConst | CT_LValue)); 423412bc76SHristo Hristov v.visit(cobj); 433412bc76SHristo Hristov assert(Fn::check_call<int&>(CT_Const | CT_LValue)); 443412bc76SHristo Hristov v.visit(std::move(obj)); 453412bc76SHristo Hristov assert(Fn::check_call<int&>(CT_NonConst | CT_RValue)); 463412bc76SHristo Hristov v.visit(std::move(cobj)); 473412bc76SHristo Hristov assert(Fn::check_call<int&>(CT_Const | CT_RValue)); 483412bc76SHristo Hristov } 493412bc76SHristo Hristov { // test call operator forwarding - single variant, multi arg 503412bc76SHristo Hristov using V = std::variant<int, long, double>; 513412bc76SHristo Hristov V v(42L); 523412bc76SHristo Hristov 533412bc76SHristo Hristov v.visit(obj); 543412bc76SHristo Hristov assert(Fn::check_call<long&>(CT_NonConst | CT_LValue)); 553412bc76SHristo Hristov v.visit(cobj); 563412bc76SHristo Hristov assert(Fn::check_call<long&>(CT_Const | CT_LValue)); 573412bc76SHristo Hristov v.visit(std::move(obj)); 583412bc76SHristo Hristov assert(Fn::check_call<long&>(CT_NonConst | CT_RValue)); 593412bc76SHristo Hristov v.visit(std::move(cobj)); 603412bc76SHristo Hristov assert(Fn::check_call<long&>(CT_Const | CT_RValue)); 613412bc76SHristo Hristov } 623412bc76SHristo Hristov } 633412bc76SHristo Hristov 643412bc76SHristo Hristov // Applies to non-member `std::visit` only. 653412bc76SHristo Hristov void test_argument_forwarding() { 663412bc76SHristo Hristov using Fn = ForwardingCallObject; 673412bc76SHristo Hristov Fn obj{}; 683412bc76SHristo Hristov const auto val = CT_LValue | CT_NonConst; 693412bc76SHristo Hristov 703412bc76SHristo Hristov { // single argument - value type 713412bc76SHristo Hristov using V = std::variant<int>; 723412bc76SHristo Hristov V v(42); 733412bc76SHristo Hristov const V& cv = v; 743412bc76SHristo Hristov 753412bc76SHristo Hristov v.visit(obj); 763412bc76SHristo Hristov assert(Fn::check_call<int&>(val)); 773412bc76SHristo Hristov cv.visit(obj); 783412bc76SHristo Hristov assert(Fn::check_call<const int&>(val)); 793412bc76SHristo Hristov std::move(v).visit(obj); 803412bc76SHristo Hristov assert(Fn::check_call<int&&>(val)); 813412bc76SHristo Hristov std::move(cv).visit(obj); 823412bc76SHristo Hristov assert(Fn::check_call<const int&&>(val)); 833412bc76SHristo Hristov } 843412bc76SHristo Hristov } 853412bc76SHristo Hristov 863412bc76SHristo Hristov void test_return_type() { 873412bc76SHristo Hristov using Fn = ForwardingCallObject; 883412bc76SHristo Hristov Fn obj{}; 893412bc76SHristo Hristov const Fn& cobj = obj; 903412bc76SHristo Hristov 913412bc76SHristo Hristov { // test call operator forwarding - single variant, single arg 923412bc76SHristo Hristov using V = std::variant<int>; 933412bc76SHristo Hristov V v(42); 943412bc76SHristo Hristov 953412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>); 963412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>); 973412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>); 983412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>); 993412bc76SHristo Hristov } 1003412bc76SHristo Hristov { // test call operator forwarding - single variant, multi arg 1013412bc76SHristo Hristov using V = std::variant<int, long, double>; 1023412bc76SHristo Hristov V v(42L); 1033412bc76SHristo Hristov 1043412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>); 1053412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>); 1063412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>); 1073412bc76SHristo Hristov static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>); 1083412bc76SHristo Hristov } 1093412bc76SHristo Hristov } 1103412bc76SHristo Hristov 1113412bc76SHristo Hristov void test_constexpr() { 1123412bc76SHristo Hristov constexpr ReturnFirst obj{}; 1133412bc76SHristo Hristov 1143412bc76SHristo Hristov { 1153412bc76SHristo Hristov using V = std::variant<int>; 1163412bc76SHristo Hristov constexpr V v(42); 1173412bc76SHristo Hristov 1183412bc76SHristo Hristov static_assert(v.visit(obj) == 42); 1193412bc76SHristo Hristov } 1203412bc76SHristo Hristov { 1213412bc76SHristo Hristov using V = std::variant<short, long, char>; 1223412bc76SHristo Hristov constexpr V v(42L); 1233412bc76SHristo Hristov 1243412bc76SHristo Hristov static_assert(v.visit(obj) == 42); 1253412bc76SHristo Hristov } 1263412bc76SHristo Hristov } 1273412bc76SHristo Hristov 1283412bc76SHristo Hristov void test_exceptions() { 1293412bc76SHristo Hristov #ifndef TEST_HAS_NO_EXCEPTIONS 1303412bc76SHristo Hristov ReturnArity obj{}; 1313412bc76SHristo Hristov 1323412bc76SHristo Hristov auto test = [&](auto&& v) { 1333412bc76SHristo Hristov try { 1343412bc76SHristo Hristov v.visit(obj); 1353412bc76SHristo Hristov } catch (const std::bad_variant_access&) { 1363412bc76SHristo Hristov return true; 1373412bc76SHristo Hristov } catch (...) { 1383412bc76SHristo Hristov } 1393412bc76SHristo Hristov return false; 1403412bc76SHristo Hristov }; 1413412bc76SHristo Hristov 1423412bc76SHristo Hristov { 1433412bc76SHristo Hristov using V = std::variant<int, MakeEmptyT>; 1443412bc76SHristo Hristov V v; 1453412bc76SHristo Hristov makeEmpty(v); 1463412bc76SHristo Hristov 1473412bc76SHristo Hristov assert(test(v)); 1483412bc76SHristo Hristov } 1493412bc76SHristo Hristov #endif 1503412bc76SHristo Hristov } 1513412bc76SHristo Hristov 1523412bc76SHristo Hristov // See https://llvm.org/PR31916 1533412bc76SHristo Hristov void test_caller_accepts_nonconst() { 1543412bc76SHristo Hristov struct A {}; 1553412bc76SHristo Hristov struct Visitor { 1563412bc76SHristo Hristov void operator()(A&) {} 1573412bc76SHristo Hristov }; 1583412bc76SHristo Hristov std::variant<A> v; 1593412bc76SHristo Hristov 1603412bc76SHristo Hristov v.visit(Visitor{}); 1613412bc76SHristo Hristov } 1623412bc76SHristo Hristov 1633412bc76SHristo Hristov struct MyVariant : std::variant<short, long, float> {}; 1643412bc76SHristo Hristov 165*5dfdac74SNikolas Klauser // FIXME: This is UB according to [namespace.std] 1663412bc76SHristo Hristov namespace std { 1673412bc76SHristo Hristov template <std::size_t Index> 1683412bc76SHristo Hristov void get(const MyVariant&) { 1693412bc76SHristo Hristov assert(false); 1703412bc76SHristo Hristov } 1713412bc76SHristo Hristov } // namespace std 1723412bc76SHristo Hristov 1733412bc76SHristo Hristov void test_derived_from_variant() { 1743412bc76SHristo Hristov auto v1 = MyVariant{42}; 1753412bc76SHristo Hristov const auto cv1 = MyVariant{142}; 1763412bc76SHristo Hristov 1773412bc76SHristo Hristov v1.visit([](auto x) { assert(x == 42); }); 1783412bc76SHristo Hristov cv1.visit([](auto x) { assert(x == 142); }); 1793412bc76SHristo Hristov MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); 1803412bc76SHristo Hristov std::move(v1).visit([](auto x) { assert(x == 42); }); 1813412bc76SHristo Hristov std::move(cv1).visit([](auto x) { assert(x == 142); }); 1823412bc76SHristo Hristov 1833412bc76SHristo Hristov // Check that visit does not take index nor valueless_by_exception members from the base class. 1843412bc76SHristo Hristov struct EvilVariantBase { 1853412bc76SHristo Hristov int index; 1863412bc76SHristo Hristov char valueless_by_exception; 1873412bc76SHristo Hristov }; 1883412bc76SHristo Hristov 1893412bc76SHristo Hristov struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase { 1903412bc76SHristo Hristov using std::variant<int, long, double>::variant; 1913412bc76SHristo Hristov }; 1923412bc76SHristo Hristov 1933412bc76SHristo Hristov EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); 1943412bc76SHristo Hristov EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); 1953412bc76SHristo Hristov 1963412bc76SHristo Hristov // Check that visit unambiguously picks the variant, even if the other base has __impl member. 1973412bc76SHristo Hristov struct ImplVariantBase { 1983412bc76SHristo Hristov struct Callable { 1993412bc76SHristo Hristov bool operator()() const { 2003412bc76SHristo Hristov assert(false); 2013412bc76SHristo Hristov return false; 2023412bc76SHristo Hristov } 2033412bc76SHristo Hristov }; 2043412bc76SHristo Hristov 2053412bc76SHristo Hristov Callable __impl; 2063412bc76SHristo Hristov }; 2073412bc76SHristo Hristov 2083412bc76SHristo Hristov struct EvilVariant2 : std::variant<int, long, double>, ImplVariantBase { 2093412bc76SHristo Hristov using std::variant<int, long, double>::variant; 2103412bc76SHristo Hristov }; 2113412bc76SHristo Hristov 2123412bc76SHristo Hristov EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); 2133412bc76SHristo Hristov EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); 2143412bc76SHristo Hristov } 2153412bc76SHristo Hristov 2163412bc76SHristo Hristov int main(int, char**) { 2173412bc76SHristo Hristov test_call_operator_forwarding(); 2183412bc76SHristo Hristov test_argument_forwarding(); 2193412bc76SHristo Hristov test_return_type(); 2203412bc76SHristo Hristov test_constexpr(); 2213412bc76SHristo Hristov test_exceptions(); 2223412bc76SHristo Hristov test_caller_accepts_nonconst(); 2233412bc76SHristo Hristov test_derived_from_variant(); 2243412bc76SHristo Hristov 2253412bc76SHristo Hristov return 0; 2263412bc76SHristo Hristov } 227