[PATCH] D37104: [libc++] PR34298: Change std::function constructor and move assignment operator SFINAE checks to allow std::function with an incomplete return type

Alex Lorenz via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 24 04:31:29 PDT 2017

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.




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
@@ -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,
@@ -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...)>::operator=(_Fp&& __f)

-------------- next part --------------
A non-text attachment was scrubbed...
Name: D37104.112537.patch
Type: text/x-patch
Size: 2522 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170824/22a8438d/attachment-0001.bin>

More information about the cfe-commits mailing list