[libcxx] [clang] [llvm] [libc] [compiler-rt] [clang-tools-extra] [lldb] [flang] [libc++][variant] P2637R3 - Member `visit` (PR #76447)

Hristo Hristov via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 27 07:48:21 PST 2023


https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/76447

Implements parts of: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2637r3.html (https://eel.is/c++draft/variant.visit)

Adds member `visit` tests and (NFC) refactors + reformats the non-member `visit` tests to accomodate the member `visit` additions for consistency.

>From f8c52dc689243062ca7627c3b6ca04bea69e67e9 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 18 Dec 2023 14:46:15 +0200
Subject: [PATCH 01/10] [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 3b01e5e126d9fa..c5810c218a43a7 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<class Self, class Visitor>
+      constexpr decltype(auto) visit(this Self&&, Visitor&&);
+    template<class R, class Self, class Visitor>
+      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 <class _Self, class _Visitor>
+  constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
+    using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+    return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
+  }
+
+  template <class _R, class _Self, class _Visitor>
+  constexpr _R visit(this _Self&& __self, _Visitor&& __visitor) {
+    using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, 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 097b784f2bf2ce..0dcda177ba3f8f 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<int &>(CT_NonConst | CT_RValue));
     std::visit(std::move(cobj), v);
     assert(Fn::check_call<int &>(CT_Const | CT_RValue));
+
+    v.visit(obj);
+    assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
   }
   { // test call operator forwarding - single variant, multi arg
     using V = std::variant<int, long, double>;

>From 68075dde56db65d8bbde8660cafe8008eba17f46 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 24 Dec 2023 09:35:42 +0200
Subject: [PATCH 02/10] 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 a4f8371ba6acdf..0da61901ce35ff 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1283,16 +1283,10 @@ public:
 #  if _LIBCPP_STD_VER >= 26
   // [variant.visit], visitation
   template <class _Self, class _Visitor>
-  constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor) {
-    using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
-    return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
-  }
+  constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);
 
   template <class _R, class _Self, class _Visitor>
-  constexpr _R visit(this _Self&& __self, _Visitor&& __visitor) {
-    using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, 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 <class... _Types>
+template <class _Self, class _Visitor>
+constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
+  using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+  return std::visit(std::forward<_Visitor>(__visitor), (_V)__self);
+}
+
+template <class... _Types>
+template <class _Rp, class _Self, class _Visitor>
+constexpr _Rp variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
+  using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, variant>>;
+  return std::visit<_Rp>(std::forward<_Visitor>(__visitor), (_V)__self);
+}
+#  endif
+
 template <class... _Types>
 _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 0dcda177ba3f8f..b46924683af66e 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<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));                                            \
+    variants.visit(object);                                                                                            \
+    assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));
+#else
+#  define TEST_VISIT(object, variants, expectedValue, type, ...)                                                       \
+    std::visit(object, variants);                                                                                      \
+    assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(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<int>;
     V v(42);
+
+    // non-member
     std::visit(obj, v);
-    assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
+    assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
     std::visit(cobj, v);
-    assert(Fn::check_call<int &>(CT_Const | CT_LValue));
+    assert(Fn::check_call<int&>(CT_Const | CT_LValue));
     std::visit(std::move(obj), v);
-    assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
+    assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
     std::visit(std::move(cobj), v);
-    assert(Fn::check_call<int &>(CT_Const | CT_RValue));
+    assert(Fn::check_call<int&>(CT_Const | CT_RValue));
 
+    // member
+#if _LIBCPP_STD_VER >= 26
     v.visit(obj);
-    assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
+    assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+    v.visit(cobj);
+    assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+    v.visit(std::move(obj));
+    assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+    v.visit(std::move(cobj));
+    assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+#endif
+
+#define TEST_VISIT1(type, object, variants, expectedValue)                                                             \
+  std::visit(object, variants);                                                                                        \
+  assert(Fn::check_call<type&>(expectedValue));                                                                        \
+  variants.visit(object);                                                                                              \
+  assert(Fn::check_call<type&>(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<int, long, double>;
     V v(42l);
     std::visit(obj, v);
-    assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
+    assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
     std::visit(cobj, v);
-    assert(Fn::check_call<long &>(CT_Const | CT_LValue));
+    assert(Fn::check_call<long&>(CT_Const | CT_LValue));
     std::visit(std::move(obj), v);
-    assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
+    assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
     std::visit(std::move(cobj), v);
-    assert(Fn::check_call<long &>(CT_Const | CT_RValue));
+    assert(Fn::check_call<long&>(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<int, long, double>;
-    using V2 = std::variant<int *, std::string>;
+    using V  = std::variant<int, long, double>;
+    using V2 = std::variant<int*, std::string>;
     V v(42l);
     V2 v2("hello");
     std::visit(obj, v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
     std::visit(cobj, v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
     std::visit(std::move(obj), v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
     std::visit(std::move(cobj), v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&>(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<long&, std::string&>(CT_NonConst | CT_RValue)));
+    TEST_VISIT(std::move(cobj), v, v2);
+    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
     std::visit(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
     std::visit(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
     std::visit(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
     std::visit(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
     std::visit(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
     std::visit(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
     std::visit(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
     std::visit(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
   }
 }
 
@@ -110,76 +163,76 @@ void test_argument_forwarding() {
   { // single argument - value type
     using V = std::variant<int>;
     V v(42);
-    const V &cv = v;
+    const V& cv = v;
     std::visit(obj, v);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit(obj, cv);
-    assert(Fn::check_call<const int &>(Val));
+    assert(Fn::check_call<const int&>(Val));
     std::visit(obj, std::move(v));
-    assert(Fn::check_call<int &&>(Val));
+    assert(Fn::check_call<int&&>(Val));
     std::visit(obj, std::move(cv));
-    assert(Fn::check_call<const int &&>(Val));
+    assert(Fn::check_call<const int&&>(Val));
   }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   { // single argument - lvalue reference
-    using V = std::variant<int &>;
-    int x = 42;
+    using V = std::variant<int&>;
+    int x   = 42;
     V v(x);
-    const V &cv = v;
+    const V& cv = v;
     std::visit(obj, v);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit(obj, cv);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit(obj, std::move(v));
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit(obj, std::move(cv));
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
   }
   { // single argument - rvalue reference
-    using V = std::variant<int &&>;
-    int x = 42;
+    using V = std::variant<int&&>;
+    int x   = 42;
     V v(std::move(x));
-    const V &cv = v;
+    const V& cv = v;
     std::visit(obj, v);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit(obj, cv);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit(obj, std::move(v));
-    assert(Fn::check_call<int &&>(Val));
+    assert(Fn::check_call<int&&>(Val));
     std::visit(obj, std::move(cv));
-    assert(Fn::check_call<int &&>(Val));
+    assert(Fn::check_call<int&&>(Val));
   }
 #endif
   { // multi argument - multi variant
     using V = std::variant<int, std::string, long>;
     V v1(42), v2("hello"), v3(43l);
     std::visit(obj, v1, v2, v3);
-    assert((Fn::check_call<int &, std::string &, long &>(Val)));
+    assert((Fn::check_call<int&, std::string&, long&>(Val)));
     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
-    assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));
+    assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
     std::visit(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val)));
+    assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(Val)));
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
     std::visit(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
     std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));
+    assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(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<decltype(std::visit(obj)), Fn&>);
     static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
@@ -203,8 +256,8 @@ void test_return_type() {
     static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
   }
   { // test call operator forwarding - multi variant, multi arg
-    using V = std::variant<int, long, double>;
-    using V2 = std::variant<int *, std::string>;
+    using V  = std::variant<int, long, double>;
+    using V2 = std::variant<int*, std::string>;
     V v(42l);
     V2 v2("hello");
     static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
@@ -245,7 +298,7 @@ void test_constexpr() {
   }
   {
     using V1 = std::variant<int>;
-    using V2 = std::variant<int, char *, long long>;
+    using V2 = std::variant<int, char*, long long>;
     using V3 = std::variant<bool, int, int>;
     constexpr V1 v1;
     constexpr V2 v2(nullptr);
@@ -254,20 +307,20 @@ void test_constexpr() {
   }
   {
     using V1 = std::variant<int>;
-    using V2 = std::variant<int, char *, long long>;
-    using V3 = std::variant<void *, int, int>;
+    using V2 = std::variant<int, char*, long long>;
+    using V3 = std::variant<void*, int, int>;
     constexpr V1 v1;
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
     static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
   }
   {
-    using V = std::variant<int, long, double, int *>;
+    using V = std::variant<int, long, double, int*>;
     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<int, long, double, long long, int *>;
+    using V = std::variant<int, long, double, long long, int*>;
     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<int, MakeEmptyT>;
-    using V2 = std::variant<long, std::string, void *>;
+    using V  = std::variant<int, MakeEmptyT>;
+    using V2 = std::variant<long, std::string, void*>;
     V v;
     makeEmpty(v);
     V2 v2("hello");
     assert(test(v, v2));
   }
   {
-    using V = std::variant<int, MakeEmptyT>;
-    using V2 = std::variant<long, std::string, void *>;
+    using V  = std::variant<int, MakeEmptyT>;
+    using V2 = std::variant<long, std::string, void*>;
     V v;
     makeEmpty(v);
     V2 v2("hello");
     assert(test(v2, v));
   }
   {
-    using V = std::variant<int, MakeEmptyT>;
-    using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
+    using V  = std::variant<int, MakeEmptyT>;
+    using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
     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<int, long, double>,
-                        std::tuple<int>,
-                        EvilVariantBase {
+  struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
     using std::variant<int, long, double>::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 <typename T, typename = decltype(std::visit(
-                          std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit(std::declval<any_visitor&>(), std::declval<T>()))>
 constexpr bool has_visit(int) {
   return true;
 }

>From 0bc0832e848bd01c40337dab9344aa506501a792 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 24 Dec 2023 09:43:27 +0200
Subject: [PATCH 03/10] 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 b46924683af66e..3fac6b21f2682a 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<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));                                            \
-    variants.visit(object);                                                                                            \
-    assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(expectedValue));
-#else
-#  define TEST_VISIT(object, variants, expectedValue, type, ...)                                                       \
-    std::visit(object, variants);                                                                                      \
-    assert(Fn::check_call<type __VA_OPT__(, ) __VA_ARGS__>(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<int>;
     V v(42);
-
-    // non-member
-    std::visit(obj, v);
-    assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
-    std::visit(cobj, v);
-    assert(Fn::check_call<int&>(CT_Const | CT_LValue));
-    std::visit(std::move(obj), v);
-    assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
-    std::visit(std::move(cobj), v);
-    assert(Fn::check_call<int&>(CT_Const | CT_RValue));
-
-    // member
 #if _LIBCPP_STD_VER >= 26
-    v.visit(obj);
-    assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
-    v.visit(cobj);
-    assert(Fn::check_call<int&>(CT_Const | CT_LValue));
-    v.visit(std::move(obj));
-    assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
-    v.visit(std::move(cobj));
-    assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+    // member
+    {
+      v.visit(obj);
+      assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+      v.visit(cobj);
+      assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+      v.visit(std::move(obj));
+      assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+      v.visit(std::move(cobj));
+      assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+    }
 #endif
 
-#define TEST_VISIT1(type, object, variants, expectedValue)                                                             \
-  std::visit(object, variants);                                                                                        \
-  assert(Fn::check_call<type&>(expectedValue));                                                                        \
-  variants.visit(object);                                                                                              \
-  assert(Fn::check_call<type&>(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<int&>(CT_NonConst | CT_LValue));
+      std::visit(cobj, v);
+      assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+      std::visit(std::move(obj), v);
+      assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+      std::visit(std::move(cobj), v);
+      assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+    }
   }
   { // test call operator forwarding - single variant, multi arg
     using V = std::variant<int, long, double>;
     V v(42l);
-    std::visit(obj, v);
-    assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
-    std::visit(cobj, v);
-    assert(Fn::check_call<long&>(CT_Const | CT_LValue));
-    std::visit(std::move(obj), v);
-    assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
-    std::visit(std::move(cobj), v);
-    assert(Fn::check_call<long&>(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<long&>(CT_NonConst | CT_LValue));
+      v.visit(cobj);
+      assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+      v.visit(std::move(obj));
+      assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+      v.visit(std::move(cobj));
+      assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+    }
+#endif
+
+    // non-member
+    {
+      std::visit(obj, v);
+      assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+      std::visit(cobj, v);
+      assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+      std::visit(std::move(obj), v);
+      assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+      std::visit(std::move(cobj), v);
+      assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+    }
   }
   { // test call operator forwarding - multi variant, multi arg
     using V  = std::variant<int, long, double>;
@@ -122,13 +108,6 @@ void test_call_operator_forwarding() {
     assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
     std::visit(std::move(cobj), v, v2);
     assert((Fn::check_call<long&, std::string&>(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<long&, std::string&>(CT_NonConst | CT_RValue)));
-    TEST_VISIT(std::move(cobj), v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
   }
   {
     using V = std::variant<int, long, double, std::string>;

>From 1de898e6d27795b159526055b400e68faa7aff11 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 24 Dec 2023 10:09:54 +0200
Subject: [PATCH 04/10] 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 a7ebc4662f517c..5c700d2cb0d6d3 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 ff83648aa76830..a3214ab2bfe75c 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -17,7 +17,7 @@
 "`P0792R14 <https://wg21.link/P0792R14>`__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","",""
 "`P2874R2 <https://wg21.link/P2874R2>`__","LWG","Mandating Annex D Require No More","Varna June 2023","","",""
 "`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
-"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","","","|format|"
+"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Partial| [#note-P2637R3]","18.0",""
 "`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
 "`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","","",""
 "`P2697R1 <https://wg21.link/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 6f17fa32648d41..6f095891693867 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
 
 // <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+//   constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// template<class R, class Self, class Visitor>
+//   constexpr R visit(this Self&&, Visitor&&);              // since C++26
+
 // template <class Visitor, class... Variants>
 // constexpr see below visit(Visitor&& vis, Variants&&... vars);
 
@@ -17,27 +24,42 @@
 #include "test_macros.h"
 
 struct Incomplete;
-template<class T> struct Holder { T t; };
-
-constexpr bool test(bool do_it)
-{
-    if (do_it) {
-        std::variant<Holder<Incomplete>*, int> v = nullptr;
-        std::visit([](auto){}, v);
-        std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
+template <class T>
+struct Holder {
+  T t;
+};
+
+constexpr bool test(bool do_it) {
+  if (do_it) {
+    std::variant<Holder<Incomplete>*, int> v = nullptr;
+
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.visit([](auto) {});
+      v.visit([](auto) -> Holder<Incomplete>* { return nullptr; });
+      v.visit<void>([](auto) {});
+      v.visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; });
+    }
+#endif
+
+    // non-member
+    {
+      std::visit([](auto) {}, v);
+      std::visit([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
 #if TEST_STD_VER > 17
-        std::visit<void>([](auto){}, v);
-        std::visit<void*>([](auto) -> Holder<Incomplete>* { return nullptr; }, v);
+      std::visit<void>([](auto) {}, v);
+      std::visit<void*>([](auto) -> Holder<Incomplete>* { 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 3fac6b21f2682a..72c9ca22802194 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
 
 // <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+//   constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// template<class R, class Self, class Visitor>
+//   constexpr R visit(this Self&&, Visitor&&);              // since C++26
+
 // template <class Visitor, class... Variants>
 // 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<int>;
     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<int, long, double>;
-    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<int, long, double>;
     using V2 = std::variant<int*, std::string>;
-    V v(42l);
+    V v(42L);
     V2 v2("hello");
-    std::visit(obj, v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
-    std::visit(cobj, v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
-    std::visit(std::move(obj), v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
-    std::visit(std::move(cobj), v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
+
+    // non-member
+    {
+      std::visit(obj, v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
+      std::visit(cobj, v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
+      std::visit(std::move(obj), v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
+      std::visit(std::move(cobj), v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
+    }
   }
   {
     using V = std::variant<int, long, double, std::string>;
-    V v1(42l), v2("hello"), v3(101), v4(1.1);
-    std::visit(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
-    std::visit(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
-    std::visit(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
-    std::visit(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(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<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
+      std::visit(cobj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
+      std::visit(std::move(obj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
+      std::visit(std::move(cobj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
+    }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
-    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
-    std::visit(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
-    std::visit(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
-    std::visit(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
-    std::visit(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(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<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
+      std::visit(cobj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
+      std::visit(std::move(obj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
+      std::visit(std::move(cobj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(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<int>;
     V v(42);
     const V& cv = v;
-    std::visit(obj, v);
-    assert(Fn::check_call<int&>(Val));
-    std::visit(obj, cv);
-    assert(Fn::check_call<const int&>(Val));
-    std::visit(obj, std::move(v));
-    assert(Fn::check_call<int&&>(Val));
-    std::visit(obj, std::move(cv));
-    assert(Fn::check_call<const int&&>(Val));
+
+    // non-member
+    {
+      std::visit(obj, v);
+      assert(Fn::check_call<int&>(Val));
+      std::visit(obj, cv);
+      assert(Fn::check_call<const int&>(Val));
+      std::visit(obj, std::move(v));
+      assert(Fn::check_call<int&&>(Val));
+      std::visit(obj, std::move(cv));
+      assert(Fn::check_call<const int&&>(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<int&>(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<int&>(Val));
     std::visit(obj, cv);
@@ -184,7 +216,8 @@ void test_argument_forwarding() {
 #endif
   { // multi argument - multi variant
     using V = std::variant<int, std::string, long>;
-    V v1(42), v2("hello"), v3(43l);
+    V v1(42), v2("hello"), v3(43L);
+
     std::visit(obj, v1, v2, v3);
     assert((Fn::check_call<int&, std::string&, long&>(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<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
+
     std::visit(obj, v1, v2, v3, v4);
     assert((Fn::check_call<long&, std::string&, int&, double&>(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<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+
     std::visit(obj, v1, v2, v3, v4);
     assert((Fn::check_call<long&, std::string&, int*&, double&>(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<decltype(std::visit(obj)), Fn&>);
     static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
@@ -221,59 +257,114 @@ void test_return_type() {
   { // test call operator forwarding - single variant, single arg
     using V = std::variant<int>;
     V v(42);
-    static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+      static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+      static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+      static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
+    }
+#endif
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+    }
   }
   { // test call operator forwarding - single variant, multi arg
     using V = std::variant<int, long, double>;
-    V v(42l);
-    static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+    V v(42L);
+
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      static_assert(std::is_same_v<decltype(v.visit(obj)), Fn&>);
+      static_assert(std::is_same_v<decltype(v.visit(cobj)), const Fn&>);
+      static_assert(std::is_same_v<decltype(v.visit(std::move(obj))), Fn&&>);
+      static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
+    }
+#endif
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(cobj, v)), const Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v)), Fn&&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v)), const Fn&&>);
+    }
   }
   { // test call operator forwarding - multi variant, multi arg
     using V  = std::variant<int, long, double>;
     using V2 = std::variant<int*, std::string>;
-    V v(42l);
+    V v(42L);
     V2 v2("hello");
-    static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit(obj, v, v2)), Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(cobj, v, v2)), const Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v, v2)), Fn&&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v, v2)), const Fn&&>);
+    }
   }
   {
     using V = std::variant<int, long, double, std::string>;
-    V v1(42l), v2("hello"), v3(101), v4(1.1);
-    static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+    V v1(42L), v2("hello"), v3(101), v4(1.1);
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+    }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
-    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
-    static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+    V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit(obj, v1, v2, v3, v4)), Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(cobj, v1, v2, v3, v4)), const Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(obj), v1, v2, v3, v4)), Fn&&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(cobj), v1, v2, v3, v4)), const Fn&&>);
+    }
   }
 }
 
 void test_constexpr() {
   constexpr ReturnFirst obj{};
   constexpr ReturnArity aobj{};
+
   {
     using V = std::variant<int>;
     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<short, long, char>;
-    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<int>;
@@ -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<int>;
@@ -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<int, long, double, int*>;
-    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<int, long, double, long long, int*>;
-    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<A> 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<short, long, float> {};
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 eb425c07f93222..f8cdb70a28fa3b 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
 
 // <variant>
+
+// class variant;
+// template<class Self, class Visitor>
+//   constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+// template<class R, class Self, class Visitor>
+//   constexpr R visit(this Self&&, Visitor&&);              // since C++26
+
 // template <class R, class Visitor, class... Variants>
 // constexpr R visit(Visitor&& vis, Variants&&... vars);
 
@@ -26,78 +33,100 @@ template <typename ReturnType>
 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<ReturnType>(obj);
-    assert(Fn::check_call<>(CT_NonConst | CT_LValue));
-    std::visit<ReturnType>(cobj);
-    assert(Fn::check_call<>(CT_Const | CT_LValue));
-    std::visit<ReturnType>(std::move(obj));
-    assert(Fn::check_call<>(CT_NonConst | CT_RValue));
-    std::visit<ReturnType>(std::move(cobj));
-    assert(Fn::check_call<>(CT_Const | CT_RValue));
+    // non-member
+    {
+      std::visit<ReturnType>(obj);
+      assert(Fn::check_call<>(CT_NonConst | CT_LValue));
+      std::visit<ReturnType>(cobj);
+      assert(Fn::check_call<>(CT_Const | CT_LValue));
+      std::visit<ReturnType>(std::move(obj));
+      assert(Fn::check_call<>(CT_NonConst | CT_RValue));
+      std::visit<ReturnType>(std::move(cobj));
+      assert(Fn::check_call<>(CT_Const | CT_RValue));
+    }
   }
   { // test call operator forwarding - single variant, single arg
     using V = std::variant<int>;
     V v(42);
-    std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<int &>(CT_NonConst | CT_LValue));
-    std::visit<ReturnType>(cobj, v);
-    assert(Fn::check_call<int &>(CT_Const | CT_LValue));
-    std::visit<ReturnType>(std::move(obj), v);
-    assert(Fn::check_call<int &>(CT_NonConst | CT_RValue));
-    std::visit<ReturnType>(std::move(cobj), v);
-    assert(Fn::check_call<int &>(CT_Const | CT_RValue));
+
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.visit<ReturnType>(obj);
+      assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+      v.visit<ReturnType>(cobj);
+      assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+      v.visit<ReturnType>(std::move(obj));
+      assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+      v.visit<ReturnType>(std::move(cobj));
+      assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+    }
+#endif
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v);
+      assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
+      std::visit<ReturnType>(cobj, v);
+      assert(Fn::check_call<int&>(CT_Const | CT_LValue));
+      std::visit<ReturnType>(std::move(obj), v);
+      assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
+      std::visit<ReturnType>(std::move(cobj), v);
+      assert(Fn::check_call<int&>(CT_Const | CT_RValue));
+    }
   }
   { // test call operator forwarding - single variant, multi arg
     using V = std::variant<int, long, double>;
     V v(42l);
     std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<long &>(CT_NonConst | CT_LValue));
+    assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
     std::visit<ReturnType>(cobj, v);
-    assert(Fn::check_call<long &>(CT_Const | CT_LValue));
+    assert(Fn::check_call<long&>(CT_Const | CT_LValue));
     std::visit<ReturnType>(std::move(obj), v);
-    assert(Fn::check_call<long &>(CT_NonConst | CT_RValue));
+    assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
     std::visit<ReturnType>(std::move(cobj), v);
-    assert(Fn::check_call<long &>(CT_Const | CT_RValue));
+    assert(Fn::check_call<long&>(CT_Const | CT_RValue));
   }
   { // test call operator forwarding - multi variant, multi arg
-    using V = std::variant<int, long, double>;
-    using V2 = std::variant<int *, std::string>;
+    using V  = std::variant<int, long, double>;
+    using V2 = std::variant<int*, std::string>;
     V v(42l);
     V2 v2("hello");
     std::visit<int>(obj, v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
     std::visit<ReturnType>(cobj, v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_Const | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
     std::visit<ReturnType>(std::move(obj), v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_NonConst | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
     std::visit<ReturnType>(std::move(cobj), v, v2);
-    assert((Fn::check_call<long &, std::string &>(CT_Const | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
     std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
     std::visit<ReturnType>(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
     std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_NonConst | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
     std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(CT_Const | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
     std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
     std::visit<ReturnType>(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_LValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
     std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_NonConst | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
     std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(CT_Const | CT_RValue)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
   }
 }
 
@@ -109,69 +138,69 @@ void test_argument_forwarding() {
   { // single argument - value type
     using V = std::variant<int>;
     V v(42);
-    const V &cv = v;
+    const V& cv = v;
     std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit<ReturnType>(obj, cv);
-    assert(Fn::check_call<const int &>(Val));
+    assert(Fn::check_call<const int&>(Val));
     std::visit<ReturnType>(obj, std::move(v));
-    assert(Fn::check_call<int &&>(Val));
+    assert(Fn::check_call<int&&>(Val));
     std::visit<ReturnType>(obj, std::move(cv));
-    assert(Fn::check_call<const int &&>(Val));
+    assert(Fn::check_call<const int&&>(Val));
   }
 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
   { // single argument - lvalue reference
-    using V = std::variant<int &>;
-    int x = 42;
+    using V = std::variant<int&>;
+    int x   = 42;
     V v(x);
-    const V &cv = v;
+    const V& cv = v;
     std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit<ReturnType>(obj, cv);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit<ReturnType>(obj, std::move(v));
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit<ReturnType>(obj, std::move(cv));
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
   }
   { // single argument - rvalue reference
-    using V = std::variant<int &&>;
-    int x = 42;
+    using V = std::variant<int&&>;
+    int x   = 42;
     V v(std::move(x));
-    const V &cv = v;
+    const V& cv = v;
     std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit<ReturnType>(obj, cv);
-    assert(Fn::check_call<int &>(Val));
+    assert(Fn::check_call<int&>(Val));
     std::visit<ReturnType>(obj, std::move(v));
-    assert(Fn::check_call<int &&>(Val));
+    assert(Fn::check_call<int&&>(Val));
     std::visit<ReturnType>(obj, std::move(cv));
-    assert(Fn::check_call<int &&>(Val));
+    assert(Fn::check_call<int&&>(Val));
   }
 #endif
   { // multi argument - multi variant
     using V = std::variant<int, std::string, long>;
     V v1(42), v2("hello"), v3(43l);
     std::visit<ReturnType>(obj, v1, v2, v3);
-    assert((Fn::check_call<int &, std::string &, long &>(Val)));
+    assert((Fn::check_call<int&, std::string&, long&>(Val)));
     std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
-    assert((Fn::check_call<const int &, const std::string &, long &&>(Val)));
+    assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
     std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int &, double &>(Val)));
+    assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
     std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long &, const std::string &, int &&, double &&>(Val)));
+    assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(Val)));
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
     std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long &, std::string &, int *&, double &>(Val)));
+    assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
     std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long &, const std::string &, int *&&, double &&>(Val)));
+    assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
   }
 }
 
@@ -179,7 +208,7 @@ template <typename ReturnType>
 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<decltype(std::visit<ReturnType>(obj)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj)), ReturnType>);
@@ -203,8 +232,8 @@ void test_return_type() {
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>);
   }
   { // test call operator forwarding - multi variant, multi arg
-    using V = std::variant<int, long, double>;
-    using V2 = std::variant<int *, std::string>;
+    using V  = std::variant<int, long, double>;
+    using V2 = std::variant<int*, std::string>;
     V v(42l);
     V2 v2("hello");
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v, v2)), ReturnType>);
@@ -245,7 +274,7 @@ void test_constexpr_void() {
   }
   {
     using V1 = std::variant<int>;
-    using V2 = std::variant<int, char *, long long>;
+    using V2 = std::variant<int, char*, long long>;
     using V3 = std::variant<bool, int, int>;
     constexpr V1 v1;
     constexpr V2 v2(nullptr);
@@ -254,20 +283,20 @@ void test_constexpr_void() {
   }
   {
     using V1 = std::variant<int>;
-    using V2 = std::variant<int, char *, long long>;
-    using V3 = std::variant<void *, int, int>;
+    using V2 = std::variant<int, char*, long long>;
+    using V3 = std::variant<void*, int, int>;
     constexpr V1 v1;
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
     static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, "");
   }
   {
-    using V = std::variant<int, long, double, int *>;
+    using V = std::variant<int, long, double, int*>;
     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
     static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, "");
   }
   {
-    using V = std::variant<int, long, double, long long, int *>;
+    using V = std::variant<int, long, double, long long, int*>;
     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
     static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, "");
   }
@@ -288,7 +317,7 @@ void test_constexpr_int() {
   }
   {
     using V1 = std::variant<int>;
-    using V2 = std::variant<int, char *, long long>;
+    using V2 = std::variant<int, char*, long long>;
     using V3 = std::variant<bool, int, int>;
     constexpr V1 v1;
     constexpr V2 v2(nullptr);
@@ -297,20 +326,20 @@ void test_constexpr_int() {
   }
   {
     using V1 = std::variant<int>;
-    using V2 = std::variant<int, char *, long long>;
-    using V3 = std::variant<void *, int, int>;
+    using V2 = std::variant<int, char*, long long>;
+    using V3 = std::variant<void*, int, int>;
     constexpr V1 v1;
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
     static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, "");
   }
   {
-    using V = std::variant<int, long, double, int *>;
+    using V = std::variant<int, long, double, int*>;
     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
     static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, "");
   }
   {
-    using V = std::variant<int, long, double, long long, int *>;
+    using V = std::variant<int, long, double, long long, int*>;
     constexpr V v1(42l), v2(101), v3(nullptr), v4(1.1);
     static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, "");
   }
@@ -320,10 +349,10 @@ template <typename ReturnType>
 void test_exceptions() {
 #ifndef TEST_HAS_NO_EXCEPTIONS
   ReturnArity obj{};
-  auto test = [&](auto &&... args) {
+  auto test = [&](auto&&... args) {
     try {
       std::visit<ReturnType>(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<int, MakeEmptyT>;
-    using V2 = std::variant<long, std::string, void *>;
+    using V  = std::variant<int, MakeEmptyT>;
+    using V2 = std::variant<long, std::string, void*>;
     V v;
     makeEmpty(v);
     V2 v2("hello");
     assert(test(v, v2));
   }
   {
-    using V = std::variant<int, MakeEmptyT>;
-    using V2 = std::variant<long, std::string, void *>;
+    using V  = std::variant<int, MakeEmptyT>;
+    using V2 = std::variant<long, std::string, void*>;
     V v;
     makeEmpty(v);
     V2 v2("hello");
     assert(test(v2, v));
   }
   {
-    using V = std::variant<int, MakeEmptyT>;
-    using V2 = std::variant<long, std::string, void *, MakeEmptyT>;
+    using V  = std::variant<int, MakeEmptyT>;
+    using V2 = std::variant<long, std::string, void*, MakeEmptyT>;
     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<ReturnType>)
-      {
+      if constexpr (!std::is_void_v<ReturnType>) {
         return ReturnType{};
       }
     }
@@ -426,9 +454,7 @@ void test_derived_from_variant() {
     char valueless_by_exception;
   };
 
-  struct EvilVariant1 : std::variant<int, long, double>,
-                        std::tuple<int>,
-                        EvilVariantBase {
+  struct EvilVariant1 : std::variant<int, long, double>, std::tuple<int>, EvilVariantBase {
     using std::variant<int, long, double>::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 <typename T, typename = decltype(std::visit<bool>(
-                          std::declval<any_visitor&>(), std::declval<T>()))>
+template <typename T, typename = decltype(std::visit<bool>(std::declval<any_visitor&>(), std::declval<T>()))>
 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 2f506f32f565cb..ed89c1e679015f 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 <zingam at outlook.com>
Date: Mon, 25 Dec 2023 13:13:36 +0200
Subject: [PATCH 05/10] 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 0da61901ce35ff..4c9b04942f2779 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1282,7 +1282,7 @@ public:
 
 #  if _LIBCPP_STD_VER >= 26
   // [variant.visit], visitation
-  template <class _Self, class _Visitor>
+  template <int=0, class _Self, class _Visitor>
   constexpr decltype(auto) visit(this _Self&& __self, _Visitor&& __visitor);
 
   template <class _R, class _Self, class _Visitor>
@@ -1552,7 +1552,7 @@ visit(_Visitor&& __visitor, _Vs&&... __vs) {
 // [variant.visit], visitation
 
 template <class... _Types>
-template <class _Self, class _Visitor>
+template <int, class _Self, class _Visitor>
 constexpr decltype(auto) variant<_Types...>::visit(this _Self&& __self, _Visitor&& __visitor) {
   using _V = _OverrideRef<_Self&&, _CopyConst<remove_reference_t<_Self>, 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 72c9ca22802194..adbc131a6477ae 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<GoodVariant2>(0));
 }
 
+template <class... Ts>
+struct overloaded : Ts... {
+  using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+  using V = std::variant<float, long, std::string>;
+  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<std::string>(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<V>(overloaded{
+      []([[maybe_unused]] auto x) {
+        assert(false);
+        return 0;
+      },
+      [](const std::string& x) {
+        assert(x == "baba"s);
+        return x + " zmt"s;
+      }});
+  assert(std::get<std::string>(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 <zingam at outlook.com>
Date: Wed, 27 Dec 2023 16:13:41 +0200
Subject: [PATCH 06/10] 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 adbc131a6477ae..6aff2194fa68dd 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<int>;
     V v(42);
     const V& cv = v;
 
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.visit(obj);
+      assert(Fn::check_call<int&>(val));
+      cv.visit(obj);
+      assert(Fn::check_call<const int&>(val));
+      std::move(v).visit(obj);
+      assert(Fn::check_call<int&&>(val));
+      std::move(cv).visit(obj);
+      assert(Fn::check_call<const int&&>(val));
+    }
+#endif
+
     // non-member
     {
       std::visit(obj, v);
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit(obj, cv);
-      assert(Fn::check_call<const int&>(Val));
+      assert(Fn::check_call<const int&>(val));
       std::visit(obj, std::move(v));
-      assert(Fn::check_call<int&&>(Val));
+      assert(Fn::check_call<int&&>(val));
       std::visit(obj, std::move(cv));
-      assert(Fn::check_call<const int&&>(Val));
+      assert(Fn::check_call<const int&&>(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<int&>(Val));
-    std::visit(obj, cv);
-    assert(Fn::check_call<int&>(Val));
-    std::visit(obj, std::move(v));
-    assert(Fn::check_call<int&>(Val));
-    std::visit(obj, std::move(cv));
-    assert(Fn::check_call<int&>(Val));
+    // #  if _LIBCPP_STD_VER >= 26
+    //     // member
+    //     {
+    //       v.visit(obj);
+    //       assert(Fn::check_call<int&>(val));
+    //       cv.visit(obj);
+    //       assert(Fn::check_call<int&>(val));
+    //       std::move(v).visit(obj);
+    //       assert(Fn::check_call<int&>(val));
+    //       std::move(cv).visit(obj);
+    //       assert(Fn::check_call<int>(CT_NonConst));
+    //       assert(false);
+    //     }
+    // #  endif
+
+    // non-member
+    {
+      std::visit(obj, v);
+      assert(Fn::check_call<int&>(val));
+      std::visit(obj, cv);
+      assert(Fn::check_call<int&>(val));
+      std::visit(obj, std::move(v));
+      assert(Fn::check_call<int&>(val));
+      std::visit(obj, std::move(cv));
+      assert(Fn::check_call<int&>(val));
+    }
   }
   { // single argument - rvalue reference
     using V = std::variant<int&&>;
@@ -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<int&>(Val));
-    std::visit(obj, cv);
-    assert(Fn::check_call<int&>(Val));
-    std::visit(obj, std::move(v));
-    assert(Fn::check_call<int&&>(Val));
-    std::visit(obj, std::move(cv));
-    assert(Fn::check_call<int&&>(Val));
+    // non-member
+    {
+      std::visit(obj, v);
+      assert(Fn::check_call<int&>(val));
+      std::visit(obj, cv);
+      assert(Fn::check_call<int&>(val));
+      std::visit(obj, std::move(v));
+      assert(Fn::check_call<int&&>(val));
+      std::visit(obj, std::move(cv));
+      assert(Fn::check_call<int&&>(val));
+    }
   }
 #endif
   { // multi argument - multi variant
     using V = std::variant<int, std::string, long>;
     V v1(42), v2("hello"), v3(43L);
 
-    std::visit(obj, v1, v2, v3);
-    assert((Fn::check_call<int&, std::string&, long&>(Val)));
-    std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
-    assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
+    // non-member
+    {
+      std::visit(obj, v1, v2, v3);
+      assert((Fn::check_call<int&, std::string&, long&>(val)));
+      std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
+      assert((Fn::check_call<const int&, const std::string&, long&&>(val)));
+    }
   }
   {
     using V = std::variant<int, long, double, std::string>;
-    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<long&, std::string&, int&, double&>(Val)));
-    std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(Val)));
+    // non-member
+    {
+      std::visit(obj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(val)));
+      std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
+      assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(val)));
+    }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
-    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<long&, std::string&, int*&, double&>(Val)));
-    std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
+    // non-member
+    {
+      std::visit(obj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(val)));
+      std::visit(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
+      assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(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<decltype(std::visit(obj)), Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
-    static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit(obj)), Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(cobj)), const Fn&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(obj))), Fn&&>);
+      static_assert(std::is_same_v<decltype(std::visit(std::move(cobj))), const Fn&&>);
+    }
   }
   { // test call operator forwarding - single variant, single arg
     using V = std::variant<int>;
@@ -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<int, long, double, int*>;
     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<int, long, double, long long, int*>;
     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<int, MakeEmptyT>;
     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<int, MakeEmptyT>;
@@ -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<int, MakeEmptyT>;
@@ -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<int, MakeEmptyT>;
@@ -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<int, long, double, MakeEmptyT>;
     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<int, long, double, long long, MakeEmptyT>;
@@ -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<int, long, double>::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<int, long, double>::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<GoodVariant2>(0));
 }
 
-template <class... Ts>
-struct overloaded : Ts... {
-  using Ts::operator()...;
-};
-
-void test_overload_ambiguity() {
-#if _LIBCPP_STD_VER >= 26
-  using V = std::variant<float, long, std::string>;
-  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<std::string>(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<V>(overloaded{
-      []([[maybe_unused]] auto x) {
-        assert(false);
-        return 0;
-      },
-      [](const std::string& x) {
-        assert(x == "baba"s);
-        return x + " zmt"s;
-      }});
-  assert(std::get<std::string>(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 f8cdb70a28fa3b..db4fb1961c48ec 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<int, long, double>;
     V v(42l);
-    std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
-    std::visit<ReturnType>(cobj, v);
-    assert(Fn::check_call<long&>(CT_Const | CT_LValue));
-    std::visit<ReturnType>(std::move(obj), v);
-    assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
-    std::visit<ReturnType>(std::move(cobj), v);
-    assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.visit<ReturnType>(obj);
+      assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+      v.visit<ReturnType>(cobj);
+      assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+      v.visit<ReturnType>(std::move(obj));
+      assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+      v.visit<ReturnType>(std::move(cobj));
+      assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+    }
+#endif
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v);
+      assert(Fn::check_call<long&>(CT_NonConst | CT_LValue));
+      std::visit<ReturnType>(cobj, v);
+      assert(Fn::check_call<long&>(CT_Const | CT_LValue));
+      std::visit<ReturnType>(std::move(obj), v);
+      assert(Fn::check_call<long&>(CT_NonConst | CT_RValue));
+      std::visit<ReturnType>(std::move(cobj), v);
+      assert(Fn::check_call<long&>(CT_Const | CT_RValue));
+    }
   }
   { // test call operator forwarding - multi variant, multi arg
     using V  = std::variant<int, long, double>;
     using V2 = std::variant<int*, std::string>;
     V v(42l);
     V2 v2("hello");
-    std::visit<int>(obj, v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
-    std::visit<ReturnType>(cobj, v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
-    std::visit<ReturnType>(std::move(obj), v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
-    std::visit<ReturnType>(std::move(cobj), v, v2);
-    assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
+
+    // non-member
+    {
+      std::visit<int>(obj, v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_LValue)));
+      std::visit<ReturnType>(cobj, v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_Const | CT_LValue)));
+      std::visit<ReturnType>(std::move(obj), v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_NonConst | CT_RValue)));
+      std::visit<ReturnType>(std::move(cobj), v, v2);
+      assert((Fn::check_call<long&, std::string&>(CT_Const | CT_RValue)));
+    }
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
-    std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
-    std::visit<ReturnType>(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
-    std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
-    std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_LValue)));
+      std::visit<ReturnType>(cobj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_LValue)));
+      std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_NonConst | CT_RValue)));
+      std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(CT_Const | CT_RValue)));
+    }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
-    std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
-    std::visit<ReturnType>(cobj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
-    std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
-    std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_RValue)));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_LValue)));
+      std::visit<ReturnType>(cobj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_Const | CT_LValue)));
+      std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(CT_NonConst | CT_RValue)));
+      std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(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<int>;
     V v(42);
     const V& cv = v;
-    std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<int&>(Val));
-    std::visit<ReturnType>(obj, cv);
-    assert(Fn::check_call<const int&>(Val));
-    std::visit<ReturnType>(obj, std::move(v));
-    assert(Fn::check_call<int&&>(Val));
-    std::visit<ReturnType>(obj, std::move(cv));
-    assert(Fn::check_call<const int&&>(Val));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v);
+      assert(Fn::check_call<int&>(Val));
+      std::visit<ReturnType>(obj, cv);
+      assert(Fn::check_call<const int&>(Val));
+      std::visit<ReturnType>(obj, std::move(v));
+      assert(Fn::check_call<int&&>(Val));
+      std::visit<ReturnType>(obj, std::move(cv));
+      assert(Fn::check_call<const int&&>(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<ReturnType>(obj, v);
-    assert(Fn::check_call<int&>(Val));
-    std::visit<ReturnType>(obj, cv);
-    assert(Fn::check_call<int&>(Val));
-    std::visit<ReturnType>(obj, std::move(v));
-    assert(Fn::check_call<int&>(Val));
-    std::visit<ReturnType>(obj, std::move(cv));
-    assert(Fn::check_call<int&>(Val));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v);
+      assert(Fn::check_call<int&>(Val));
+      std::visit<ReturnType>(obj, cv);
+      assert(Fn::check_call<int&>(Val));
+      std::visit<ReturnType>(obj, std::move(v));
+      assert(Fn::check_call<int&>(Val));
+      std::visit<ReturnType>(obj, std::move(cv));
+      assert(Fn::check_call<int&>(Val));
+    }
   }
   { // single argument - rvalue reference
     using V = std::variant<int&&>;
     int x   = 42;
     V v(std::move(x));
     const V& cv = v;
-    std::visit<ReturnType>(obj, v);
-    assert(Fn::check_call<int&>(Val));
-    std::visit<ReturnType>(obj, cv);
-    assert(Fn::check_call<int&>(Val));
-    std::visit<ReturnType>(obj, std::move(v));
-    assert(Fn::check_call<int&&>(Val));
-    std::visit<ReturnType>(obj, std::move(cv));
-    assert(Fn::check_call<int&&>(Val));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v);
+      assert(Fn::check_call<int&>(Val));
+      std::visit<ReturnType>(obj, cv);
+      assert(Fn::check_call<int&>(Val));
+      std::visit<ReturnType>(obj, std::move(v));
+      assert(Fn::check_call<int&&>(Val));
+      std::visit<ReturnType>(obj, std::move(cv));
+      assert(Fn::check_call<int&&>(Val));
+    }
   }
 #endif
   { // multi argument - multi variant
     using V = std::variant<int, std::string, long>;
     V v1(42), v2("hello"), v3(43l);
-    std::visit<ReturnType>(obj, v1, v2, v3);
-    assert((Fn::check_call<int&, std::string&, long&>(Val)));
-    std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
-    assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v1, v2, v3);
+      assert((Fn::check_call<int&, std::string&, long&>(Val)));
+      std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
+      assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
+    }
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42l), v2("hello"), v3(101), v4(1.1);
-    std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
-    std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(Val)));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
+      std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
+      assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(Val)));
+    }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
-    std::visit<ReturnType>(obj, v1, v2, v3, v4);
-    assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
-    std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-    assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
+
+    // non-member
+    {
+      std::visit<ReturnType>(obj, v1, v2, v3, v4);
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
+      std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
+      assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(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<decltype(std::visit<ReturnType>(obj)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj)), ReturnType>);
@@ -525,6 +581,36 @@ void test_sfinae() {
   static_assert(!has_visit<BadVariant>(int()));
 }
 
