diff options
author | Eric Fiselier <eric@efcs.ca> | 2015-02-10 16:48:45 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2015-02-10 16:48:45 +0000 |
commit | 54519a6be9296fb115b949f1f0785d9cbfacc7c5 (patch) | |
tree | d99921a0bd8162f333fba7fe5ecd741c09e89805 /libcxx | |
parent | 51544023a955929cbb3d105421b2e59f6be43964 (diff) | |
download | bcm5719-llvm-54519a6be9296fb115b949f1f0785d9cbfacc7c5.tar.gz bcm5719-llvm-54519a6be9296fb115b949f1f0785d9cbfacc7c5.zip |
[libcxx] Fix PR 22468 - std::function<void()> does not accept non-void-returning functions
Summary:
The bug can be found here: http://llvm.org/bugs/show_bug.cgi?id=22468
`__invoke_void_return_wrapper` is needed to properly handle calling a function that returns a value but where the std::function return type is void. Without this '-Wsystem-headers' will cause `function::operator()(...)` to not compile.
Reviewers: eugenis, K-ballo, mclow.lists
Reviewed By: mclow.lists
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D7444
llvm-svn: 228705
Diffstat (limited to 'libcxx')
8 files changed, 169 insertions, 6 deletions
diff --git a/libcxx/include/__functional_03 b/libcxx/include/__functional_03 index d8a9f05fa12..157d6bf8932 100644 --- a/libcxx/include/__functional_03 +++ b/libcxx/include/__functional_03 @@ -369,7 +369,8 @@ template<class _Fp, class _Alloc, class _Rp> _Rp __func<_Fp, _Alloc, _Rp()>::operator()() { - return __invoke(__f_.first()); + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_.first()); } #ifndef _LIBCPP_NO_RTTI @@ -452,7 +453,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0> _Rp __func<_Fp, _Alloc, _Rp(_A0)>::operator()(_A0 __a0) { - return __invoke(__f_.first(), __a0); + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_.first(), __a0); } #ifndef _LIBCPP_NO_RTTI @@ -535,7 +537,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0, class _A1> _Rp __func<_Fp, _Alloc, _Rp(_A0, _A1)>::operator()(_A0 __a0, _A1 __a1) { - return __invoke(__f_.first(), __a0, __a1); + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_.first(), __a0, __a1); } #ifndef _LIBCPP_NO_RTTI @@ -618,7 +621,8 @@ template<class _Fp, class _Alloc, class _Rp, class _A0, class _A1, class _A2> _Rp __func<_Fp, _Alloc, _Rp(_A0, _A1, _A2)>::operator()(_A0 __a0, _A1 __a1, _A2 __a2) { - return __invoke(__f_.first(), __a0, __a1, __a2); + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_.first(), __a0, __a1, __a2); } #ifndef _LIBCPP_NO_RTTI diff --git a/libcxx/include/__functional_base b/libcxx/include/__functional_base index 6766793d7c8..e174e0ca003 100644 --- a/libcxx/include/__functional_base +++ b/libcxx/include/__functional_base @@ -419,6 +419,26 @@ struct __invoke_return typedef decltype(__invoke(_VSTD::declval<_Tp>(), _VSTD::declval<_Args>()...)) type; }; +template <class _Ret> +struct __invoke_void_return_wrapper +{ + template <class ..._Args> + static _Ret __call(_Args&&... __args) + { + return __invoke(_VSTD::forward<_Args>(__args)...); + } +}; + +template <> +struct __invoke_void_return_wrapper<void> +{ + template <class ..._Args> + static void __call(_Args&&... __args) + { + __invoke(_VSTD::forward<_Args>(__args)...); + } +}; + template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY reference_wrapper : public __weak_result_type<_Tp> diff --git a/libcxx/include/__functional_base_03 b/libcxx/include/__functional_base_03 index 22c06add90f..65502778666 100644 --- a/libcxx/include/__functional_base_03 +++ b/libcxx/include/__functional_base_03 @@ -995,6 +995,63 @@ struct __invoke_return2 _VSTD::declval<_A2>())) type; }; +template <class _Ret> +struct __invoke_void_return_wrapper +{ + template <class _Fn> + static _Ret __call(_Fn __f) + { + return __invoke(__f); + } + + template <class _Fn, class _A0> + static _Ret __call(_Fn __f, _A0& __a0) + { + return __invoke(__f, __a0); + } + + template <class _Fn, class _A0, class _A1> + static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1) + { + return __invoke(__f, __a0, __a1); + } + + template <class _Fn, class _A0, class _A1, class _A2> + static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) + { + return __invoke(__f, __a0, __a1, __a2); + } +}; + + +template <> +struct __invoke_void_return_wrapper<void> +{ + template <class _Fn> + static void __call(_Fn __f) + { + __invoke(__f); + } + + template <class _Fn, class _A0> + static void __call(_Fn __f, _A0& __a0) + { + __invoke(__f, __a0); + } + + template <class _Fn, class _A0, class _A1> + static void __call(_Fn __f, _A0& __a0, _A1& __a1) + { + __invoke(__f, __a0, __a1); + } + + template <class _Fn, class _A0, class _A1, class _A2> + static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) + { + __invoke(__f, __a0, __a1, __a2); + } +}; + template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY reference_wrapper : public __weak_result_type<_Tp> diff --git a/libcxx/include/functional b/libcxx/include/functional index d14b46bb76a..36d422c9978 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -1367,7 +1367,8 @@ template<class _Fp, class _Alloc, class _Rp, class ..._ArgTypes> _Rp __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&& ... __arg) { - return __invoke(__f_.first(), _VSTD::forward<_ArgTypes>(__arg)...); + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_.first(), _VSTD::forward<_ArgTypes>(__arg)...); } #ifndef _LIBCPP_NO_RTTI @@ -1429,7 +1430,7 @@ class _LIBCPP_TYPE_VIS_ONLY function<_Rp(_ArgTypes...)> template <class _Fp> struct __callable<_Fp, true> { - static const bool value = + static const bool value = is_same<void, _Rp>::value || is_convertible<typename __invoke_of<_Fp&, _ArgTypes...>::type, _Rp>::value; }; diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp index f506af0e001..cd86e4cbf8e 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp @@ -81,4 +81,10 @@ int main() assert(globalMemCounter.checkOutstandingNewEq(0)); assert(f.target<int (A::*)(int) const>() != 0); } + { + std::function<void(int)> f(&g); + assert(f); + assert(f.target<int(*)(int)>() != 0); + f(1); + } } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_assign.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_assign.pass.cpp index 7784943cb13..11716e7946b 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_assign.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_assign.pass.cpp @@ -88,4 +88,11 @@ int main() assert(globalMemCounter.checkOutstandingNewEq(0)); assert(f.target<int (A::*)(int) const>() != 0); } + { + std::function<void(int)> f; + f = &g; + assert(f); + assert(f.target<int(*)(int)>() != 0); + f(1); + } } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp index 17601db7c42..28e44a67a71 100644 --- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp @@ -89,4 +89,12 @@ int main() fun(10); } #endif + { + std::function<void(int)> fun(std::allocator_arg, + test_allocator<int(*)(int)>(), + &g); + assert(fun); + assert(fun.target<int(*)(int)>() != 0); + fun(10); + } } diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_no_variadics.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_no_variadics.pass.cpp new file mode 100644 index 00000000000..c0a14fd96fc --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke_no_variadics.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <functional> + +// class function<R()> + +// Test that we properly return both values and void for all non-variadic +// overloads of function::operator()(...) + +#define _LIBCPP_HAS_NO_VARIADICS +#include <functional> +#include <cassert> + +int foo0() { return 42; } +int foo1(int) { return 42; } +int foo2(int, int) { return 42; } +int foo3(int, int, int) { return 42; } + +int main() +{ + { + std::function<int()> f(&foo0); + assert(f() == 42); + } + { + std::function<int(int)> f(&foo1); + assert(f(1) == 42); + } + { + std::function<int(int, int)> f(&foo2); + assert(f(1, 1) == 42); + } + { + std::function<int(int, int, int)> f(&foo3); + assert(f(1, 1, 1) == 42); + } + { + std::function<void()> f(&foo0); + f(); + } + { + std::function<void(int)> f(&foo1); + f(1); + } + { + std::function<void(int, int)> f(&foo2); + f(1, 1); + } + { + std::function<void(int, int, int)> f(&foo3); + f(1, 1, 1); + } +} |