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