+template <class... Ts>
+struct overloaded : Ts... {
+  using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+  using V = std::variant<float, long, std::string>;
+  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<std::string>(v) == "baba"s);
+
+  // Test the constraint.
+  v = std::move(v).visit<V>(overloaded{
+      []([[maybe_unused]] auto x) {
+        assert(false);
+        return 0;
+      },
+      [](const std::string& x) {
+        assert(x == "baba"s);
+        return x + " zmt"s;
+      }});
+  assert(std::get<std::string>(v) == "baba zmt"s);
+#endif
+}
+
 int main(int, char**) {
   test_call_operator_forwarding<void>();
   test_argument_forwarding<void>();
@@ -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 <zingam at outlook.com>
Date: Wed, 27 Dec 2023 16:35:24 +0200
Subject: [PATCH 07/10] 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 6aff2194fa68dd..9eea5f60e31388 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<int&>(val));
-    //       cv.visit(obj);
-    //       assert(Fn::check_call<int&>(val));
-    //       std::move(v).visit(obj);
-    //       assert(Fn::check_call<int&>(val));
-    //       std::move(cv).visit(obj);
-    //       assert(Fn::check_call<int>(CT_NonConst));
-    //       assert(false);
-    //     }
-    // #  endif
+#  if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.visit(obj);
+      assert(Fn::check_call<int&>(val));
+      cv.visit(obj);
+      assert(Fn::check_call<int&>(val));
+      std::move(v).visit(obj);
+      assert(Fn::check_call<int&>(val));
+      std::move(cv).visit(obj);
+      assert(Fn::check_call<int&>(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<int&>(val));
+      cvstd::visit(obj);
+      assert(Fn::check_call<int&>(val));
+      std::move(v).visit(obj);
+      assert(Fn::check_call<int&&>(val));
+      std::move(cv).visit(obj);
+      assert(Fn::check_call<int&&>(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 db4fb1961c48ec..31d7665d6b3ae4 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 <class... Ts>
+struct overloaded : Ts... {
+  using Ts::operator()...;
+};
+
+void test_overload_ambiguity() {
+#if _LIBCPP_STD_VER >= 26
+  using V = std::variant<float, long, std::string>;
+  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<std::string>(v) == "baba"s);
+
+  // Test the constraint.
+  v = std::move(v).visit<V>(overloaded{
+      []([[maybe_unused]] auto x) {
+        assert(false);
+        return 0;
+      },
+      [](const std::string& x) {
+        assert(x == "baba"s);
+        return x + " zmt"s;
+      }});
+  assert(std::get<std::string>(v) == "baba zmt"s);
+#endif
+}
+
 template <typename ReturnType>
 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<int, long, double>;
-    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<int, long, double>;
     using V2 = std::variant<int*, std::string>;
-    V v(42l);
+    V v(42L);
     V2 v2("hello");
 
     // non-member
@@ -128,7 +158,7 @@ void test_call_operator_forwarding() {
   }
   {
     using V = std::variant<int, long, double, std::string>;
-    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<int, long, double, int*, std::string>;
-    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 <typename ReturnType>
 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<int>;
     V v(42);
     const V& cv = v;
 
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.visit<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+      cv.visit<ReturnType>(obj);
+      assert(Fn::check_call<const int&>(val));
+      std::move(v).visit<ReturnType>(obj);
+      assert(Fn::check_call<int&&>(val));
+      std::move(cv).visit<ReturnType>(obj);
+      assert(Fn::check_call<const int&&>(val));
+    }
+#endif
+
     // non-member
     {
       std::visit<ReturnType>(obj, v);
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit<ReturnType>(obj, cv);
-      assert(Fn::check_call<const int&>(Val));
+      assert(Fn::check_call<const int&>(val));
       std::visit<ReturnType>(obj, std::move(v));
-      assert(Fn::check_call<int&&>(Val));
+      assert(Fn::check_call<int&&>(val));
       std::visit<ReturnType>(obj, std::move(cv));
-      assert(Fn::check_call<const int&&>(Val));
+      assert(Fn::check_call<const int&&>(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<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+      cv.visit<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+      std::move(v).visit<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+      std::move(cv).visit<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+    }
+#  endif
+
     // non-member
     {
       std::visit<ReturnType>(obj, v);
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit<ReturnType>(obj, cv);
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit<ReturnType>(obj, std::move(v));
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit<ReturnType>(obj, std::move(cv));
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(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<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+      cv.visit<ReturnType>(obj);
+      assert(Fn::check_call<int&>(val));
+      std::move(v).visit<ReturnType>(obj);
+      assert(Fn::check_call<int&&>(val));
+      std::move(cv).visit<ReturnType>(obj);
+      assert(Fn::check_call<int&&>(val));
+    }
+#  endif
+
     // non-member
     {
       std::visit<ReturnType>(obj, v);
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit<ReturnType>(obj, cv);
-      assert(Fn::check_call<int&>(Val));
+      assert(Fn::check_call<int&>(val));
       std::visit<ReturnType>(obj, std::move(v));
-      assert(Fn::check_call<int&&>(Val));
+      assert(Fn::check_call<int&&>(val));
       std::visit<ReturnType>(obj, std::move(cv));
-      assert(Fn::check_call<int&&>(Val));
+      assert(Fn::check_call<int&&>(val));
     }
   }
 #endif
   { // multi argument - multi variant
     using V = std::variant<int, std::string, long>;
-    V v1(42), v2("hello"), v3(43l);
+    V v1(42), v2("hello"), v3(43L);
 
     // non-member
     {
       std::visit<ReturnType>(obj, v1, v2, v3);
-      assert((Fn::check_call<int&, std::string&, long&>(Val)));
+      assert((Fn::check_call<int&, std::string&, long&>(val)));
       std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3));
-      assert((Fn::check_call<const int&, const std::string&, long&&>(Val)));
+      assert((Fn::check_call<const int&, const std::string&, long&&>(val)));
     }
   }
   {
     using V = std::variant<int, long, double, std::string>;
-    V v1(42l), v2("hello"), v3(101), v4(1.1);
+    V v1(42L), v2("hello"), v3(101), v4(1.1);
 
     // non-member
     {
       std::visit<ReturnType>(obj, v1, v2, v3, v4);
-      assert((Fn::check_call<long&, std::string&, int&, double&>(Val)));
+      assert((Fn::check_call<long&, std::string&, int&, double&>(val)));
       std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-      assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(Val)));
+      assert((Fn::check_call<const long&, const std::string&, int&&, double&&>(val)));
     }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
-    V v1(42l), v2("hello"), v3(nullptr), v4(1.1);
+    V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
 
     // non-member
     {
       std::visit<ReturnType>(obj, v1, v2, v3, v4);
-      assert((Fn::check_call<long&, std::string&, int*&, double&>(Val)));
+      assert((Fn::check_call<long&, std::string&, int*&, double&>(val)));
       std::visit<ReturnType>(obj, std::as_const(v1), std::as_const(v2), std::move(v3), std::move(v4));
-      assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(Val)));
+      assert((Fn::check_call<const long&, const std::string&, int*&&, double&&>(val)));
     }
   }
 }
