|  | // -*- C++ -*- | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | #ifndef SUPPORT_VARIANT_TEST_HELPERS_H | 
|  | #define SUPPORT_VARIANT_TEST_HELPERS_H | 
|  |  | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  | #include <cassert> | 
|  |  | 
|  | #include "test_macros.h" | 
|  | #include "type_id.h" | 
|  |  | 
|  | #if TEST_STD_VER <= 14 | 
|  | #error This file requires C++17 | 
|  | #endif | 
|  |  | 
|  | // FIXME: Currently the variant<T&> tests are disabled using this macro. | 
|  | #define TEST_VARIANT_HAS_NO_REFERENCES | 
|  | #ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT | 
|  | # define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS | 
|  | #endif | 
|  |  | 
|  | #ifdef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS | 
|  | constexpr bool VariantAllowsNarrowingConversions = true; | 
|  | #else | 
|  | constexpr bool VariantAllowsNarrowingConversions = false; | 
|  | #endif | 
|  |  | 
|  | #ifndef TEST_HAS_NO_EXCEPTIONS | 
|  | struct CopyThrows { | 
|  | CopyThrows() = default; | 
|  | CopyThrows(CopyThrows const&) { throw 42; } | 
|  | CopyThrows& operator=(CopyThrows const&) { throw 42; } | 
|  | }; | 
|  |  | 
|  | struct MoveThrows { | 
|  | static int alive; | 
|  | MoveThrows() { ++alive; } | 
|  | MoveThrows(MoveThrows const&) {++alive;} | 
|  | MoveThrows(MoveThrows&&) {  throw 42; } | 
|  | MoveThrows& operator=(MoveThrows const&) { return *this; } | 
|  | MoveThrows& operator=(MoveThrows&&) { throw 42; } | 
|  | ~MoveThrows() { --alive; } | 
|  | }; | 
|  |  | 
|  | int MoveThrows::alive = 0; | 
|  |  | 
|  | struct MakeEmptyT { | 
|  | static int alive; | 
|  | MakeEmptyT() { ++alive; } | 
|  | MakeEmptyT(MakeEmptyT const&) { | 
|  | ++alive; | 
|  | // Don't throw from the copy constructor since variant's assignment | 
|  | // operator performs a copy before committing to the assignment. | 
|  | } | 
|  | MakeEmptyT(MakeEmptyT &&) { | 
|  | throw 42; | 
|  | } | 
|  | MakeEmptyT& operator=(MakeEmptyT const&) { | 
|  | throw 42; | 
|  | } | 
|  | MakeEmptyT& operator=(MakeEmptyT&&) { | 
|  | throw 42; | 
|  | } | 
|  | ~MakeEmptyT() { --alive; } | 
|  | }; | 
|  | static_assert(std::is_swappable_v<MakeEmptyT>, ""); // required for test | 
|  |  | 
|  | int MakeEmptyT::alive = 0; | 
|  |  | 
|  | template <class Variant> | 
|  | void makeEmpty(Variant& v) { | 
|  | Variant v2(std::in_place_type<MakeEmptyT>); | 
|  | try { | 
|  | v = std::move(v2); | 
|  | assert(false); | 
|  | } catch (...) { | 
|  | assert(v.valueless_by_exception()); | 
|  | } | 
|  | } | 
|  | #endif // TEST_HAS_NO_EXCEPTIONS | 
|  |  | 
|  | 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> | 
|  | ForwardingCallObject& operator()(Args&&...) & { | 
|  | set_call<Args &&...>(CT_NonConst | CT_LValue); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | template <class... Args> | 
|  | const ForwardingCallObject& operator()(Args&&...) const & { | 
|  | set_call<Args &&...>(CT_Const | CT_LValue); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | template <class... Args> | 
|  | ForwardingCallObject&& operator()(Args&&...) && { | 
|  | set_call<Args &&...>(CT_NonConst | CT_RValue); | 
|  | return std::move(*this); | 
|  | } | 
|  |  | 
|  | template <class... Args> | 
|  | const ForwardingCallObject&& operator()(Args&&...) const && { | 
|  | set_call<Args &&...>(CT_Const | CT_RValue); | 
|  | return std::move(*this); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | // To check explicit return type for visit<R> | 
|  | constexpr operator int() const | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static CallType last_call_type; | 
|  | static const TypeID *last_call_args; | 
|  | }; | 
|  |  | 
|  | CallType ForwardingCallObject::last_call_type = CT_None; | 
|  | const TypeID *ForwardingCallObject::last_call_args = nullptr; | 
|  |  | 
|  | 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); | 
|  | } | 
|  | }; | 
|  |  | 
|  | #endif // SUPPORT_VARIANT_TEST_HELPERS_H |