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