1aa60b3fdSChandler Carruth //===- FunctionExtrasTest.cpp - Unit tests for function type erasure ------===//
2aa60b3fdSChandler Carruth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6aa60b3fdSChandler Carruth //
7aa60b3fdSChandler Carruth //===----------------------------------------------------------------------===//
8aa60b3fdSChandler Carruth 
9aa60b3fdSChandler Carruth #include "llvm/ADT/FunctionExtras.h"
10aa60b3fdSChandler Carruth #include "gtest/gtest.h"
11aa60b3fdSChandler Carruth 
12aa60b3fdSChandler Carruth #include <memory>
138c288db2SSam McCall #include <type_traits>
14aa60b3fdSChandler Carruth 
15aa60b3fdSChandler Carruth using namespace llvm;
16aa60b3fdSChandler Carruth 
17aa60b3fdSChandler Carruth namespace {
18aa60b3fdSChandler Carruth 
TEST(UniqueFunctionTest,Basic)19aa60b3fdSChandler Carruth TEST(UniqueFunctionTest, Basic) {
20aa60b3fdSChandler Carruth   unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
21aa60b3fdSChandler Carruth   EXPECT_EQ(Sum(1, 2), 3);
22aa60b3fdSChandler Carruth 
23aa60b3fdSChandler Carruth   unique_function<int(int, int)> Sum2 = std::move(Sum);
24aa60b3fdSChandler Carruth   EXPECT_EQ(Sum2(1, 2), 3);
25aa60b3fdSChandler Carruth 
26aa60b3fdSChandler Carruth   unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
27aa60b3fdSChandler Carruth   Sum2 = std::move(Sum3);
28aa60b3fdSChandler Carruth   EXPECT_EQ(Sum2(1, 2), 3);
29aa60b3fdSChandler Carruth 
30aa60b3fdSChandler Carruth   Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
31aa60b3fdSChandler Carruth   EXPECT_EQ(Sum2(1, 2), 3);
32aa60b3fdSChandler Carruth 
33aa60b3fdSChandler Carruth   // Explicit self-move test.
34aa60b3fdSChandler Carruth   *&Sum2 = std::move(Sum2);
35aa60b3fdSChandler Carruth   EXPECT_EQ(Sum2(1, 2), 3);
36aa60b3fdSChandler Carruth 
37aa60b3fdSChandler Carruth   Sum2 = unique_function<int(int, int)>();
38aa60b3fdSChandler Carruth   EXPECT_FALSE(Sum2);
39aa60b3fdSChandler Carruth 
40aa60b3fdSChandler Carruth   // Make sure we can forward through l-value reference parameters.
41aa60b3fdSChandler Carruth   unique_function<void(int &)> Inc = [](int &X) { ++X; };
42aa60b3fdSChandler Carruth   int X = 42;
43aa60b3fdSChandler Carruth   Inc(X);
44aa60b3fdSChandler Carruth   EXPECT_EQ(X, 43);
45aa60b3fdSChandler Carruth 
46aa60b3fdSChandler Carruth   // Make sure we can forward through r-value reference parameters with
47aa60b3fdSChandler Carruth   // move-only types.
48aa60b3fdSChandler Carruth   unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
49aa60b3fdSChandler Carruth       [](std::unique_ptr<int> &&Ptr) {
50aa60b3fdSChandler Carruth         int V = *Ptr;
51aa60b3fdSChandler Carruth         Ptr.reset();
52aa60b3fdSChandler Carruth         return V;
53aa60b3fdSChandler Carruth       };
54aa60b3fdSChandler Carruth   std::unique_ptr<int> Ptr{new int(13)};
55aa60b3fdSChandler Carruth   EXPECT_EQ(ReadAndDeallocByRef(std::move(Ptr)), 13);
56aa60b3fdSChandler Carruth   EXPECT_FALSE((bool)Ptr);
57aa60b3fdSChandler Carruth 
58aa60b3fdSChandler Carruth   // Make sure we can pass a move-only temporary as opposed to a local variable.
59aa60b3fdSChandler Carruth   EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
60aa60b3fdSChandler Carruth 
61aa60b3fdSChandler Carruth   // Make sure we can pass a move-only type by-value.
62aa60b3fdSChandler Carruth   unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
63aa60b3fdSChandler Carruth       [](std::unique_ptr<int> Ptr) {
64aa60b3fdSChandler Carruth         int V = *Ptr;
65aa60b3fdSChandler Carruth         Ptr.reset();
66aa60b3fdSChandler Carruth         return V;
67aa60b3fdSChandler Carruth       };
68aa60b3fdSChandler Carruth   Ptr.reset(new int(13));
69aa60b3fdSChandler Carruth   EXPECT_EQ(ReadAndDeallocByVal(std::move(Ptr)), 13);
70aa60b3fdSChandler Carruth   EXPECT_FALSE((bool)Ptr);
71aa60b3fdSChandler Carruth 
72aa60b3fdSChandler Carruth   EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
73aa60b3fdSChandler Carruth }
74aa60b3fdSChandler Carruth 
TEST(UniqueFunctionTest,Captures)75aa60b3fdSChandler Carruth TEST(UniqueFunctionTest, Captures) {
76aa60b3fdSChandler Carruth   long A = 1, B = 2, C = 3, D = 4, E = 5;
77aa60b3fdSChandler Carruth 
78aa60b3fdSChandler Carruth   unique_function<long()> Tmp;
79aa60b3fdSChandler Carruth 
80aa60b3fdSChandler Carruth   unique_function<long()> C1 = [A]() { return A; };
81aa60b3fdSChandler Carruth   EXPECT_EQ(C1(), 1);
82aa60b3fdSChandler Carruth   Tmp = std::move(C1);
83aa60b3fdSChandler Carruth   EXPECT_EQ(Tmp(), 1);
84aa60b3fdSChandler Carruth 
85aa60b3fdSChandler Carruth   unique_function<long()> C2 = [A, B]() { return A + B; };
86aa60b3fdSChandler Carruth   EXPECT_EQ(C2(), 3);
87aa60b3fdSChandler Carruth   Tmp = std::move(C2);
88aa60b3fdSChandler Carruth   EXPECT_EQ(Tmp(), 3);
89aa60b3fdSChandler Carruth 
90aa60b3fdSChandler Carruth   unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
91aa60b3fdSChandler Carruth   EXPECT_EQ(C3(), 6);
92aa60b3fdSChandler Carruth   Tmp = std::move(C3);
93aa60b3fdSChandler Carruth   EXPECT_EQ(Tmp(), 6);
94aa60b3fdSChandler Carruth 
95aa60b3fdSChandler Carruth   unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
96aa60b3fdSChandler Carruth   EXPECT_EQ(C4(), 10);
97aa60b3fdSChandler Carruth   Tmp = std::move(C4);
98aa60b3fdSChandler Carruth   EXPECT_EQ(Tmp(), 10);
99aa60b3fdSChandler Carruth 
100aa60b3fdSChandler Carruth   unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
101aa60b3fdSChandler Carruth   EXPECT_EQ(C5(), 15);
102aa60b3fdSChandler Carruth   Tmp = std::move(C5);
103aa60b3fdSChandler Carruth   EXPECT_EQ(Tmp(), 15);
104aa60b3fdSChandler Carruth }
105aa60b3fdSChandler Carruth 
TEST(UniqueFunctionTest,MoveOnly)106aa60b3fdSChandler Carruth TEST(UniqueFunctionTest, MoveOnly) {
107aa60b3fdSChandler Carruth   struct SmallCallable {
108aa60b3fdSChandler Carruth     std::unique_ptr<int> A{new int(1)};
109aa60b3fdSChandler Carruth 
110aa60b3fdSChandler Carruth     int operator()(int B) { return *A + B; }
111aa60b3fdSChandler Carruth   };
112aa60b3fdSChandler Carruth   unique_function<int(int)> Small = SmallCallable();
113aa60b3fdSChandler Carruth   EXPECT_EQ(Small(2), 3);
114aa60b3fdSChandler Carruth   unique_function<int(int)> Small2 = std::move(Small);
115aa60b3fdSChandler Carruth   EXPECT_EQ(Small2(2), 3);
116aa60b3fdSChandler Carruth 
117aa60b3fdSChandler Carruth   struct LargeCallable {
118aa60b3fdSChandler Carruth     std::unique_ptr<int> A{new int(1)};
119aa60b3fdSChandler Carruth     std::unique_ptr<int> B{new int(2)};
120aa60b3fdSChandler Carruth     std::unique_ptr<int> C{new int(3)};
121aa60b3fdSChandler Carruth     std::unique_ptr<int> D{new int(4)};
122aa60b3fdSChandler Carruth     std::unique_ptr<int> E{new int(5)};
123aa60b3fdSChandler Carruth 
124aa60b3fdSChandler Carruth     int operator()() { return *A + *B + *C + *D + *E; }
125aa60b3fdSChandler Carruth   };
126aa60b3fdSChandler Carruth   unique_function<int()> Large = LargeCallable();
127aa60b3fdSChandler Carruth   EXPECT_EQ(Large(), 15);
128aa60b3fdSChandler Carruth   unique_function<int()> Large2 = std::move(Large);
129aa60b3fdSChandler Carruth   EXPECT_EQ(Large2(), 15);
130aa60b3fdSChandler Carruth }
131aa60b3fdSChandler Carruth 
TEST(UniqueFunctionTest,CountForwardingCopies)132aa60b3fdSChandler Carruth TEST(UniqueFunctionTest, CountForwardingCopies) {
133aa60b3fdSChandler Carruth   struct CopyCounter {
134aa60b3fdSChandler Carruth     int &CopyCount;
135aa60b3fdSChandler Carruth 
136aa60b3fdSChandler Carruth     CopyCounter(int &CopyCount) : CopyCount(CopyCount) {}
137aa60b3fdSChandler Carruth     CopyCounter(const CopyCounter &Arg) : CopyCount(Arg.CopyCount) {
138aa60b3fdSChandler Carruth       ++CopyCount;
139aa60b3fdSChandler Carruth     }
140aa60b3fdSChandler Carruth   };
141aa60b3fdSChandler Carruth 
142aa60b3fdSChandler Carruth   unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
143aa60b3fdSChandler Carruth   int CopyCount = 0;
144aa60b3fdSChandler Carruth   ByValF(CopyCounter(CopyCount));
145aa60b3fdSChandler Carruth   EXPECT_EQ(1, CopyCount);
146aa60b3fdSChandler Carruth 
147aa60b3fdSChandler Carruth   CopyCount = 0;
148aa60b3fdSChandler Carruth   {
149aa60b3fdSChandler Carruth     CopyCounter Counter{CopyCount};
150aa60b3fdSChandler Carruth     ByValF(Counter);
151aa60b3fdSChandler Carruth   }
152aa60b3fdSChandler Carruth   EXPECT_EQ(2, CopyCount);
153aa60b3fdSChandler Carruth 
154aa60b3fdSChandler Carruth   // Check that we don't generate a copy at all when we can bind a reference all
155aa60b3fdSChandler Carruth   // the way down, even if that reference could *in theory* allow copies.
156aa60b3fdSChandler Carruth   unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
157aa60b3fdSChandler Carruth   };
158aa60b3fdSChandler Carruth   CopyCount = 0;
159aa60b3fdSChandler Carruth   ByRefF(CopyCounter(CopyCount));
160aa60b3fdSChandler Carruth   EXPECT_EQ(0, CopyCount);
161aa60b3fdSChandler Carruth 
162aa60b3fdSChandler Carruth   CopyCount = 0;
163aa60b3fdSChandler Carruth   {
164aa60b3fdSChandler Carruth     CopyCounter Counter{CopyCount};
165aa60b3fdSChandler Carruth     ByRefF(Counter);
166aa60b3fdSChandler Carruth   }
167aa60b3fdSChandler Carruth   EXPECT_EQ(0, CopyCount);
168aa60b3fdSChandler Carruth 
169aa60b3fdSChandler Carruth   // If we use a reference, we can make a stronger guarantee that *no* copy
170aa60b3fdSChandler Carruth   // occurs.
171aa60b3fdSChandler Carruth   struct Uncopyable {
172aa60b3fdSChandler Carruth     Uncopyable() = default;
173aa60b3fdSChandler Carruth     Uncopyable(const Uncopyable &) = delete;
174aa60b3fdSChandler Carruth   };
175aa60b3fdSChandler Carruth   unique_function<void(const Uncopyable &)> UncopyableF =
176aa60b3fdSChandler Carruth       [](const Uncopyable &) {};
177aa60b3fdSChandler Carruth   UncopyableF(Uncopyable());
178aa60b3fdSChandler Carruth   Uncopyable X;
179aa60b3fdSChandler Carruth   UncopyableF(X);
180aa60b3fdSChandler Carruth }
181aa60b3fdSChandler Carruth 
TEST(UniqueFunctionTest,CountForwardingMoves)182aa60b3fdSChandler Carruth TEST(UniqueFunctionTest, CountForwardingMoves) {
183aa60b3fdSChandler Carruth   struct MoveCounter {
184aa60b3fdSChandler Carruth     int &MoveCount;
185aa60b3fdSChandler Carruth 
186aa60b3fdSChandler Carruth     MoveCounter(int &MoveCount) : MoveCount(MoveCount) {}
187aa60b3fdSChandler Carruth     MoveCounter(MoveCounter &&Arg) : MoveCount(Arg.MoveCount) { ++MoveCount; }
188aa60b3fdSChandler Carruth   };
189aa60b3fdSChandler Carruth 
190aa60b3fdSChandler Carruth   unique_function<void(MoveCounter)> ByValF = [](MoveCounter) {};
191aa60b3fdSChandler Carruth   int MoveCount = 0;
192aa60b3fdSChandler Carruth   ByValF(MoveCounter(MoveCount));
193aa60b3fdSChandler Carruth   EXPECT_EQ(1, MoveCount);
194aa60b3fdSChandler Carruth 
195aa60b3fdSChandler Carruth   MoveCount = 0;
196aa60b3fdSChandler Carruth   {
197aa60b3fdSChandler Carruth     MoveCounter Counter{MoveCount};
198aa60b3fdSChandler Carruth     ByValF(std::move(Counter));
199aa60b3fdSChandler Carruth   }
200aa60b3fdSChandler Carruth   EXPECT_EQ(2, MoveCount);
201aa60b3fdSChandler Carruth 
202aa60b3fdSChandler Carruth   // Check that when we use an r-value reference we get no spurious copies.
203aa60b3fdSChandler Carruth   unique_function<void(MoveCounter &&)> ByRefF = [](MoveCounter &&) {};
204aa60b3fdSChandler Carruth   MoveCount = 0;
205aa60b3fdSChandler Carruth   ByRefF(MoveCounter(MoveCount));
206aa60b3fdSChandler Carruth   EXPECT_EQ(0, MoveCount);
207aa60b3fdSChandler Carruth 
208aa60b3fdSChandler Carruth   MoveCount = 0;
209aa60b3fdSChandler Carruth   {
210aa60b3fdSChandler Carruth     MoveCounter Counter{MoveCount};
211aa60b3fdSChandler Carruth     ByRefF(std::move(Counter));
212aa60b3fdSChandler Carruth   }
213aa60b3fdSChandler Carruth   EXPECT_EQ(0, MoveCount);
214aa60b3fdSChandler Carruth 
215aa60b3fdSChandler Carruth   // If we use an r-value reference we can in fact make a stronger guarantee
216aa60b3fdSChandler Carruth   // with an unmovable type.
217aa60b3fdSChandler Carruth   struct Unmovable {
218aa60b3fdSChandler Carruth     Unmovable() = default;
219aa60b3fdSChandler Carruth     Unmovable(Unmovable &&) = delete;
220aa60b3fdSChandler Carruth   };
221aa60b3fdSChandler Carruth   unique_function<void(const Unmovable &)> UnmovableF = [](const Unmovable &) {
222aa60b3fdSChandler Carruth   };
223aa60b3fdSChandler Carruth   UnmovableF(Unmovable());
224aa60b3fdSChandler Carruth   Unmovable X;
225aa60b3fdSChandler Carruth   UnmovableF(X);
226aa60b3fdSChandler Carruth }
227aa60b3fdSChandler Carruth 
TEST(UniqueFunctionTest,Const)2288c288db2SSam McCall TEST(UniqueFunctionTest, Const) {
2298c288db2SSam McCall   // Can assign from const lambda.
2308c288db2SSam McCall   unique_function<int(int) const> Plus2 = [X(std::make_unique<int>(2))](int Y) {
2318c288db2SSam McCall     return *X + Y;
2328c288db2SSam McCall   };
2338c288db2SSam McCall   EXPECT_EQ(5, Plus2(3));
2348c288db2SSam McCall 
2358c288db2SSam McCall   // Can call through a const ref.
2368c288db2SSam McCall   const auto &Plus2Ref = Plus2;
2378c288db2SSam McCall   EXPECT_EQ(5, Plus2Ref(3));
2388c288db2SSam McCall 
2398c288db2SSam McCall   // Can move-construct and assign.
2408c288db2SSam McCall   unique_function<int(int) const> Plus2A = std::move(Plus2);
2418c288db2SSam McCall   EXPECT_EQ(5, Plus2A(3));
2428c288db2SSam McCall   unique_function<int(int) const> Plus2B;
2438c288db2SSam McCall   Plus2B = std::move(Plus2A);
2448c288db2SSam McCall   EXPECT_EQ(5, Plus2B(3));
2458c288db2SSam McCall 
2468c288db2SSam McCall   // Can convert to non-const function type, but not back.
2478c288db2SSam McCall   unique_function<int(int)> Plus2C = std::move(Plus2B);
2488c288db2SSam McCall   EXPECT_EQ(5, Plus2C(3));
2498c288db2SSam McCall 
2508c288db2SSam McCall   // Overloaded call operator correctly resolved.
2518c288db2SSam McCall   struct ChooseCorrectOverload {
2528c288db2SSam McCall     StringRef operator()() { return "non-const"; }
2538c288db2SSam McCall     StringRef operator()() const { return "const"; }
2548c288db2SSam McCall   };
2558c288db2SSam McCall   unique_function<StringRef()> ChooseMutable = ChooseCorrectOverload();
2568c288db2SSam McCall   ChooseCorrectOverload A;
2578c288db2SSam McCall   EXPECT_EQ("non-const", ChooseMutable());
2588c288db2SSam McCall   EXPECT_EQ("non-const", A());
2598c288db2SSam McCall   unique_function<StringRef() const> ChooseConst = ChooseCorrectOverload();
2608c288db2SSam McCall   const ChooseCorrectOverload &X = A;
2618c288db2SSam McCall   EXPECT_EQ("const", ChooseConst());
2628c288db2SSam McCall   EXPECT_EQ("const", X());
2638c288db2SSam McCall }
2648c288db2SSam McCall 
2659ebc837fSSam McCall // Test that overloads on unique_functions are resolved as expected.
returns(StringRef)2669ebc837fSSam McCall std::string returns(StringRef) { return "not a function"; }
returns(unique_function<double ()> F)2679ebc837fSSam McCall std::string returns(unique_function<double()> F) { return "number"; }
returns(unique_function<StringRef ()> F)2689ebc837fSSam McCall std::string returns(unique_function<StringRef()> F) { return "string"; }
2699ebc837fSSam McCall 
TEST(UniqueFunctionTest,SFINAE)2709ebc837fSSam McCall TEST(UniqueFunctionTest, SFINAE) {
2719ebc837fSSam McCall   EXPECT_EQ("not a function", returns("boo!"));
2729ebc837fSSam McCall   EXPECT_EQ("number", returns([] { return 42; }));
2739ebc837fSSam McCall   EXPECT_EQ("string", returns([] { return "hello"; }));
2749ebc837fSSam McCall }
2759ebc837fSSam McCall 
276e3eaff10SYevgeny Rouban // A forward declared type, and a templated type.
277e3eaff10SYevgeny Rouban class Incomplete;
278e3eaff10SYevgeny Rouban template <typename T> class Templated { T A; };
279e3eaff10SYevgeny Rouban 
280e3eaff10SYevgeny Rouban // Check that we can define unique_function that have references to
281e3eaff10SYevgeny Rouban // incomplete types, even if those types are templated over an
282e3eaff10SYevgeny Rouban // incomplete type.
TEST(UniqueFunctionTest,IncompleteTypes)283e3eaff10SYevgeny Rouban TEST(UniqueFunctionTest, IncompleteTypes) {
284e3eaff10SYevgeny Rouban   unique_function<void(Templated<Incomplete> &&)>
285e3eaff10SYevgeny Rouban       IncompleteArgumentRValueReference;
286e3eaff10SYevgeny Rouban   unique_function<void(Templated<Incomplete> &)>
287e3eaff10SYevgeny Rouban       IncompleteArgumentLValueReference;
288e3eaff10SYevgeny Rouban   unique_function<void(Templated<Incomplete> *)> IncompleteArgumentPointer;
289e3eaff10SYevgeny Rouban   unique_function<Templated<Incomplete> &()> IncompleteResultLValueReference;
290e3eaff10SYevgeny Rouban   unique_function<Templated<Incomplete> && ()> IncompleteResultRValueReference2;
291e3eaff10SYevgeny Rouban   unique_function<Templated<Incomplete> *()> IncompleteResultPointer;
292e3eaff10SYevgeny Rouban }
293e3eaff10SYevgeny Rouban 
294*b39f6a79SFehr Mathieu // Incomplete function returning an incomplete type
295*b39f6a79SFehr Mathieu Incomplete incompleteFunction();
296*b39f6a79SFehr Mathieu const Incomplete incompleteFunctionConst();
297*b39f6a79SFehr Mathieu 
298*b39f6a79SFehr Mathieu // Check that we can assign a callable to a unique_function when the
299*b39f6a79SFehr Mathieu // callable return value is incomplete.
TEST(UniqueFunctionTest,IncompleteCallableType)300*b39f6a79SFehr Mathieu TEST(UniqueFunctionTest, IncompleteCallableType) {
301*b39f6a79SFehr Mathieu   unique_function<Incomplete()> IncompleteReturnInCallable{incompleteFunction};
302*b39f6a79SFehr Mathieu   unique_function<const Incomplete()> IncompleteReturnInCallableConst{
303*b39f6a79SFehr Mathieu       incompleteFunctionConst};
304*b39f6a79SFehr Mathieu   unique_function<const Incomplete()> IncompleteReturnInCallableConstConversion{
305*b39f6a79SFehr Mathieu       incompleteFunction};
306*b39f6a79SFehr Mathieu }
307*b39f6a79SFehr Mathieu 
308*b39f6a79SFehr Mathieu // Define the incomplete function
309*b39f6a79SFehr Mathieu class Incomplete {};
incompleteFunction()310*b39f6a79SFehr Mathieu Incomplete incompleteFunction() { return {}; }
incompleteFunctionConst()311*b39f6a79SFehr Mathieu const Incomplete incompleteFunctionConst() { return {}; }
312*b39f6a79SFehr Mathieu 
313aa60b3fdSChandler Carruth } // anonymous namespace
314