1 //===----------------------------------------------------------------------===//
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 // std::function support for the "blocks" extension
10 
11 // UNSUPPORTED: c++03
12 
13 // This test requires the Blocks runtime, which is (only?) available
14 // on Darwin out-of-the-box.
15 // REQUIRES: has-fblocks && darwin
16 
17 // RUN: %{build} -fblocks
18 // RUN: %{run}
19 
20 #include <functional>
21 #include <cstdlib>
22 #include <cassert>
23 
24 #include <Block.h>
25 
26 #include "test_macros.h"
27 #include "count_new.h"
28 
29 
30 struct A {
31   static int count;
32   int id_;
AA33   explicit A(int id) { ++count; id_ = id; }
AA34   A(const A &a) { id_ = a.id_; ++count; }
~AA35   ~A() { id_ = -1; --count; }
operator ()A36   int operator()() const { return -1; }
operator ()A37   int operator()(int i) const { return i; }
operator ()A38   int operator()(int, int) const { return -2; }
operator ()A39   int operator()(int, int, int) const { return -3; }
idA40   int id() const { return id_; }
41 };
42 
43 int A::count = 0;
44 
g(int)45 int g(int) { return 0; }
46 
main(int,char **)47 int main(int, char**)
48 {
49     // swap
50     {
51         std::function<int(int)> f1 = g;
52         std::function<int(int)> f2 = ^(int x) { return x + 1; };
53         assert(globalMemCounter.checkOutstandingNewEq(0));
54         RTTI_ASSERT(*f1.target<int(*)(int)>() == g);
55         RTTI_ASSERT(*f2.target<int(^)(int)>() != 0);
56         swap(f1, f2);
57         assert(globalMemCounter.checkOutstandingNewEq(0));
58         RTTI_ASSERT(*f1.target<int(^)(int)>() != 0);
59         RTTI_ASSERT(*f2.target<int(*)(int)>() == g);
60     }
61 
62     // operator bool
63     {
64         std::function<int(int)> f;
65         assert(!f);
66         f = ^(int x) { return x+1; };
67         assert(f);
68     }
69 
70     // operator()
71     {
72         std::function<int ()> r1(^{ return 4; });
73         assert(r1() == 4);
74     }
75     {
76         __block bool called = false;
77         std::function<void ()> r1(^{ called = true; });
78         r1();
79         assert(called);
80     }
81     {
82         __block int param = 0;
83         std::function<void (int)> r1(^(int x){ param = x; });
84         r1(4);
85         assert(param == 4);
86     }
87     {
88         std::function<int (int)> r1(^(int x){ return x + 4; });
89         assert(r1(3) == 7);
90     }
91     {
92         __block int param1 = 0;
93         __block int param2 = 0;
94         std::function<void (int, int)> r1(^(int x, int y){ param1 = x; param2 = y; });
95         r1(3, 4);
96         assert(param1 == 3);
97         assert(param2 == 4);
98     }
99     {
100         std::function<int (int, int)> r1(^(int x, int y){ return x + y; });
101         assert(r1(3, 4) == 7);
102     }
103 
104     // swap
105     {
106         std::function<int(int)> f1 = A(999);
107         std::function<int(int)> f2 = ^(int x) { return x + 1; };
108         assert(A::count == 1);
109         assert(globalMemCounter.checkOutstandingNewEq(1));
110         RTTI_ASSERT(f1.target<A>()->id() == 999);
111         RTTI_ASSERT((*f2.target<int(^)(int)>())(13) == 14);
112         f1.swap(f2);
113         assert(A::count == 1);
114         assert(globalMemCounter.checkOutstandingNewEq(1));
115         RTTI_ASSERT((*f1.target<int(^)(int)>())(13) == 14);
116         RTTI_ASSERT(f2.target<A>()->id() == 999);
117     }
118     assert(globalMemCounter.checkOutstandingNewEq(0));
119     assert(A::count == 0);
120 
121     // operator== and operator!=
122     {
123         std::function<int(int)> f;
124         assert(f == nullptr);
125         assert(nullptr == f);
126         f = ^(int x) { return x + 1; };
127         assert(f != nullptr);
128         assert(nullptr != f);
129     }
130 
131     // target
132     {
133         int (^block)(int) = Block_copy(^(int x) { return x + 1; });
134         std::function<int(int)> f = block;
135         RTTI_ASSERT(*f.target<int(^)(int)>() == block);
136         RTTI_ASSERT(f.target<int(*)(int)>() == 0);
137         Block_release(block);
138     }
139 
140     // target_type
141     {
142         std::function<int(int)> f = ^(int x) { return x + 1; };
143         RTTI_ASSERT(f.target_type() == typeid(int(^)(int)));
144     }
145 
146     return 0;
147 }
148