Bug 42593 - [c++0x] [4.5 Regression] std::bind not assignable to std::function
Summary: [c++0x] [4.5 Regression] std::bind not assignable to std::function
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.5.0
: P1 blocker
Target Milestone: 4.5.0
Assignee: Jonathan Wakely
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-01-03 12:37 UTC by Daniel Frey
Modified: 2010-01-12 00:55 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-01-03 14:12:57


Attachments
preliminary patch (2.41 KB, patch)
2010-01-03 17:57 UTC, Jonathan Wakely
Details | Diff
updated patch (4.57 KB, patch)
2010-01-03 22:10 UTC, Jonathan Wakely
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Frey 2010-01-03 12:37:38 UTC
The following code compiles fine with GCC 4.3.3 and 4.4.2, but fails to compile with 4.5 (snapshot from 2009-12-31):

#include <functional>
void f( int ) {}
int main() { std::function< void( int ) > pf = std::bind( &f, std::placeholders::_1 ); }

with the following error:

In file included from t.cc:1:0:
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional: In static member function &#130;Äòstatic void std::_Function_handler<void(_ArgTypes ...), _Functor>::_M_invoke(const std::_Any_data&, _ArgTypes ...) [with _Functor = std::_Bind<void (*(std::_Placeholder<1>))(int)>, _ArgTypes = {int}]&#130;Äô:
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional:2127:6:   instantiated from &#130;Äòstd::function<_Res(_ArgTypes ...)>::function(_Functor, typename __gnu_cxx::__enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::__type) [with _Functor = std::_Bind<void (*(std::_Placeholder<1>))(int)>, _Res = void, _ArgTypes = {int}, typename __gnu_cxx::__enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::__type = std::function<void(int)>::_Useless]&#130;Äô
t.cc:3:85:   instantiated from here
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional:1748:9: error: no match for call to &#130;Äò(std::_Bind<void (*(std::_Placeholder<1>))(int)>) (int)&#130;Äô
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional:1219:9: note: candidates are: typename std::result_of<_Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) [with _Args = {int}, _Functor = void (*)(int), _Bound_args = {std::_Placeholder<1>}, typename std::result_of<_Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type = void]
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional:1230:9: note:                typename std::result_of<const _Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) const [with _Args = {int}, _Functor = void (*)(int), _Bound_args = {std::_Placeholder<1>}, typename std::result_of<const _Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type = void]
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional:1242:9: note:                typename std::result_of<volatile _Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) volatile [with _Args = {int}, _Functor = void (*)(int), _Bound_args = {std::_Placeholder<1>}, typename std::result_of<volatile _Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type = void]
/home/frey/work/install/gcc-4.5-snapshot/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../include/c++/4.5.0/functional:1255:9: note:                typename std::result_of<const volatile _Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) const volatile [with _Args = {int}, _Functor = void (*)(int), _Bound_args = {std::_Placeholder<1>}, typename std::result_of<const volatile _Functor(typename std::result_of<std::_Mu<_Bound_args>(_Bound_args, std::tuple<_UElements ...>)>::type ...)>::type = void]
Comment 1 Paolo Carlini 2010-01-03 12:47:29 UTC
Thanks Daniel. Jon, can you have a look? I verified that the tr1 code we were using in 4.4.x and before is fine, thus should be either the std::function changes vs rvalue references or, less likely I believe, the void special case changes.
Comment 2 Paolo Carlini 2010-01-03 14:26:12 UTC
Thanks.
Comment 3 Jonathan Wakely 2010-01-03 15:07:24 UTC
From a quick look, I think the problem is that std::function now uses perfect forwarding, but std::bind doesn't yet.
So invoking the function passes an rvalue to _Bind::operator() which fails to bind to _Args&
Previously, std::function took its arguments by value, and _Bind::operator()(_Args&...) bound an lvalue reference to that by-value parameter:
      return _M_invoker(_M_functor, __args...);

Now it does this:

      return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...);

and so the rvalue cannot bind to _Args&

This will be fixed when std::bind supports rvalue references. I was going to finish those changes after updating <future>, but I have been delayed by some unexpected events and am away from my home PC which contains my work in progress.
Comment 4 Paolo Carlini 2010-01-03 15:10:48 UTC
Ok, Jon, thanks. At some point, however, *soon* I'm afraid given the gcc4.5 schedule, we'll have to make a tough choice: if updating only std::function leads to bad regressions in common usages of std::bind, and the latter isn't ready in time for gcc4.5 for whatever reason, we can't ship something half halfway through, I think...
Comment 5 Paolo Carlini 2010-01-03 16:03:04 UTC
Jon, I'm raising Priority and Severity not because the isssue per se is that deadly serious (after all the whole C++0x is experimental, nothing should be really critical about it), but because we want to make sure we don't forget when (soon) we'll branch and will be in Stage 4, close to the release, and we'll have to make the final decisions about <functional>.
Comment 6 Jonathan Wakely 2010-01-03 16:28:21 UTC
ok, understood - I'm looking at finishing the bind changes at the moment
Comment 7 Paolo Carlini 2010-01-03 16:34:28 UTC
Let's keep a P1 for now, we really don't want to forget.
Comment 8 Jonathan Wakely 2010-01-03 17:57:28 UTC
Created attachment 19453 [details]
preliminary patch

I'm testing this, which is not ready for checkin, but updates std::bind to handle rvalues and fixes this bug.

As well as fixing the affected testcases (done but not included in this patch) and fixing the formatting, the decaying behaviour from the resolution to LWG 817 needs to be implemented:
http://home.roadrunner.com/~hinnant/issue_review/lwg-active.html#817