@@ -274,6 +346,7 @@ void test_return_type() {
   { // test call operator forwarding - single variant, single arg
     using V = std::variant<int>;
     V v(42);
+
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(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<int, long, double>;
-    V v(42l);
+    V v(42L);
+
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(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<int, long, double>;
     using V2 = std::variant<int*, std::string>;
-    V v(42l);
+    V v(42L);
     V2 v2("hello");
+
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v, v2)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v, v2)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v, v2)), ReturnType>);
@@ -299,7 +374,8 @@ void test_return_type() {
   }
   {
     using V = std::variant<int, long, double, std::string>;
-    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<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>);
@@ -307,7 +383,8 @@ void test_return_type() {
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
-    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<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>);
     static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>);
@@ -321,11 +398,13 @@ void test_constexpr_void() {
   {
     using V = std::variant<int>;
     constexpr V v(42);
+
     static_assert((std::visit<void>(obj, v), 42) == 42, "");
   }
   {
     using V = std::variant<short, long, char>;
-    constexpr V v(42l);
+    constexpr V v(42L);
+
     static_assert((std::visit<void>(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<void>(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<void>(aobj, v1, v2, v3), 3) == 3, "");
   }
   {
     using V = std::variant<int, long, double, int*>;
-    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<void>(aobj, v1, v2, v3, v4), 4) == 4, "");
   }
   {
     using V = std::variant<int, long, double, long long, int*>;
-    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<void>(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<int>;
     constexpr V v(42);
+
     static_assert(std::visit<int>(obj, v) == 42, "");
   }
   {
     using V = std::variant<short, long, char>;
-    constexpr V v(42l);
+    constexpr V v(42L);
+
     static_assert(std::visit<int>(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<int>(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<int>(aobj, v1, v2, v3) == 3, "");
   }
   {
     using V = std::variant<int, long, double, int*>;
-    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<int>(aobj, v1, v2, v3, v4) == 4, "");
   }
   {
     using V = std::variant<int, long, double, long long, int*>;
-    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<int>(aobj, v1, v2, v3, v4) == 4, "");
   }
 }
@@ -581,37 +671,8 @@ void test_sfinae() {
   static_assert(!has_visit<BadVariant>(int()));
 }
 
-template <class... Ts>
-struct overloaded : Ts... {
-  using Ts::operator()...;
-};
-
-void test_overload_ambiguity() {
-#if _LIBCPP_STD_VER >= 26
-  using V = std::variant<float, long, std::string>;
-  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<std::string>(v) == "baba"s);
-
-  // Test the constraint.
-  v = std::move(v).visit<V>(overloaded{
-      []([[maybe_unused]] auto x) {
-        assert(false);
-        return 0;
-      },
-      [](const std::string& x) {
-        assert(x == "baba"s);
-        return x + " zmt"s;
-      }});
-  assert(std::get<std::string>(v) == "baba zmt"s);
-#endif
-}
-
 int main(int, char**) {
+  test_overload_ambiguity();
   test_call_operator_forwarding<void>();
   test_argument_forwarding<void>();
   test_return_type<void>();
@@ -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 <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:08:46 +0200
Subject: [PATCH 08/10] 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 9eea5f60e31388..4bc35edeed3e0e 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<int&>(CT_Const | CT_RValue));
     }
 #endif
