[llvm-branch-commits] [libcxx] 6872509 - [libc++] Fix std::function's handling of blocks under Objc ARC

Tobias Hieta via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Oct 17 23:30:14 PDT 2022


Author: Louis Dionne
Date: 2022-10-18T08:29:03+02:00
New Revision: 687250913265a0160c8fba2c0bd93ddd933ec9c2

URL: https://github.com/llvm/llvm-project/commit/687250913265a0160c8fba2c0bd93ddd933ec9c2
DIFF: https://github.com/llvm/llvm-project/commit/687250913265a0160c8fba2c0bd93ddd933ec9c2.diff

LOG: [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

(cherry picked from commit 0e4802bf45952b1120c52d4d1bf6bfa2800fd102)

Added: 
    libcxx/test/libcxx/utilities/function.objects/func.blocks.arc.pass.mm
    libcxx/test/libcxx/utilities/function.objects/func.blocks.pass.cpp

Modified: 
    libcxx/include/__functional/function.h

Removed: 
    libcxx/test/libcxx/utilities/function.objects/func.blocks.sh.cpp


################################################################################
diff  --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index db3af6e24101b..55b607f3f8047 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -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 *);
@@ -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 {
@@ -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;
     }
 
@@ -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
 

diff  --git a/libcxx/test/libcxx/utilities/function.objects/func.blocks.arc.pass.mm b/libcxx/test/libcxx/utilities/function.objects/func.blocks.arc.pass.mm
new file mode 100644
index 0000000000000..186fe22e6e476
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/func.blocks.arc.pass.mm
@@ -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;
+}

diff  --git a/libcxx/test/libcxx/utilities/function.objects/func.blocks.sh.cpp b/libcxx/test/libcxx/utilities/function.objects/func.blocks.pass.cpp
similarity index 98%
rename from libcxx/test/libcxx/utilities/function.objects/func.blocks.sh.cpp
rename to libcxx/test/libcxx/utilities/function.objects/func.blocks.pass.cpp
index ecebc7c9800ff..b95b6ebb534a1 100644
--- a/libcxx/test/libcxx/utilities/function.objects/func.blocks.sh.cpp
+++ b/libcxx/test/libcxx/utilities/function.objects/func.blocks.pass.cpp
@@ -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>


        


More information about the llvm-branch-commits mailing list