@@ -0,0 +1,268 @@
+//===--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+//
+
+// class variant;
+
+// template
+// constexpr decltype(auto) visit(this Self&&, Visitor&&); // since C++26
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "test_macros.h"
+#include "variant_test_helpers.h"
+
+void test_call_operator_forwarding() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ const Fn& cobj = obj;
+
+ { // test call operator forwarding - no variant
+// non-member
+{
+ std::visit(obj);
+ assert(Fn::check_call<>(CT_NonConst | CT_LValue));
+ std::visit(cobj);
+ assert(Fn::check_call<>(CT_Const | CT_LValue));
+ std::visit(std::move(obj));
+ assert(Fn::check_call<>(CT_NonConst | CT_RValue));
+ std::visit(std::move(cobj));
+ assert(Fn::check_call<>(CT_Const | CT_RValue));
+}
+ }
+ { // test call operator forwarding - single variant, single arg
+using V = std::variant;
+V v(42);
+
+v.visit(obj);
+assert(Fn::check_call(CT_NonConst | CT_LValue));
+v.visit(cobj);
+assert(Fn::check_call(CT_Const | CT_LValue));
+v.visit(std::move(obj));
+assert(Fn::check_call(CT_NonConst | CT_RValue));
+v.visit(std::move(cobj));
+assert(Fn::check_call(CT_Const | CT_RValue));
+ }
+ { // test call operator forwarding - single variant, multi arg
+using V = std::variant;
+V v(42L);
+
+v.visit(obj);
+assert(Fn::check_call(CT_NonConst | CT_LValue));
+v.visit(cobj);
+assert(Fn::check_call(CT_Const | CT_LValue));
+v.visit(std::move(obj));
+assert(Fn::check_call(CT_NonConst | CT_RValue));
+v.visit(std::move(cobj));
+assert(Fn::check_call(CT_Const | CT_RValue));
+ }
+}
+
+// Applies to non-member `std::visit` only.
+void test_argument_forwarding() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ const auto val = CT_LValue | CT_NonConst;
+
+ { // single argument - value type
+using V = std::variant;
+V v(42);
+const V& cv = v;
+
+v.visit(obj);
+assert(Fn::check_call(val));
+cv.visit(obj);
+assert(Fn::check_call(val));
+std::move(v).visit(obj);
+assert(Fn::check_call(val));
+std::move(cv).visit(obj);
+assert(Fn::check_call(val));
+ }
+#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
+ { // single argument - lvalue reference
+using V = std::variant;
+int x = 42;
+V v(x);
+const V& cv = v;
+
+v.visit(obj);
+assert(Fn::check_call(val));
+cv.visit(obj);
+assert(Fn::check_call(val));
+std::move(v).visit(obj);
+assert(Fn::check_call(val));
+std::move(cv).visit(obj);
+assert(Fn::check_call(val));
+assert(false);
+ }
+ { // single argument - rvalue reference
+using V = std::variant;
+int x = 42;
+V v(std::move(x));
+const V& cv = v;
+
+v.visit(obj);
+assert(Fn::check_call(val));
+cvstd::visit(obj);
+assert(Fn::check_call(val));
+std::move(v).visit(obj);
+assert(Fn::check_call(val));
+std::move(cv).visit(obj);
+assert(Fn::check_call(val));
+ }
+#endif
+}
+
+void test_return_type() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ const Fn& cobj = obj;
+
+ { // test call operator forwarding - single variant, single arg
+using V = std::variant;
+V v(42);
+
+static_assert(std::is_same_v);
+static_assert(std::is_same_v);
+static_assert(std::is_same_v);
+static_assert(std::is_same_v);
+ }
+ { // test call operator forwarding - single variant, multi arg
+using V = std::variant;
+V v(42L);
+
+static_assert(std::is_same_v);
+static_assert(std::is_same_v);
+static_assert(std::is_same_v);
+static_assert(std::is_same_v);
+ }
+}
+
+void test_constexpr() {
+ constexpr ReturnFirst obj{};
+
+ {
+using V = std::variant;
+constexpr V v(42);
+
+static_assert(v.visit(obj) == 42);
+ }
+ {
+using V = std::variant;
+constexpr V v(42L);
+
+static_assert(v.visit(obj) == 42);
+ }
+}
+
+void test_exceptions() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ ReturnArity obj{};
+
+ auto test = [&](auto&& v) {
+try {
+ v.visit(obj);
+} catch (const std::bad_variant_access&) {
+ return true;
+} catch (...) {
+}
+return false;
+ };
+
+ {
+using V = std::variant;
+V v;
+makeEmpty(v);
+
+assert(test(v));
+ }
+#endif
+}
+
+// See https://llvm.org/PR31916
+void test_caller_accepts_nonconst() {
+ struct A {};
+ struct Visitor {
+void operator()(A&) {}
+ };
+ std::variant v;
+
+ v.visit(Visitor{});
+}
+
+struct MyVariant : std::variant {};
+
+n