14c46801fSEric Fiselier //===----------------------------------------------------------------------===// 24c46801fSEric Fiselier // 357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64c46801fSEric Fiselier // 74c46801fSEric Fiselier //===----------------------------------------------------------------------===// 84c46801fSEric Fiselier 9a21a6ed8SMartin Storsjö // FIXME: In MSVC mode, even "std::function<int(int)> f(aref);" causes 10a21a6ed8SMartin Storsjö // allocations. 1107c96a31SMartin Storsjö // XFAIL: target=x86_64-pc-windows-msvc && stdlib=libc++ 124f7fa06aSMartin Storsjö 134c46801fSEric Fiselier // <functional> 144c46801fSEric Fiselier 154c46801fSEric Fiselier // class function<R(ArgTypes...)> 164c46801fSEric Fiselier 174c46801fSEric Fiselier // function(const function& f); 18859bf407SMarshall Clow // function(function&& f); // noexcept in C++20 194c46801fSEric Fiselier 20b4fb705eSLouis Dionne // This test runs in C++03, but we have deprecated using std::function in C++03. 21*c475e31aSNikolas Klauser // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS -D_LIBCPP_ENABLE_CXX03_FUNCTION 22b4fb705eSLouis Dionne 234c46801fSEric Fiselier #include <functional> 244c46801fSEric Fiselier #include <memory> 254c46801fSEric Fiselier #include <cstdlib> 264c46801fSEric Fiselier #include <cassert> 274c46801fSEric Fiselier 284c46801fSEric Fiselier #include "test_macros.h" 29cc89063bSNico Weber #include "count_new.h" 304c46801fSEric Fiselier 314c46801fSEric Fiselier class A 324c46801fSEric Fiselier { 334c46801fSEric Fiselier int data_[10]; 344c46801fSEric Fiselier public: 354c46801fSEric Fiselier static int count; 364c46801fSEric Fiselier A()374c46801fSEric Fiselier A() 384c46801fSEric Fiselier { 394c46801fSEric Fiselier ++count; 404c46801fSEric Fiselier for (int i = 0; i < 10; ++i) 414c46801fSEric Fiselier data_[i] = i; 424c46801fSEric Fiselier } 434c46801fSEric Fiselier A(const A &)444c46801fSEric Fiselier A(const A&) {++count;} 454c46801fSEric Fiselier ~A()464c46801fSEric Fiselier ~A() {--count;} 474c46801fSEric Fiselier operator ()(int i) const484c46801fSEric Fiselier int operator()(int i) const 494c46801fSEric Fiselier { 504c46801fSEric Fiselier for (int j = 0; j < 10; ++j) 514c46801fSEric Fiselier i += data_[j]; 524c46801fSEric Fiselier return i; 534c46801fSEric Fiselier } 544c46801fSEric Fiselier }; 554c46801fSEric Fiselier 564c46801fSEric Fiselier int A::count = 0; 574c46801fSEric Fiselier g(int)584c46801fSEric Fiselierint g(int) {return 0;} 594c46801fSEric Fiselier main(int,char **)602df59c50SJF Bastienint main(int, char**) 614c46801fSEric Fiselier { 629c5d0ea6SDan Albert globalMemCounter.reset(); 634c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 644c46801fSEric Fiselier { 654c46801fSEric Fiselier std::function<int(int)> f = A(); 664c46801fSEric Fiselier assert(A::count == 1); 674c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(1)); 68bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>()); 69bb09ef95SLouis Dionne RTTI_ASSERT(f.target<int(*)(int)>() == 0); 704c46801fSEric Fiselier std::function<int(int)> f2 = f; 714c46801fSEric Fiselier assert(A::count == 2); 724c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(2)); 73bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<A>()); 74bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<int(*)(int)>() == 0); 754c46801fSEric Fiselier } 764c46801fSEric Fiselier assert(A::count == 0); 774c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 784c46801fSEric Fiselier { 794c46801fSEric Fiselier std::function<int(int)> f = g; 804c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 81bb09ef95SLouis Dionne RTTI_ASSERT(f.target<int(*)(int)>()); 82bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>() == 0); 834c46801fSEric Fiselier std::function<int(int)> f2 = f; 844c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 85bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<int(*)(int)>()); 86bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<A>() == 0); 874c46801fSEric Fiselier } 884c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 894c46801fSEric Fiselier { 904c46801fSEric Fiselier std::function<int(int)> f; 914c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 92bb09ef95SLouis Dionne RTTI_ASSERT(f.target<int(*)(int)>() == 0); 93bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>() == 0); 944c46801fSEric Fiselier std::function<int(int)> f2 = f; 954c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 96bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<int(*)(int)>() == 0); 97bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<A>() == 0); 984c46801fSEric Fiselier } 994c46801fSEric Fiselier { 1004c46801fSEric Fiselier std::function<int(int)> f; 1014c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 102bb09ef95SLouis Dionne RTTI_ASSERT(f.target<int(*)(int)>() == 0); 103bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>() == 0); 1044c46801fSEric Fiselier assert(!f); 1054c46801fSEric Fiselier std::function<long(int)> g = f; 1064c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 107bb09ef95SLouis Dionne RTTI_ASSERT(g.target<long(*)(int)>() == 0); 108bb09ef95SLouis Dionne RTTI_ASSERT(g.target<A>() == 0); 1094c46801fSEric Fiselier assert(!g); 1104c46801fSEric Fiselier } 1114c46801fSEric Fiselier #if TEST_STD_VER >= 11 1124c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 1134c46801fSEric Fiselier { // Test rvalue references 1144c46801fSEric Fiselier std::function<int(int)> f = A(); 1154c46801fSEric Fiselier assert(A::count == 1); 1164c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(1)); 117bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>()); 118bb09ef95SLouis Dionne RTTI_ASSERT(f.target<int(*)(int)>() == 0); 119859bf407SMarshall Clow LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); 120859bf407SMarshall Clow #if TEST_STD_VER > 17 121859bf407SMarshall Clow ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); 122859bf407SMarshall Clow #endif 1234c46801fSEric Fiselier std::function<int(int)> f2 = std::move(f); 1244c46801fSEric Fiselier assert(A::count == 1); 1254c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(1)); 126bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<A>()); 127bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<int(*)(int)>() == 0); 128bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>() == 0); 129bb09ef95SLouis Dionne RTTI_ASSERT(f.target<int(*)(int)>() == 0); 1304c46801fSEric Fiselier } 1314c46801fSEric Fiselier assert(globalMemCounter.checkOutstandingNewEq(0)); 1324c46801fSEric Fiselier { 1334c46801fSEric Fiselier // Test that moving a function constructed from a reference wrapper 1344c46801fSEric Fiselier // is done without allocating. 1354c46801fSEric Fiselier DisableAllocationGuard g; 1364c46801fSEric Fiselier using Ref = std::reference_wrapper<A>; 1374c46801fSEric Fiselier A a; 1384c46801fSEric Fiselier Ref aref(a); 1394c46801fSEric Fiselier std::function<int(int)> f(aref); 1404c46801fSEric Fiselier assert(A::count == 1); 141bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>() == nullptr); 142bb09ef95SLouis Dionne RTTI_ASSERT(f.target<Ref>()); 143859bf407SMarshall Clow LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); 144859bf407SMarshall Clow #if TEST_STD_VER > 17 145859bf407SMarshall Clow ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); 146859bf407SMarshall Clow #endif 1474c46801fSEric Fiselier std::function<int(int)> f2(std::move(f)); 1484c46801fSEric Fiselier assert(A::count == 1); 149bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<A>() == nullptr); 150bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<Ref>()); 151bb09ef95SLouis Dionne #if defined(_LIBCPP_VERSION) 152bb09ef95SLouis Dionne RTTI_ASSERT(f.target<Ref>()); // f is unchanged because the target is small 153bb09ef95SLouis Dionne #endif 1544c46801fSEric Fiselier } 1554c46801fSEric Fiselier { 1564c46801fSEric Fiselier // Test that moving a function constructed from a function pointer 1574c46801fSEric Fiselier // is done without allocating 1584c46801fSEric Fiselier DisableAllocationGuard guard; 1594c46801fSEric Fiselier using Ptr = int(*)(int); 1604c46801fSEric Fiselier Ptr p = g; 1614c46801fSEric Fiselier std::function<int(int)> f(p); 162bb09ef95SLouis Dionne RTTI_ASSERT(f.target<A>() == nullptr); 163bb09ef95SLouis Dionne RTTI_ASSERT(f.target<Ptr>()); 164859bf407SMarshall Clow LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); 165859bf407SMarshall Clow #if TEST_STD_VER > 17 166859bf407SMarshall Clow ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f))); 167859bf407SMarshall Clow #endif 1684c46801fSEric Fiselier std::function<int(int)> f2(std::move(f)); 169bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<A>() == nullptr); 170bb09ef95SLouis Dionne RTTI_ASSERT(f2.target<Ptr>()); 171bb09ef95SLouis Dionne #if defined(_LIBCPP_VERSION) 172bb09ef95SLouis Dionne RTTI_ASSERT(f.target<Ptr>()); // f is unchanged because the target is small 173bb09ef95SLouis Dionne #endif 1744c46801fSEric Fiselier } 1754c46801fSEric Fiselier #endif // TEST_STD_VER >= 11 1762df59c50SJF Bastien 1772df59c50SJF Bastien return 0; 1784c46801fSEric Fiselier } 179