I *think* the patch is correct, but testsuite/30_threads/call_once/39909.cc fails due to a front-end bug:
/home/redi/src/gcc/build/x86_64-unknown-linux-gnu/libstdc++-v3/include/functional:1179:67: sorry, unimplemented: unable to determine the declared type of expression 'declval<std::reference_wrapper<Inc> >()()'

A workaround for this is to change call_once to use bind<void>() instead of bind() i.e.
Index: include/std/mutex
===================================================================
--- include/std/mutex	(revision 155587)
+++ include/std/mutex	(working copy)
@@ -722,12 +722,12 @@ namespace std
     call_once(once_flag& __once, _Callable __f, _Args&&... __args)
     {
 #ifdef _GLIBCXX_HAVE_TLS
-      auto __bound_functor = std::bind(__f, __args...);
+      auto __bound_functor = std::bind<void>(__f, __args...),
       __once_callable = &__bound_functor;
       __once_call = &__once_call_impl<decltype(__bound_functor)>;
 #else
       unique_lock<mutex> __functor_lock(__get_once_mutex());
-      __once_functor = std::bind(__f, __args...);
+      __once_functor = std::bind<void>(__f, __args...);
       __set_once_functor_lock_ptr(&__functor_lock);
 #endif
 
(the ability to use this workaround was the main reason I fixed std::bind<void> recently)
Comment 9 Paolo Carlini 2010-01-03 18:05:09 UTC
Great. Let's go ahead this way, then!
Comment 10 Jonathan Wakely 2010-01-03 18:07:02 UTC
OK

P.S.

(In reply to comment #8)
> 
> (the ability to use this workaround was the main reason I fixed std::bind<void>
> recently)

I think I've mentioned to Paolo in private mail that we could use bind<R> (specifically, bind<void>) in several places because doing so should reduce compile time, as it avoids using result_of and decltype to determine the return type.  I haven't done so yet, because deducing the return type provides better testcases for std::bind while I'm still working on it. Once the work is complete, we should consider using bind<R> in <mutex> and <future> 

Comment 11 Paolo Carlini 2010-01-03 20:57:50 UTC
By the way, Jon, I don't think we should delay committing this work only because of DR 817, after all isn't even Ready...
Comment 12 Paolo Carlini 2010-01-03 21:02:41 UTC
... if we have something rather satisfactory wrt all the other isses / testcases we are aware of in this area the sooner we commit the code, the better: I'm sure that Daniel can help testing it further on his code base: worst case, if after the branch point things look really bad, we revert the whole package for the release, luckily we are not talking about tons of code intertwined with the rest of the library. Only, we have to keep the eyes open the next few weeks. We can make it ;)
Comment 13 Jonathan Wakely 2010-01-03 22:10:15 UTC
Created attachment 19458 [details]
updated patch

this fixes the formatting in the previous patch, includes the call_once workaround, and updates the testsuite.
This patch disables the volatile-qualified _Bind::operator() overloads with '#if 0' because I'm not smart enough to figure out how to support that.  If those overloads are enabled then you get errors when trying to pass reference_wrapper or _Bind as an argument to _Bind::operator().
IMHO we can live without volatile support for 4.5 because I don't think it's a widely-used feature.

As well as this bug, it fixes bug 35569 and its dup

I want to do some more tests to be sure this is ready
Comment 14 Paolo Carlini 2010-01-04 10:30:13 UTC
For sure Jon the code is very, very clean, excellent.
Comment 15 Paolo Carlini 2010-01-10 13:46:09 UTC
Jon, what do you think, shall we go ahead?
Comment 16 Jonathan Wakely 2010-01-10 16:26:37 UTC
Let's go for it, I check it in later today
Comment 17 Jonathan Wakely 2010-01-12 00:54:01 UTC
Subject: Bug 42593

Author: redi
Date: Tue Jan 12 00:53:30 2010
New Revision: 155826

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=155826
Log:
2010-01-12  Jonathan Wakely  <jwakely.gcc@gmail.com>

	PR libstdc++/24803
	PR libstdc++/35569
	PR libstdc++/42593
	* include/std/functional (bind): Forward rvalues and detect correct
	result type of bound function object.
	* include/std/mutex (call_once): Specify bind result type.
	* testsuite/20_util/reference_wrapper/invoke.cc: Remove invalid tests.
	* testsuite/20_util/reference_wrapper/24803.cc: Remove invalid tests
	and enable FIXME tests.
	* testsuite/20_util/bind/35569.cc: New.
	* testsuite/20_util/bind/ref2.cc: New.
	* testsuite/20_util/bind/38889.cc: New.
	* testsuite/20_util/bind/ref_neg.cc: New.
	* testsuite/20_util/bind/42593.cc: New.


Added:
    trunk/libstdc++-v3/testsuite/20_util/bind/35569.cc
    trunk/libstdc++-v3/testsuite/20_util/bind/38889.cc
    trunk/libstdc++-v3/testsuite/20_util/bind/42593.cc
    trunk/libstdc++-v3/testsuite/20_util/bind/ref2.cc
    trunk/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/std/functional
    trunk/libstdc++-v3/include/std/mutex
    trunk/libstdc++-v3/testsuite/20_util/reference_wrapper/24803.cc
    trunk/libstdc++-v3/testsuite/20_util/reference_wrapper/invoke.cc

Comment 18 Jonathan Wakely 2010-01-12 00:55:42 UTC
Fixed for 4.5.0