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 #ifndef TEST_HAS_NO_EXCEPTIONS 25 struct CopyThrows { 26 CopyThrows() = default; CopyThrowsCopyThrows27 CopyThrows(CopyThrows const&) { throw 42; } 28 CopyThrows& operator=(CopyThrows const&) { throw 42; } 29 }; 30 31 struct MoveThrows { 32 static int alive; MoveThrowsMoveThrows33 MoveThrows() { ++alive; } MoveThrowsMoveThrows34 MoveThrows(MoveThrows const&) {++alive;} MoveThrowsMoveThrows35 MoveThrows(MoveThrows&&) { throw 42; } 36 MoveThrows& operator=(MoveThrows const&) { return *this; } 37 MoveThrows& operator=(MoveThrows&&) { throw 42; } ~MoveThrowsMoveThrows38 ~MoveThrows() { --alive; } 39 }; 40 41 int MoveThrows::alive = 0; 42 43 struct MakeEmptyT { 44 static int alive; MakeEmptyTMakeEmptyT45 MakeEmptyT() { ++alive; } MakeEmptyTMakeEmptyT46 MakeEmptyT(MakeEmptyT const&) { 47 ++alive; 48 // Don't throw from the copy constructor since variant's assignment 49 // operator performs a copy before committing to the assignment. 50 } MakeEmptyTMakeEmptyT51 MakeEmptyT(MakeEmptyT &&) { 52 throw 42; 53 } 54 MakeEmptyT& operator=(MakeEmptyT const&) { 55 throw 42; 56 } 57 MakeEmptyT& operator=(MakeEmptyT&&) { 58 throw 42; 59 } ~MakeEmptyTMakeEmptyT60 ~MakeEmptyT() { --alive; } 61 }; 62 static_assert(std::is_swappable_v<MakeEmptyT>, ""); // required for test 63 64 int MakeEmptyT::alive = 0; 65 66 template <class Variant> makeEmpty(Variant & v)67void makeEmpty(Variant& v) { 68 Variant v2(std::in_place_type<MakeEmptyT>); 69 try { 70 v = std::move(v2); 71 assert(false); 72 } catch (...) { 73 assert(v.valueless_by_exception()); 74 } 75 } 76 #endif // TEST_HAS_NO_EXCEPTIONS 77 78 enum CallType : unsigned { 79 CT_None, 80 CT_NonConst = 1, 81 CT_Const = 2, 82 CT_LValue = 4, 83 CT_RValue = 8 84 }; 85 86 inline constexpr CallType operator|(CallType LHS, CallType RHS) { 87 return static_cast<CallType>(static_cast<unsigned>(LHS) | 88 static_cast<unsigned>(RHS)); 89 } 90 91 struct ForwardingCallObject { 92 93 template <class... Args> operatorForwardingCallObject94 ForwardingCallObject& operator()(Args&&...) & { 95 set_call<Args &&...>(CT_NonConst | CT_LValue); 96 return *this; 97 } 98 99 template <class... Args> operatorForwardingCallObject100 const ForwardingCallObject& operator()(Args&&...) const & { 101 set_call<Args &&...>(CT_Const | CT_LValue); 102 return *this; 103 } 104 105 template <class... Args> operatorForwardingCallObject106 ForwardingCallObject&& operator()(Args&&...) && { 107 set_call<Args &&...>(CT_NonConst | CT_RValue); 108 return std::move(*this); 109 } 110 111 template <class... Args> operatorForwardingCallObject112 const ForwardingCallObject&& operator()(Args&&...) const && { 113 set_call<Args &&...>(CT_Const | CT_RValue); 114 return std::move(*this); 115 } 116 set_callForwardingCallObject117 template <class... Args> static void set_call(CallType type) { 118 assert(last_call_type == CT_None); 119 assert(last_call_args == nullptr); 120 last_call_type = type; 121 last_call_args = std::addressof(makeArgumentID<Args...>()); 122 } 123 check_callForwardingCallObject124 template <class... Args> static bool check_call(CallType type) { 125 bool result = last_call_type == type && last_call_args && 126 *last_call_args == makeArgumentID<Args...>(); 127 last_call_type = CT_None; 128 last_call_args = nullptr; 129 return result; 130 } 131 132 // To check explicit return type for visit<R> 133 constexpr operator int() const 134 { 135 return 0; 136 } 137 138 static CallType last_call_type; 139 static const TypeID *last_call_args; 140 }; 141 142 CallType ForwardingCallObject::last_call_type = CT_None; 143 const TypeID *ForwardingCallObject::last_call_args = nullptr; 144 145 struct ReturnFirst { operatorReturnFirst146 template <class... Args> constexpr int operator()(int f, Args &&...) const { 147 return f; 148 } 149 }; 150 151 struct ReturnArity { operatorReturnArity152 template <class... Args> constexpr int operator()(Args &&...) const { 153 return sizeof...(Args); 154 } 155 }; 156 157 #endif // SUPPORT_VARIANT_TEST_HELPERS_H 158