-
     // non-member
     {
       std::visit(obj, v);
@@ -94,7 +93,6 @@ void test_call_operator_forwarding() {
       assert(Fn::check_call<long&>(CT_Const | CT_RValue));
     }
 #endif
-
     // non-member
     {
       std::visit(obj, v);
@@ -183,7 +181,6 @@ void test_argument_forwarding() {
       assert(Fn::check_call<const int&&>(val));
     }
 #endif
-
     // non-member
     {
       std::visit(obj, v);
@@ -249,7 +246,6 @@ void test_argument_forwarding() {
       assert(Fn::check_call<int&&>(val));
     }
 #  endif
-
     // non-member
     {
       std::visit(obj, v);
@@ -328,7 +324,6 @@ void test_return_type() {
       static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
     }
 #endif
-
     // non-member
     {
       static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
@@ -350,7 +345,6 @@ void test_return_type() {
       static_assert(std::is_same_v<decltype(v.visit(std::move(cobj))), const Fn&&>);
     }
 #endif
-
     // non-member
     {
       static_assert(std::is_same_v<decltype(std::visit(obj, v)), Fn&>);
@@ -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<int, long, double, MakeEmptyT>;
     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 31d7665d6b3ae4..34d90c96e43f2e 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<int&>(CT_Const | CT_RValue));
     }
 #endif
-
     // non-member
     {
       std::visit<ReturnType>(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<decltype(std::visit<ReturnType>(obj)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj))), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj))), ReturnType>);
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj))), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj))), ReturnType>);
+    }
   }
   { // test call operator forwarding - single variant, single arg
     using V = std::variant<int>;
     V v(42);
 
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>);
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
+    }
+#endif
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>);
+    }
   }
   { // test call operator forwarding - single variant, multi arg
     using V = std::variant<int, long, double>;
     V v(42L);
 
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>);
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(obj)), ReturnType>);
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(cobj)), ReturnType>);
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(obj))), ReturnType>);
+      static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
+    }
+#endif
+
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v)), ReturnType>);
+    }
   }
   { // test call operator forwarding - multi variant, multi arg
     using V  = std::variant<int, long, double>;
@@ -367,28 +395,37 @@ void test_return_type() {
     V v(42L);
     V2 v2("hello");
 
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v, v2)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v, v2)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v, v2)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v, v2)), ReturnType>);
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v, v2)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v, v2)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v, v2)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v, v2)), ReturnType>);
+    }
   }
   {
     using V = std::variant<int, long, double, std::string>;
     V v1(42L), v2("hello"), v3(101), v4(1.1);
 
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>);
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>);
+    }
   }
   {
     using V = std::variant<int, long, double, int*, std::string>;
     V v1(42L), v2("hello"), v3(nullptr), v4(1.1);
 
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>);
-    static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>);
+    // non-member
+    {
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v1, v2, v3, v4)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(cobj, v1, v2, v3, v4)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(obj), v1, v2, v3, v4)), ReturnType>);
+      static_assert(std::is_same_v<decltype(std::visit<ReturnType>(std::move(cobj), v1, v2, v3, v4)), ReturnType>);
+    }
   }
 }
 
