diff mbox

libstdc++/60594 - std::function<incomplete()>

Message ID 20140415152603.GN6807@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely April 15, 2014, 3:26 p.m. UTC
The bug in the PR is that is_copy_constructible<std::function<bar()>>
performs overload resolution for function(const function&), which
instantiates the SFINAE constraints on the function(F) constructor
template, which instantiates is_convertible<bar, bar>, which is
ill-formed when bar is incomplete.

When bar is later completed you can't call the function(F) constructor
with any function object returning bar, because the constraints have
already been instantiated and so continue to produce the same result.

The fix is to exclude the function type from the constraints checks,
so that only the copy constructor is considered, and the function(F)
constructor template can be used later when bar is complete.

The new test also checks for the same problem with assignment.

Tested x86_64-linux, committed to trunk.
I plan to fix this for 4.8.3 and 4.9.1 too.
commit 1f0672b59e27a808e291891f97d38278b221d30a
Author: Jonathan Wakely <accu@kayari.org>
Date:   Tue Apr 15 15:25:14 2014 +0100

    	PR libstdc++/60594
    	* include/std/functional (function::_Callable): Exclude own type
    	from the callable checks.
    	* testsuite/20_util/function/60594.cc: New.
diff mbox

Patch

diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 5a987d9..0e80fa3 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -2149,8 +2149,15 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
 	using _Invoke = decltype(__callable_functor(std::declval<_Functor&>())
 				 (std::declval<_ArgTypes>()...) );
 
+      // Used so the return type convertibility checks aren't done when
+      // performing overload resolution for copy construction/assignment.
+      template<typename _Tp>
+	using _NotSelf = __not_<is_same<_Tp, function>>;
+
       template<typename _Functor>
-	using _Callable = __check_func_return_type<_Invoke<_Functor>, _Res>;
+	using _Callable
+	  = __and_<_NotSelf<_Functor>,
+		   __check_func_return_type<_Invoke<_Functor>, _Res>>;
 
       template<typename _Cond, typename _Tp>
 	using _Requires = typename enable_if<_Cond::value, _Tp>::type;
@@ -2291,7 +2298,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
        *  reference_wrapper<F>, this function will not throw.
        */
       template<typename _Functor>
-	_Requires<_Callable<_Functor>, function&>
+	_Requires<_Callable<typename decay<_Functor>::type>, function&>
 	operator=(_Functor&& __f)
 	{
 	  function(std::forward<_Functor>(__f)).swap(*this);
diff --git a/libstdc++-v3/testsuite/20_util/function/60594.cc b/libstdc++-v3/testsuite/20_util/function/60594.cc
new file mode 100644
index 0000000..be80b3f
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function/60594.cc
@@ -0,0 +1,36 @@ 
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2011-2014 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// libstdc++/60594
+
+#include <functional>
+#include <type_traits>
+struct bar;
+using F = std::function<bar()>;
+// check for copy constructible and assignable while 'bar' is incomplete
+constexpr int c = std::is_copy_constructible<F>::value;
+constexpr int a = std::is_copy_assignable<F>::value;
+struct bar { };
+bar func();
+void test()
+{
+  F g{ &func };
+  g = func;
+}