1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 #ifndef SUPPORT_VARIANT_TEST_HELPERS_H 10 #define SUPPORT_VARIANT_TEST_HELPERS_H 11 12 #include <type_traits> 13 #include <utility> 14 #include <cassert> 15 16 #include "test_macros.h" 17 #include "type_id.h" 18 19 #if TEST_STD_VER <= 14 20 #error This file requires C++17 21 #endif 22 23 // FIXME: Currently the variant<T&> tests are disabled using this macro. 24 #define TEST_VARIANT_HAS_NO_REFERENCES 25 #ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT 26 # define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS 27 #endif 28 29 #ifdef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS 30 constexpr bool VariantAllowsNarrowingConversions = true; 31 #else 32 constexpr bool VariantAllowsNarrowingConversions = false; 33 #endif 34 35 #ifndef TEST_HAS_NO_EXCEPTIONS 36 struct CopyThrows { 37 CopyThrows() = default; 38 CopyThrows(CopyThrows const&) { throw 42; } 39 CopyThrows& operator=(CopyThrows const&) { throw 42; } 40 }; 41 42 struct MoveThrows { 43 static int alive; 44 MoveThrows() { ++alive; } 45 MoveThrows(MoveThrows const&) {++alive;} 46 MoveThrows(MoveThrows&&) { throw 42; } 47 MoveThrows& operator=(MoveThrows const&) { return *this; } 48 MoveThrows& operator=(MoveThrows&&) { throw 42; } 49 ~MoveThrows() { --alive; } 50 }; 51 52 int MoveThrows::alive = 0; 53 54 struct MakeEmptyT { 55 static int alive; 56 MakeEmptyT() { ++alive; } 57 MakeEmptyT(MakeEmptyT const&) { 58 ++alive; 59 // Don't throw from the copy constructor since variant's assignment 60 // operator performs a copy before committing to the assignment. 61 } 62 MakeEmptyT(MakeEmptyT &&) { 63 throw 42; 64 } 65 MakeEmptyT& operator=(MakeEmptyT const&) { 66 throw 42; 67 } 68 MakeEmptyT& operator=(MakeEmptyT&&) { 69 throw 42; 70 } 71 ~MakeEmptyT() { --alive; } 72 }; 73 static_assert(std::is_swappable_v<MakeEmptyT>, ""); // required for test 74 75 int MakeEmptyT::alive = 0; 76 77 template <class Variant> 78 void makeEmpty(Variant& v) { 79 Variant v2(std::in_place_type<MakeEmptyT>); 80 try { 81 v = std::move(v2); 82 assert(false); 83 } catch (...) { 84 assert(v.valueless_by_exception()); 85 } 86 } 87 #endif // TEST_HAS_NO_EXCEPTIONS 88 89 enum CallType : unsigned { 90 CT_None, 91 CT_NonConst = 1, 92 CT_Const = 2, 93 CT_LValue = 4, 94 CT_RValue = 8 95 }; 96 97 inline constexpr CallType operator|(CallType LHS, CallType RHS) { 98 return static_cast<CallType>(static_cast<unsigned>(LHS) | 99 static_cast<unsigned>(RHS)); 100 } 101 102 struct ForwardingCallObject { 103 104 template <class... Args> 105 ForwardingCallObject& operator()(Args&&...) & { 106 set_call<Args &&...>(CT_NonConst | CT_LValue); 107 return *this; 108 } 109 110 template <class... Args> 111 const ForwardingCallObject& operator()(Args&&...) const & { 112 set_call<Args &&...>(CT_Const | CT_LValue); 113 return *this; 114 } 115 116 template <class... Args> 117 ForwardingCallObject&& operator()(Args&&...) && { 118 set_call<Args &&...>(CT_NonConst | CT_RValue); 119 return std::move(*this); 120 } 121 122 template <class... Args> 123 const ForwardingCallObject&& operator()(Args&&...) const && { 124 set_call<Args &&...>(CT_Const | CT_RValue); 125 return std::move(*this); 126 } 127 128 template <class... Args> static void set_call(CallType type) { 129 assert(last_call_type == CT_None); 130 assert(last_call_args == nullptr); 131 last_call_type = type; 132 last_call_args = std::addressof(makeArgumentID<Args...>()); 133 } 134 135 template <class... Args> static bool check_call(CallType type) { 136 bool result = last_call_type == type && last_call_args && 137 *last_call_args == makeArgumentID<Args...>(); 138 last_call_type = CT_None; 139 last_call_args = nullptr; 140 return result; 141 } 142 143 // To check explicit return type for visit<R> 144 constexpr operator int() const 145 { 146 return 0; 147 } 148 149 static CallType last_call_type; 150 static const TypeID *last_call_args; 151 }; 152 153 CallType ForwardingCallObject::last_call_type = CT_None; 154 const TypeID *ForwardingCallObject::last_call_args = nullptr; 155 156 struct ReturnFirst { 157 template <class... Args> constexpr int operator()(int f, Args &&...) const { 158 return f; 159 } 160 }; 161 162 struct ReturnArity { 163 template <class... Args> constexpr int operator()(Args &&...) const { 164 return sizeof...(Args); 165 } 166 }; 167 168 #endif // SUPPORT_VARIANT_TEST_HELPERS_H 169