@@ -399,13 +436,25 @@ void test_constexpr_void() {
     using V = std::variant<int>;
     constexpr V v(42);
 
-    static_assert((std::visit<void>(obj, v), 42) == 42, "");
+#if _LIBCPP_STD_VER >= 26
+    // member
+    { static_assert((v.visit<void>(obj), 42) == 42); }
+#endif
+
+    // non-member
+    { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
   }
   {
     using V = std::variant<short, long, char>;
     constexpr V v(42L);
 
-    static_assert((std::visit<void>(obj, v), 42) == 42, "");
+#if _LIBCPP_STD_VER >= 26
+    // member
+    { static_assert((v.visit<void>(obj), 42) == 42); }
+#endif
+
+    // non-member
+    { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
   }
   {
     using V1 = std::variant<int>;
@@ -415,7 +464,8 @@ void test_constexpr_void() {
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
 
-    static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, "");
+    // non-member
+    { static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); }
   }
   {
     using V1 = std::variant<int>;
@@ -425,19 +475,21 @@ void test_constexpr_void() {
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
 
-    static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, "");
+    // non-member
+    { static_assert((std::visit<void>(aobj, v1, v2, v3), 3) == 3, ""); }
   }
   {
     using V = std::variant<int, long, double, int*>;
     constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
 
-    static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, "");
+    // non-member
+    { static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
   }
   {
     using V = std::variant<int, long, double, long long, int*>;
     constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
-
-    static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, "");
+    // non-member
+    { static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
   }
 }
 
