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 Fiselier int g(int) {return 0;}
594c46801fSEric Fiselier 
main(int,char **)602df59c50SJF Bastien int 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