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
15using namespace llvm;
16
17namespace {
18
19TEST(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(p: 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
75TEST(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
106TEST(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
132TEST(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
182TEST(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
228TEST(UniqueFunctionTest, Const) {
229 // Can assign from const lambda.
230 unique_function<int(int) const> Plus2 = [X(std::make_unique<int>(args: 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.
266std::string returns(StringRef) { return "not a function"; }
267std::string returns(unique_function<double()> F) { return "number"; }
268std::string returns(unique_function<StringRef()> F) { return "string"; }
269
270TEST(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.
277class Incomplete;
278template <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.
283TEST(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
295Incomplete incompleteFunction();
296const Incomplete incompleteFunctionConst();
297
298// Check that we can assign a callable to a unique_function when the
299// callable return value is incomplete.
300TEST(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
309class Incomplete {};
310Incomplete incompleteFunction() { return {}; }
311const Incomplete incompleteFunctionConst() { return {}; }
312
313} // anonymous namespace
314

source code of llvm/unittests/ADT/FunctionExtrasTest.cpp