xref: /llvm-project/llvm/unittests/ADT/FunctionExtrasTest.cpp (revision 52bfb2611f8d30fae3306c652af7ba5c7e88c147)
1 //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ADT/FunctionExtras.h"
10 #include "CountCopyAndMove.h"
11 #include "gtest/gtest.h"
12 
13 #include <memory>
14 #include <type_traits>
15 
16 using namespace llvm;
17 
18 namespace {
19 
20 TEST(UniqueFunctionTest, Basic) {
21   unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
22   EXPECT_EQ(Sum(1, 2), 3);
23 
24   unique_function<int(int, int)> Sum2 = std::move(Sum);
25   EXPECT_EQ(Sum2(1, 2), 3);
26 
27   unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
28   Sum2 = std::move(Sum3);
29   EXPECT_EQ(Sum2(1, 2), 3);
30 
31   Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
32   EXPECT_EQ(Sum2(1, 2), 3);
33 
34   // Explicit self-move test.
35   *&Sum2 = std::move(Sum2);
36   EXPECT_EQ(Sum2(1, 2), 3);
37 
38   Sum2 = unique_function<int(int, int)>();
39   EXPECT_FALSE(Sum2);
40 
41   // Make sure we can forward through l-value reference parameters.
42   unique_function<void(int &)> Inc = [](int &X) { ++X; };
43   int X = 42;
44   Inc(X);
45   EXPECT_EQ(X, 43);
46 
47   // Make sure we can forward through r-value reference parameters with
48   // move-only types.
49   unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
50       [](std::unique_ptr<int> &&Ptr) {
51         int V = *Ptr;
52         Ptr.reset();
53         return V;
54       };
55   std::unique_ptr<int> Ptr{new int(13)};
56   EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13);
57   EXPECT_FALSE((bool)Ptr);
58 
59   // Make sure we can pass a move-only temporary as opposed to a local variable.
60   EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
61 
62   // Make sure we can pass a move-only type by-value.
63   unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
64       [](std::unique_ptr<int> Ptr) {
65         int V = *Ptr;
66         Ptr.reset();
67         return V;
68       };
69   Ptr.reset(new int(13));
70   EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13);
71   EXPECT_FALSE((bool)Ptr);
72 
73   EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
74 }
75 
76 TEST(UniqueFunctionTest, Captures) {
77   long A = 1, B = 2, C = 3, D = 4, E = 5;
78 
79   unique_function<long()> Tmp;
80 
81   unique_function<long()> C1 = [A]() { return A; };
82   EXPECT_EQ(C1(), 1);
83   Tmp = std::move(C1);
84   EXPECT_EQ(Tmp(), 1);
85 
86   unique_function<long()> C2 = [A, B]() { return A + B; };
87   EXPECT_EQ(C2(), 3);
88   Tmp = std::move(C2);
89   EXPECT_EQ(Tmp(), 3);
90 
91   unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
92   EXPECT_EQ(C3(), 6);
93   Tmp = std::move(C3);
94   EXPECT_EQ(Tmp(), 6);
95 
96   unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
97   EXPECT_EQ(C4(), 10);
98   Tmp = std::move(C4);
99   EXPECT_EQ(Tmp(), 10);
100 
101   unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
102   EXPECT_EQ(C5(), 15);
103   Tmp = std::move(C5);
104   EXPECT_EQ(Tmp(), 15);
105 }
106 
107 TEST(UniqueFunctionTest, MoveOnly) {
108   struct SmallCallable {
109     std::unique_ptr<int> A{new int(1)};
110 
111     int operator()(int B) { return *A + B; }
112   };
113   unique_function<int(int)> Small = SmallCallable();
114   EXPECT_EQ(Small(2), 3);
115   unique_function<int(int)> Small2 = std::move(Small);
116   EXPECT_EQ(Small2(2), 3);
117 
118   struct LargeCallable {
119     std::unique_ptr<int> A{new int(1)};
120     std::unique_ptr<int> B{new int(2)};
121     std::unique_ptr<int> C{new int(3)};
122     std::unique_ptr<int> D{new int(4)};
123     std::unique_ptr<int> E{new int(5)};
124 
125     int operator()() { return *A + *B + *C + *D + *E; }
126   };
127   unique_function<int()> Large = LargeCallable();
128   EXPECT_EQ(Large(), 15);
129   unique_function<int()> Large2 = std::move(Large);
130   EXPECT_EQ(Large2(), 15);
131 }
132 
133 TEST(UniqueFunctionTest, CountForwardingCopies) {
134   struct CopyCounter {
135     int &CopyCount;
136 
137     CopyCounter(int &CopyCount) : CopyCount(CopyCount) {}
138     CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) {
139       ++CopyCount;
140     }
141   };
142 
143   unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
144   int CopyCount = 0;
145   ByValF(CopyCounter(CopyCount));
146   EXPECT_EQ(1, CopyCount);
147 
148   CopyCount = 0;
149   {
150     CopyCounter Counter{CopyCount};
151     ByValF(Counter);
152   }
153   EXPECT_EQ(2, CopyCount);
154 
155   // Check that we don't generate a copy at all when we can bind a reference all
156   // the way down, even if that reference could *in theory* allow copies.
157   unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
158   };
159   CopyCount = 0;
160   ByRefF(CopyCounter(CopyCount));
161   EXPECT_EQ(0, CopyCount);
162 
163   CopyCount = 0;
164   {
165     CopyCounter Counter{CopyCount};
166     ByRefF(Counter);
167   }
168   EXPECT_EQ(0, CopyCount);
169 
170   // If we use a reference, we can make a stronger guarantee that *no* copy
171   // occurs.
172   struct Uncopyable {
173     Uncopyable() = default;
174     Uncopyable(const Uncopyable &) = delete;
175   };
176   unique_function<void(const Uncopyable &)> UncopyableF =
177       [](const Uncopyable &) {};
178   UncopyableF(Uncopyable());
179   Uncopyable X;
180   UncopyableF(X);
181 }
182 
183 TEST(UniqueFunctionTest, CountForwardingMoves) {
184   struct MoveCounter {
185     int &MoveCount;
186 
187     MoveCounter(int &MoveCount) : MoveCount(MoveCount) {}
188     MoveCounter(MoveCounter &&Arg) : MoveCount(Arg.MoveCount) { ++MoveCount; }
189   };
190 
191   unique_function<void(MoveCounter)> ByValF = [](MoveCounter) {};
192   int MoveCount = 0;
193   ByValF(MoveCounter(MoveCount));
194   EXPECT_EQ(1, MoveCount);
195 
196   MoveCount = 0;
197   {
198     MoveCounter Counter{MoveCount};
199     ByValF(std::move(Counter));
200   }
201   EXPECT_EQ(2, MoveCount);
202 
203   // Check that when we use an r-value reference we get no spurious copies.
204   unique_function<void(MoveCounter &&)> ByRefF = [](MoveCounter &&) {};
205   MoveCount = 0;
206   ByRefF(MoveCounter(MoveCount));
207   EXPECT_EQ(0, MoveCount);
208 
209   MoveCount = 0;
210   {
211     MoveCounter Counter{MoveCount};
212     ByRefF(std::move(Counter));
213   }
214   EXPECT_EQ(0, MoveCount);
215 
216   // If we use an r-value reference we can in fact make a stronger guarantee
217   // with an unmovable type.
218   struct Unmovable {
219     Unmovable() = default;
220     Unmovable(Unmovable &&) = delete;
221   };
222   unique_function<void(const Unmovable &)> UnmovableF = [](const Unmovable &) {
223   };
224   UnmovableF(Unmovable());
225   Unmovable X;
226   UnmovableF(X);
227 }
228 
229 TEST(UniqueFunctionTest, Const) {
230   // Can assign from const lambda.
231   unique_function<int(int) const> Plus2 = [X(std::make_unique<int>(2))](int Y) {
232     return *X + Y;
233   };
234   EXPECT_EQ(5, Plus2(3));
235 
236   // Can call through a const ref.
237   const auto &Plus2Ref = Plus2;
238   EXPECT_EQ(5, Plus2Ref(3));
239 
240   // Can move-construct and assign.
241   unique_function<int(int) const> Plus2A = std::move(Plus2);
242   EXPECT_EQ(5, Plus2A(3));
243   unique_function<int(int) const> Plus2B;
244   Plus2B = std::move(Plus2A);
245   EXPECT_EQ(5, Plus2B(3));
246 
247   // Can convert to non-const function type, but not back.
248   unique_function<int(int)> Plus2C = std::move(Plus2B);
249   EXPECT_EQ(5, Plus2C(3));
250 
251   // Overloaded call operator correctly resolved.
252   struct ChooseCorrectOverload {
253     StringRef operator()() { return "non-const"; }
254     StringRef operator()() const { return "const"; }
255   };
256   unique_function<StringRef()> ChooseMutable = ChooseCorrectOverload();
257   ChooseCorrectOverload A;
258   EXPECT_EQ("non-const", ChooseMutable());
259   EXPECT_EQ("non-const", A());
260   unique_function<StringRef() const> ChooseConst = ChooseCorrectOverload();
261   const ChooseCorrectOverload &X = A;
262   EXPECT_EQ("const", ChooseConst());
263   EXPECT_EQ("const", X());
264 }
265 
266 // Test that overloads on unique_functions are resolved as expected.
267 std::string returns(StringRef) { return "not a function"; }
268 std::string returns(unique_function<double()> F) { return "number"; }
269 std::string returns(unique_function<StringRef()> F) { return "string"; }
270 
271 TEST(UniqueFunctionTest, SFINAE) {
272   EXPECT_EQ("not a function", returns("boo!"));
273   EXPECT_EQ("number", returns([] { return 42; }));
274   EXPECT_EQ("string", returns([] { return "hello"; }));
275 }
276 
277 // A forward declared type, and a templated type.
278 class Incomplete;
279 template <typename T> class Templated { T A; };
280 
281 // Check that we can define unique_function that have references to
282 // incomplete types, even if those types are templated over an
283 // incomplete type.
284 TEST(UniqueFunctionTest, IncompleteTypes) {
285   unique_function<void(Templated<Incomplete> &&)>
286       IncompleteArgumentRValueReference;
287   unique_function<void(Templated<Incomplete> &)>
288       IncompleteArgumentLValueReference;
289   unique_function<void(Templated<Incomplete> *)> IncompleteArgumentPointer;
290   unique_function<Templated<Incomplete> &()> IncompleteResultLValueReference;
291   unique_function<Templated<Incomplete> && ()> IncompleteResultRValueReference2;
292   unique_function<Templated<Incomplete> *()> IncompleteResultPointer;
293 }
294 
295 // Incomplete function returning an incomplete type
296 Incomplete incompleteFunction();
297 const Incomplete incompleteFunctionConst();
298 
299 // Check that we can assign a callable to a unique_function when the
300 // callable return value is incomplete.
301 TEST(UniqueFunctionTest, IncompleteCallableType) {
302   unique_function<Incomplete()> IncompleteReturnInCallable{incompleteFunction};
303   unique_function<const Incomplete()> IncompleteReturnInCallableConst{
304       incompleteFunctionConst};
305   unique_function<const Incomplete()> IncompleteReturnInCallableConstConversion{
306       incompleteFunction};
307 }
308 
309 // Define the incomplete function
310 class Incomplete {};
311 Incomplete incompleteFunction() { return {}; }
312 const Incomplete incompleteFunctionConst() { return {}; }
313 
314 // Check that we can store a pointer-sized payload inline in the unique_function.
315 TEST(UniqueFunctionTest, InlineStorageWorks) {
316   // We do assume a couple of implementation details of the unique_function here:
317   //  - It can store certain small-enough payload inline
318   //  - Inline storage size is at least >= sizeof(void*)
319   void *ptr = nullptr;
320   unique_function<void(void *)> UniqueFunctionWithInlineStorage{
321       [ptr](void *self) {
322         auto mid = reinterpret_cast<uintptr_t>(&ptr);
323         auto beg = reinterpret_cast<uintptr_t>(self);
324         auto end = reinterpret_cast<uintptr_t>(self) +
325                    sizeof(unique_function<void(void *)>);
326         // Make sure the address of the captured pointer lies somewhere within
327         // the unique_function object.
328         EXPECT_TRUE(mid >= beg && mid < end);
329       }};
330   UniqueFunctionWithInlineStorage(&UniqueFunctionWithInlineStorage);
331 }
332 
333 // Check that the moved-from captured state is properly destroyed during
334 // move construction/assignment.
335 TEST(UniqueFunctionTest, MovedFromStateIsDestroyedCorrectly) {
336   CountCopyAndMove::ResetCounts();
337   {
338     unique_function<void()> CapturingFunction{
339         [Counter = CountCopyAndMove{}] {}};
340     unique_function<void()> CapturingFunctionMoved{
341         std::move(CapturingFunction)};
342   }
343   EXPECT_EQ(CountCopyAndMove::TotalConstructions(),
344             CountCopyAndMove::Destructions);
345 }
346 
347 } // anonymous namespace
348