Skip to content

Commit

Permalink
[libc++] Fix std::function's handling of blocks under Objc ARC
Browse files Browse the repository at this point in the history
Previously, some uses of std::function with blocks would crash when ARC was enabled.

rdar://100907096

Differential Revision: https://reviews.llvm.org/D135706
  • Loading branch information
ldionne committed Oct 17, 2022
1 parent dd9afdb commit 0e4802b
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 4 deletions.
14 changes: 12 additions & 2 deletions libcxx/include/__functional/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ template <class _Rp, class... _ArgTypes> class __policy_func<_Rp(_ArgTypes...)>
#endif // _LIBCPP_NO_RTTI
};

#if defined(_LIBCPP_HAS_BLOCKS_RUNTIME) && !defined(_LIBCPP_HAS_OBJC_ARC)
#if defined(_LIBCPP_HAS_BLOCKS_RUNTIME)

extern "C" void *_Block_copy(const void *);
extern "C" void _Block_release(const void *);
Expand All @@ -898,14 +898,22 @@ class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>
public:
_LIBCPP_INLINE_VISIBILITY
explicit __func(__block_type const& __f)
#ifdef _LIBCPP_HAS_OBJC_ARC
: __f_(__f)
#else
: __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr))
#endif
{ }

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

_LIBCPP_INLINE_VISIBILITY
explicit __func(__block_type __f, const _Alloc& /* unused */)
#ifdef _LIBCPP_HAS_OBJC_ARC
: __f_(__f)
#else
: __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr))
#endif
{ }

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

virtual void destroy() _NOEXCEPT {
#ifndef _LIBCPP_HAS_OBJC_ARC
if (__f_)
_Block_release(__f_);
#endif
__f_ = 0;
}

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

#endif // _LIBCPP_HAS_EXTENSION_BLOCKS && !_LIBCPP_HAS_OBJC_ARC
#endif // _LIBCPP_HAS_EXTENSION_BLOCKS

} // namespace __function

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// std::function support for "blocks" when ARC is enabled

// UNSUPPORTED: c++03

// This test requires the Blocks runtime, which is (only?) available on Darwin
// out-of-the-box.
// REQUIRES: has-fblocks && darwin

// ADDITIONAL_COMPILE_FLAGS: -fblocks -fobjc-arc

#include <functional>

#include <cassert>
#include <cstddef>
#include <string>

struct Foo {
Foo() = default;
Foo(std::size_t (^bl)()) : f(bl) {}

std::function<int()> f;
};

Foo Factory(std::size_t (^bl)()) {
Foo result(bl);
return result;
}

Foo Factory2() {
auto hello = std::string("Hello world");
return Factory(^() {
return hello.size();
});
}

Foo AssignmentFactory(std::size_t (^bl)()) {
Foo result;
result.f = bl;
return result;
}

Foo AssignmentFactory2() {
auto hello = std::string("Hello world");
return AssignmentFactory(^() {
return hello.size();
});
}

int main(int, char **) {
// Case 1, works
{
auto hello = std::string("Hello world");
auto f = AssignmentFactory(^() {
return hello.size();
});
assert(f.f() == 11);
}

// Case 2, works
{
auto f = AssignmentFactory2();
assert(f.f() == 11);
}

// Case 3, works
{
auto hello = std::string("Hello world");
auto f = Factory(^() {
return hello.size();
});
assert(f.f() == 11);
}

// Case 4, used to crash under ARC
{
auto f = Factory2();
assert(f.f() == 11);
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
// on Darwin out-of-the-box.
// REQUIRES: has-fblocks && darwin

// RUN: %{build} -fblocks
// RUN: %{run}
// ADDITIONAL_COMPILE_FLAGS: -fblocks

#include <functional>
#include <cstdlib>
Expand Down

0 comments on commit 0e4802b

Please sign in to comment.