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