@@ -449,13 +501,25 @@ void test_constexpr_int() {
     using V = std::variant<int>;
     constexpr V v(42);
 
-    static_assert(std::visit<int>(obj, v) == 42, "");
+#if _LIBCPP_STD_VER >= 26
+    // member
+    { static_assert(v.visit<int>(obj) == 42); }
+#endif
+
+    // non-member
+    { static_assert(std::visit<int>(obj, v) == 42, ""); }
   }
   {
     using V = std::variant<short, long, char>;
     constexpr V v(42L);
 
-    static_assert(std::visit<int>(obj, v) == 42, "");
+#if _LIBCPP_STD_VER >= 26
+    // member
+    { static_assert(v.visit<int>(obj) == 42); }
+#endif
+
+    // non-member
+    { static_assert(std::visit<int>(obj, v) == 42, ""); }
   }
   {
     using V1 = std::variant<int>;
@@ -465,7 +529,8 @@ void test_constexpr_int() {
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
 
-    static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, "");
+    // non-member
+    { static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); }
   }
   {
     using V1 = std::variant<int>;
@@ -475,19 +540,22 @@ void test_constexpr_int() {
     constexpr V2 v2(nullptr);
     constexpr V3 v3;
 
-    static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, "");
+    // non-member
+    { static_assert(std::visit<int>(aobj, v1, v2, v3) == 3, ""); }
   }
   {
     using V = std::variant<int, long, double, int*>;
     constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
 
-    static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, "");
+    // non-member
+    { static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); }
   }
   {
     using V = std::variant<int, long, double, long long, int*>;
     constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
 
-    static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, "");
+    // non-member
+    { static_assert(std::visit<int>(aobj, v1, v2, v3, v4) == 4, ""); }
   }
 }
 
