Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -314,6 +314,10 @@ #define _LIBCPP_HAS_NO_STRONG_ENUMS #endif +#if __has_extension(blocks) +#define _LIBCPP_HAS_BLOCKS +#endif + #if !(__has_feature(cxx_constexpr)) #define _LIBCPP_HAS_NO_CONSTEXPR #endif Index: include/functional =================================================================== --- include/functional +++ include/functional @@ -479,6 +479,10 @@ #include <__functional_base> +#if defined(_LIBCPP_HAS_BLOCKS) && !defined(_LIBCPP_HAS_OBJC_ARC) +#include +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -1390,6 +1394,99 @@ #endif // _LIBCPP_NO_RTTI +#if defined(_LIBCPP_HAS_BLOCKS) && !defined(_LIBCPP_HAS_OBJC_ARC) + +template +class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)> + : public __base<_Rp(_ArgTypes...)> +{ + typedef _Rp1(^__block_type)(_ArgTypes1...); + __block_type __f_; +public: + _LIBCPP_INLINE_VISIBILITY + explicit __func(__block_type __f) + : __f_(__f ? Block_copy(__f) : (__block_type)0) {} + + _LIBCPP_INLINE_VISIBILITY + explicit __func(__block_type __f, const _Alloc& /* unused */) + : __f_(__f ? Block_copy(__f) : (__block_type)0) {} + + virtual __base<_Rp(_ArgTypes...)>* __clone() const; + virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; + virtual void destroy() _NOEXCEPT; + virtual void destroy_deallocate() _NOEXCEPT; + virtual _Rp operator()(_ArgTypes&& ... __arg); +#ifndef _LIBCPP_NO_RTTI + virtual const void* target(const type_info&) const _NOEXCEPT; + virtual const std::type_info& target_type() const _NOEXCEPT; +#endif // _LIBCPP_NO_RTTI +}; + +template +__base<_Rp(_ArgTypes...)>* +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::__clone() const +{ + // Block pointers are just pointers, so it should always fit in __buf_. This version + // of __clone should never get invoked. + _LIBCPP_ASSERT(false, "std::function should capture blocks internally"); + return 0; +} + +template +void +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const +{ + ::new (__p) __func(__f_); +} + +template +void +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::destroy() _NOEXCEPT +{ + if (__f_) + Block_release(__f_); + __f_ = 0; +} + +template +void +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate() _NOEXCEPT +{ + // Block pointers are just pointers, so it should always fit in __buf_. This version + // of destroy should never get invoked. + _LIBCPP_ASSERT(false, "std::function should capture blocks internally"); + return 0; +} + +template +_Rp +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&& ... __arg) +{ + return __invoke(__f_, _VSTD::forward<_ArgTypes>(__arg)...); +} + +#ifndef _LIBCPP_NO_RTTI + +template +const void* +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::target(const type_info& __ti) const _NOEXCEPT +{ + if (__ti == typeid(__func::__block_type)) + return &__f_; + return (const void*)0; +} + +template +const std::type_info& +__func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>::target_type() const _NOEXCEPT +{ + return typeid(__func::__block_type); +} + +#endif // _LIBCPP_NO_RTTI +#endif // _LIBCPP_HAS_BLOCKS && !_LIBCPP_HAS_OBJC_ARC + + } // __function template @@ -1422,6 +1519,11 @@ template _LIBCPP_INLINE_VISIBILITY static bool __not_null(const function<_R2(_Ap...)>& __p) {return !!__p;} +#ifdef _LIBCPP_HAS_BLOCKS + template + _LIBCPP_INLINE_VISIBILITY + static bool __not_null(_R2 (^__p)(_Ap...)) {return __p;} +#endif template ::value && __invokable<_Fp&, _ArgTypes...>::value> Index: test/lit.cfg =================================================================== --- test/lit.cfg +++ test/lit.cfg @@ -387,7 +387,7 @@ 'C++ ABI setting %s unsupported for tests' % cxx_abi) if sys.platform == 'darwin': - self.link_flags += ['-lSystem'] + self.link_flags += ['-lSystem', '-fblocks'] elif sys.platform == 'linux2': self.link_flags += ['-lgcc_eh', '-lc', '-lm', '-lpthread', '-lrt', '-lgcc_s'] Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.alg/swap.pass.cpp @@ -132,4 +132,19 @@ } assert(A::count == 0); assert(new_called == 0); +#ifdef _LIBCPP_HAS_BLOCKS + { + std::function f1 = g; + std::function f2 = ^(int x) { return x + 1; }; + assert(A::count == 0); + assert(new_called == 0); + assert(*f1.target() == g); + assert(*f2.target() != 0); + swap(f1, f2); + assert(A::count == 0); + assert(new_called == 0); + assert(*f1.target() != 0); + assert(*f2.target() == g); + } +#endif } Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp @@ -26,4 +26,12 @@ f = g; assert(f); } +#ifdef _LIBCPP_HAS_BLOCKS + { + std::function f; + assert(!f); + f = ^(int x) { return x+1; }; + assert(f); + } +#endif } Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_int_0.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_int_0.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_int_0.pass.cpp @@ -50,6 +50,13 @@ std::function r1(a0); assert(r1() == 4); } +#ifdef _LIBCPP_HAS_BLOCKS + // block + { + std::function r1 = ^{ return 5; }; + assert(r1() == 5); + } +#endif } int main() Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_void_0.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_void_0.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_void_0.pass.cpp @@ -59,6 +59,15 @@ assert(count == save_count+1); save_count = count; } +#ifdef _LIBCPP_HAS_BLOCKS + // block + { + std::function r1(^{ ++count; }); + r1(); + assert(count == save_count+1); + save_count = count; + } +#endif } int main() Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.mod/swap.pass.cpp @@ -131,4 +131,19 @@ } assert(A::count == 0); assert(new_called == 0); +#ifdef _LIBCPP_HAS_BLOCKS + { + std::function f1 = A(1); + std::function f2 = ^(int x) { return x + 1; }; + assert(A::count == 1); + assert(new_called == 1); + assert(f1.target()->id() == 1); + assert((*f2.target())(13) == 14); + f1.swap(f2); + assert(A::count == 1); + assert(new_called == 1); + assert((*f1.target())(13) == 14); + assert(f2.target()->id() == 1); + } +#endif } Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.nullptr/operator_==.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.nullptr/operator_==.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.nullptr/operator_==.pass.cpp @@ -37,5 +37,10 @@ f = g; assert(f != nullptr); assert(nullptr != f); +#ifdef _LIBCPP_HAS_BLOCKS + f = ^(int x) { return x + 1; }; + assert(f != nullptr); + assert(nullptr != f); +#endif } } Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.targ/target.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.targ/target.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.targ/target.pass.cpp @@ -86,4 +86,13 @@ assert(f.target() == 0); } assert(A::count == 0); +#ifdef _LIBCPP_HAS_BLOCKS + { + int (^block)(int) = Block_copy(^(int x) { return x + 1; }); + std::function f = block; + assert(*f.target() == block); + assert(f.target() == 0); + Block_release(block); + } +#endif } Index: test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.targ/target_type.pass.cpp =================================================================== --- test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.targ/target_type.pass.cpp +++ test/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.targ/target_type.pass.cpp @@ -58,4 +58,10 @@ std::function f; assert(f.target_type() == typeid(void)); } +#ifdef _LIBCPP_HAS_BLOCKS + { + std::function f = ^(int x) { return x + 1; }; + assert(f.target_type() == typeid(int(^)(int))); + } +#endif }