From f8c52dc689243062ca7627c3b6ca04bea69e67e9 Mon Sep 17 00:00:00 2001 From: Zingam Date: Mon, 18 Dec 2023 14:46:15 +0200 Subject: [PATCH 01/34] [libc++][variant] P2637R3 - Member visit --- libcxx/include/variant | 22 +++++++++++++++++++ .../variant/variant.visit/visit.pass.cpp | 3 +++ 2 files changed, 25 insertions(+) diff --git a/libcxx/include/variant b/libcxx/include/variant index 3b01e5e126d9f..c5810c218a43a 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -69,6 +69,12 @@ namespace std { // 20.7.2.6, swap void swap(variant&) noexcept(see below); + + // [variant.visit], visitation + template + constexpr decltype(auto) visit(this Self&&, Visitor&&); + template + constexpr R visit(this Self&&, Visitor&&); }; // 20.7.3, variant helper classes @@ -235,6 +241,7 @@ namespace std { #include <__type_traits/void_t.h> #include <__utility/declval.h> #include <__utility/forward.h> +#include <__utility/forward_like.h> #include <__utility/in_place.h> #include <__utility/move.h> #include <__utility/swap.h> @@ -1490,6 +1497,21 @@ public: __impl_.__swap(__that.__impl_); } +# if _LIBCPP_STD_VER >= 26 + // [variant.visit], visitation + template + constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { + using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); + } + + template + constexpr _R visit(this _Self&& __self, _Visitor&& __visitor) { + using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit<_R>(std::forward<_Visitor>(__visitor), (_V)__self); + } +# endif + private: __variant_detail::__impl<_Types...> __impl_; diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 097b784f2bf2c..0dcda177ba3f8 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -47,6 +47,9 @@ void test_call_operator_forwarding() { assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); assert(Fn::check_call(CT_Const | CT_RValue)); + + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; From 68075dde56db65d8bbde8660cafe8008eba17f46 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 24 Dec 2023 09:35:42 +0200 Subject: [PATCH 02/34] WIP: Test via macro --- libcxx/include/variant | 28 ++- .../variant/variant.visit/visit.pass.cpp | 197 +++++++++++------- 2 files changed, 145 insertions(+), 80 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index a4f8371ba6acd..0da61901ce35f 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1283,16 +1283,10 @@ public: # if _LIBCPP_STD_VER >= 26 // [variant.visit], visitation template - constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { - using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; - return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); - } + constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor); template - constexpr _R visit(this _Self&& __self, _Visitor&& __visitor) { - using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; - return std::visit<_R>(std::forward<_Visitor>(__visitor), (_V)__self); - } + constexpr _R visit(this _Self&& __self, _Visitor&& __visitor); # endif private: @@ -1554,6 +1548,24 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) { } # endif +# if _LIBCPP_STD_VER >= 26 +// [variant.visit], visitation + +template +template +constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) { + using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); +} + +template +template +constexpr _Rp variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) { + using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self); +} +# endif + template _LIBCPP_HIDE_FROM_ABI auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 0dcda177ba3f8..b46924683af66 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -22,10 +22,22 @@ #include "test_macros.h" #include "variant_test_helpers.h" +#if _LIBCPP_STD_VER >= 26 +# define TEST_VISIT(object, variants, expectedValue, type, ...) \ + std::visit(object, variants); \ + assert(Fn::check_call(expectedValue)); \ + variants.visit(object); \ + assert(Fn::check_call(expectedValue)); +#else +# define TEST_VISIT(object, variants, expectedValue, type, ...) \ + std::visit(object, variants); \ + assert(Fn::check_call(expectedValue)); +#endif + void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn &cobj = obj; + const Fn& cobj = obj; { // test call operator forwarding - no variant std::visit(obj); assert(Fn::check_call<>(CT_NonConst | CT_LValue)); @@ -39,67 +51,108 @@ void test_call_operator_forwarding() { { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); + + // non-member std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); + // member +#if _LIBCPP_STD_VER >= 26 v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); +#endif + +#define TEST_VISIT1(type, object, variants, expectedValue) \ + std::visit(object, variants); \ + assert(Fn::check_call(expectedValue)); \ + variants.visit(object); \ + assert(Fn::check_call(expectedValue)); + + TEST_VISIT1(int, obj, v, (CT_NonConst | CT_LValue)); + TEST_VISIT1(int, cobj, v, (CT_Const | CT_LValue)); + TEST_VISIT1(int, std::move(obj), v, (CT_NonConst | CT_RValue)); + TEST_VISIT1(int, std::move(cobj), v, (CT_Const | CT_RValue)); + + TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), int&); + TEST_VISIT(cobj, v, (CT_Const | CT_LValue), int&); + TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), int&); + TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), int&); + + // TEST_VISIT2(td::move(cobj), v, (CT_Const | CT_RValue), int&, long&, float&); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42l); std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); + + TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), long&); + TEST_VISIT(cobj, v, (CT_Const | CT_LValue), long&); + TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), long&); + TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), long&); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); + + TEST_VISIT(obj, v, v2, CT_NonConst | CT_LValue))); + TEST_VISIT(cobj, v, v2, (CT_Const | CT_LValue))); + TEST_VISIT(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + TEST_VISIT(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } } @@ -110,76 +163,76 @@ void test_argument_forwarding() { { // single argument - value type using V = std::variant; V v(42); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(x); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } { // single argument - rvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(std::move(x)); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #endif { // multi argument - multi variant using V = std::variant; V v1(42), v2("hello"), v3(43l); std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } } void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn &cobj = obj; + const Fn& cobj = obj; { // test call operator forwarding - no variant static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -203,8 +256,8 @@ void test_return_type() { static_assert(std::is_same_v); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); static_assert(std::is_same_v); @@ -245,7 +298,7 @@ void test_constexpr() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -254,20 +307,20 @@ void test_constexpr() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } @@ -276,10 +329,10 @@ void test_constexpr() { void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - auto test = [&](auto &&... args) { + auto test = [&](auto&&... args) { try { std::visit(obj, args...); - } catch (const std::bad_variant_access &) { + } catch (const std::bad_variant_access&) { return true; } catch (...) { } @@ -292,24 +345,24 @@ void test_exceptions() { assert(test(v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v, v2)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v2, v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2; @@ -354,7 +407,7 @@ void get(const MyVariant&) { } // namespace std void test_derived_from_variant() { - auto v1 = MyVariant{42}; + auto v1 = MyVariant{42}; const auto cv1 = MyVariant{142}; std::visit([](auto x) { assert(x == 42); }, v1); std::visit([](auto x) { assert(x == 142); }, cv1); @@ -368,9 +421,7 @@ void test_derived_from_variant() { char valueless_by_exception; }; - struct EvilVariant1 : std::variant, - std::tuple, - EvilVariantBase { + struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { using std::variant::variant; }; @@ -380,7 +431,10 @@ void test_derived_from_variant() { // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { struct Callable { - bool operator()() const { assert(false); return false; } + bool operator()() const { + assert(false); + return false; + } }; Callable __impl; @@ -399,8 +453,7 @@ struct any_visitor { void operator()(const T&) const {} }; -template (), std::declval()))> +template (), std::declval()))> constexpr bool has_visit(int) { return true; } From 0bc0832e848bd01c40337dab9344aa506501a792 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 24 Dec 2023 09:43:27 +0200 Subject: [PATCH 03/34] WIP: visit.pass --- .../variant/variant.visit/visit.pass.cpp | 115 +++++++----------- 1 file changed, 47 insertions(+), 68 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index b46924683af66..3fac6b21f2682 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -22,18 +22,6 @@ #include "test_macros.h" #include "variant_test_helpers.h" -#if _LIBCPP_STD_VER >= 26 -# define TEST_VISIT(object, variants, expectedValue, type, ...) \ - std::visit(object, variants); \ - assert(Fn::check_call(expectedValue)); \ - variants.visit(object); \ - assert(Fn::check_call(expectedValue)); -#else -# define TEST_VISIT(object, variants, expectedValue, type, ...) \ - std::visit(object, variants); \ - assert(Fn::check_call(expectedValue)); -#endif - void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; @@ -51,63 +39,61 @@ void test_call_operator_forwarding() { { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - - // non-member - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - - // member #if _LIBCPP_STD_VER >= 26 - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } #endif -#define TEST_VISIT1(type, object, variants, expectedValue) \ - std::visit(object, variants); \ - assert(Fn::check_call(expectedValue)); \ - variants.visit(object); \ - assert(Fn::check_call(expectedValue)); - - TEST_VISIT1(int, obj, v, (CT_NonConst | CT_LValue)); - TEST_VISIT1(int, cobj, v, (CT_Const | CT_LValue)); - TEST_VISIT1(int, std::move(obj), v, (CT_NonConst | CT_RValue)); - TEST_VISIT1(int, std::move(cobj), v, (CT_Const | CT_RValue)); - - TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), int&); - TEST_VISIT(cobj, v, (CT_Const | CT_LValue), int&); - TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), int&); - TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), int&); - - // TEST_VISIT2(td::move(cobj), v, (CT_Const | CT_RValue), int&, long&, float&); + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42l); - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - TEST_VISIT(obj, v, (CT_NonConst | CT_LValue), long&); - TEST_VISIT(cobj, v, (CT_Const | CT_LValue), long&); - TEST_VISIT(std::move(obj), v, (CT_NonConst | CT_RValue), long&); - TEST_VISIT(std::move(cobj), v, (CT_Const | CT_RValue), long&); +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } } { // test call operator forwarding - multi variant, multi arg using V = std::variant; @@ -122,13 +108,6 @@ void test_call_operator_forwarding() { assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v, v2); assert((Fn::check_call(CT_Const | CT_RValue))); - - TEST_VISIT(obj, v, v2, CT_NonConst | CT_LValue))); - TEST_VISIT(cobj, v, v2, (CT_Const | CT_LValue))); - TEST_VISIT(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - TEST_VISIT(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; From 1de898e6d27795b159526055b400e68faa7aff11 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 24 Dec 2023 10:09:54 +0200 Subject: [PATCH 04/34] template_argument --- libcxx/docs/Status/Cxx2c.rst | 2 + libcxx/docs/Status/Cxx2cPapers.csv | 2 +- .../variant.visit/robust_against_adl.pass.cpp | 54 ++-- .../variant/variant.visit/visit.pass.cpp | 264 ++++++++++++------ .../variant.visit/visit_return_type.pass.cpp | 206 ++++++++------ .../generate_feature_test_macro_components.py | 6 +- 6 files changed, 348 insertions(+), 186 deletions(-) diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst index a7ebc4662f517..5c700d2cb0d6d 100644 --- a/libcxx/docs/Status/Cxx2c.rst +++ b/libcxx/docs/Status/Cxx2c.rst @@ -40,6 +40,8 @@ Paper Status .. note:: .. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.) + .. [#note-P2637R3] P2637R3: Implemented `variant` member `visit` + .. _issues-status-cxx2c: diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index ff83648aa7683..a3214ab2bfe75 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -17,7 +17,7 @@ "`P0792R14 `__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","","" "`P2874R2 `__","LWG","Mandating Annex D Require No More","Varna June 2023","","","" "`P2757R3 `__","LWG","Type-checking format args","Varna June 2023","","","|format|" -"`P2637R3 `__","LWG","Member ``visit``","Varna June 2023","","","|format|" +"`P2637R3 `__","LWG","Member ``visit``","Varna June 2023","|Partial| [#note-P2637R3]","18.0","" "`P2641R4 `__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","","" "`P1759R6 `__","LWG","Native handles and file streams","Varna June 2023","","","" "`P2697R1 `__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0","" diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp index 6f17fa32648d4..6f09589169386 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -9,6 +9,13 @@ // UNSUPPORTED: c++03, c++11, c++14 // + +// class variant; +// template +// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26 +// template +// constexpr R visit(this Self&&, Visitor&&); // since C++26 + // template // constexpr see below visit(Visitor&& vis, Variants&&... vars); @@ -17,27 +24,42 @@ #include "test_macros.h" struct Incomplete; -template struct Holder { T t; }; - -constexpr bool test(bool do_it) -{ - if (do_it) { - std::variant*, int> v = nullptr; - std::visit([](auto){}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); +template +struct Holder { + T t; +}; + +constexpr bool test(bool do_it) { + if (do_it) { + std::variant*, int> v = nullptr; + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit([](auto) {}); + v.visit([](auto) -> Holder* { return nullptr; }); + v.visit([](auto) {}); + v.visit([](auto) -> Holder* { return nullptr; }); + } +#endif + + // non-member + { + std::visit([](auto) {}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #if TEST_STD_VER > 17 - std::visit([](auto){}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); + std::visit([](auto) {}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #endif } - return true; + } + return true; } -int main(int, char**) -{ - test(true); +int main(int, char**) { + test(true); #if TEST_STD_VER > 17 - static_assert(test(true)); + static_assert(test(true)); #endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 3fac6b21f2682..72c9ca2280219 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -9,6 +9,13 @@ // UNSUPPORTED: c++03, c++11, c++14 // + +// class variant; +// template +// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26 +// template +// constexpr R visit(this Self&&, Visitor&&); // since C++26 + // template // constexpr see below visit(Visitor&& vis, Variants&&... vars); @@ -26,19 +33,24 @@ void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const Fn& cobj = obj; + { // test call operator forwarding - no variant - std::visit(obj); - assert(Fn::check_call<>(CT_NonConst | CT_LValue)); - std::visit(cobj); - assert(Fn::check_call<>(CT_Const | CT_LValue)); - std::visit(std::move(obj)); - assert(Fn::check_call<>(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj)); - assert(Fn::check_call<>(CT_Const | CT_RValue)); + // non-member + { + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); + #if _LIBCPP_STD_VER >= 26 // member { @@ -67,7 +79,7 @@ void test_call_operator_forwarding() { } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42l); + V v(42L); #if _LIBCPP_STD_VER >= 26 // member @@ -98,59 +110,77 @@ void test_call_operator_forwarding() { { // test call operator forwarding - multi variant, multi arg using V = std::variant; using V2 = std::variant; - V v(42l); + V v(42L); V2 v2("hello"); - std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); + + // non-member + { + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } { using V = std::variant; - V v1(42l), v2("hello"), v3(101), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } { using V = std::variant; - V v1(42l), v2("hello"), v3(nullptr), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } } +// Applies to non-member `std::visit` only. void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const auto Val = CT_LValue | CT_NonConst; + { // single argument - value type using V = std::variant; V v(42); const V& cv = v; - std::visit(obj, v); - assert(Fn::check_call(Val)); - std::visit(obj, cv); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference @@ -158,6 +188,7 @@ void test_argument_forwarding() { int x = 42; V v(x); const V& cv = v; + std::visit(obj, v); assert(Fn::check_call(Val)); std::visit(obj, cv); @@ -172,6 +203,7 @@ void test_argument_forwarding() { int x = 42; V v(std::move(x)); const V& cv = v; + std::visit(obj, v); assert(Fn::check_call(Val)); std::visit(obj, cv); @@ -184,7 +216,8 @@ void test_argument_forwarding() { #endif { // multi argument - multi variant using V = std::variant; - V v1(42), v2("hello"), v3(43l); + V v1(42), v2("hello"), v3(43L); + std::visit(obj, v1, v2, v3); assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); @@ -193,6 +226,7 @@ void test_argument_forwarding() { { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); @@ -201,6 +235,7 @@ void test_argument_forwarding() { { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); @@ -212,6 +247,7 @@ void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; const Fn& cobj = obj; + { // test call operator forwarding - no variant static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -221,59 +257,114 @@ void test_return_type() { { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } +#endif + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42l); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } +#endif + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } } { // test call operator forwarding - multi variant, multi arg using V = std::variant; using V2 = std::variant; - V v(42l); + V v(42L); V2 v2("hello"); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } } { using V = std::variant; - V v1(42l), v2("hello"), v3(101), v4(1.1); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } } { using V = std::variant; - V v1(42l), v2("hello"), v3(nullptr), v4(1.1); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } } } void test_constexpr() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; + { using V = std::variant; constexpr V v(42); - static_assert(std::visit(obj, v) == 42, ""); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + + //non-member + { static_assert(std::visit(obj, v) == 42, ""); } } { using V = std::variant; - constexpr V v(42l); - static_assert(std::visit(obj, v) == 42, ""); + constexpr V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + + //non-member + { static_assert(std::visit(obj, v) == 42, ""); } } { using V1 = std::variant; @@ -282,7 +373,9 @@ void test_constexpr() { constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + + //non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } } { using V1 = std::variant; @@ -291,17 +384,23 @@ void test_constexpr() { constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + + //non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } } { using V = std::variant; - constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); - static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + //non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } { using V = std::variant; - constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); - static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + //non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } } @@ -373,7 +472,14 @@ void test_caller_accepts_nonconst() { void operator()(A&) {} }; std::variant v; - std::visit(Visitor{}, v); + +#if _LIBCPP_STD_VER >= 26 + // member + { v.visit(Visitor{}); } +#endif + + //non-member + { std::visit(Visitor{}, v); } } struct MyVariant : std::variant {}; diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index eb425c07f9322..f8cdb70a28fa3 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -9,6 +9,13 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // + +// class variant; +// template +// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26 +// template +// constexpr R visit(this Self&&, Visitor&&); // since C++26 + // template // constexpr R visit(Visitor&& vis, Variants&&... vars); @@ -26,78 +33,100 @@ template void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn &cobj = obj; + const Fn& cobj = obj; + { // test call operator forwarding - no variant - std::visit(obj); - assert(Fn::check_call<>(CT_NonConst | CT_LValue)); - std::visit(cobj); - assert(Fn::check_call<>(CT_Const | CT_LValue)); - std::visit(std::move(obj)); - assert(Fn::check_call<>(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj)); - assert(Fn::check_call<>(CT_Const | CT_RValue)); + // non-member + { + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42l); std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } } @@ -109,69 +138,69 @@ void test_argument_forwarding() { { // single argument - value type using V = std::variant; V v(42); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(x); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } { // single argument - rvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(std::move(x)); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #endif { // multi argument - multi variant using V = std::variant; V v1(42), v2("hello"), v3(43l); std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } } @@ -179,7 +208,7 @@ template void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn &cobj = obj; + const Fn& cobj = obj; { // test call operator forwarding - no variant static_assert(std::is_same_v(obj)), ReturnType>); static_assert(std::is_same_v(cobj)), ReturnType>); @@ -203,8 +232,8 @@ void test_return_type() { static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); static_assert(std::is_same_v(obj, v, v2)), ReturnType>); @@ -245,7 +274,7 @@ void test_constexpr_void() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -254,20 +283,20 @@ void test_constexpr_void() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } @@ -288,7 +317,7 @@ void test_constexpr_int() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -297,20 +326,20 @@ void test_constexpr_int() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } @@ -320,10 +349,10 @@ template void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - auto test = [&](auto &&... args) { + auto test = [&](auto&&... args) { try { std::visit(obj, args...); - } catch (const std::bad_variant_access &) { + } catch (const std::bad_variant_access&) { return true; } catch (...) { } @@ -336,24 +365,24 @@ void test_exceptions() { assert(test(v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v, v2)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v2, v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2; @@ -384,8 +413,7 @@ void test_caller_accepts_nonconst() { struct A {}; struct Visitor { auto operator()(A&) { - if constexpr (!std::is_void_v) - { + if constexpr (!std::is_void_v) { return ReturnType{}; } } @@ -426,9 +454,7 @@ void test_derived_from_variant() { char valueless_by_exception; }; - struct EvilVariant1 : std::variant, - std::tuple, - EvilVariantBase { + struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { using std::variant::variant; }; @@ -448,7 +474,10 @@ void test_derived_from_variant() { // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { struct Callable { - bool operator()() const { assert(false); return false; } + bool operator()() const { + assert(false); + return false; + } }; Callable __impl; @@ -479,8 +508,7 @@ struct any_visitor { } }; -template ( - std::declval(), std::declval()))> +template (std::declval(), std::declval()))> constexpr bool has_visit(int) { return true; } diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 2f506f32f565c..ed89c1e679015 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1264,7 +1264,11 @@ def add_version_header(tc): }, { "name": "__cpp_lib_variant", - "values": {"c++17": 202102}, + "values": { + "c++17": 202102, # std::visit for classes derived from std::variant + # "c++20": 202106, # Fully constexpr std::variant + # "c++26": 202306, # Member visit + }, "headers": ["variant"], }, { From a52349b46a758bf8d0ba0d46ef036ff1901a1e82 Mon Sep 17 00:00:00 2001 From: Zingam Date: Mon, 25 Dec 2023 13:13:36 +0200 Subject: [PATCH 05/34] Implemented missing `visit` constraint + test --- libcxx/include/variant | 4 +-- .../variant/variant.visit/visit.pass.cpp | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 0da61901ce35f..4c9b04942f277 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1282,7 +1282,7 @@ public: # if _LIBCPP_STD_VER >= 26 // [variant.visit], visitation - template + template constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor); template @@ -1552,7 +1552,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) { // [variant.visit], visitation template -template +template constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) { using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 72c9ca2280219..adbc131a6477a 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -562,6 +562,38 @@ void test_sfinae() { static_assert(has_visit(0)); } +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +void test_overload_ambiguity() { +#if _LIBCPP_STD_VER >= 26 + using V = std::variant; + using namespace std::string_literals; + V v{"baba"s}; + + // member + v.visit( + overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); + assert(std::get(v) == "baba"s); + + // `constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);` + // vs + // `constexpr _R visit(this _Self&& __self, _Visitor&& __visitor);` + v = std::move(v).visit(overloaded{ + []([[maybe_unused]] auto x) { + assert(false); + return 0; + }, + [](const std::string& x) { + assert(x == "baba"s); + return x + " zmt"s; + }}); + assert(std::get(v) == "baba zmt"s); +#endif +} + int main(int, char**) { test_call_operator_forwarding(); test_argument_forwarding(); @@ -571,6 +603,7 @@ int main(int, char**) { test_caller_accepts_nonconst(); test_derived_from_variant(); test_sfinae(); + test_overload_ambiguity(); return 0; } From 9b7064d177f5205f5540f0c13aa33cdc93032cc8 Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 27 Dec 2023 16:13:41 +0200 Subject: [PATCH 06/34] WIP: Updated visit tests --- .../variant/variant.visit/visit.pass.cpp | 261 +++++++++++------- .../variant.visit/visit_return_type.pass.cpp | 223 ++++++++++----- 2 files changed, 321 insertions(+), 163 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index adbc131a6477a..6aff2194fa68d 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -163,23 +163,37 @@ void test_call_operator_forwarding() { void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const auto Val = CT_LValue | CT_NonConst; + const auto val = CT_LValue | CT_NonConst; { // single argument - value type using V = std::variant; V v(42); const V& cv = v; +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +#endif + // non-member { std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); } } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) @@ -189,14 +203,32 @@ void test_argument_forwarding() { V v(x); const V& cv = v; - std::visit(obj, v); - assert(Fn::check_call(Val)); - std::visit(obj, cv); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + // # if _LIBCPP_STD_VER >= 26 + // // member + // { + // v.visit(obj); + // assert(Fn::check_call(val)); + // cv.visit(obj); + // assert(Fn::check_call(val)); + // std::move(v).visit(obj); + // assert(Fn::check_call(val)); + // std::move(cv).visit(obj); + // assert(Fn::check_call(CT_NonConst)); + // assert(false); + // } + // # endif + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } } { // single argument - rvalue reference using V = std::variant; @@ -204,42 +236,54 @@ void test_argument_forwarding() { V v(std::move(x)); const V& cv = v; - std::visit(obj, v); - assert(Fn::check_call(Val)); - std::visit(obj, cv); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } } #endif { // multi argument - multi variant using V = std::variant; V v1(42), v2("hello"), v3(43L); - std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + // non-member + { + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(val))); + } } { using V = std::variant; - V v1(42l), v2("hello"), v3(101), v4(1.1); + V v1(42L), v2("hello"), v3(101), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(val))); + } } { using V = std::variant; - V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(val))); + } } } @@ -249,10 +293,13 @@ void test_return_type() { const Fn& cobj = obj; { // test call operator forwarding - no variant - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } } { // test call operator forwarding - single variant, single arg using V = std::variant; @@ -351,7 +398,7 @@ void test_constexpr() { { static_assert(v.visit(obj) == 42); } #endif - //non-member + // non-member { static_assert(std::visit(obj, v) == 42, ""); } } { @@ -363,7 +410,7 @@ void test_constexpr() { { static_assert(v.visit(obj) == 42); } #endif - //non-member + // non-member { static_assert(std::visit(obj, v) == 42, ""); } } { @@ -374,7 +421,7 @@ void test_constexpr() { constexpr V2 v2(nullptr); constexpr V3 v3; - //non-member + // non-member { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } } { @@ -385,21 +432,21 @@ void test_constexpr() { constexpr V2 v2(nullptr); constexpr V3 v3; - //non-member + // non-member { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } } { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - //non-member + // non-member { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - //non-member + // non-member { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } } @@ -407,7 +454,22 @@ void test_constexpr() { void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - auto test = [&](auto&&... args) { + +# if _LIBCPP_STD_VER >= 26 + // member + auto test_member = [&](auto&& v) { + try { + v.visit(obj); + } catch (const std::bad_variant_access&) { + return true; + } catch (...) { + } + return false; + }; +# endif + + // non-member + auto test_nonmember = [&](auto&&... args) { try { std::visit(obj, args...); } catch (const std::bad_variant_access&) { @@ -416,11 +478,16 @@ void test_exceptions() { } return false; }; + { using V = std::variant; V v; +# if _LIBCPP_STD_VER >= 26 + makeEmpty(v); + assert(test_member(v)); +# endif makeEmpty(v); - assert(test(v)); + assert(test_nonmember(v)); } { using V = std::variant; @@ -428,7 +495,7 @@ void test_exceptions() { V v; makeEmpty(v); V2 v2("hello"); - assert(test(v, v2)); + assert(test_nonmember(v, v2)); } { using V = std::variant; @@ -436,7 +503,7 @@ void test_exceptions() { V v; makeEmpty(v); V2 v2("hello"); - assert(test(v2, v)); + assert(test_nonmember(v2, v)); } { using V = std::variant; @@ -445,13 +512,13 @@ void test_exceptions() { makeEmpty(v); V2 v2; makeEmpty(v2); - assert(test(v, v2)); + assert(test_nonmember(v, v2)); } { using V = std::variant; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); - assert(test(v1, v2, v3, v4)); + assert(test_nonmember(v1, v2, v3, v4)); } { using V = std::variant; @@ -460,7 +527,7 @@ void test_exceptions() { makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); - assert(test(v1, v2, v3, v4)); + assert(test_nonmember(v1, v2, v3, v4)); } #endif } @@ -478,7 +545,7 @@ void test_caller_accepts_nonconst() { { v.visit(Visitor{}); } #endif - //non-member + // non-member { std::visit(Visitor{}, v); } } @@ -494,11 +561,26 @@ void get(const MyVariant&) { void test_derived_from_variant() { auto v1 = MyVariant{42}; const auto cv1 = MyVariant{142}; - std::visit([](auto x) { assert(x == 42); }, v1); - std::visit([](auto x) { assert(x == 142); }, cv1); - std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); - std::visit([](auto x) { assert(x == 42); }, std::move(v1)); - std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v1.visit([](auto x) { assert(x == 42); }); + cv1.visit([](auto x) { assert(x == 142); }); + MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); + std::move(v1).visit([](auto x) { assert(x == 42); }); + std::move(cv1).visit([](auto x) { assert(x == 142); }); + } +#endif + + // non-member + { + std::visit([](auto x) { assert(x == 42); }, v1); + std::visit([](auto x) { assert(x == 142); }, cv1); + std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); + std::visit([](auto x) { assert(x == 42); }, std::move(v1)); + std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); + } // Check that visit does not take index nor valueless_by_exception members from the base class. struct EvilVariantBase { @@ -510,8 +592,19 @@ void test_derived_from_variant() { using std::variant::variant; }; - std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); - std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); + EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); + } +#endif + + // non-member + { + std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); + } // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { @@ -529,8 +622,19 @@ void test_derived_from_variant() { using std::variant::variant; }; - std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); - std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); + EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); + } +#endif + + // non-member + { + std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); + } } struct any_visitor { @@ -562,38 +666,6 @@ void test_sfinae() { static_assert(has_visit(0)); } -template -struct overloaded : Ts... { - using Ts::operator()...; -}; - -void test_overload_ambiguity() { -#if _LIBCPP_STD_VER >= 26 - using V = std::variant; - using namespace std::string_literals; - V v{"baba"s}; - - // member - v.visit( - overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); - assert(std::get(v) == "baba"s); - - // `constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);` - // vs - // `constexpr _R visit(this _Self&& __self, _Visitor&& __visitor);` - v = std::move(v).visit(overloaded{ - []([[maybe_unused]] auto x) { - assert(false); - return 0; - }, - [](const std::string& x) { - assert(x == "baba"s); - return x + " zmt"s; - }}); - assert(std::get(v) == "baba zmt"s); -#endif -} - int main(int, char**) { test_call_operator_forwarding(); test_argument_forwarding(); @@ -603,7 +675,6 @@ int main(int, char**) { test_caller_accepts_nonconst(); test_derived_from_variant(); test_sfinae(); - test_overload_ambiguity(); return 0; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index f8cdb70a28fa3..db4fb1961c48e 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -81,52 +81,82 @@ void test_call_operator_forwarding() { { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42l); - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } } { // test call operator forwarding - multi variant, multi arg using V = std::variant; using V2 = std::variant; V v(42l); V2 v2("hello"); - std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); + + // non-member + { + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } } } @@ -135,18 +165,23 @@ void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; const auto Val = CT_LValue | CT_NonConst; + { // single argument - value type using V = std::variant; V v(42); const V& cv = v; - std::visit(obj, v); - assert(Fn::check_call(Val)); - std::visit(obj, cv); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference @@ -154,53 +189,73 @@ void test_argument_forwarding() { int x = 42; V v(x); const V& cv = v; - std::visit(obj, v); - assert(Fn::check_call(Val)); - std::visit(obj, cv); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } } { // single argument - rvalue reference using V = std::variant; int x = 42; V v(std::move(x)); const V& cv = v; - std::visit(obj, v); - assert(Fn::check_call(Val)); - std::visit(obj, cv); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); + } } #endif { // multi argument - multi variant using V = std::variant; V v1(42), v2("hello"), v3(43l); - std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + + // non-member + { + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(Val))); + } } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); + } } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); + } } } @@ -209,6 +264,7 @@ void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; const Fn& cobj = obj; + { // test call operator forwarding - no variant static_assert(std::is_same_v(obj)), ReturnType>); static_assert(std::is_same_v(cobj)), ReturnType>); @@ -525,6 +581,36 @@ void test_sfinae() { static_assert(!has_visit(int())); } +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +void test_overload_ambiguity() { +#if _LIBCPP_STD_VER >= 26 + using V = std::variant; + using namespace std::string_literals; + V v{"baba"s}; + + // member + v.visit( + overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); + assert(std::get(v) == "baba"s); + + // Test the constraint. + v = std::move(v).visit(overloaded{ + []([[maybe_unused]] auto x) { + assert(false); + return 0; + }, + [](const std::string& x) { + assert(x == "baba"s); + return x + " zmt"s; + }}); + assert(std::get(v) == "baba zmt"s); +#endif +} + int main(int, char**) { test_call_operator_forwarding(); test_argument_forwarding(); @@ -541,6 +627,7 @@ int main(int, char**) { test_constexpr_explicit_side_effect(); test_derived_from_variant(); test_sfinae(); + test_overload_ambiguity(); return 0; } From 2d47529005c5f4444396b039f2f889cf86835d75 Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 27 Dec 2023 16:35:24 +0200 Subject: [PATCH 07/34] WIP: tests --- .../variant/variant.visit/visit.pass.cpp | 42 ++-- .../variant.visit/visit_return_type.pass.cpp | 194 ++++++++++++------ 2 files changed, 155 insertions(+), 81 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 6aff2194fa68d..9eea5f60e3138 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -203,20 +203,20 @@ void test_argument_forwarding() { V v(x); const V& cv = v; - // # if _LIBCPP_STD_VER >= 26 - // // member - // { - // v.visit(obj); - // assert(Fn::check_call(val)); - // cv.visit(obj); - // assert(Fn::check_call(val)); - // std::move(v).visit(obj); - // assert(Fn::check_call(val)); - // std::move(cv).visit(obj); - // assert(Fn::check_call(CT_NonConst)); - // assert(false); - // } - // # endif +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + assert(false); + } +# endif // non-member { @@ -236,6 +236,20 @@ void test_argument_forwarding() { V v(std::move(x)); const V& cv = v; +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cvstd::visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +# endif + // non-member { std::visit(obj, v); diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index db4fb1961c48e..31d7665d6b3ae 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -29,6 +29,36 @@ #include "test_macros.h" #include "variant_test_helpers.h" +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +void test_overload_ambiguity() { +#if _LIBCPP_STD_VER >= 26 + using V = std::variant; + using namespace std::string_literals; + V v{"baba"s}; + + // member + v.visit( + overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); + assert(std::get(v) == "baba"s); + + // Test the constraint. + v = std::move(v).visit(overloaded{ + []([[maybe_unused]] auto x) { + assert(false); + return 0; + }, + [](const std::string& x) { + assert(x == "baba"s); + return x + " zmt"s; + }}); + assert(std::get(v) == "baba zmt"s); +#endif +} + template void test_call_operator_forwarding() { using Fn = ForwardingCallObject; @@ -80,7 +110,7 @@ void test_call_operator_forwarding() { } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42l); + V v(42L); #if _LIBCPP_STD_VER >= 26 // member @@ -111,7 +141,7 @@ void test_call_operator_forwarding() { { // test call operator forwarding - multi variant, multi arg using V = std::variant; using V2 = std::variant; - V v(42l); + V v(42L); V2 v2("hello"); // non-member @@ -128,7 +158,7 @@ void test_call_operator_forwarding() { } { using V = std::variant; - V v1(42l), v2("hello"), v3(101), v4(1.1); + V v1(42L), v2("hello"), v3(101), v4(1.1); // non-member { @@ -144,7 +174,7 @@ void test_call_operator_forwarding() { } { using V = std::variant; - V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); // non-member { @@ -164,23 +194,37 @@ template void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const auto Val = CT_LValue | CT_NonConst; + const auto val = CT_LValue | CT_NonConst; { // single argument - value type using V = std::variant; V v(42); const V& cv = v; +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +#endif + // non-member { std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); } } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) @@ -190,16 +234,30 @@ void test_argument_forwarding() { V v(x); const V& cv = v; +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +# endif + // non-member { std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); } } { // single argument - rvalue reference @@ -208,53 +266,67 @@ void test_argument_forwarding() { V v(std::move(x)); const V& cv = v; +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +# endif + // non-member { std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(val)); } } #endif { // multi argument - multi variant using V = std::variant; - V v1(42), v2("hello"), v3(43l); + V v1(42), v2("hello"), v3(43L); // non-member { std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); + assert((Fn::check_call(val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(val))); } } { using V = std::variant; - V v1(42l), v2("hello"), v3(101), v4(1.1); + V v1(42L), v2("hello"), v3(101), v4(1.1); // non-member { std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(val))); } } { using V = std::variant; - V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); // non-member { std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(val))); } } } @@ -274,6 +346,7 @@ void test_return_type() { { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); + static_assert(std::is_same_v(obj, v)), ReturnType>); static_assert(std::is_same_v(cobj, v)), ReturnType>); static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); @@ -281,7 +354,8 @@ void test_return_type() { } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42l); + V v(42L); + static_assert(std::is_same_v(obj, v)), ReturnType>); static_assert(std::is_same_v(cobj, v)), ReturnType>); static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); @@ -290,8 +364,9 @@ void test_return_type() { { // test call operator forwarding - multi variant, multi arg using V = std::variant; using V2 = std::variant; - V v(42l); + V v(42L); V2 v2("hello"); + static_assert(std::is_same_v(obj, v, v2)), ReturnType>); static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); @@ -299,7 +374,8 @@ void test_return_type() { } { using V = std::variant; - V v1(42l), v2("hello"), v3(101), v4(1.1); + V v1(42L), v2("hello"), v3(101), v4(1.1); + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); @@ -307,7 +383,8 @@ void test_return_type() { } { using V = std::variant; - V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); @@ -321,11 +398,13 @@ void test_constexpr_void() { { using V = std::variant; constexpr V v(42); + static_assert((std::visit(obj, v), 42) == 42, ""); } { using V = std::variant; - constexpr V v(42l); + constexpr V v(42L); + static_assert((std::visit(obj, v), 42) == 42, ""); } { @@ -335,6 +414,7 @@ void test_constexpr_void() { constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; + static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { @@ -344,16 +424,19 @@ void test_constexpr_void() { constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; + static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { using V = std::variant; - constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } { using V = std::variant; - constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } } @@ -361,14 +444,17 @@ void test_constexpr_void() { void test_constexpr_int() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; + { using V = std::variant; constexpr V v(42); + static_assert(std::visit(obj, v) == 42, ""); } { using V = std::variant; - constexpr V v(42l); + constexpr V v(42L); + static_assert(std::visit(obj, v) == 42, ""); } { @@ -378,6 +464,7 @@ void test_constexpr_int() { constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { @@ -387,16 +474,19 @@ void test_constexpr_int() { constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { using V = std::variant; - constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { using V = std::variant; - constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } @@ -581,37 +671,8 @@ void test_sfinae() { static_assert(!has_visit(int())); } -template -struct overloaded : Ts... { - using Ts::operator()...; -}; - -void test_overload_ambiguity() { -#if _LIBCPP_STD_VER >= 26 - using V = std::variant; - using namespace std::string_literals; - V v{"baba"s}; - - // member - v.visit( - overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); - assert(std::get(v) == "baba"s); - - // Test the constraint. - v = std::move(v).visit(overloaded{ - []([[maybe_unused]] auto x) { - assert(false); - return 0; - }, - [](const std::string& x) { - assert(x == "baba"s); - return x + " zmt"s; - }}); - assert(std::get(v) == "baba zmt"s); -#endif -} - int main(int, char**) { + test_overload_ambiguity(); test_call_operator_forwarding(); test_argument_forwarding(); test_return_type(); @@ -627,7 +688,6 @@ int main(int, char**) { test_constexpr_explicit_side_effect(); test_derived_from_variant(); test_sfinae(); - test_overload_ambiguity(); return 0; } From 55516cd85c29695d58b6602e5c4f49319280cd8d Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 27 Dec 2023 17:08:46 +0200 Subject: [PATCH 08/34] WIP: more test refactoring --- .../variant/variant.visit/visit.pass.cpp | 19 +- .../variant.visit/visit_return_type.pass.cpp | 205 ++++++++++++++---- 2 files changed, 165 insertions(+), 59 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 9eea5f60e3138..4bc35edeed3e0 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -64,7 +64,6 @@ void test_call_operator_forwarding() { assert(Fn::check_call(CT_Const | CT_RValue)); } #endif - // non-member { std::visit(obj, v); @@ -94,7 +93,6 @@ void test_call_operator_forwarding() { assert(Fn::check_call(CT_Const | CT_RValue)); } #endif - // non-member { std::visit(obj, v); @@ -183,7 +181,6 @@ void test_argument_forwarding() { assert(Fn::check_call(val)); } #endif - // non-member { std::visit(obj, v); @@ -249,7 +246,6 @@ void test_argument_forwarding() { assert(Fn::check_call(val)); } # endif - // non-member { std::visit(obj, v); @@ -328,7 +324,6 @@ void test_return_type() { static_assert(std::is_same_v); } #endif - // non-member { static_assert(std::is_same_v); @@ -350,7 +345,6 @@ void test_return_type() { static_assert(std::is_same_v); } #endif - // non-member { static_assert(std::is_same_v); @@ -411,7 +405,6 @@ void test_constexpr() { // member { static_assert(v.visit(obj) == 42); } #endif - // non-member { static_assert(std::visit(obj, v) == 42, ""); } } @@ -481,7 +474,6 @@ void test_exceptions() { return false; }; # endif - // non-member auto test_nonmember = [&](auto&&... args) { try { @@ -498,9 +490,11 @@ void test_exceptions() { V v; # if _LIBCPP_STD_VER >= 26 makeEmpty(v); + assert(test_member(v)); # endif makeEmpty(v); + assert(test_nonmember(v)); } { @@ -509,6 +503,7 @@ void test_exceptions() { V v; makeEmpty(v); V2 v2("hello"); + assert(test_nonmember(v, v2)); } { @@ -517,6 +512,7 @@ void test_exceptions() { V v; makeEmpty(v); V2 v2("hello"); + assert(test_nonmember(v2, v)); } { @@ -526,12 +522,14 @@ void test_exceptions() { makeEmpty(v); V2 v2; makeEmpty(v2); + assert(test_nonmember(v, v2)); } { using V = std::variant; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); + assert(test_nonmember(v1, v2, v3, v4)); } { @@ -541,6 +539,7 @@ void test_exceptions() { makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); + assert(test_nonmember(v1, v2, v3, v4)); } #endif @@ -558,7 +557,6 @@ void test_caller_accepts_nonconst() { // member { v.visit(Visitor{}); } #endif - // non-member { std::visit(Visitor{}, v); } } @@ -586,7 +584,6 @@ void test_derived_from_variant() { std::move(cv1).visit([](auto x) { assert(x == 142); }); } #endif - // non-member { std::visit([](auto x) { assert(x == 42); }, v1); @@ -613,7 +610,6 @@ void test_derived_from_variant() { EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); } #endif - // non-member { std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); @@ -643,7 +639,6 @@ void test_derived_from_variant() { EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); } #endif - // non-member { std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index 31d7665d6b3ae..34d90c96e43f2 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -95,7 +95,6 @@ void test_call_operator_forwarding() { assert(Fn::check_call(CT_Const | CT_RValue)); } #endif - // non-member { std::visit(obj, v); @@ -338,28 +337,57 @@ void test_return_type() { const Fn& cobj = obj; { // test call operator forwarding - no variant - static_assert(std::is_same_v(obj)), ReturnType>); - static_assert(std::is_same_v(cobj)), ReturnType>); - static_assert(std::is_same_v(std::move(obj))), ReturnType>); - static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + // non-member + { + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - static_assert(std::is_same_v(obj, v)), ReturnType>); - static_assert(std::is_same_v(cobj, v)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } +#endif + + // non-member + { + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); + } } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42L); - static_assert(std::is_same_v(obj, v)), ReturnType>); - static_assert(std::is_same_v(cobj, v)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } +#endif + + // non-member + { + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); + } } { // test call operator forwarding - multi variant, multi arg using V = std::variant; @@ -367,28 +395,37 @@ void test_return_type() { V v(42L); V2 v2("hello"); - static_assert(std::is_same_v(obj, v, v2)), ReturnType>); - static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); + // non-member + { + static_assert(std::is_same_v(obj, v, v2)), ReturnType>); + static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); + } } { using V = std::variant; V v1(42L), v2("hello"), v3(101), v4(1.1); - static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + // non-member + { + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + } } { using V = std::variant; V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + // non-member + { + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + } } } @@ -399,13 +436,25 @@ void test_constexpr_void() { using V = std::variant; constexpr V v(42); - static_assert((std::visit(obj, v), 42) == 42, ""); +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert((v.visit(obj), 42) == 42); } +#endif + + // non-member + { static_assert((std::visit(obj, v), 42) == 42, ""); } } { using V = std::variant; constexpr V v(42L); - static_assert((std::visit(obj, v), 42) == 42, ""); +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert((v.visit(obj), 42) == 42); } +#endif + + // non-member + { static_assert((std::visit(obj, v), 42) == 42, ""); } } { using V1 = std::variant; @@ -415,7 +464,8 @@ void test_constexpr_void() { constexpr V2 v2(nullptr); constexpr V3 v3; - static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); + // non-member + { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } } { using V1 = std::variant; @@ -425,19 +475,21 @@ void test_constexpr_void() { constexpr V2 v2(nullptr); constexpr V3 v3; - static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); + // non-member + { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } } { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); + // non-member + { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } } { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); + // non-member + { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } } } @@ -449,13 +501,25 @@ void test_constexpr_int() { using V = std::variant; constexpr V v(42); - static_assert(std::visit(obj, v) == 42, ""); +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + + // non-member + { static_assert(std::visit(obj, v) == 42, ""); } } { using V = std::variant; constexpr V v(42L); - static_assert(std::visit(obj, v) == 42, ""); +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + + // non-member + { static_assert(std::visit(obj, v) == 42, ""); } } { using V1 = std::variant; @@ -465,7 +529,8 @@ void test_constexpr_int() { constexpr V2 v2(nullptr); constexpr V3 v3; - static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + // non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } } { using V1 = std::variant; @@ -475,19 +540,22 @@ void test_constexpr_int() { constexpr V2 v2(nullptr); constexpr V3 v3; - static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); + // non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } } { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + // non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); + // non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } } @@ -495,7 +563,22 @@ template void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - auto test = [&](auto&&... args) { + +# if _LIBCPP_STD_VER >= 26 + // member + auto test_member = [&](auto&& v) { + try { + v.template visit(obj); + } catch (const std::bad_variant_access&) { + return true; + } catch (...) { + } + return false; + }; +# endif + + // non-member + auto test_nonmember = [&](auto&&... args) { try { std::visit(obj, args...); } catch (const std::bad_variant_access&) { @@ -504,11 +587,18 @@ void test_exceptions() { } return false; }; + { using V = std::variant; V v; +# if _LIBCPP_STD_VER >= 26 + makeEmpty(v); + + assert(test_member(v)); +# endif makeEmpty(v); - assert(test(v)); + + assert(test_nonmember(v)); } { using V = std::variant; @@ -516,7 +606,8 @@ void test_exceptions() { V v; makeEmpty(v); V2 v2("hello"); - assert(test(v, v2)); + + assert(test_nonmember(v, v2)); } { using V = std::variant; @@ -524,7 +615,8 @@ void test_exceptions() { V v; makeEmpty(v); V2 v2("hello"); - assert(test(v2, v)); + + assert(test_nonmember(v2, v)); } { using V = std::variant; @@ -533,13 +625,15 @@ void test_exceptions() { makeEmpty(v); V2 v2; makeEmpty(v2); - assert(test(v, v2)); + + assert(test_nonmember(v, v2)); } { using V = std::variant; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); - assert(test(v1, v2, v3, v4)); + + assert(test_nonmember(v1, v2, v3, v4)); } { using V = std::variant; @@ -548,7 +642,8 @@ void test_exceptions() { makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); - assert(test(v1, v2, v3, v4)); + + assert(test_nonmember(v1, v2, v3, v4)); } #endif } @@ -565,13 +660,29 @@ void test_caller_accepts_nonconst() { } }; std::variant v; - std::visit(Visitor{}, v); + +#if _LIBCPP_STD_VER >= 26 + // member + { v.template visit(Visitor{}); } +#endif + // non-member + { std::visit(Visitor{}, v); } } void test_constexpr_explicit_side_effect() { auto test_lambda = [](int arg) constexpr { std::variant v = 101; - std::visit([arg](int& x) constexpr { x = arg; }, v); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.template visit([arg](int& x) constexpr { x = arg; }); + } +#endif + // non-member + { + std::visit([arg](int& x) constexpr { x = arg; }, v); + } return std::get(v); }; From 5097751e32cc89cdce94c77d813f38102cd5d22b Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 27 Dec 2023 17:28:02 +0200 Subject: [PATCH 09/34] Completed: visit_return_type.pass --- .../variant.visit/robust_against_adl.pass.cpp | 1 - .../variant/variant.visit/visit.pass.cpp | 2 - .../variant.visit/visit_return_type.pass.cpp | 136 +++++++++++------- 3 files changed, 87 insertions(+), 52 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp index 6f09589169386..3723037d4e6d1 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -42,7 +42,6 @@ constexpr bool test(bool do_it) { v.visit([](auto) -> Holder* { return nullptr; }); } #endif - // non-member { std::visit([](auto) {}, v); diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 4bc35edeed3e0..9eb2680c47ffd 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -214,7 +214,6 @@ void test_argument_forwarding() { assert(false); } # endif - // non-member { std::visit(obj, v); @@ -416,7 +415,6 @@ void test_constexpr() { // member { static_assert(v.visit(obj) == 42); } #endif - // non-member { static_assert(std::visit(obj, v) == 42, ""); } } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index 34d90c96e43f2..b0d1055973f6c 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -124,7 +124,6 @@ void test_call_operator_forwarding() { assert(Fn::check_call(CT_Const | CT_RValue)); } #endif - // non-member { std::visit(obj, v); @@ -213,7 +212,6 @@ void test_argument_forwarding() { assert(Fn::check_call(val)); } #endif - // non-member { std::visit(obj, v); @@ -246,7 +244,6 @@ void test_argument_forwarding() { assert(Fn::check_call(val)); } # endif - // non-member { std::visit(obj, v); @@ -278,7 +275,6 @@ void test_argument_forwarding() { assert(Fn::check_call(val)); } # endif - // non-member { std::visit(obj, v); @@ -358,7 +354,6 @@ void test_return_type() { static_assert(std::is_same_v(std::move(cobj))), ReturnType>); } #endif - // non-member { static_assert(std::is_same_v(obj, v)), ReturnType>); @@ -380,7 +375,6 @@ void test_return_type() { static_assert(std::is_same_v(std::move(cobj))), ReturnType>); } #endif - // non-member { static_assert(std::is_same_v(obj, v)), ReturnType>); @@ -440,7 +434,6 @@ void test_constexpr_void() { // member { static_assert((v.visit(obj), 42) == 42); } #endif - // non-member { static_assert((std::visit(obj, v), 42) == 42, ""); } } @@ -452,7 +445,6 @@ void test_constexpr_void() { // member { static_assert((v.visit(obj), 42) == 42); } #endif - // non-member { static_assert((std::visit(obj, v), 42) == 42, ""); } } @@ -488,6 +480,7 @@ void test_constexpr_void() { { using V = std::variant; constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + // non-member { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } } @@ -505,7 +498,6 @@ void test_constexpr_int() { // member { static_assert(v.visit(obj) == 42); } #endif - // non-member { static_assert(std::visit(obj, v) == 42, ""); } } @@ -517,7 +509,6 @@ void test_constexpr_int() { // member { static_assert(v.visit(obj) == 42); } #endif - // non-member { static_assert(std::visit(obj, v) == 42, ""); } } @@ -576,7 +567,6 @@ void test_exceptions() { return false; }; # endif - // non-member auto test_nonmember = [&](auto&&... args) { try { @@ -630,14 +620,14 @@ void test_exceptions() { } { using V = std::variant; - V v1(42l), v2(101), v3(202), v4(1.1); + V v1(42L), v2(101), v3(202), v4(1.1); makeEmpty(v1); assert(test_nonmember(v1, v2, v3, v4)); } { using V = std::variant; - V v1(42l), v2(101), v3(202), v4(1.1); + V v1(42L), v2(101), v3(202), v4(1.1); makeEmpty(v1); makeEmpty(v2); makeEmpty(v3); @@ -692,18 +682,34 @@ void test_constexpr_explicit_side_effect() { void test_derived_from_variant() { struct MyVariant : std::variant {}; - std::visit( - [](auto x) { - assert(x == 42); - return true; - }, - MyVariant{42}); - std::visit( - [](auto x) { - assert(x == -1.3f); - return true; - }, - MyVariant{-1.3f}); +#if _LIBCPP_STD_VER >= 26 + // member + { + MyVariant{42}.template visit([](auto x) { + assert(x == 42); + return true; + }); + MyVariant{-1.3f}.template visit([](auto x) { + assert(x == -1.3f); + return true; + }); + } +#endif + // non-member + { + std::visit( + [](auto x) { + assert(x == 42); + return true; + }, + MyVariant{42}); + std::visit( + [](auto x) { + assert(x == -1.3f); + return true; + }, + MyVariant{-1.3f}); + } // Check that visit does not take index nor valueless_by_exception members from the base class. struct EvilVariantBase { @@ -715,18 +721,34 @@ void test_derived_from_variant() { using std::variant::variant; }; - std::visit( - [](auto x) { - assert(x == 12); - return true; - }, - EvilVariant1{12}); - std::visit( - [](auto x) { - assert(x == 12.3); - return true; - }, - EvilVariant1{12.3}); +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant1{12}.template visit([](auto x) { + assert(x == 12); + return true; + }); + EvilVariant1{12.3}.template visit([](auto x) { + assert(x == 12.3); + return true; + }); + } +#endif + // non-member + { + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant1{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant1{12.3}); + } // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { @@ -744,18 +766,34 @@ void test_derived_from_variant() { using std::variant::variant; }; - std::visit( - [](auto x) { - assert(x == 12); - return true; - }, - EvilVariant2{12}); - std::visit( - [](auto x) { - assert(x == 12.3); - return true; - }, - EvilVariant2{12.3}); +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant2{12}.template visit([](auto x) { + assert(x == 12); + return true; + }); + EvilVariant2{12.3}.template visit([](auto x) { + assert(x == 12.3); + return true; + }); + } +#endif + // non-member + { + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant2{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant2{12.3}); + } } struct any_visitor { From 653ec7af66441bf9f9885622cec12c48322767b8 Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 27 Dec 2023 17:32:53 +0200 Subject: [PATCH 10/34] Syn cleanup --- .../variant/variant.visit/robust_against_adl.pass.cpp | 2 +- .../test/std/utilities/variant/variant.visit/visit.pass.cpp | 4 +--- .../variant/variant.visit/visit_return_type.pass.cpp | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp index 3723037d4e6d1..3bd305a7c62c1 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -12,7 +12,7 @@ // class variant; // template -// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26 +// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 // template // constexpr R visit(this Self&&, Visitor&&); // since C++26 diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 9eb2680c47ffd..8781174ff7d66 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -12,9 +12,7 @@ // class variant; // template -// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26 -// template -// constexpr R visit(this Self&&, Visitor&&); // since C++26 +// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 // template // constexpr see below visit(Visitor&& vis, Variants&&... vars); diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index b0d1055973f6c..1c73d34cacd87 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -11,8 +11,6 @@ // // class variant; -// template -// constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26 // template // constexpr R visit(this Self&&, Visitor&&); // since C++26 From 9126f034eaa28d568683d3d5e3b4e91fcf014aab Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 27 Dec 2023 17:53:59 +0200 Subject: [PATCH 11/34] Fixed formatting --- libcxx/utils/generate_feature_test_macro_components.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index ed89c1e679015..1944591136cbb 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1265,9 +1265,9 @@ def add_version_header(tc): { "name": "__cpp_lib_variant", "values": { - "c++17": 202102, # std::visit for classes derived from std::variant - # "c++20": 202106, # Fully constexpr std::variant - # "c++26": 202306, # Member visit + "c++17": 202102, # std::visit for classes derived from std::variant + # "c++20": 202106, # Fully constexpr std::variant + # "c++26": 202306, # Member visit }, "headers": ["variant"], }, From ae8a8d6525320f6a5d653dfb79700cfa4e75f84a Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 30 Dec 2023 08:19:26 +0200 Subject: [PATCH 12/34] Restored original files --- .../variant.visit/member.visit.pass.cpp | 685 ++++++++++++++ .../member.visit.robust_against_adl.pass.cpp | 64 ++ .../member.visit_return_type.pass.cpp | 840 ++++++++++++++++++ .../variant.visit/robust_against_adl.pass.cpp | 53 +- .../variant/variant.visit/visit.pass.cpp | 606 ++++--------- .../variant.visit/visit_return_type.pass.cpp | 768 +++++----------- 6 files changed, 2006 insertions(+), 1010 deletions(-) create mode 100644 libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp create mode 100644 libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp create mode 100644 libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp new file mode 100644 index 0000000000000..8781174ff7d66 --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp @@ -0,0 +1,685 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// class variant; +// template +// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 + +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +void test_call_operator_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn& cobj = obj; + + { // test call operator forwarding - no variant + // non-member + { + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } + } + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42L); + V2 v2("hello"); + + // non-member + { + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + } +} + +// Applies to non-member `std::visit` only. +void test_argument_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const auto val = CT_LValue | CT_NonConst; + + { // single argument - value type + using V = std::variant; + V v(42); + const V& cv = v; + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +#endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { // single argument - lvalue reference + using V = std::variant; + int x = 42; + V v(x); + const V& cv = v; + +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + assert(false); + } +# endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } + } + { // single argument - rvalue reference + using V = std::variant; + int x = 42; + V v(std::move(x)); + const V& cv = v; + +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cvstd::visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +# endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } + } +#endif + { // multi argument - multi variant + using V = std::variant; + V v1(42), v2("hello"), v3(43L); + + // non-member + { + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(val))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(val))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(val))); + } + } +} + +void test_return_type() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn& cobj = obj; + + { // test call operator forwarding - no variant + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + } + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } +#endif + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } +#endif + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42L); + V2 v2("hello"); + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + } + } +} + +void test_constexpr() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + + { + using V = std::variant; + constexpr V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + // non-member + { static_assert(std::visit(obj, v) == 42, ""); } + } + { + using V = std::variant; + constexpr V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + // non-member + { static_assert(std::visit(obj, v) == 42, ""); } + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + } + { + using V = std::variant; + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + } + { + using V = std::variant; + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + } +} + +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + +# if _LIBCPP_STD_VER >= 26 + // member + auto test_member = [&](auto&& v) { + try { + v.visit(obj); + } catch (const std::bad_variant_access&) { + return true; + } catch (...) { + } + return false; + }; +# endif + // non-member + auto test_nonmember = [&](auto&&... args) { + try { + std::visit(obj, args...); + } catch (const std::bad_variant_access&) { + return true; + } catch (...) { + } + return false; + }; + + { + using V = std::variant; + V v; +# if _LIBCPP_STD_VER >= 26 + makeEmpty(v); + + assert(test_member(v)); +# endif + makeEmpty(v); + + assert(test_nonmember(v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + + assert(test_nonmember(v, v2)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + + assert(test_nonmember(v2, v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; + makeEmpty(v); + V2 v2; + makeEmpty(v2); + + assert(test_nonmember(v, v2)); + } + { + using V = std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + + assert(test_nonmember(v1, v2, v3, v4)); + } + { + using V = std::variant; + V v1(42l), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + makeEmpty(v2); + makeEmpty(v3); + makeEmpty(v4); + + assert(test_nonmember(v1, v2, v3, v4)); + } +#endif +} + +// See https://llvm.org/PR31916 +void test_caller_accepts_nonconst() { + struct A {}; + struct Visitor { + void operator()(A&) {} + }; + std::variant v; + +#if _LIBCPP_STD_VER >= 26 + // member + { v.visit(Visitor{}); } +#endif + // non-member + { std::visit(Visitor{}, v); } +} + +struct MyVariant : std::variant {}; + +namespace std { +template +void get(const MyVariant&) { + assert(false); +} +} // namespace std + +void test_derived_from_variant() { + auto v1 = MyVariant{42}; + const auto cv1 = MyVariant{142}; + +#if _LIBCPP_STD_VER >= 26 + // member + { + v1.visit([](auto x) { assert(x == 42); }); + cv1.visit([](auto x) { assert(x == 142); }); + MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); + std::move(v1).visit([](auto x) { assert(x == 42); }); + std::move(cv1).visit([](auto x) { assert(x == 142); }); + } +#endif + // non-member + { + std::visit([](auto x) { assert(x == 42); }, v1); + std::visit([](auto x) { assert(x == 142); }, cv1); + std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); + std::visit([](auto x) { assert(x == 42); }, std::move(v1)); + std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); + } + + // Check that visit does not take index nor valueless_by_exception members from the base class. + struct EvilVariantBase { + int index; + char valueless_by_exception; + }; + + struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { + using std::variant::variant; + }; + +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); + EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); + } +#endif + // non-member + { + std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); + } + + // Check that visit unambiguously picks the variant, even if the other base has __impl member. + struct ImplVariantBase { + struct Callable { + bool operator()() const { + assert(false); + return false; + } + }; + + Callable __impl; + }; + + struct EvilVariant2 : std::variant, ImplVariantBase { + using std::variant::variant; + }; + +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); + EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); + } +#endif + // non-member + { + std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); + } +} + +struct any_visitor { + template + void operator()(const T&) const {} +}; + +template (), std::declval()))> +constexpr bool has_visit(int) { + return true; +} + +template +constexpr bool has_visit(...) { + return false; +} + +void test_sfinae() { + struct BadVariant : std::variant, std::variant {}; + struct BadVariant2 : private std::variant {}; + struct GoodVariant : std::variant {}; + struct GoodVariant2 : GoodVariant {}; + + static_assert(!has_visit(0)); + static_assert(!has_visit(0)); + static_assert(!has_visit(0)); + static_assert(has_visit>(0)); + static_assert(has_visit(0)); + static_assert(has_visit(0)); +} + +int main(int, char**) { + test_call_operator_forwarding(); + test_argument_forwarding(); + test_return_type(); + test_constexpr(); + test_exceptions(); + test_caller_accepts_nonconst(); + test_derived_from_variant(); + test_sfinae(); + + return 0; +} diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp new file mode 100644 index 0000000000000..3bd305a7c62c1 --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// class variant; +// template +// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 +// template +// constexpr R visit(this Self&&, Visitor&&); // since C++26 + +// template +// constexpr see below visit(Visitor&& vis, Variants&&... vars); + +#include + +#include "test_macros.h" + +struct Incomplete; +template +struct Holder { + T t; +}; + +constexpr bool test(bool do_it) { + if (do_it) { + std::variant*, int> v = nullptr; + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit([](auto) {}); + v.visit([](auto) -> Holder* { return nullptr; }); + v.visit([](auto) {}); + v.visit([](auto) -> Holder* { return nullptr; }); + } +#endif + // non-member + { + std::visit([](auto) {}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); +#if TEST_STD_VER > 17 + std::visit([](auto) {}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); +#endif + } + } + return true; +} + +int main(int, char**) { + test(true); +#if TEST_STD_VER > 17 + static_assert(test(true)); +#endif + return 0; +} diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp new file mode 100644 index 0000000000000..1c73d34cacd87 --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp @@ -0,0 +1,840 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class variant; +// template +// constexpr R visit(this Self&&, Visitor&&); // since C++26 + +// template +// constexpr R visit(Visitor&& vis, Variants&&... vars); + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "variant_test_helpers.h" + +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +void test_overload_ambiguity() { +#if _LIBCPP_STD_VER >= 26 + using V = std::variant; + using namespace std::string_literals; + V v{"baba"s}; + + // member + v.visit( + overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); + assert(std::get(v) == "baba"s); + + // Test the constraint. + v = std::move(v).visit(overloaded{ + []([[maybe_unused]] auto x) { + assert(false); + return 0; + }, + [](const std::string& x) { + assert(x == "baba"s); + return x + " zmt"s; + }}); + assert(std::get(v) == "baba zmt"s); +#endif +} + +template +void test_call_operator_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn& cobj = obj; + + { // test call operator forwarding - no variant + // non-member + { + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); + } + } + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); + } +#endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); + } + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42L); + V2 v2("hello"); + + // non-member + { + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); + } + } +} + +template +void test_argument_forwarding() { + using Fn = ForwardingCallObject; + Fn obj{}; + const auto val = CT_LValue | CT_NonConst; + + { // single argument - value type + using V = std::variant; + V v(42); + const V& cv = v; + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +#endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } + } +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) + { // single argument - lvalue reference + using V = std::variant; + int x = 42; + V v(x); + const V& cv = v; + +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +# endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } + } + { // single argument - rvalue reference + using V = std::variant; + int x = 42; + V v(std::move(x)); + const V& cv = v; + +# if _LIBCPP_STD_VER >= 26 + // member + { + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + } +# endif + // non-member + { + std::visit(obj, v); + assert(Fn::check_call(val)); + std::visit(obj, cv); + assert(Fn::check_call(val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(val)); + } + } +#endif + { // multi argument - multi variant + using V = std::variant; + V v1(42), v2("hello"), v3(43L); + + // non-member + { + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(val))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(val))); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(val))); + } + } +} + +template +void test_return_type() { + using Fn = ForwardingCallObject; + Fn obj{}; + const Fn& cobj = obj; + + { // test call operator forwarding - no variant + // non-member + { + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } + } + { // test call operator forwarding - single variant, single arg + using V = std::variant; + V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } +#endif + // non-member + { + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); + } + } + { // test call operator forwarding - single variant, multi arg + using V = std::variant; + V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); + } +#endif + // non-member + { + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); + } + } + { // test call operator forwarding - multi variant, multi arg + using V = std::variant; + using V2 = std::variant; + V v(42L); + V2 v2("hello"); + + // non-member + { + static_assert(std::is_same_v(obj, v, v2)), ReturnType>); + static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(101), v4(1.1); + + // non-member + { + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + } + } + { + using V = std::variant; + V v1(42L), v2("hello"), v3(nullptr), v4(1.1); + + // non-member + { + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); + } + } +} + +void test_constexpr_void() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + { + using V = std::variant; + constexpr V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert((v.visit(obj), 42) == 42); } +#endif + // non-member + { static_assert((std::visit(obj, v), 42) == 42, ""); } + } + { + using V = std::variant; + constexpr V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert((v.visit(obj), 42) == 42); } +#endif + // non-member + { static_assert((std::visit(obj, v), 42) == 42, ""); } + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + + // non-member + { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + + // non-member + { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } + } + { + using V = std::variant; + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + // non-member + { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } + } + { + using V = std::variant; + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + // non-member + { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } + } +} + +void test_constexpr_int() { + constexpr ReturnFirst obj{}; + constexpr ReturnArity aobj{}; + + { + using V = std::variant; + constexpr V v(42); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + // non-member + { static_assert(std::visit(obj, v) == 42, ""); } + } + { + using V = std::variant; + constexpr V v(42L); + +#if _LIBCPP_STD_VER >= 26 + // member + { static_assert(v.visit(obj) == 42); } +#endif + // non-member + { static_assert(std::visit(obj, v) == 42, ""); } + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + } + { + using V1 = std::variant; + using V2 = std::variant; + using V3 = std::variant; + constexpr V1 v1; + constexpr V2 v2(nullptr); + constexpr V3 v3; + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + } + { + using V = std::variant; + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + } + { + using V = std::variant; + constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); + + // non-member + { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + } +} + +template +void test_exceptions() { +#ifndef TEST_HAS_NO_EXCEPTIONS + ReturnArity obj{}; + +# if _LIBCPP_STD_VER >= 26 + // member + auto test_member = [&](auto&& v) { + try { + v.template visit(obj); + } catch (const std::bad_variant_access&) { + return true; + } catch (...) { + } + return false; + }; +# endif + // non-member + auto test_nonmember = [&](auto&&... args) { + try { + std::visit(obj, args...); + } catch (const std::bad_variant_access&) { + return true; + } catch (...) { + } + return false; + }; + + { + using V = std::variant; + V v; +# if _LIBCPP_STD_VER >= 26 + makeEmpty(v); + + assert(test_member(v)); +# endif + makeEmpty(v); + + assert(test_nonmember(v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + + assert(test_nonmember(v, v2)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; + makeEmpty(v); + V2 v2("hello"); + + assert(test_nonmember(v2, v)); + } + { + using V = std::variant; + using V2 = std::variant; + V v; + makeEmpty(v); + V2 v2; + makeEmpty(v2); + + assert(test_nonmember(v, v2)); + } + { + using V = std::variant; + V v1(42L), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + + assert(test_nonmember(v1, v2, v3, v4)); + } + { + using V = std::variant; + V v1(42L), v2(101), v3(202), v4(1.1); + makeEmpty(v1); + makeEmpty(v2); + makeEmpty(v3); + makeEmpty(v4); + + assert(test_nonmember(v1, v2, v3, v4)); + } +#endif +} + +// See https://bugs.llvm.org/show_bug.cgi?id=31916 +template +void test_caller_accepts_nonconst() { + struct A {}; + struct Visitor { + auto operator()(A&) { + if constexpr (!std::is_void_v) { + return ReturnType{}; + } + } + }; + std::variant v; + +#if _LIBCPP_STD_VER >= 26 + // member + { v.template visit(Visitor{}); } +#endif + // non-member + { std::visit(Visitor{}, v); } +} + +void test_constexpr_explicit_side_effect() { + auto test_lambda = [](int arg) constexpr { + std::variant v = 101; + +#if _LIBCPP_STD_VER >= 26 + // member + { + v.template visit([arg](int& x) constexpr { x = arg; }); + } +#endif + // non-member + { + std::visit([arg](int& x) constexpr { x = arg; }, v); + } + return std::get(v); + }; + + static_assert(test_lambda(202) == 202, ""); +} + +void test_derived_from_variant() { + struct MyVariant : std::variant {}; + +#if _LIBCPP_STD_VER >= 26 + // member + { + MyVariant{42}.template visit([](auto x) { + assert(x == 42); + return true; + }); + MyVariant{-1.3f}.template visit([](auto x) { + assert(x == -1.3f); + return true; + }); + } +#endif + // non-member + { + std::visit( + [](auto x) { + assert(x == 42); + return true; + }, + MyVariant{42}); + std::visit( + [](auto x) { + assert(x == -1.3f); + return true; + }, + MyVariant{-1.3f}); + } + + // Check that visit does not take index nor valueless_by_exception members from the base class. + struct EvilVariantBase { + int index; + char valueless_by_exception; + }; + + struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { + using std::variant::variant; + }; + +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant1{12}.template visit([](auto x) { + assert(x == 12); + return true; + }); + EvilVariant1{12.3}.template visit([](auto x) { + assert(x == 12.3); + return true; + }); + } +#endif + // non-member + { + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant1{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant1{12.3}); + } + + // Check that visit unambiguously picks the variant, even if the other base has __impl member. + struct ImplVariantBase { + struct Callable { + bool operator()() const { + assert(false); + return false; + } + }; + + Callable __impl; + }; + + struct EvilVariant2 : std::variant, ImplVariantBase { + using std::variant::variant; + }; + +#if _LIBCPP_STD_VER >= 26 + // member + { + EvilVariant2{12}.template visit([](auto x) { + assert(x == 12); + return true; + }); + EvilVariant2{12.3}.template visit([](auto x) { + assert(x == 12.3); + return true; + }); + } +#endif + // non-member + { + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant2{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant2{12.3}); + } +} + +struct any_visitor { + template + bool operator()(const T&) { + return true; + } +}; + +template (std::declval(), std::declval()))> +constexpr bool has_visit(int) { + return true; +} + +template +constexpr bool has_visit(...) { + return false; +} + +void test_sfinae() { + struct BadVariant : std::variant, std::variant {}; + + static_assert(has_visit >(int())); + static_assert(!has_visit(int())); +} + +int main(int, char**) { + test_overload_ambiguity(); + test_call_operator_forwarding(); + test_argument_forwarding(); + test_return_type(); + test_constexpr_void(); + test_exceptions(); + test_caller_accepts_nonconst(); + test_call_operator_forwarding(); + test_argument_forwarding(); + test_return_type(); + test_constexpr_int(); + test_exceptions(); + test_caller_accepts_nonconst(); + test_constexpr_explicit_side_effect(); + test_derived_from_variant(); + test_sfinae(); + + return 0; +} diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp index 3bd305a7c62c1..6f17fa32648d4 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -9,13 +9,6 @@ // UNSUPPORTED: c++03, c++11, c++14 // - -// class variant; -// template -// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 -// template -// constexpr R visit(this Self&&, Visitor&&); // since C++26 - // template // constexpr see below visit(Visitor&& vis, Variants&&... vars); @@ -24,41 +17,27 @@ #include "test_macros.h" struct Incomplete; -template -struct Holder { - T t; -}; - -constexpr bool test(bool do_it) { - if (do_it) { - std::variant*, int> v = nullptr; - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit([](auto) {}); - v.visit([](auto) -> Holder* { return nullptr; }); - v.visit([](auto) {}); - v.visit([](auto) -> Holder* { return nullptr; }); - } -#endif - // non-member - { - std::visit([](auto) {}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); +template struct Holder { T t; }; + +constexpr bool test(bool do_it) +{ + if (do_it) { + std::variant*, int> v = nullptr; + std::visit([](auto){}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #if TEST_STD_VER > 17 - std::visit([](auto) {}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); + std::visit([](auto){}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #endif } - } - return true; + return true; } -int main(int, char**) { - test(true); +int main(int, char**) +{ + test(true); #if TEST_STD_VER > 17 - static_assert(test(true)); + static_assert(test(true)); #endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp index 8781174ff7d66..097b784f2bf2c 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.pass.cpp @@ -9,11 +9,6 @@ // UNSUPPORTED: c++03, c++11, c++14 // - -// class variant; -// template -// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 - // template // constexpr see below visit(Visitor&& vis, Variants&&... vars); @@ -30,503 +25,299 @@ void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn& cobj = obj; - + const Fn &cobj = obj; { // test call operator forwarding - no variant - // non-member - { - std::visit(obj); - assert(Fn::check_call<>(CT_NonConst | CT_LValue)); - std::visit(cobj); - assert(Fn::check_call<>(CT_Const | CT_LValue)); - std::visit(std::move(obj)); - assert(Fn::check_call<>(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj)); - assert(Fn::check_call<>(CT_Const | CT_RValue)); - } + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } + V v(42l); + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); + using V = std::variant; + using V2 = std::variant; + V v(42l); V2 v2("hello"); - - // non-member - { - std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); } } -// Applies to non-member `std::visit` only. void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const auto val = CT_LValue | CT_NonConst; - + const auto Val = CT_LValue | CT_NonConst; { // single argument - value type using V = std::variant; V v(42); - const V& cv = v; - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + const V &cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(x); - const V& cv = v; - -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - assert(false); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + const V &cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); } { // single argument - rvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(std::move(x)); - const V& cv = v; - -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cvstd::visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + const V &cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); } #endif { // multi argument - multi variant using V = std::variant; - V v1(42), v2("hello"), v3(43L); - - // non-member - { - std::visit(obj, v1, v2, v3); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(val))); - } + V v1(42), v2("hello"), v3(43l); + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(Val))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); } } void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn& cobj = obj; - + const Fn &cobj = obj; { // test call operator forwarding - no variant - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } -#endif - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } -#endif - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + V v(42l); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); + using V = std::variant; + using V2 = std::variant; + V v(42l); V2 v2("hello"); - - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } { using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + V v1(42l), v2("hello"), v3(101), v4(1.1); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } { using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } } void test_constexpr() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; - { using V = std::variant; constexpr V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } + static_assert(std::visit(obj, v) == 42, ""); } { using V = std::variant; - constexpr V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } + constexpr V v(42l); + static_assert(std::visit(obj, v) == 42, ""); } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - -# if _LIBCPP_STD_VER >= 26 - // member - auto test_member = [&](auto&& v) { - try { - v.visit(obj); - } catch (const std::bad_variant_access&) { - return true; - } catch (...) { - } - return false; - }; -# endif - // non-member - auto test_nonmember = [&](auto&&... args) { + auto test = [&](auto &&... args) { try { std::visit(obj, args...); - } catch (const std::bad_variant_access&) { + } catch (const std::bad_variant_access &) { return true; } catch (...) { } return false; }; - { using V = std::variant; V v; -# if _LIBCPP_STD_VER >= 26 - makeEmpty(v); - - assert(test_member(v)); -# endif makeEmpty(v); - - assert(test_nonmember(v)); + assert(test(v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); - - assert(test_nonmember(v, v2)); + assert(test(v, v2)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); - - assert(test_nonmember(v2, v)); + assert(test(v2, v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2; makeEmpty(v2); - - assert(test_nonmember(v, v2)); + assert(test(v, v2)); } { using V = std::variant; V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); - - assert(test_nonmember(v1, v2, v3, v4)); + assert(test(v1, v2, v3, v4)); } { using V = std::variant; @@ -535,8 +326,7 @@ void test_exceptions() { makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); - - assert(test_nonmember(v1, v2, v3, v4)); + assert(test(v1, v2, v3, v4)); } #endif } @@ -548,13 +338,7 @@ void test_caller_accepts_nonconst() { void operator()(A&) {} }; std::variant v; - -#if _LIBCPP_STD_VER >= 26 - // member - { v.visit(Visitor{}); } -#endif - // non-member - { std::visit(Visitor{}, v); } + std::visit(Visitor{}, v); } struct MyVariant : std::variant {}; @@ -567,27 +351,13 @@ void get(const MyVariant&) { } // namespace std void test_derived_from_variant() { - auto v1 = MyVariant{42}; + auto v1 = MyVariant{42}; const auto cv1 = MyVariant{142}; - -#if _LIBCPP_STD_VER >= 26 - // member - { - v1.visit([](auto x) { assert(x == 42); }); - cv1.visit([](auto x) { assert(x == 142); }); - MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); - std::move(v1).visit([](auto x) { assert(x == 42); }); - std::move(cv1).visit([](auto x) { assert(x == 142); }); - } -#endif - // non-member - { - std::visit([](auto x) { assert(x == 42); }, v1); - std::visit([](auto x) { assert(x == 142); }, cv1); - std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); - std::visit([](auto x) { assert(x == 42); }, std::move(v1)); - std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); - } + std::visit([](auto x) { assert(x == 42); }, v1); + std::visit([](auto x) { assert(x == 142); }, cv1); + std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); + std::visit([](auto x) { assert(x == 42); }, std::move(v1)); + std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); // Check that visit does not take index nor valueless_by_exception members from the base class. struct EvilVariantBase { @@ -595,30 +365,19 @@ void test_derived_from_variant() { char valueless_by_exception; }; - struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { + struct EvilVariant1 : std::variant, + std::tuple, + EvilVariantBase { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); - EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); - } -#endif - // non-member - { - std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); - std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); - } + std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { struct Callable { - bool operator()() const { - assert(false); - return false; - } + bool operator()() const { assert(false); return false; } }; Callable __impl; @@ -628,18 +387,8 @@ void test_derived_from_variant() { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); - EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); - } -#endif - // non-member - { - std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); - std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); - } + std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); + std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); } struct any_visitor { @@ -647,7 +396,8 @@ struct any_visitor { void operator()(const T&) const {} }; -template (), std::declval()))> +template (), std::declval()))> constexpr bool has_visit(int) { return true; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index 1c73d34cacd87..eb425c07f9322 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -9,11 +9,6 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // - -// class variant; -// template -// constexpr R visit(this Self&&, Visitor&&); // since C++26 - // template // constexpr R visit(Visitor&& vis, Variants&&... vars); @@ -27,162 +22,82 @@ #include "test_macros.h" #include "variant_test_helpers.h" -template -struct overloaded : Ts... { - using Ts::operator()...; -}; - -void test_overload_ambiguity() { -#if _LIBCPP_STD_VER >= 26 - using V = std::variant; - using namespace std::string_literals; - V v{"baba"s}; - - // member - v.visit( - overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); - assert(std::get(v) == "baba"s); - - // Test the constraint. - v = std::move(v).visit(overloaded{ - []([[maybe_unused]] auto x) { - assert(false); - return 0; - }, - [](const std::string& x) { - assert(x == "baba"s); - return x + " zmt"s; - }}); - assert(std::get(v) == "baba zmt"s); -#endif -} - template void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn& cobj = obj; - + const Fn &cobj = obj; { // test call operator forwarding - no variant - // non-member - { - std::visit(obj); - assert(Fn::check_call<>(CT_NonConst | CT_LValue)); - std::visit(cobj); - assert(Fn::check_call<>(CT_Const | CT_LValue)); - std::visit(std::move(obj)); - assert(Fn::check_call<>(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj)); - assert(Fn::check_call<>(CT_Const | CT_RValue)); - } + std::visit(obj); + assert(Fn::check_call<>(CT_NonConst | CT_LValue)); + std::visit(cobj); + assert(Fn::check_call<>(CT_Const | CT_LValue)); + std::visit(std::move(obj)); + assert(Fn::check_call<>(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj)); + assert(Fn::check_call<>(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } + V v(42l); + std::visit(obj, v); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + std::visit(cobj, v); + assert(Fn::check_call(CT_Const | CT_LValue)); + std::visit(std::move(obj), v); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + std::visit(std::move(cobj), v); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); + using V = std::variant; + using V2 = std::variant; + V v(42l); V2 v2("hello"); - - // non-member - { - std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + std::visit(obj, v, v2); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v, v2); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v, v2); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v, v2); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_LValue))); + std::visit(cobj, v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_LValue))); + std::visit(std::move(obj), v1, v2, v3, v4); + assert((Fn::check_call(CT_NonConst | CT_RValue))); + std::visit(std::move(cobj), v1, v2, v3, v4); + assert((Fn::check_call(CT_Const | CT_RValue))); } } @@ -190,137 +105,73 @@ template void test_argument_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const auto val = CT_LValue | CT_NonConst; - + const auto Val = CT_LValue | CT_NonConst; { // single argument - value type using V = std::variant; V v(42); - const V& cv = v; - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + const V &cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(x); - const V& cv = v; - -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + const V &cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); } { // single argument - rvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(std::move(x)); - const V& cv = v; - -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + const V &cv = v; + std::visit(obj, v); + assert(Fn::check_call(Val)); + std::visit(obj, cv); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(v)); + assert(Fn::check_call(Val)); + std::visit(obj, std::move(cv)); + assert(Fn::check_call(Val)); } #endif { // multi argument - multi variant using V = std::variant; - V v1(42), v2("hello"), v3(43L); - - // non-member - { - std::visit(obj, v1, v2, v3); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(val))); - } + V v1(42), v2("hello"), v3(43l); + std::visit(obj, v1, v2, v3); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); + assert((Fn::check_call(Val))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } + V v1(42l), v2("hello"), v3(101), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); } { using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + std::visit(obj, v1, v2, v3, v4); + assert((Fn::check_call(Val))); + std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); + assert((Fn::check_call(Val))); } } @@ -328,96 +179,54 @@ template void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn& cobj = obj; - + const Fn &cobj = obj; { // test call operator forwarding - no variant - // non-member - { - static_assert(std::is_same_v(obj)), ReturnType>); - static_assert(std::is_same_v(cobj)), ReturnType>); - static_assert(std::is_same_v(std::move(obj))), ReturnType>); - static_assert(std::is_same_v(std::move(cobj))), ReturnType>); - } + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v(obj)), ReturnType>); - static_assert(std::is_same_v(cobj)), ReturnType>); - static_assert(std::is_same_v(std::move(obj))), ReturnType>); - static_assert(std::is_same_v(std::move(cobj))), ReturnType>); - } -#endif - // non-member - { - static_assert(std::is_same_v(obj, v)), ReturnType>); - static_assert(std::is_same_v(cobj, v)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); - } + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - single variant, multi arg using V = std::variant; - V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v(obj)), ReturnType>); - static_assert(std::is_same_v(cobj)), ReturnType>); - static_assert(std::is_same_v(std::move(obj))), ReturnType>); - static_assert(std::is_same_v(std::move(cobj))), ReturnType>); - } -#endif - // non-member - { - static_assert(std::is_same_v(obj, v)), ReturnType>); - static_assert(std::is_same_v(cobj, v)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); - } + V v(42l); + static_assert(std::is_same_v(obj, v)), ReturnType>); + static_assert(std::is_same_v(cobj, v)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); + using V = std::variant; + using V2 = std::variant; + V v(42l); V2 v2("hello"); - - // non-member - { - static_assert(std::is_same_v(obj, v, v2)), ReturnType>); - static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); - } + static_assert(std::is_same_v(obj, v, v2)), ReturnType>); + static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); } { using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); - } + V v1(42l), v2("hello"), v3(101), v4(1.1); + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); } { using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); - } + V v1(42l), v2("hello"), v3(nullptr), v4(1.1); + static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); + static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); } } @@ -427,124 +236,83 @@ void test_constexpr_void() { { using V = std::variant; constexpr V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert((v.visit(obj), 42) == 42); } -#endif - // non-member - { static_assert((std::visit(obj, v), 42) == 42, ""); } + static_assert((std::visit(obj, v), 42) == 42, ""); } { using V = std::variant; - constexpr V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert((v.visit(obj), 42) == 42); } -#endif - // non-member - { static_assert((std::visit(obj, v), 42) == 42, ""); } + constexpr V v(42l); + static_assert((std::visit(obj, v), 42) == 42, ""); } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } + static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } + static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } } void test_constexpr_int() { constexpr ReturnFirst obj{}; constexpr ReturnArity aobj{}; - { using V = std::variant; constexpr V v(42); - -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } + static_assert(std::visit(obj, v) == 42, ""); } { using V = std::variant; - constexpr V v(42L); - -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } + constexpr V v(42l); + static_assert(std::visit(obj, v) == 42, ""); } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } + static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + using V = std::variant; + constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); + static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } } @@ -552,86 +320,60 @@ template void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - -# if _LIBCPP_STD_VER >= 26 - // member - auto test_member = [&](auto&& v) { - try { - v.template visit(obj); - } catch (const std::bad_variant_access&) { - return true; - } catch (...) { - } - return false; - }; -# endif - // non-member - auto test_nonmember = [&](auto&&... args) { + auto test = [&](auto &&... args) { try { std::visit(obj, args...); - } catch (const std::bad_variant_access&) { + } catch (const std::bad_variant_access &) { return true; } catch (...) { } return false; }; - { using V = std::variant; V v; -# if _LIBCPP_STD_VER >= 26 - makeEmpty(v); - - assert(test_member(v)); -# endif makeEmpty(v); - - assert(test_nonmember(v)); + assert(test(v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); - - assert(test_nonmember(v, v2)); + assert(test(v, v2)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); - - assert(test_nonmember(v2, v)); + assert(test(v2, v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2; makeEmpty(v2); - - assert(test_nonmember(v, v2)); + assert(test(v, v2)); } { using V = std::variant; - V v1(42L), v2(101), v3(202), v4(1.1); + V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); - - assert(test_nonmember(v1, v2, v3, v4)); + assert(test(v1, v2, v3, v4)); } { using V = std::variant; - V v1(42L), v2(101), v3(202), v4(1.1); + V v1(42l), v2(101), v3(202), v4(1.1); makeEmpty(v1); makeEmpty(v2); makeEmpty(v3); makeEmpty(v4); - - assert(test_nonmember(v1, v2, v3, v4)); + assert(test(v1, v2, v3, v4)); } #endif } @@ -642,35 +384,20 @@ void test_caller_accepts_nonconst() { struct A {}; struct Visitor { auto operator()(A&) { - if constexpr (!std::is_void_v) { + if constexpr (!std::is_void_v) + { return ReturnType{}; } } }; std::variant v; - -#if _LIBCPP_STD_VER >= 26 - // member - { v.template visit(Visitor{}); } -#endif - // non-member - { std::visit(Visitor{}, v); } + std::visit(Visitor{}, v); } void test_constexpr_explicit_side_effect() { auto test_lambda = [](int arg) constexpr { std::variant v = 101; - -#if _LIBCPP_STD_VER >= 26 - // member - { - v.template visit([arg](int& x) constexpr { x = arg; }); - } -#endif - // non-member - { - std::visit([arg](int& x) constexpr { x = arg; }, v); - } + std::visit([arg](int& x) constexpr { x = arg; }, v); return std::get(v); }; @@ -680,34 +407,18 @@ void test_constexpr_explicit_side_effect() { void test_derived_from_variant() { struct MyVariant : std::variant {}; -#if _LIBCPP_STD_VER >= 26 - // member - { - MyVariant{42}.template visit([](auto x) { - assert(x == 42); - return true; - }); - MyVariant{-1.3f}.template visit([](auto x) { - assert(x == -1.3f); - return true; - }); - } -#endif - // non-member - { - std::visit( - [](auto x) { - assert(x == 42); - return true; - }, - MyVariant{42}); - std::visit( - [](auto x) { - assert(x == -1.3f); - return true; - }, - MyVariant{-1.3f}); - } + std::visit( + [](auto x) { + assert(x == 42); + return true; + }, + MyVariant{42}); + std::visit( + [](auto x) { + assert(x == -1.3f); + return true; + }, + MyVariant{-1.3f}); // Check that visit does not take index nor valueless_by_exception members from the base class. struct EvilVariantBase { @@ -715,46 +426,29 @@ void test_derived_from_variant() { char valueless_by_exception; }; - struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { + struct EvilVariant1 : std::variant, + std::tuple, + EvilVariantBase { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant1{12}.template visit([](auto x) { - assert(x == 12); - return true; - }); - EvilVariant1{12.3}.template visit([](auto x) { - assert(x == 12.3); - return true; - }); - } -#endif - // non-member - { - std::visit( - [](auto x) { - assert(x == 12); - return true; - }, - EvilVariant1{12}); - std::visit( - [](auto x) { - assert(x == 12.3); - return true; - }, - EvilVariant1{12.3}); - } + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant1{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant1{12.3}); // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { struct Callable { - bool operator()() const { - assert(false); - return false; - } + bool operator()() const { assert(false); return false; } }; Callable __impl; @@ -764,34 +458,18 @@ void test_derived_from_variant() { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant2{12}.template visit([](auto x) { - assert(x == 12); - return true; - }); - EvilVariant2{12.3}.template visit([](auto x) { - assert(x == 12.3); - return true; - }); - } -#endif - // non-member - { - std::visit( - [](auto x) { - assert(x == 12); - return true; - }, - EvilVariant2{12}); - std::visit( - [](auto x) { - assert(x == 12.3); - return true; - }, - EvilVariant2{12.3}); - } + std::visit( + [](auto x) { + assert(x == 12); + return true; + }, + EvilVariant2{12}); + std::visit( + [](auto x) { + assert(x == 12.3); + return true; + }, + EvilVariant2{12.3}); } struct any_visitor { @@ -801,7 +479,8 @@ struct any_visitor { } }; -template (std::declval(), std::declval()))> +template ( + std::declval(), std::declval()))> constexpr bool has_visit(int) { return true; } @@ -819,7 +498,6 @@ void test_sfinae() { } int main(int, char**) { - test_overload_ambiguity(); test_call_operator_forwarding(); test_argument_forwarding(); test_return_type(); From 4d3ff8bd92f92404db1d1dd56e8ff4a5b5226dbb Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 30 Dec 2023 08:25:02 +0200 Subject: [PATCH 13/34] Renamed files and cleanup --- .../variant.visit/member.visit.pass.cpp | 6 ++--- .../member.visit.robust_against_adl.pass.cpp | 27 ++++--------------- .../member.visit_return_type.pass.cpp | 6 ++--- ...pe.pass.cpp => visit.return_type.pass.cpp} | 0 ....cpp => visit.robust_against_adl.pass.cpp} | 0 5 files changed, 9 insertions(+), 30 deletions(-) rename libcxx/test/std/utilities/variant/variant.visit/{visit_return_type.pass.cpp => visit.return_type.pass.cpp} (100%) rename libcxx/test/std/utilities/variant/variant.visit/{robust_against_adl.pass.cpp => visit.robust_against_adl.pass.cpp} (100%) diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp index 8781174ff7d66..e6e9e5fe64e4b 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp @@ -6,17 +6,15 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // // class variant; + // template // constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26 -// template -// constexpr see below visit(Visitor&& vis, Variants&&... vars); - #include #include #include diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp index 3bd305a7c62c1..3c59d5a4c0e06 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // @@ -16,9 +16,6 @@ // template // constexpr R visit(this Self&&, Visitor&&); // since C++26 -// template -// constexpr see below visit(Visitor&& vis, Variants&&... vars); - #include #include "test_macros.h" @@ -33,24 +30,10 @@ constexpr bool test(bool do_it) { if (do_it) { std::variant*, int> v = nullptr; -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit([](auto) {}); - v.visit([](auto) -> Holder* { return nullptr; }); - v.visit([](auto) {}); - v.visit([](auto) -> Holder* { return nullptr; }); - } -#endif - // non-member - { - std::visit([](auto) {}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); -#if TEST_STD_VER > 17 - std::visit([](auto) {}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); -#endif - } + v.visit([](auto) {}); + v.visit([](auto) -> Holder* { return nullptr; }); + v.visit([](auto) {}); + v.visit([](auto) -> Holder* { return nullptr; }); } return true; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp index 1c73d34cacd87..a1752c834effc 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp @@ -6,17 +6,15 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // // class variant; + // template // constexpr R visit(this Self&&, Visitor&&); // since C++26 -// template -// constexpr R visit(Visitor&& vis, Variants&&... vars); - #include #include #include diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp diff --git a/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp From 78f5d3e8f0d7a40d0bca00fad09d93953232d0d9 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 30 Dec 2023 09:02:40 +0200 Subject: [PATCH 14/34] Fixed: member.visit_return_type.pass.cpp --- .../member.visit_return_type.pass.cpp | 645 +++--------------- 1 file changed, 81 insertions(+), 564 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp index a1752c834effc..6ff469290e44a 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp @@ -31,12 +31,10 @@ struct overloaded : Ts... { }; void test_overload_ambiguity() { -#if _LIBCPP_STD_VER >= 26 using V = std::variant; using namespace std::string_literals; V v{"baba"s}; - // member v.visit( overloaded{[]([[maybe_unused]] auto x) { assert(false); }, [](const std::string& x) { assert(x == "baba"s); }}); assert(std::get(v) == "baba"s); @@ -52,7 +50,6 @@ void test_overload_ambiguity() { return x + " zmt"s; }}); assert(std::get(v) == "baba zmt"s); -#endif } template @@ -78,109 +75,27 @@ void test_call_operator_forwarding() { using V = std::variant; V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } - } - { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); - V2 v2("hello"); - - // non-member - { - std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); } } @@ -195,30 +110,14 @@ void test_argument_forwarding() { V v(42); const V& cv = v; -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference @@ -227,30 +126,14 @@ void test_argument_forwarding() { V v(x); const V& cv = v; -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); } { // single argument - rvalue reference using V = std::variant; @@ -258,68 +141,16 @@ void test_argument_forwarding() { V v(std::move(x)); const V& cv = v; -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); } #endif - { // multi argument - multi variant - using V = std::variant; - V v1(42), v2("hello"), v3(43L); - - // non-member - { - std::visit(obj, v1, v2, v3); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(val))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } - } } template @@ -341,208 +172,53 @@ void test_return_type() { using V = std::variant; V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v(obj)), ReturnType>); - static_assert(std::is_same_v(cobj)), ReturnType>); - static_assert(std::is_same_v(std::move(obj))), ReturnType>); - static_assert(std::is_same_v(std::move(cobj))), ReturnType>); - } -#endif - // non-member - { - static_assert(std::is_same_v(obj, v)), ReturnType>); - static_assert(std::is_same_v(cobj, v)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); - } + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v(obj)), ReturnType>); - static_assert(std::is_same_v(cobj)), ReturnType>); - static_assert(std::is_same_v(std::move(obj))), ReturnType>); - static_assert(std::is_same_v(std::move(cobj))), ReturnType>); - } -#endif - // non-member - { - static_assert(std::is_same_v(obj, v)), ReturnType>); - static_assert(std::is_same_v(cobj, v)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); - } - } - { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); - V2 v2("hello"); - - // non-member - { - static_assert(std::is_same_v(obj, v, v2)), ReturnType>); - static_assert(std::is_same_v(cobj, v, v2)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v, v2)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v, v2)), ReturnType>); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - static_assert(std::is_same_v(obj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(cobj, v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(obj), v1, v2, v3, v4)), ReturnType>); - static_assert(std::is_same_v(std::move(cobj), v1, v2, v3, v4)), ReturnType>); - } + static_assert(std::is_same_v(obj)), ReturnType>); + static_assert(std::is_same_v(cobj)), ReturnType>); + static_assert(std::is_same_v(std::move(obj))), ReturnType>); + static_assert(std::is_same_v(std::move(cobj))), ReturnType>); } } void test_constexpr_void() { constexpr ReturnFirst obj{}; - constexpr ReturnArity aobj{}; + { using V = std::variant; constexpr V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert((v.visit(obj), 42) == 42); } -#endif - // non-member - { static_assert((std::visit(obj, v), 42) == 42, ""); } + static_assert((v.visit(obj), 42) == 42); } { using V = std::variant; constexpr V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert((v.visit(obj), 42) == 42); } -#endif - // non-member - { static_assert((std::visit(obj, v), 42) == 42, ""); } - } - { - using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; - constexpr V1 v1; - constexpr V2 v2(nullptr); - constexpr V3 v3; - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } - } - { - using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; - constexpr V1 v1; - constexpr V2 v2(nullptr); - constexpr V3 v3; - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } - } - { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } - } - { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } + static_assert((v.visit(obj), 42) == 42); } } void test_constexpr_int() { constexpr ReturnFirst obj{}; - constexpr ReturnArity aobj{}; { using V = std::variant; constexpr V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } + static_assert(v.visit(obj) == 42); } { using V = std::variant; constexpr V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } - } - { - using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; - constexpr V1 v1; - constexpr V2 v2(nullptr); - constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } - } - { - using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; - constexpr V1 v1; - constexpr V2 v2(nullptr); - constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } - } - { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } - } - { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + static_assert(v.visit(obj) == 42); } } @@ -551,9 +227,7 @@ void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; -# if _LIBCPP_STD_VER >= 26 - // member - auto test_member = [&](auto&& v) { + auto test = [&](auto&& v) { try { v.template visit(obj); } catch (const std::bad_variant_access&) { @@ -562,74 +236,13 @@ void test_exceptions() { } return false; }; -# endif - // non-member - auto test_nonmember = [&](auto&&... args) { - try { - std::visit(obj, args...); - } catch (const std::bad_variant_access&) { - return true; - } catch (...) { - } - return false; - }; { using V = std::variant; V v; -# if _LIBCPP_STD_VER >= 26 makeEmpty(v); - assert(test_member(v)); -# endif - makeEmpty(v); - - assert(test_nonmember(v)); - } - { - using V = std::variant; - using V2 = std::variant; - V v; - makeEmpty(v); - V2 v2("hello"); - - assert(test_nonmember(v, v2)); - } - { - using V = std::variant; - using V2 = std::variant; - V v; - makeEmpty(v); - V2 v2("hello"); - - assert(test_nonmember(v2, v)); - } - { - using V = std::variant; - using V2 = std::variant; - V v; - makeEmpty(v); - V2 v2; - makeEmpty(v2); - - assert(test_nonmember(v, v2)); - } - { - using V = std::variant; - V v1(42L), v2(101), v3(202), v4(1.1); - makeEmpty(v1); - - assert(test_nonmember(v1, v2, v3, v4)); - } - { - using V = std::variant; - V v1(42L), v2(101), v3(202), v4(1.1); - makeEmpty(v1); - makeEmpty(v2); - makeEmpty(v3); - makeEmpty(v4); - - assert(test_nonmember(v1, v2, v3, v4)); + assert(test(v)); } #endif } @@ -647,65 +260,34 @@ void test_caller_accepts_nonconst() { }; std::variant v; -#if _LIBCPP_STD_VER >= 26 - // member - { v.template visit(Visitor{}); } -#endif - // non-member - { std::visit(Visitor{}, v); } + v.template visit(Visitor{}); } void test_constexpr_explicit_side_effect() { auto test_lambda = [](int arg) constexpr { std::variant v = 101; -#if _LIBCPP_STD_VER >= 26 - // member { v.template visit([arg](int& x) constexpr { x = arg; }); } -#endif - // non-member - { - std::visit([arg](int& x) constexpr { x = arg; }, v); - } + return std::get(v); }; - static_assert(test_lambda(202) == 202, ""); + static_assert(test_lambda(202) == 202); } void test_derived_from_variant() { struct MyVariant : std::variant {}; -#if _LIBCPP_STD_VER >= 26 - // member - { - MyVariant{42}.template visit([](auto x) { - assert(x == 42); - return true; - }); - MyVariant{-1.3f}.template visit([](auto x) { - assert(x == -1.3f); - return true; - }); - } -#endif - // non-member - { - std::visit( - [](auto x) { - assert(x == 42); - return true; - }, - MyVariant{42}); - std::visit( - [](auto x) { - assert(x == -1.3f); - return true; - }, - MyVariant{-1.3f}); - } + MyVariant{42}.template visit([](auto x) { + assert(x == 42); + return true; + }); + MyVariant{-1.3f}.template visit([](auto x) { + assert(x == -1.3f); + return true; + }); // Check that visit does not take index nor valueless_by_exception members from the base class. struct EvilVariantBase { @@ -717,34 +299,14 @@ void test_derived_from_variant() { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant1{12}.template visit([](auto x) { - assert(x == 12); - return true; - }); - EvilVariant1{12.3}.template visit([](auto x) { - assert(x == 12.3); - return true; - }); - } -#endif - // non-member - { - std::visit( - [](auto x) { - assert(x == 12); - return true; - }, - EvilVariant1{12}); - std::visit( - [](auto x) { - assert(x == 12.3); - return true; - }, - EvilVariant1{12.3}); - } + EvilVariant1{12}.template visit([](auto x) { + assert(x == 12); + return true; + }); + EvilVariant1{12.3}.template visit([](auto x) { + assert(x == 12.3); + return true; + }); // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { @@ -762,58 +324,14 @@ void test_derived_from_variant() { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant2{12}.template visit([](auto x) { - assert(x == 12); - return true; - }); - EvilVariant2{12.3}.template visit([](auto x) { - assert(x == 12.3); - return true; - }); - } -#endif - // non-member - { - std::visit( - [](auto x) { - assert(x == 12); - return true; - }, - EvilVariant2{12}); - std::visit( - [](auto x) { - assert(x == 12.3); - return true; - }, - EvilVariant2{12.3}); - } -} - -struct any_visitor { - template - bool operator()(const T&) { + EvilVariant2{12}.template visit([](auto x) { + assert(x == 12); return true; - } -}; - -template (std::declval(), std::declval()))> -constexpr bool has_visit(int) { - return true; -} - -template -constexpr bool has_visit(...) { - return false; -} - -void test_sfinae() { - struct BadVariant : std::variant, std::variant {}; - - static_assert(has_visit >(int())); - static_assert(!has_visit(int())); + }); + EvilVariant2{12.3}.template visit([](auto x) { + assert(x == 12.3); + return true; + }); } int main(int, char**) { @@ -832,7 +350,6 @@ int main(int, char**) { test_caller_accepts_nonconst(); test_constexpr_explicit_side_effect(); test_derived_from_variant(); - test_sfinae(); return 0; } From 1bcbb51d5d7b680fb622a3e09c733297c685bc94 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 30 Dec 2023 09:11:28 +0200 Subject: [PATCH 15/34] Fixed: member.visit.pass.cpp --- .../variant.visit/member.visit.pass.cpp | 541 ++---------------- 1 file changed, 63 insertions(+), 478 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp index e6e9e5fe64e4b..3269cd412f2a2 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp @@ -47,109 +47,27 @@ void test_call_operator_forwarding() { using V = std::variant; V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - v.visit(cobj); - assert(Fn::check_call(CT_Const | CT_LValue)); - v.visit(std::move(obj)); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - v.visit(std::move(cobj)); - assert(Fn::check_call(CT_Const | CT_RValue)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); - std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); - std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); - } - } - { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); - V2 v2("hello"); - - // non-member - { - std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); - std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); - std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); - std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); - } + v.visit(obj); + assert(Fn::check_call(CT_NonConst | CT_LValue)); + v.visit(cobj); + assert(Fn::check_call(CT_Const | CT_LValue)); + v.visit(std::move(obj)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); + v.visit(std::move(cobj)); + assert(Fn::check_call(CT_Const | CT_RValue)); } } @@ -164,30 +82,14 @@ void test_argument_forwarding() { V v(42); const V& cv = v; -#if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -#endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference @@ -196,31 +98,15 @@ void test_argument_forwarding() { V v(x); const V& cv = v; -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cv.visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - assert(false); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + v.visit(obj); + assert(Fn::check_call(val)); + cv.visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); + assert(false); } { // single argument - rvalue reference using V = std::variant; @@ -228,68 +114,16 @@ void test_argument_forwarding() { V v(std::move(x)); const V& cv = v; -# if _LIBCPP_STD_VER >= 26 - // member - { - v.visit(obj); - assert(Fn::check_call(val)); - cvstd::visit(obj); - assert(Fn::check_call(val)); - std::move(v).visit(obj); - assert(Fn::check_call(val)); - std::move(cv).visit(obj); - assert(Fn::check_call(val)); - } -# endif - // non-member - { - std::visit(obj, v); - assert(Fn::check_call(val)); - std::visit(obj, cv); - assert(Fn::check_call(val)); - std::visit(obj, std::move(v)); - assert(Fn::check_call(val)); - std::visit(obj, std::move(cv)); - assert(Fn::check_call(val)); - } + v.visit(obj); + assert(Fn::check_call(val)); + cvstd::visit(obj); + assert(Fn::check_call(val)); + std::move(v).visit(obj); + assert(Fn::check_call(val)); + std::move(cv).visit(obj); + assert(Fn::check_call(val)); } #endif - { // multi argument - multi variant - using V = std::variant; - V v1(42), v2("hello"), v3(43L); - - // non-member - { - std::visit(obj, v1, v2, v3); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(val))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(val))); - std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(val))); - } - } } void test_return_type() { @@ -297,158 +131,40 @@ void test_return_type() { Fn obj{}; const Fn& cobj = obj; - { // test call operator forwarding - no variant - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } - } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } -#endif - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } -#endif - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } - } - { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; - V v(42L); - V2 v2("hello"); - - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(101), v4(1.1); - - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } - } - { - using V = std::variant; - V v1(42L), v2("hello"), v3(nullptr), v4(1.1); - - // non-member - { - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - static_assert(std::is_same_v); - } + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } } void test_constexpr() { constexpr ReturnFirst obj{}; - constexpr ReturnArity aobj{}; { using V = std::variant; constexpr V v(42); -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } + static_assert(v.visit(obj) == 42); } { using V = std::variant; constexpr V v(42L); -#if _LIBCPP_STD_VER >= 26 - // member - { static_assert(v.visit(obj) == 42); } -#endif - // non-member - { static_assert(std::visit(obj, v) == 42, ""); } - } - { - using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; - constexpr V1 v1; - constexpr V2 v2(nullptr); - constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } - } - { - using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; - constexpr V1 v1; - constexpr V2 v2(nullptr); - constexpr V3 v3; - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } - } - { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } - } - { - using V = std::variant; - constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1); - - // non-member - { static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } + static_assert(v.visit(obj) == 42); } } @@ -456,9 +172,7 @@ void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; -# if _LIBCPP_STD_VER >= 26 - // member - auto test_member = [&](auto&& v) { + auto test = [&](auto&& v) { try { v.visit(obj); } catch (const std::bad_variant_access&) { @@ -467,74 +181,13 @@ void test_exceptions() { } return false; }; -# endif - // non-member - auto test_nonmember = [&](auto&&... args) { - try { - std::visit(obj, args...); - } catch (const std::bad_variant_access&) { - return true; - } catch (...) { - } - return false; - }; { using V = std::variant; V v; -# if _LIBCPP_STD_VER >= 26 - makeEmpty(v); - - assert(test_member(v)); -# endif makeEmpty(v); - assert(test_nonmember(v)); - } - { - using V = std::variant; - using V2 = std::variant; - V v; - makeEmpty(v); - V2 v2("hello"); - - assert(test_nonmember(v, v2)); - } - { - using V = std::variant; - using V2 = std::variant; - V v; - makeEmpty(v); - V2 v2("hello"); - - assert(test_nonmember(v2, v)); - } - { - using V = std::variant; - using V2 = std::variant; - V v; - makeEmpty(v); - V2 v2; - makeEmpty(v2); - - assert(test_nonmember(v, v2)); - } - { - using V = std::variant; - V v1(42l), v2(101), v3(202), v4(1.1); - makeEmpty(v1); - - assert(test_nonmember(v1, v2, v3, v4)); - } - { - using V = std::variant; - V v1(42l), v2(101), v3(202), v4(1.1); - makeEmpty(v1); - makeEmpty(v2); - makeEmpty(v3); - makeEmpty(v4); - - assert(test_nonmember(v1, v2, v3, v4)); + assert(test(v)); } #endif } @@ -547,12 +200,7 @@ void test_caller_accepts_nonconst() { }; std::variant v; -#if _LIBCPP_STD_VER >= 26 - // member - { v.visit(Visitor{}); } -#endif - // non-member - { std::visit(Visitor{}, v); } + v.visit(Visitor{}); } struct MyVariant : std::variant {}; @@ -568,24 +216,11 @@ void test_derived_from_variant() { auto v1 = MyVariant{42}; const auto cv1 = MyVariant{142}; -#if _LIBCPP_STD_VER >= 26 - // member - { - v1.visit([](auto x) { assert(x == 42); }); - cv1.visit([](auto x) { assert(x == 142); }); - MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); - std::move(v1).visit([](auto x) { assert(x == 42); }); - std::move(cv1).visit([](auto x) { assert(x == 142); }); - } -#endif - // non-member - { - std::visit([](auto x) { assert(x == 42); }, v1); - std::visit([](auto x) { assert(x == 142); }, cv1); - std::visit([](auto x) { assert(x == -1.25f); }, MyVariant{-1.25f}); - std::visit([](auto x) { assert(x == 42); }, std::move(v1)); - std::visit([](auto x) { assert(x == 142); }, std::move(cv1)); - } + v1.visit([](auto x) { assert(x == 42); }); + cv1.visit([](auto x) { assert(x == 142); }); + MyVariant{-1.25f}.visit([](auto x) { assert(x == -1.25f); }); + std::move(v1).visit([](auto x) { assert(x == 42); }); + std::move(cv1).visit([](auto x) { assert(x == 142); }); // Check that visit does not take index nor valueless_by_exception members from the base class. struct EvilVariantBase { @@ -597,18 +232,8 @@ void test_derived_from_variant() { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); - EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); - } -#endif - // non-member - { - std::visit([](auto x) { assert(x == 12); }, EvilVariant1{12}); - std::visit([](auto x) { assert(x == 12.3); }, EvilVariant1{12.3}); - } + EvilVariant1{12}.visit([](auto x) { assert(x == 12); }); + EvilVariant1{12.3}.visit([](auto x) { assert(x == 12.3); }); // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { @@ -626,47 +251,8 @@ void test_derived_from_variant() { using std::variant::variant; }; -#if _LIBCPP_STD_VER >= 26 - // member - { - EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); - EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); - } -#endif - // non-member - { - std::visit([](auto x) { assert(x == 12); }, EvilVariant2{12}); - std::visit([](auto x) { assert(x == 12.3); }, EvilVariant2{12.3}); - } -} - -struct any_visitor { - template - void operator()(const T&) const {} -}; - -template (), std::declval()))> -constexpr bool has_visit(int) { - return true; -} - -template -constexpr bool has_visit(...) { - return false; -} - -void test_sfinae() { - struct BadVariant : std::variant, std::variant {}; - struct BadVariant2 : private std::variant {}; - struct GoodVariant : std::variant {}; - struct GoodVariant2 : GoodVariant {}; - - static_assert(!has_visit(0)); - static_assert(!has_visit(0)); - static_assert(!has_visit(0)); - static_assert(has_visit>(0)); - static_assert(has_visit(0)); - static_assert(has_visit(0)); + EvilVariant2{12}.visit([](auto x) { assert(x == 12); }); + EvilVariant2{12.3}.visit([](auto x) { assert(x == 12.3); }); } int main(int, char**) { @@ -677,7 +263,6 @@ int main(int, char**) { test_exceptions(); test_caller_accepts_nonconst(); test_derived_from_variant(); - test_sfinae(); return 0; } From 5df0feaf854c9f24282ae87a8ee9e30017819234 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 30 Dec 2023 09:23:28 +0200 Subject: [PATCH 16/34] Formatted: visit.return_type.pass.cpp and visit.robust_against_adl.pass.cpp --- .../variant.visit/visit.return_type.pass.cpp | 153 +++++++++--------- .../visit.robust_against_adl.pass.cpp | 33 ++-- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp index eb425c07f9322..246b01a68f6aa 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp @@ -26,7 +26,7 @@ template void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn &cobj = obj; + const Fn& cobj = obj; { // test call operator forwarding - no variant std::visit(obj); assert(Fn::check_call<>(CT_NonConst | CT_LValue)); @@ -41,63 +41,63 @@ void test_call_operator_forwarding() { using V = std::variant; V v(42); std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42l); std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } } @@ -109,69 +109,69 @@ void test_argument_forwarding() { { // single argument - value type using V = std::variant; V v(42); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(x); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } { // single argument - rvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(std::move(x)); - const V &cv = v; + const V& cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #endif { // multi argument - multi variant using V = std::variant; V v1(42), v2("hello"), v3(43l); std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } } @@ -179,7 +179,7 @@ template void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn &cobj = obj; + const Fn& cobj = obj; { // test call operator forwarding - no variant static_assert(std::is_same_v(obj)), ReturnType>); static_assert(std::is_same_v(cobj)), ReturnType>); @@ -203,8 +203,8 @@ void test_return_type() { static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); static_assert(std::is_same_v(obj, v, v2)), ReturnType>); @@ -245,7 +245,7 @@ void test_constexpr_void() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -254,20 +254,20 @@ void test_constexpr_void() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } @@ -288,7 +288,7 @@ void test_constexpr_int() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -297,20 +297,20 @@ void test_constexpr_int() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } @@ -320,10 +320,10 @@ template void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - auto test = [&](auto &&... args) { + auto test = [&](auto&&... args) { try { std::visit(obj, args...); - } catch (const std::bad_variant_access &) { + } catch (const std::bad_variant_access&) { return true; } catch (...) { } @@ -336,24 +336,24 @@ void test_exceptions() { assert(test(v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v, v2)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v2, v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2; @@ -384,8 +384,7 @@ void test_caller_accepts_nonconst() { struct A {}; struct Visitor { auto operator()(A&) { - if constexpr (!std::is_void_v) - { + if constexpr (!std::is_void_v) { return ReturnType{}; } } @@ -426,9 +425,7 @@ void test_derived_from_variant() { char valueless_by_exception; }; - struct EvilVariant1 : std::variant, - std::tuple, - EvilVariantBase { + struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { using std::variant::variant; }; @@ -448,7 +445,10 @@ void test_derived_from_variant() { // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { struct Callable { - bool operator()() const { assert(false); return false; } + bool operator()() const { + assert(false); + return false; + } }; Callable __impl; @@ -479,8 +479,7 @@ struct any_visitor { } }; -template ( - std::declval(), std::declval()))> +template (std::declval(), std::declval()))> constexpr bool has_visit(int) { return true; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp index 6f17fa32648d4..125ac20490d6a 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp @@ -17,27 +17,28 @@ #include "test_macros.h" struct Incomplete; -template struct Holder { T t; }; +template +struct Holder { + T t; +}; -constexpr bool test(bool do_it) -{ - if (do_it) { - std::variant*, int> v = nullptr; - std::visit([](auto){}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); +constexpr bool test(bool do_it) { + if (do_it) { + std::variant*, int> v = nullptr; + std::visit([](auto) {}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #if TEST_STD_VER > 17 - std::visit([](auto){}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); + std::visit([](auto) {}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #endif - } - return true; + } + return true; } -int main(int, char**) -{ - test(true); +int main(int, char**) { + test(true); #if TEST_STD_VER > 17 - static_assert(test(true)); + static_assert(test(true)); #endif - return 0; + return 0; } From 8eaaa410716356ceb5ff876dfb58257148d6fb56 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 31 Dec 2023 10:20:12 +0200 Subject: [PATCH 17/34] Addressed comments --- libcxx/docs/Status/Cxx2c.rst | 2 - libcxx/docs/Status/Cxx2cPapers.csv | 2 +- ...l.pass.cpp => robust_against_adl.pass.cpp} | 33 ++-- ...pe.pass.cpp => visit_return_type.pass.cpp} | 153 +++++++++--------- 4 files changed, 94 insertions(+), 96 deletions(-) rename libcxx/test/std/utilities/variant/variant.visit/{visit.robust_against_adl.pass.cpp => robust_against_adl.pass.cpp} (57%) rename libcxx/test/std/utilities/variant/variant.visit/{visit.return_type.pass.cpp => visit_return_type.pass.cpp} (76%) diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst index 5c700d2cb0d6d..a7ebc4662f517 100644 --- a/libcxx/docs/Status/Cxx2c.rst +++ b/libcxx/docs/Status/Cxx2c.rst @@ -40,8 +40,6 @@ Paper Status .. note:: .. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.) - .. [#note-P2637R3] P2637R3: Implemented `variant` member `visit` - .. _issues-status-cxx2c: diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index a3214ab2bfe75..380686ceb8305 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -17,7 +17,7 @@ "`P0792R14 `__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","","" "`P2874R2 `__","LWG","Mandating Annex D Require No More","Varna June 2023","","","" "`P2757R3 `__","LWG","Type-checking format args","Varna June 2023","","","|format|" -"`P2637R3 `__","LWG","Member ``visit``","Varna June 2023","|Partial| [#note-P2637R3]","18.0","" +"`P2637R3 `__","LWG","Member ``visit``","Varna June 2023","|Partial|","18.0","" "`P2641R4 `__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","","" "`P1759R6 `__","LWG","Native handles and file streams","Varna June 2023","","","" "`P2697R1 `__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0","" diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp similarity index 57% rename from libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp index 125ac20490d6a..6f17fa32648d4 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/robust_against_adl.pass.cpp @@ -17,28 +17,27 @@ #include "test_macros.h" struct Incomplete; -template -struct Holder { - T t; -}; +template struct Holder { T t; }; -constexpr bool test(bool do_it) { - if (do_it) { - std::variant*, int> v = nullptr; - std::visit([](auto) {}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); +constexpr bool test(bool do_it) +{ + if (do_it) { + std::variant*, int> v = nullptr; + std::visit([](auto){}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #if TEST_STD_VER > 17 - std::visit([](auto) {}, v); - std::visit([](auto) -> Holder* { return nullptr; }, v); + std::visit([](auto){}, v); + std::visit([](auto) -> Holder* { return nullptr; }, v); #endif - } - return true; + } + return true; } -int main(int, char**) { - test(true); +int main(int, char**) +{ + test(true); #if TEST_STD_VER > 17 - static_assert(test(true)); + static_assert(test(true)); #endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp similarity index 76% rename from libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp index 246b01a68f6aa..eb425c07f9322 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/visit.return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/visit_return_type.pass.cpp @@ -26,7 +26,7 @@ template void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn& cobj = obj; + const Fn &cobj = obj; { // test call operator forwarding - no variant std::visit(obj); assert(Fn::check_call<>(CT_NonConst | CT_LValue)); @@ -41,63 +41,63 @@ void test_call_operator_forwarding() { using V = std::variant; V v(42); std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - single variant, multi arg using V = std::variant; V v(42l); std::visit(obj, v); - assert(Fn::check_call(CT_NonConst | CT_LValue)); + assert(Fn::check_call(CT_NonConst | CT_LValue)); std::visit(cobj, v); - assert(Fn::check_call(CT_Const | CT_LValue)); + assert(Fn::check_call(CT_Const | CT_LValue)); std::visit(std::move(obj), v); - assert(Fn::check_call(CT_NonConst | CT_RValue)); + assert(Fn::check_call(CT_NonConst | CT_RValue)); std::visit(std::move(cobj), v); - assert(Fn::check_call(CT_Const | CT_RValue)); + assert(Fn::check_call(CT_Const | CT_RValue)); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); std::visit(obj, v, v2); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v, v2); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v, v2); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v, v2); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_LValue))); + assert((Fn::check_call(CT_NonConst | CT_LValue))); std::visit(cobj, v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_LValue))); + assert((Fn::check_call(CT_Const | CT_LValue))); std::visit(std::move(obj), v1, v2, v3, v4); - assert((Fn::check_call(CT_NonConst | CT_RValue))); + assert((Fn::check_call(CT_NonConst | CT_RValue))); std::visit(std::move(cobj), v1, v2, v3, v4); - assert((Fn::check_call(CT_Const | CT_RValue))); + assert((Fn::check_call(CT_Const | CT_RValue))); } } @@ -109,69 +109,69 @@ void test_argument_forwarding() { { // single argument - value type using V = std::variant; V v(42); - const V& cv = v; + const V &cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(x); - const V& cv = v; + const V &cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } { // single argument - rvalue reference - using V = std::variant; - int x = 42; + using V = std::variant; + int x = 42; V v(std::move(x)); - const V& cv = v; + const V &cv = v; std::visit(obj, v); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, cv); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(v)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); std::visit(obj, std::move(cv)); - assert(Fn::check_call(Val)); + assert(Fn::check_call(Val)); } #endif { // multi argument - multi variant using V = std::variant; V v1(42), v2("hello"), v3(43l); std::visit(obj, v1, v2, v3); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(101), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } { using V = std::variant; V v1(42l), v2("hello"), v3(nullptr), v4(1.1); std::visit(obj, v1, v2, v3, v4); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4)); - assert((Fn::check_call(Val))); + assert((Fn::check_call(Val))); } } @@ -179,7 +179,7 @@ template void test_return_type() { using Fn = ForwardingCallObject; Fn obj{}; - const Fn& cobj = obj; + const Fn &cobj = obj; { // test call operator forwarding - no variant static_assert(std::is_same_v(obj)), ReturnType>); static_assert(std::is_same_v(cobj)), ReturnType>); @@ -203,8 +203,8 @@ void test_return_type() { static_assert(std::is_same_v(std::move(cobj), v)), ReturnType>); } { // test call operator forwarding - multi variant, multi arg - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v(42l); V2 v2("hello"); static_assert(std::is_same_v(obj, v, v2)), ReturnType>); @@ -245,7 +245,7 @@ void test_constexpr_void() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -254,20 +254,20 @@ void test_constexpr_void() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert((std::visit(aobj, v1, v2, v3), 3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert((std::visit(aobj, v1, v2, v3, v4), 4) == 4, ""); } @@ -288,7 +288,7 @@ void test_constexpr_int() { } { using V1 = std::variant; - using V2 = std::variant; + using V2 = std::variant; using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); @@ -297,20 +297,20 @@ void test_constexpr_int() { } { using V1 = std::variant; - using V2 = std::variant; - using V3 = std::variant; + using V2 = std::variant; + using V3 = std::variant; constexpr V1 v1; constexpr V2 v2(nullptr); constexpr V3 v3; static_assert(std::visit(aobj, v1, v2, v3) == 3, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } { - using V = std::variant; + using V = std::variant; constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1); static_assert(std::visit(aobj, v1, v2, v3, v4) == 4, ""); } @@ -320,10 +320,10 @@ template void test_exceptions() { #ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; - auto test = [&](auto&&... args) { + auto test = [&](auto &&... args) { try { std::visit(obj, args...); - } catch (const std::bad_variant_access&) { + } catch (const std::bad_variant_access &) { return true; } catch (...) { } @@ -336,24 +336,24 @@ void test_exceptions() { assert(test(v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v, v2)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2("hello"); assert(test(v2, v)); } { - using V = std::variant; - using V2 = std::variant; + using V = std::variant; + using V2 = std::variant; V v; makeEmpty(v); V2 v2; @@ -384,7 +384,8 @@ void test_caller_accepts_nonconst() { struct A {}; struct Visitor { auto operator()(A&) { - if constexpr (!std::is_void_v) { + if constexpr (!std::is_void_v) + { return ReturnType{}; } } @@ -425,7 +426,9 @@ void test_derived_from_variant() { char valueless_by_exception; }; - struct EvilVariant1 : std::variant, std::tuple, EvilVariantBase { + struct EvilVariant1 : std::variant, + std::tuple, + EvilVariantBase { using std::variant::variant; }; @@ -445,10 +448,7 @@ void test_derived_from_variant() { // Check that visit unambiguously picks the variant, even if the other base has __impl member. struct ImplVariantBase { struct Callable { - bool operator()() const { - assert(false); - return false; - } + bool operator()() const { assert(false); return false; } }; Callable __impl; @@ -479,7 +479,8 @@ struct any_visitor { } }; -template (std::declval(), std::declval()))> +template ( + std::declval(), std::declval()))> constexpr bool has_visit(int) { return true; } From 38e8f433d90440a811ce0df72727b5f12921749c Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 31 Dec 2023 10:30:10 +0200 Subject: [PATCH 18/34] Removed test case --- .../variant/variant.visit/member.visit.pass.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp index 3269cd412f2a2..d140fb54afe00 100644 --- a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp @@ -30,19 +30,6 @@ void test_call_operator_forwarding() { Fn obj{}; const Fn& cobj = obj; - { // test call operator forwarding - no variant - // non-member - { - std::visit(obj); - assert(Fn::check_call<>(CT_NonConst | CT_LValue)); - std::visit(cobj); - assert(Fn::check_call<>(CT_Const | CT_LValue)); - std::visit(std::move(obj)); - assert(Fn::check_call<>(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj)); - assert(Fn::check_call<>(CT_Const | CT_RValue)); - } - } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); From 6de98f30f855e5d8c3f3b2929c778bdf229081fd Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 31 Dec 2023 10:40:29 +0200 Subject: [PATCH 19/34] Addressed comment --- libcxx/include/variant | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 4c9b04942f277..2c7e1f6a56d3f 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -72,9 +72,9 @@ namespace std { // [variant.visit], visitation template - constexpr decltype(auto) visit(this Self&&, Visitor&&); + constexpr decltype(auto) visit(this Self&&, Visitor&&); // Since C++26 template - constexpr R visit(this Self&&, Visitor&&); + constexpr R visit(this Self&&, Visitor&&); // Since C++26 }; // 20.7.3, variant helper classes From 759e0d545426b2ee3851cc33803d80661ce6bc41 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 31 Dec 2023 11:03:15 +0200 Subject: [PATCH 20/34] WIP: Experiment with forward declaration --- libcxx/include/variant | 92 +++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 2c7e1f6a56d3f..f6cc3311a09fc 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1137,6 +1137,52 @@ using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp, } // namespace __variant_detail +# define __VISIT_FORWARD_DECL + +# ifdef __VISIT_FORWARD_DECL +template < class _Visitor, class... _Vs, typename = void_t()))...> > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) +visit(_Visitor&& __visitor, _Vs&&... __vs); + +# if _LIBCPP_STD_VER >= 20 +template < class _Rp, + class _Visitor, + class... _Vs, + typename = void_t()))...> > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp +visit(_Visitor&& __visitor, _Vs&&... __vs); +# endif +# else // __VISIT_FORWARD_DECL +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) { + const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception()); + if (__valueless) { + __throw_bad_variant_access(); + } +} + +template < class _Visitor, class... _Vs, typename = void_t()))...> > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) +visit(_Visitor&& __visitor, _Vs&&... __vs) { + using __variant_detail::__visitation::__variant; + std::__throw_if_valueless(std::forward<_Vs>(__vs)...); + return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); +} + +# if _LIBCPP_STD_VER >= 20 +template < class _Rp, + class _Visitor, + class... _Vs, + typename = void_t()))...> > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp +visit(_Visitor&& __visitor, _Vs&&... __vs) { + using __variant_detail::__visitation::__variant; + std::__throw_if_valueless(std::forward<_Vs>(__vs)...); + return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); +} +# endif +# endif // __VISIT_FORWARD_DECL + template class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant : private __sfinae_ctor_base< __all...>::value, @@ -1282,11 +1328,18 @@ public: # if _LIBCPP_STD_VER >= 26 // [variant.visit], visitation - template - constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor); - template - constexpr _R visit(this _Self&& __self, _Visitor&& __visitor); + template + constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { + using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); + } + + template + constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) { + using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self); + } # endif private: @@ -1519,6 +1572,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs, return __variant::__visit_value_at(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } +# ifdef __VISIT_FORWARD_DECL template _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) { const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception()); @@ -1527,7 +1581,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr vo } } -template < class _Visitor, class... _Vs, typename = void_t()))...> > +template < class _Visitor, class... _Vs, typename> _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; @@ -1535,36 +1589,16 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) { return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); } -# if _LIBCPP_STD_VER >= 20 -template < class _Rp, - class _Visitor, - class... _Vs, - typename = void_t()))...> > +# if _LIBCPP_STD_VER >= 20 +template < class _Rp, class _Visitor, class... _Vs, typename> _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; std::__throw_if_valueless(std::forward<_Vs>(__vs)...); return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); } -# endif - -# if _LIBCPP_STD_VER >= 26 -// [variant.visit], visitation - -template -template -constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) { - using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; - return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); -} - -template -template -constexpr _Rp variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) { - using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; - return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self); -} -# endif +# endif +# endif // __VISIT_FORWARD_DECL template _LIBCPP_HIDE_FROM_ABI auto From 0a99bd9e9402240b9165314b7b45d4c59175c5f4 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sun, 31 Dec 2023 11:07:41 +0200 Subject: [PATCH 21/34] Used forward declaration: `std::visit` --- libcxx/include/variant | 43 ++++-------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index f6cc3311a09fc..c3a4bb5782cf5 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1137,51 +1137,18 @@ using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp, } // namespace __variant_detail -# define __VISIT_FORWARD_DECL - -# ifdef __VISIT_FORWARD_DECL template < class _Visitor, class... _Vs, typename = void_t()))...> > _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs); -# if _LIBCPP_STD_VER >= 20 +# if _LIBCPP_STD_VER >= 20 template < class _Rp, class _Visitor, class... _Vs, typename = void_t()))...> > _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs); -# endif -# else // __VISIT_FORWARD_DECL -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) { - const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception()); - if (__valueless) { - __throw_bad_variant_access(); - } -} - -template < class _Visitor, class... _Vs, typename = void_t()))...> > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) -visit(_Visitor&& __visitor, _Vs&&... __vs) { - using __variant_detail::__visitation::__variant; - std::__throw_if_valueless(std::forward<_Vs>(__vs)...); - return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); -} - -# if _LIBCPP_STD_VER >= 20 -template < class _Rp, - class _Visitor, - class... _Vs, - typename = void_t()))...> > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp -visit(_Visitor&& __visitor, _Vs&&... __vs) { - using __variant_detail::__visitation::__variant; - std::__throw_if_valueless(std::forward<_Vs>(__vs)...); - return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); -} -# endif -# endif // __VISIT_FORWARD_DECL +# endif template class _LIBCPP_TEMPLATE_VIS _LIBCPP_DECLSPEC_EMPTY_BASES variant @@ -1572,7 +1539,6 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs, return __variant::__visit_value_at(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } -# ifdef __VISIT_FORWARD_DECL template _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void __throw_if_valueless(_Vs&&... __vs) { const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception()); @@ -1589,7 +1555,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) { return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); } -# if _LIBCPP_STD_VER >= 20 +# if _LIBCPP_STD_VER >= 20 template < class _Rp, class _Visitor, class... _Vs, typename> _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) { @@ -1597,8 +1563,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) { std::__throw_if_valueless(std::forward<_Vs>(__vs)...); return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...); } -# endif -# endif // __VISIT_FORWARD_DECL +# endif template _LIBCPP_HIDE_FROM_ABI auto From ed7bc128d235de430ce3130cf3abcd8d76bcee15 Mon Sep 17 00:00:00 2001 From: Zingam Date: Mon, 1 Jan 2024 10:10:44 +0200 Subject: [PATCH 22/34] Moved member `visit` to a separate folder. --- .../robust_against_adl.pass.cpp} | 0 .../member.visit.pass.cpp => variant.visit.member/visit.pass.cpp} | 0 .../visit_return_type.pass.cpp} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename libcxx/test/std/utilities/variant/{variant.visit/member.visit.robust_against_adl.pass.cpp => variant.visit.member/robust_against_adl.pass.cpp} (100%) rename libcxx/test/std/utilities/variant/{variant.visit/member.visit.pass.cpp => variant.visit.member/visit.pass.cpp} (100%) rename libcxx/test/std/utilities/variant/{variant.visit/member.visit_return_type.pass.cpp => variant.visit.member/visit_return_type.pass.cpp} (100%) diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/variant/variant.visit/member.visit.robust_against_adl.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/variant/variant.visit/member.visit.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp diff --git a/libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp similarity index 100% rename from libcxx/test/std/utilities/variant/variant.visit/member.visit_return_type.pass.cpp rename to libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp From fde8ea9592c471834c13bca2ae05a7739c708afb Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 3 Jan 2024 14:18:17 +0200 Subject: [PATCH 23/34] Applied frederick-vs-ja's suggestion --- libcxx/include/variant | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index c3a4bb5782cf5..32851caec589b 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1296,7 +1296,11 @@ public: # if _LIBCPP_STD_VER >= 26 // [variant.visit], visitation - template + struct __variant_visit_barrier_tag { // unnamable when using standard library modules + explicit __variant_visit_barrier_tag() = default; + }; + + template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor> constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); From 989203e4d771e7e37de427a19e04ef8404334010 Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 17 Jan 2024 17:53:33 +0200 Subject: [PATCH 24/34] Try to fix CI --- libcxx/include/variant | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 32851caec589b..164c5decc778b 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1297,17 +1297,17 @@ public: // [variant.visit], visitation struct __variant_visit_barrier_tag { // unnamable when using standard library modules - explicit __variant_visit_barrier_tag() = default; + _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default; }; template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor> - constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); } template - constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) { + _LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) { using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self); } From 668f3371ad36b643e509fddee3b6bb5159ebe6f6 Mon Sep 17 00:00:00 2001 From: Zingam Date: Wed, 17 Jan 2024 18:10:26 +0200 Subject: [PATCH 25/34] Try to fix CI --- libcxx/include/variant | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 164c5decc778b..aa911728c75fe 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1302,14 +1302,14 @@ public: template <__variant_visit_barrier_tag = __variant_visit_barrier_tag{}, class _Self, class _Visitor> _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) { - using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; - return std::visit(std::forward<_Visitor>(__visitor), (_V)__self); + using _VariantT = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit(std::forward<_Visitor>(__visitor), (_VariantT)__self); } template _LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(this _Self&& __self, _Visitor&& __visitor) { - using _V = _OverrideRef<_Self&&, _CopyConst, variant>>; - return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self); + using _VariantT = _OverrideRef<_Self&&, _CopyConst, variant>>; + return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_VariantT)__self); } # endif From 06a2402830c4aa0d1f945131bebdb69be28f3950 Mon Sep 17 00:00:00 2001 From: Zingam Date: Thu, 18 Jan 2024 16:29:19 +0200 Subject: [PATCH 26/34] Fix CI on AIX and Arm --- libcxx/include/variant | 4 +--- .../variant.visit.member/robust_against_adl.pass.cpp | 7 +++++-- .../variant/variant.visit.member/visit.pass.cpp | 12 ++++++++---- .../variant.visit.member/visit_return_type.pass.cpp | 4 ++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index aa911728c75fe..17a98ab3072c1 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1293,9 +1293,7 @@ public: __impl_.__swap(__that.__impl_); } -# if _LIBCPP_STD_VER >= 26 - // [variant.visit], visitation - +# if _LIBCPP_STD_VER >= 26 && (!defined(_LIBCPP_COMPILER_CLANG_BASED) || _LIBCPP_CLANG_VER >= 1800) struct __variant_visit_barrier_tag { // unnamable when using standard library modules _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default; }; diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp index 3c59d5a4c0e06..cf8dc028d9c41 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp @@ -20,6 +20,8 @@ #include "test_macros.h" +#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 + struct Incomplete; template struct Holder { @@ -40,8 +42,9 @@ constexpr bool test(bool do_it) { int main(int, char**) { test(true); -#if TEST_STD_VER > 17 static_assert(test(true)); -#endif + return 0; } + +#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp index d140fb54afe00..7ef55b910dcfe 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp @@ -25,6 +25,8 @@ #include "test_macros.h" #include "variant_test_helpers.h" +#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 + void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; @@ -78,7 +80,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) +# if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference using V = std::variant; int x = 42; @@ -110,7 +112,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -#endif +# endif } void test_return_type() { @@ -156,7 +158,7 @@ void test_constexpr() { } void test_exceptions() { -#ifndef TEST_HAS_NO_EXCEPTIONS +# ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; auto test = [&](auto&& v) { @@ -176,7 +178,7 @@ void test_exceptions() { assert(test(v)); } -#endif +# endif } // See https://llvm.org/PR31916 @@ -253,3 +255,5 @@ int main(int, char**) { return 0; } + +#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp index 6ff469290e44a..f3f8f107c1b0f 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp @@ -25,6 +25,8 @@ #include "test_macros.h" #include "variant_test_helpers.h" +#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 + template struct overloaded : Ts... { using Ts::operator()...; @@ -353,3 +355,5 @@ int main(int, char**) { return 0; } + +#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 From 3d760da2c2ad4cb3d6e97724330201518fd11099 Mon Sep 17 00:00:00 2001 From: Zingam Date: Thu, 18 Jan 2024 16:36:09 +0200 Subject: [PATCH 27/34] Try to fix CI --- .../variant.visit.member/visit_return_type.pass.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp index f3f8f107c1b0f..36f9f977042b1 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp @@ -121,7 +121,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) +# if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference using V = std::variant; int x = 42; @@ -152,7 +152,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -#endif +# endif } template @@ -226,7 +226,7 @@ void test_constexpr_int() { template void test_exceptions() { -#ifndef TEST_HAS_NO_EXCEPTIONS +# ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; auto test = [&](auto&& v) { @@ -246,7 +246,7 @@ void test_exceptions() { assert(test(v)); } -#endif +# endif } // See https://bugs.llvm.org/show_bug.cgi?id=31916 From b2ced9e51b50c01e676d484aedb7939ac11a26d2 Mon Sep 17 00:00:00 2001 From: Zingam Date: Thu, 18 Jan 2024 16:59:44 +0200 Subject: [PATCH 28/34] Try to fix CI on AIX --- .../robust_against_adl.pass.cpp | 6 ++---- .../variant/variant.visit.member/visit.pass.cpp | 14 ++++++-------- .../visit_return_type.pass.cpp | 14 ++++++-------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp index cf8dc028d9c41..e7476a58983d2 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp @@ -8,6 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// XFAIL: clang-16 || clang-17 + // // class variant; @@ -20,8 +22,6 @@ #include "test_macros.h" -#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 - struct Incomplete; template struct Holder { @@ -46,5 +46,3 @@ int main(int, char**) { return 0; } - -#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp index 7ef55b910dcfe..f380133858346 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp @@ -8,6 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// XFAIL: clang-16 || clang-17 + // // class variant; @@ -25,8 +27,6 @@ #include "test_macros.h" #include "variant_test_helpers.h" -#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 - void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; @@ -80,7 +80,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -# if !defined(TEST_VARIANT_HAS_NO_REFERENCES) +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference using V = std::variant; int x = 42; @@ -112,7 +112,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -# endif +#endif } void test_return_type() { @@ -158,7 +158,7 @@ void test_constexpr() { } void test_exceptions() { -# ifndef TEST_HAS_NO_EXCEPTIONS +#ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; auto test = [&](auto&& v) { @@ -178,7 +178,7 @@ void test_exceptions() { assert(test(v)); } -# endif +#endif } // See https://llvm.org/PR31916 @@ -255,5 +255,3 @@ int main(int, char**) { return 0; } - -#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp index 36f9f977042b1..f00e236f8de8c 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp @@ -8,6 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// XFAIL: clang-16 || clang-17 + // // class variant; @@ -25,8 +27,6 @@ #include "test_macros.h" #include "variant_test_helpers.h" -#if !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 - template struct overloaded : Ts... { using Ts::operator()...; @@ -121,7 +121,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -# if !defined(TEST_VARIANT_HAS_NO_REFERENCES) +#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { // single argument - lvalue reference using V = std::variant; int x = 42; @@ -152,7 +152,7 @@ void test_argument_forwarding() { std::move(cv).visit(obj); assert(Fn::check_call(val)); } -# endif +#endif } template @@ -226,7 +226,7 @@ void test_constexpr_int() { template void test_exceptions() { -# ifndef TEST_HAS_NO_EXCEPTIONS +#ifndef TEST_HAS_NO_EXCEPTIONS ReturnArity obj{}; auto test = [&](auto&& v) { @@ -246,7 +246,7 @@ void test_exceptions() { assert(test(v)); } -# endif +#endif } // See https://bugs.llvm.org/show_bug.cgi?id=31916 @@ -355,5 +355,3 @@ int main(int, char**) { return 0; } - -#endif // !defined(TEST_COMPILER_CLANG) || TEST_CLANG_VER >= 1800 From 059b1505a303fd51583c9f1a026a5edfcbbdebed Mon Sep 17 00:00:00 2001 From: Zingam Date: Thu, 18 Jan 2024 23:28:05 +0200 Subject: [PATCH 29/34] Addressed comments --- .../variant/variant.visit.member/robust_against_adl.pass.cpp | 4 ++-- .../std/utilities/variant/variant.visit.member/visit.pass.cpp | 4 ++-- .../variant/variant.visit.member/visit_return_type.pass.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp index e7476a58983d2..060efded40c52 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 - -// XFAIL: clang-16 || clang-17 +// The tested functionality needs deducing this. +// UNSUPPORTED: clang-16 || clang-17 // diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp index f380133858346..ecb15365bc7da 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 - -// XFAIL: clang-16 || clang-17 +// The tested functionality needs deducing this. +// UNSUPPORTED: clang-16 || clang-17 // diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp index f00e236f8de8c..86df87f451942 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 - -// XFAIL: clang-16 || clang-17 +// The tested functionality needs deducing this. +// UNSUPPORTED: clang-16 || clang-17 // From c0dc05432d99efac33593c90a6b856a8e65c6e08 Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 20 Jan 2024 06:59:29 +0200 Subject: [PATCH 30/34] Defined `_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER` --- libcxx/include/__config | 5 +++++ libcxx/include/variant | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 90a4585938a13..5b5e6e819b549 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1513,6 +1513,11 @@ __sanitizer_verify_double_ended_contiguous_container(const void*, const void*, c # define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK # endif +// Clang-18 has support for deducing this, but it does not set the FTM. +#if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER ) &&_LIBCPP_CLANG_VER >= 1800) +# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +#endif + #endif // __cplusplus #endif // _LIBCPP___CONFIG diff --git a/libcxx/include/variant b/libcxx/include/variant index 17a98ab3072c1..4959ba5d1f737 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1293,7 +1293,7 @@ public: __impl_.__swap(__that.__impl_); } -# if _LIBCPP_STD_VER >= 26 && (!defined(_LIBCPP_COMPILER_CLANG_BASED) || _LIBCPP_CLANG_VER >= 1800) +# if defined (_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) struct __variant_visit_barrier_tag { // unnamable when using standard library modules _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default; }; From 3bff454f9519807917b03f0155a484c8c9a3cb9b Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 20 Jan 2024 07:21:55 +0200 Subject: [PATCH 31/34] Unsupport tests on *apple-clang* --- .../variant/variant.visit.member/robust_against_adl.pass.cpp | 2 +- .../std/utilities/variant/variant.visit.member/visit.pass.cpp | 2 +- .../variant/variant.visit.member/visit_return_type.pass.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp index 060efded40c52..26d73a2417d4b 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp @@ -8,7 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // The tested functionality needs deducing this. -// UNSUPPORTED: clang-16 || clang-17 +// UNSUPPORTED: clang-16 || clang-17 || apple-clang // diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp index ecb15365bc7da..b2b658f4d9072 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp @@ -8,7 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // The tested functionality needs deducing this. -// UNSUPPORTED: clang-16 || clang-17 +// UNSUPPORTED: clang-16 || clang-17 || apple-clang // diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp index 86df87f451942..d6bd0e9c26908 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp @@ -8,7 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // The tested functionality needs deducing this. -// UNSUPPORTED: clang-16 || clang-17 +// UNSUPPORTED: clang-16 || clang-17 || apple-clang // From 8376b452f3352e17c927c8d5850be7054a9781cf Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 20 Jan 2024 08:22:32 +0200 Subject: [PATCH 32/34] Fix the mistake --- libcxx/include/variant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 4959ba5d1f737..6d7745c21dee7 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1293,7 +1293,7 @@ public: __impl_.__swap(__that.__impl_); } -# if defined (_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) +# if _LIBCPP_STD_VER >= 26 && defined (_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) struct __variant_visit_barrier_tag { // unnamable when using standard library modules _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default; }; From e68fe51460c0ea0f97a42b32eeee7fccdfd2378f Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 20 Jan 2024 08:31:23 +0200 Subject: [PATCH 33/34] Fixed formatting --- libcxx/include/variant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/variant b/libcxx/include/variant index 6d7745c21dee7..35b352ea853e9 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1293,7 +1293,7 @@ public: __impl_.__swap(__that.__impl_); } -# if _LIBCPP_STD_VER >= 26 && defined (_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) +# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) struct __variant_visit_barrier_tag { // unnamable when using standard library modules _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default; }; From fa2cb781d60266b08e5b14b6a83dc5f5ddb324de Mon Sep 17 00:00:00 2001 From: Zingam Date: Sat, 20 Jan 2024 21:53:46 +0200 Subject: [PATCH 34/34] Addressed comments --- libcxx/include/__config | 6 +++--- libcxx/include/variant | 15 +++++++++------ .../robust_against_adl.pass.cpp | 3 ++- .../variant/variant.visit.member/visit.pass.cpp | 3 ++- .../visit_return_type.pass.cpp | 16 ++-------------- .../generate_feature_test_macro_components.py | 2 +- 6 files changed, 19 insertions(+), 26 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 5b5e6e819b549..2825d03b7c205 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1514,9 +1514,9 @@ __sanitizer_verify_double_ended_contiguous_container(const void*, const void*, c # endif // Clang-18 has support for deducing this, but it does not set the FTM. -#if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER ) &&_LIBCPP_CLANG_VER >= 1800) -# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER -#endif +# if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1800) +# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# endif #endif // __cplusplus diff --git a/libcxx/include/variant b/libcxx/include/variant index 35b352ea853e9..ac69645a0fab0 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1137,15 +1137,15 @@ using __best_match_t = typename invoke_result_t<_MakeOverloads<_Types...>, _Tp, } // namespace __variant_detail -template < class _Visitor, class... _Vs, typename = void_t()))...> > +template ()))...>> _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs); # if _LIBCPP_STD_VER >= 20 -template < class _Rp, - class _Visitor, - class... _Vs, - typename = void_t()))...> > +template ()))...>> _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs); # endif @@ -1294,7 +1294,10 @@ public: } # if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) - struct __variant_visit_barrier_tag { // unnamable when using standard library modules + // Helper class to implement [variant.visit]/10 + // Constraints: The call to visit does not use an explicit template-argument-list + // that begins with a type template-argument. + struct __variant_visit_barrier_tag { _LIBCPP_HIDE_FROM_ABI explicit __variant_visit_barrier_tag() = default; }; diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp index 26d73a2417d4b..c54f2b722d46a 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // The tested functionality needs deducing this. -// UNSUPPORTED: clang-16 || clang-17 || apple-clang +// UNSUPPORTED: clang-16 || clang-17 +// XFAIL: apple-clang // diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp index b2b658f4d9072..68706d6c32af4 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // The tested functionality needs deducing this. -// UNSUPPORTED: clang-16 || clang-17 || apple-clang +// UNSUPPORTED: clang-16 || clang-17 +// XFAIL: apple-clang // diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp index d6bd0e9c26908..20472c62fc5f9 100644 --- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp @@ -8,7 +8,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 // The tested functionality needs deducing this. -// UNSUPPORTED: clang-16 || clang-17 || apple-clang +// UNSUPPORTED: clang-16 || clang-17 +// XFAIL: apple-clang // @@ -60,19 +61,6 @@ void test_call_operator_forwarding() { Fn obj{}; const Fn& cobj = obj; - { // test call operator forwarding - no variant - // non-member - { - std::visit(obj); - assert(Fn::check_call<>(CT_NonConst | CT_LValue)); - std::visit(cobj); - assert(Fn::check_call<>(CT_Const | CT_LValue)); - std::visit(std::move(obj)); - assert(Fn::check_call<>(CT_NonConst | CT_RValue)); - std::visit(std::move(cobj)); - assert(Fn::check_call<>(CT_Const | CT_RValue)); - } - } { // test call operator forwarding - single variant, single arg using V = std::variant; V v(42); diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index d0beb81a13a93..a5df187b046f6 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1270,7 +1270,7 @@ def add_version_header(tc): "values": { "c++17": 202102, # std::visit for classes derived from std::variant # "c++20": 202106, # Fully constexpr std::variant - # "c++26": 202306, # Member visit + # "c++26": 202306, # Member visit (implemented) }, "headers": ["variant"], },