@@ -495,7 +563,22 @@ template <typename ReturnType>
 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<ReturnType>(obj);
+    } catch (const std::bad_variant_access&) {
+      return true;
+    } catch (...) {
+    }
+    return false;
+  };
+#  endif
+
+  // non-member
+  auto test_nonmember = [&](auto&&... args) {
     try {
       std::visit<ReturnType>(obj, args...);
     } catch (const std::bad_variant_access&) {
@@ -504,11 +587,18 @@ void test_exceptions() {
     }
     return false;
   };
+
   {
     using V = std::variant<int, MakeEmptyT>;
     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<int, MakeEmptyT>;
@@ -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<int, MakeEmptyT>;
@@ -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<int, MakeEmptyT>;
@@ -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<int, long, double, MakeEmptyT>;
     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<int, long, double, long long, MakeEmptyT>;
@@ -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<A> v;
-  std::visit<ReturnType>(Visitor{}, v);
+
+#if _LIBCPP_STD_VER >= 26
+  // member
+  { v.template visit<ReturnType>(Visitor{}); }
+#endif
+  // non-member
+  { std::visit<ReturnType>(Visitor{}, v); }
 }
 
 void test_constexpr_explicit_side_effect() {
   auto test_lambda = [](int arg) constexpr {
     std::variant<int> v = 101;
-    std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
+
+#if _LIBCPP_STD_VER >= 26
+    // member
+    {
+      v.template visit<void>([arg](int& x) constexpr { x = arg; });
+    }
+#endif
+    // non-member
+    {
+      std::visit<void>([arg](int& x) constexpr { x = arg; }, v);
+    }
     return std::get<int>(v);
   };
 

>From 5097751e32cc89cdce94c77d813f38102cd5d22b Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:28:02 +0200
Subject: [PATCH 09/10] 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 6f095891693867..3723037d4e6d10 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<void*>([](auto) -> Holder<Incomplete>* { 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 4bc35edeed3e0e..9eb2680c47ffd5 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 34d90c96e43f2e..b0d1055973f6c7 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<long&>(CT_Const | CT_RValue));
     }
 #endif
-
     // non-member
     {
       std::visit<ReturnType>(obj, v);
@@ -213,7 +212,6 @@ void test_argument_forwarding() {
       assert(Fn::check_call<const int&&>(val));
     }
 #endif
-
     // non-member
     {
       std::visit<ReturnType>(obj, v);
@@ -246,7 +244,6 @@ void test_argument_forwarding() {
       assert(Fn::check_call<int&>(val));
     }
 #  endif
-
     // non-member
     {
       std::visit<ReturnType>(obj, v);
@@ -278,7 +275,6 @@ void test_argument_forwarding() {
       assert(Fn::check_call<int&&>(val));
     }
 #  endif
-
     // non-member
     {
       std::visit<ReturnType>(obj, v);
@@ -358,7 +354,6 @@ void test_return_type() {
       static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
     }
 #endif
-
     // non-member
     {
       static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
@@ -380,7 +375,6 @@ void test_return_type() {
       static_assert(std::is_same_v<decltype(v.visit<ReturnType>(std::move(cobj))), ReturnType>);
     }
 #endif
-
     // non-member
     {
       static_assert(std::is_same_v<decltype(std::visit<ReturnType>(obj, v)), ReturnType>);
@@ -440,7 +434,6 @@ void test_constexpr_void() {
     // member
     { static_assert((v.visit<void>(obj), 42) == 42); }
 #endif
-
     // non-member
     { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
   }
@@ -452,7 +445,6 @@ void test_constexpr_void() {
     // member
     { static_assert((v.visit<void>(obj), 42) == 42); }
 #endif
-
     // non-member
     { static_assert((std::visit<void>(obj, v), 42) == 42, ""); }
   }
@@ -488,6 +480,7 @@ void test_constexpr_void() {
   {
     using V = std::variant<int, long, double, long long, int*>;
     constexpr V v1(42L), v2(101), v3(nullptr), v4(1.1);
+
     // non-member
     { static_assert((std::visit<void>(aobj, v1, v2, v3, v4), 4) == 4, ""); }
   }
@@ -505,7 +498,6 @@ void test_constexpr_int() {
     // member
     { static_assert(v.visit<int>(obj) == 42); }
 #endif
-
     // non-member
     { static_assert(std::visit<int>(obj, v) == 42, ""); }
   }
@@ -517,7 +509,6 @@ void test_constexpr_int() {
     // member
     { static_assert(v.visit<int>(obj) == 42); }
 #endif
-
     // non-member
     { static_assert(std::visit<int>(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<int, long, double, MakeEmptyT>;
-    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<int, long, double, long long, MakeEmptyT>;
-    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<short, long, float> {};
 
-  std::visit<bool>(
-      [](auto x) {
-        assert(x == 42);
-        return true;
-      },
-      MyVariant{42});
-  std::visit<bool>(
-      [](auto x) {
-        assert(x == -1.3f);
-        return true;
-      },
-      MyVariant{-1.3f});
+#if _LIBCPP_STD_VER >= 26
+  // member
+  {
+    MyVariant{42}.template visit<bool>([](auto x) {
+      assert(x == 42);
+      return true;
+    });
+    MyVariant{-1.3f}.template visit<bool>([](auto x) {
+      assert(x == -1.3f);
+      return true;
+    });
+  }
+#endif
+  // non-member
+  {
+    std::visit<bool>(
+        [](auto x) {
+          assert(x == 42);
+          return true;
+        },
+        MyVariant{42});
+    std::visit<bool>(
+        [](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<int, long, double>::variant;
   };
 
-  std::visit<bool>(
-      [](auto x) {
-        assert(x == 12);
-        return true;
-      },
-      EvilVariant1{12});
-  std::visit<bool>(
-      [](auto x) {
-        assert(x == 12.3);
-        return true;
-      },
-      EvilVariant1{12.3});
+#if _LIBCPP_STD_VER >= 26
+  // member
+  {
+    EvilVariant1{12}.template visit<bool>([](auto x) {
+      assert(x == 12);
+      return true;
+    });
+    EvilVariant1{12.3}.template visit<bool>([](auto x) {
+      assert(x == 12.3);
+      return true;
+    });
+  }
+#endif
+  // non-member
+  {
+    std::visit<bool>(
+        [](auto x) {
+          assert(x == 12);
+          return true;
+        },
+        EvilVariant1{12});
+    std::visit<bool>(
+        [](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<int, long, double>::variant;
   };
 
-  std::visit<bool>(
-      [](auto x) {
-        assert(x == 12);
-        return true;
-      },
-      EvilVariant2{12});
-  std::visit<bool>(
-      [](auto x) {
-        assert(x == 12.3);
-        return true;
-      },
-      EvilVariant2{12.3});
+#if _LIBCPP_STD_VER >= 26
+  // member
+  {
+    EvilVariant2{12}.template visit<bool>([](auto x) {
+      assert(x == 12);
+      return true;
+    });
+    EvilVariant2{12.3}.template visit<bool>([](auto x) {
+      assert(x == 12.3);
+      return true;
+    });
+  }
+#endif
+  // non-member
+  {
+    std::visit<bool>(
+        [](auto x) {
+          assert(x == 12);
+          return true;
+        },
+        EvilVariant2{12});
+    std::visit<bool>(
+        [](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 <zingam at outlook.com>
Date: Wed, 27 Dec 2023 17:32:53 +0200
Subject: [PATCH 10/10] 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 3723037d4e6d10..3bd305a7c62c17 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<class Self, class Visitor>
-//   constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
+//   constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
 // template<class R, class Self, class Visitor>
 //   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 9eb2680c47ffd5..8781174ff7d669 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<class Self, class Visitor>
-//   constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
-// template<class R, class Self, class Visitor>
-//   constexpr R visit(this Self&&, Visitor&&);              // since C++26
+//   constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
 
 // template <class Visitor, class... Variants>
 // 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 b0d1055973f6c7..1c73d34cacd87f 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 @@
 // <variant>
 
 // class variant;
-// template<class Self, class Visitor>
-//   constexpr decltype(auto) visit(this Self&&, Visitor&&); //since C++26
 // template<class R, class Self, class Visitor>
 //   constexpr R visit(this Self&&, Visitor&&);              // since C++26
 



More information about the cfe-commits mailing list