Add <variant> tests but disable them for libc++
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@287728 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/std/utilities/variant/variant.visit/visit.pass.cpp b/test/std/utilities/variant/variant.visit/visit.pass.cpp
new file mode 100644
index 0000000..1783fe9
--- /dev/null
+++ b/test/std/utilities/variant/variant.visit/visit.pass.cpp
@@ -0,0 +1,291 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+
+// <variant>
+// template <class Visitor, class... Variants>
+// constexpr see below visit(Visitor&& vis, Variants&&... vars);
+
+#include <cassert>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+#include "test_macros.h"
+#include "type_id.h"
+#include "variant_test_helpers.hpp"
+
+enum CallType : unsigned {
+ CT_None,
+ CT_NonConst = 1,
+ CT_Const = 2,
+ CT_LValue = 4,
+ CT_RValue = 8
+};
+
+inline constexpr CallType operator|(CallType LHS, CallType RHS) {
+ return static_cast<CallType>(static_cast<unsigned>(LHS) |
+ static_cast<unsigned>(RHS));
+}
+
+struct ForwardingCallObject {
+
+ template <class... Args> bool operator()(Args &&...) & {
+ set_call<Args &&...>(CT_NonConst | CT_LValue);
+ return true;
+ }
+
+ template <class... Args> bool operator()(Args &&...) const & {
+ set_call<Args &&...>(CT_Const | CT_LValue);
+ return true;
+ }
+
+ // Don't allow the call operator to be invoked as an rvalue.
+ template <class... Args> bool operator()(Args &&...) && {
+ set_call<Args &&...>(CT_NonConst | CT_RValue);
+ return true;
+ }
+
+ template <class... Args> bool operator()(Args &&...) const && {
+ set_call<Args &&...>(CT_Const | CT_RValue);
+ return true;
+ }
+
+ template <class... Args> static void set_call(CallType type) {
+ assert(last_call_type == CT_None);
+ assert(last_call_args == nullptr);
+ last_call_type = type;
+ last_call_args = std::addressof(makeArgumentID<Args...>());
+ }
+
+ template <class... Args> static bool check_call(CallType type) {
+ bool result = last_call_type == type && last_call_args &&
+ *last_call_args == makeArgumentID<Args...>();
+ last_call_type = CT_None;
+ last_call_args = nullptr;
+ return result;
+ }
+
+ static CallType last_call_type;
+ static TypeID const *last_call_args;
+};
+
+CallType ForwardingCallObject::last_call_type = CT_None;
+TypeID const *ForwardingCallObject::last_call_args = nullptr;
+
+void test_call_operator_forwarding() {
+ using Fn = ForwardingCallObject;
+ Fn obj{};
+ Fn const &cobj = obj;
+ { // test call operator forwarding - single variant, single arg
+ using V = std::variant<int>;
+ V v(42);
+ 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 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(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)));
+ }
+}
+
+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);
+ V const &cv = v;
+ std::visit(obj, v);
+ assert(Fn::check_call<int &>(Val));
+ std::visit(obj, cv);
+ assert(Fn::check_call<int const &>(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
+ using V = std::variant<int &>;
+ int x = 42;
+ V v(x);
+ V const &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));
+ }
+ { // single argument - rvalue reference
+ using V = std::variant<int &&>;
+ int x = 42;
+ V v(std::move(x));
+ V const &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));
+ }
+ { // multi argument - multi variant
+ using S = std::string const &;
+ using V = std::variant<int, S, long &&>;
+ std::string const str = "hello";
+ long l = 43;
+ V v1(42);
+ V const &cv1 = v1;
+ V v2(str);
+ V const &cv2 = v2;
+ V v3(std::move(l));
+ V const &cv3 = v3;
+ std::visit(obj, v1, v2, v3);
+ assert((Fn::check_call<int &, S, long &>(Val)));
+ std::visit(obj, cv1, cv2, std::move(v3));
+ assert((Fn::check_call<const int &, S, long &&>(Val)));
+ }
+#endif
+}
+
+struct ReturnFirst {
+ template <class... Args> constexpr int operator()(int f, Args &&...) const {
+ return f;
+ }
+};
+
+struct ReturnArity {
+ template <class... Args> constexpr int operator()(Args &&...) const {
+ return sizeof...(Args);
+ }
+};
+
+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, "");
+ }
+ {
+ using V = std::variant<short, long, char>;
+ constexpr V v(42l);
+ static_assert(std::visit(obj, v) == 42, "");
+ }
+ {
+ using V1 = std::variant<int>;
+ using V2 = std::variant<int, char *, long long>;
+ using V3 = std::variant<bool, int, int>;
+ constexpr V1 v1;
+ constexpr V2 v2(nullptr);
+ constexpr V3 v3;
+ static_assert(std::visit(aobj, v1, v2, v3) == 3, "");
+ }
+ {
+ using V1 = std::variant<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, "");
+ }
+}
+
+void test_exceptions() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ ReturnArity obj{};
+ auto test = [&](auto &&... args) {
+ try {
+ std::visit(obj, args...);
+ } catch (std::bad_variant_access const &) {
+ return true;
+ } catch (...) {
+ }
+ return false;
+ };
+ {
+ using V = std::variant<int, MakeEmptyT>;
+ V v;
+ makeEmpty(v);
+ assert(test(v));
+ }
+ {
+ 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 *>;
+ 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>;
+ V v;
+ makeEmpty(v);
+ V2 v2;
+ makeEmpty(v2);
+ assert(test(v, v2));
+ }
+#endif
+}
+
+int main() {
+ test_call_operator_forwarding();
+ test_argument_forwarding();
+ test_constexpr();
+ test_exceptions();
+}