Skip to content

Commit 0e4802b

Browse files
committed
[libc++] Fix std::function's handling of blocks under Objc ARC
Previously, some uses of std::function with blocks would crash when ARC was enabled. rdar://100907096 Differential Revision: https://reviews.llvm.org/D135706
1 parent dd9afdb commit 0e4802b

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

libcxx/include/__functional/function.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ template <class _Rp, class... _ArgTypes> class __policy_func<_Rp(_ArgTypes...)>
883883
#endif // _LIBCPP_NO_RTTI
884884
};
885885

886-
#if defined(_LIBCPP_HAS_BLOCKS_RUNTIME) && !defined(_LIBCPP_HAS_OBJC_ARC)
886+
#if defined(_LIBCPP_HAS_BLOCKS_RUNTIME)
887887

888888
extern "C" void *_Block_copy(const void *);
889889
extern "C" void _Block_release(const void *);
@@ -898,14 +898,22 @@ class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>
898898
public:
899899
_LIBCPP_INLINE_VISIBILITY
900900
explicit __func(__block_type const& __f)
901+
#ifdef _LIBCPP_HAS_OBJC_ARC
902+
: __f_(__f)
903+
#else
901904
: __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr))
905+
#endif
902906
{ }
903907

904908
// [TODO] add && to save on a retain
905909

906910
_LIBCPP_INLINE_VISIBILITY
907911
explicit __func(__block_type __f, const _Alloc& /* unused */)
912+
#ifdef _LIBCPP_HAS_OBJC_ARC
913+
: __f_(__f)
914+
#else
908915
: __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr))
916+
#endif
909917
{ }
910918

911919
virtual __base<_Rp(_ArgTypes...)>* __clone() const {
@@ -921,8 +929,10 @@ class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>
921929
}
922930

923931
virtual void destroy() _NOEXCEPT {
932+
#ifndef _LIBCPP_HAS_OBJC_ARC
924933
if (__f_)
925934
_Block_release(__f_);
935+
#endif
926936
__f_ = 0;
927937
}
928938

@@ -950,7 +960,7 @@ class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>
950960
#endif // _LIBCPP_NO_RTTI
951961
};
952962

953-
#endif // _LIBCPP_HAS_EXTENSION_BLOCKS && !_LIBCPP_HAS_OBJC_ARC
963+
#endif // _LIBCPP_HAS_EXTENSION_BLOCKS
954964

955965
} // namespace __function
956966

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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 "blocks" when ARC is enabled
10+
11+
// UNSUPPORTED: c++03
12+
13+
// This test requires the Blocks runtime, which is (only?) available on Darwin
14+
// out-of-the-box.
15+
// REQUIRES: has-fblocks && darwin
16+
17+
// ADDITIONAL_COMPILE_FLAGS: -fblocks -fobjc-arc
18+
19+
#include <functional>
20+
21+
#include <cassert>
22+
#include <cstddef>
23+
#include <string>
24+
25+
struct Foo {
26+
Foo() = default;
27+
Foo(std::size_t (^bl)()) : f(bl) {}
28+
29+
std::function<int()> f;
30+
};
31+
32+
Foo Factory(std::size_t (^bl)()) {
33+
Foo result(bl);
34+
return result;
35+
}
36+
37+
Foo Factory2() {
38+
auto hello = std::string("Hello world");
39+
return Factory(^() {
40+
return hello.size();
41+
});
42+
}
43+
44+
Foo AssignmentFactory(std::size_t (^bl)()) {
45+
Foo result;
46+
result.f = bl;
47+
return result;
48+
}
49+
50+
Foo AssignmentFactory2() {
51+
auto hello = std::string("Hello world");
52+
return AssignmentFactory(^() {
53+
return hello.size();
54+
});
55+
}
56+
57+
int main(int, char **) {
58+
// Case 1, works
59+
{
60+
auto hello = std::string("Hello world");
61+
auto f = AssignmentFactory(^() {
62+
return hello.size();
63+
});
64+
assert(f.f() == 11);
65+
}
66+
67+
// Case 2, works
68+
{
69+
auto f = AssignmentFactory2();
70+
assert(f.f() == 11);
71+
}
72+
73+
// Case 3, works
74+
{
75+
auto hello = std::string("Hello world");
76+
auto f = Factory(^() {
77+
return hello.size();
78+
});
79+
assert(f.f() == 11);
80+
}
81+
82+
// Case 4, used to crash under ARC
83+
{
84+
auto f = Factory2();
85+
assert(f.f() == 11);
86+
}
87+
88+
return 0;
89+
}

libcxx/test/libcxx/utilities/function.objects/func.blocks.sh.cpp renamed to libcxx/test/libcxx/utilities/function.objects/func.blocks.pass.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
// on Darwin out-of-the-box.
1515
// REQUIRES: has-fblocks && darwin
1616

17-
// RUN: %{build} -fblocks
18-
// RUN: %{run}
17+
// ADDITIONAL_COMPILE_FLAGS: -fblocks
1918

2019
#include <functional>
2120
#include <cstdlib>

0 commit comments

Comments
 (0)