arphaman created this revision. This patch fixes PR34298 (https://bugs.llvm.org/show_bug.cgi?id=34298). Since Clang changed in r284549, Clang and libc++ prohibit the use of `std::function` with an incomplete return type, like in the example below:
struct Continuation { std::function<Continuation ()> fn; }; This code failed to compile because of the way SFINAE checks were performed in libc++. Essentially when `Continuation` was defining a copy-constructor, it tried to find a matching overload for the copy constructor of `fn`, and thus tried to instantiate `std::function`s `function(_Fp)` constructor with a `std::function<Continuation ()>` substitute for `_Fp`. That constructor did check against `function` in its SFINAE checks, but it did so after trying to invoke `_Fp`. This caused an error while evaluating `__invokable_r` because `Continuation` is incomplete, and the incomplete type checker for `__invokable_r` didn't take `std::function<>` types into account. This patch ensures that the SFINAE check verify that `_Fp` is not a `std::function` before trying to figure out if `_Fp` is invokable. Repository: rL LLVM https://reviews.llvm.org/D37104 Files: include/functional test/libcxx/utilities/function.objects/func.require/incomplete_return_type.pass.cpp Index: test/libcxx/utilities/function.objects/func.require/incomplete_return_type.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/function.objects/func.require/incomplete_return_type.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// Non-standard extension: +// std::function is allowed to take a function with an incomplete return type. + +// [func.require] + +#include <functional> + +struct IncompleteReturnType { + std::function<IncompleteReturnType ()> fn; +}; + +int main() { + return 0; +} Index: include/functional =================================================================== --- include/functional +++ include/functional @@ -1623,7 +1623,10 @@ function(const function&); function(function&&) _NOEXCEPT; template<class _Fp, class = typename enable_if< - __callable<_Fp>::value && !is_same<_Fp, function>::value + is_same<typename enable_if<!is_same<_Fp, function>::value>::type, + void + >::value && + __callable<_Fp>::value >::type> function(_Fp); @@ -1648,8 +1651,11 @@ template<class _Fp> typename enable_if < - __callable<typename decay<_Fp>::type>::value && - !is_same<typename remove_reference<_Fp>::type, function>::value, + is_same<typename enable_if< + !is_same<typename remove_reference<_Fp>::type, function>::value>::type, + void + >::value && + __callable<typename decay<_Fp>::type>::value, function& >::type operator=(_Fp&&); @@ -1857,8 +1863,11 @@ template <class _Fp> typename enable_if < - function<_Rp(_ArgTypes...)>::template __callable<typename decay<_Fp>::type>::value && - !is_same<typename remove_reference<_Fp>::type, function<_Rp(_ArgTypes...)>>::value, + is_same<typename enable_if< + !is_same<typename remove_reference<_Fp>::type, function<_Rp(_ArgTypes...)>>::value>::type, + void + >::value && + function<_Rp(_ArgTypes...)>::template __callable<typename decay<_Fp>::type>::value, function<_Rp(_ArgTypes...)>& >::type function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f)
Index: test/libcxx/utilities/function.objects/func.require/incomplete_return_type.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/function.objects/func.require/incomplete_return_type.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// Non-standard extension: +// std::function is allowed to take a function with an incomplete return type. + +// [func.require] + +#include <functional> + +struct IncompleteReturnType { + std::function<IncompleteReturnType ()> fn; +}; + +int main() { + return 0; +} Index: include/functional =================================================================== --- include/functional +++ include/functional @@ -1623,7 +1623,10 @@ function(const function&); function(function&&) _NOEXCEPT; template<class _Fp, class = typename enable_if< - __callable<_Fp>::value && !is_same<_Fp, function>::value + is_same<typename enable_if<!is_same<_Fp, function>::value>::type, + void + >::value && + __callable<_Fp>::value >::type> function(_Fp); @@ -1648,8 +1651,11 @@ template<class _Fp> typename enable_if < - __callable<typename decay<_Fp>::type>::value && - !is_same<typename remove_reference<_Fp>::type, function>::value, + is_same<typename enable_if< + !is_same<typename remove_reference<_Fp>::type, function>::value>::type, + void + >::value && + __callable<typename decay<_Fp>::type>::value, function& >::type operator=(_Fp&&); @@ -1857,8 +1863,11 @@ template <class _Fp> typename enable_if < - function<_Rp(_ArgTypes...)>::template __callable<typename decay<_Fp>::type>::value && - !is_same<typename remove_reference<_Fp>::type, function<_Rp(_ArgTypes...)>>::value, + is_same<typename enable_if< + !is_same<typename remove_reference<_Fp>::type, function<_Rp(_ArgTypes...)>>::value>::type, + void + >::value && + function<_Rp(_ArgTypes...)>::template __callable<typename decay<_Fp>::type>::value, function<_Rp(_ArgTypes...)>& >::type function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits