xref: /llvm-project/libcxx/test/support/variant_test_helpers.h (revision 5d73c7d1af78379827759dfb57887246e47a503e)
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 // TODO(LLVM-19): Remove TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
28 #ifdef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
29 # define TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
30 #endif
31 #ifdef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
32 constexpr bool VariantAllowsNarrowingConversions = true;
33 #else
34 constexpr bool VariantAllowsNarrowingConversions = false;
35 #endif
36 
37 #ifndef TEST_HAS_NO_EXCEPTIONS
38 struct CopyThrows {
39   CopyThrows() = default;
40   CopyThrows(CopyThrows const&) { throw 42; }
41   CopyThrows& operator=(CopyThrows const&) { throw 42; }
42 };
43 
44 struct MoveThrows {
45   static int alive;
46   MoveThrows() { ++alive; }
47   MoveThrows(MoveThrows const&) {++alive;}
48   MoveThrows(MoveThrows&&) {  throw 42; }
49   MoveThrows& operator=(MoveThrows const&) { return *this; }
50   MoveThrows& operator=(MoveThrows&&) { throw 42; }
51   ~MoveThrows() { --alive; }
52 };
53 
54 int MoveThrows::alive = 0;
55 
56 struct MakeEmptyT {
57   static int alive;
58   MakeEmptyT() { ++alive; }
59   MakeEmptyT(MakeEmptyT const&) {
60       ++alive;
61       // Don't throw from the copy constructor since variant's assignment
62       // operator performs a copy before committing to the assignment.
63   }
64   MakeEmptyT(MakeEmptyT &&) {
65       throw 42;
66   }
67   MakeEmptyT& operator=(MakeEmptyT const&) {
68       throw 42;
69   }
70   MakeEmptyT& operator=(MakeEmptyT&&) {
71       throw 42;
72   }
73    ~MakeEmptyT() { --alive; }
74 };
75 static_assert(std::is_swappable_v<MakeEmptyT>, ""); // required for test
76 
77 int MakeEmptyT::alive = 0;
78 
79 template <class Variant>
80 void makeEmpty(Variant& v) {
81     Variant v2(std::in_place_type<MakeEmptyT>);
82     try {
83         v = std::move(v2);
84         assert(false);
85     } catch (...) {
86         assert(v.valueless_by_exception());
87     }
88 }
89 #endif // TEST_HAS_NO_EXCEPTIONS
90 
91 enum CallType : unsigned {
92   CT_None,
93   CT_NonConst = 1,
94   CT_Const = 2,
95   CT_LValue = 4,
96   CT_RValue = 8
97 };
98 
99 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
100   return static_cast<CallType>(static_cast<unsigned>(LHS) |
101                                static_cast<unsigned>(RHS));
102 }
103 
104 struct ForwardingCallObject {
105 
106   template <class... Args>
107   ForwardingCallObject& operator()(Args&&...) & {
108     set_call<Args &&...>(CT_NonConst | CT_LValue);
109     return *this;
110   }
111 
112   template <class... Args>
113   const ForwardingCallObject& operator()(Args&&...) const & {
114     set_call<Args &&...>(CT_Const | CT_LValue);
115     return *this;
116   }
117 
118   template <class... Args>
119   ForwardingCallObject&& operator()(Args&&...) && {
120     set_call<Args &&...>(CT_NonConst | CT_RValue);
121     return std::move(*this);
122   }
123 
124   template <class... Args>
125   const ForwardingCallObject&& operator()(Args&&...) const && {
126     set_call<Args &&...>(CT_Const | CT_RValue);
127     return std::move(*this);
128   }
129 
130   template <class... Args> static void set_call(CallType type) {
131     assert(last_call_type == CT_None);
132     assert(last_call_args == nullptr);
133     last_call_type = type;
134     last_call_args = std::addressof(makeArgumentID<Args...>());
135   }
136 
137   template <class... Args> static bool check_call(CallType type) {
138     bool result = last_call_type == type && last_call_args &&
139                   *last_call_args == makeArgumentID<Args...>();
140     last_call_type = CT_None;
141     last_call_args = nullptr;
142     return result;
143   }
144 
145   // To check explicit return type for visit<R>
146   constexpr operator int() const
147   {
148     return 0;
149   }
150 
151   static CallType last_call_type;
152   static const TypeID *last_call_args;
153 };
154 
155 CallType ForwardingCallObject::last_call_type = CT_None;
156 const TypeID *ForwardingCallObject::last_call_args = nullptr;
157 
158 struct ReturnFirst {
159   template <class... Args> constexpr int operator()(int f, Args &&...) const {
160     return f;
161   }
162 };
163 
164 struct ReturnArity {
165   template <class... Args> constexpr int operator()(Args &&...) const {
166     return sizeof...(Args);
167   }
168 };
169 
170 #endif // SUPPORT_VARIANT_TEST_HELPERS_H
171