diff mbox

libstdc++/45893 [C++0x] [DR 817] Finish updating std::bind to rvalue refs

Message ID AANLkTinfe_kaynxF=Sor1OzyB-96NTfyJhg+T8QxnnJ+@mail.gmail.com
State New
Headers show

Commit Message

Jonathan Wakely Oct. 8, 2010, 12:44 a.m. UTC
PR libstdc++/45893
        * include/std/functional (bind): Implement DR 817 and add support
        for volatile-qualified call wrappers.
        * include/std/mutex (call_once): Implement DR 891.
        * include/std/thread (thread::thread): Implement DR 929.
        * include/std/future: Optimise use of std::bind.
        * testsuite/20_util/bind/cv_quals.cc: Test volatile-qualification.
        * testsuite/20_util/bind/move.cc: New.

Tested x86_64-linux, committed to trunk.
diff mbox

Patch

Index: include/std/functional
===================================================================
--- include/std/functional	(revision 165130)
+++ include/std/functional	(working copy)
@@ -957,7 +957,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
        */
       template<typename _CVRef, typename _Tuple>
         result_type
-        operator()(_CVRef& __arg, _Tuple&&) const volatile
+        operator()(_CVRef& __arg, _Tuple&) const volatile
         { return __arg.get(); }
     };
 
@@ -970,33 +970,26 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
     class _Mu<_Arg, true, false>
     {
     public:
-      template<typename _Signature> class result;
-
-      // Determine the result type when we pass the arguments along. This
-      // involves passing along the cv-qualifiers placed on _Mu and
-      // unwrapping the argument bundle.
-      template<typename _CVMu, typename _CVArg, typename... _Args>
-        class result<_CVMu(_CVArg, tuple<_Args...>)>
-	: public result_of<_CVArg(_Args...)> { };
-
       template<typename _CVArg, typename... _Args>
-        typename result_of<_CVArg(_Args...)>::type
+        auto
         operator()(_CVArg& __arg,
-		   tuple<_Args...>&& __tuple) const volatile
+		   tuple<_Args...>& __tuple) const volatile
+        -> decltype(__arg(declval<_Args>()...))
         {
 	  // Construct an index tuple and forward to __call
 	  typedef typename _Build_index_tuple<sizeof...(_Args)>::__type
 	    _Indexes;
-	  return this->__call(__arg, std::move(__tuple), _Indexes());
+	  return this->__call(__arg, __tuple, _Indexes());
 	}
 
     private:
       // Invokes the underlying function object __arg by unpacking all
       // of the arguments in the tuple. 
       template<typename _CVArg, typename... _Args, int... _Indexes>
-        typename result_of<_CVArg(_Args...)>::type
-        __call(_CVArg& __arg, tuple<_Args...>&& __tuple,
+        auto
+        __call(_CVArg& __arg, tuple<_Args...>& __tuple,
 	       const _Index_tuple<_Indexes...>&) const volatile
+        -> decltype(__arg(declval<_Args>()...))
         {
 	  return __arg(std::forward<_Args>(get<_Indexes>(__tuple))...);
 	}
@@ -1029,7 +1022,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
 
       template<typename _Tuple>
         typename result<_Mu(_Arg, _Tuple)>::type
-        operator()(const volatile _Arg&, _Tuple&& __tuple) const volatile
+        operator()(const volatile _Arg&, _Tuple& __tuple) const volatile
         {
 	  return std::forward<typename result<_Mu(_Arg, _Tuple)>::type>(
               ::std::get<(is_placeholder<_Arg>::value - 1)>(__tuple));
@@ -1056,7 +1049,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
       // Pick up the cv-qualifiers of the argument
       template<typename _CVArg, typename _Tuple>
         _CVArg&&
-        operator()(_CVArg&& __arg, _Tuple&&) const volatile
+        operator()(_CVArg&& __arg, _Tuple&) const volatile
         { return std::forward<_CVArg>(__arg); }
     };
 
@@ -1069,10 +1062,14 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
     struct _Maybe_wrap_member_pointer
     {
       typedef _Tp type;
-      
+
       static const _Tp&
       __do_wrap(const _Tp& __x)
       { return __x; }
+
+      static _Tp&&
+      __do_wrap(_Tp&& __x)
+      { return static_cast<_Tp&&>(__x); }
     };
 
   /**
@@ -1100,6 +1097,20 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
       typedef void type;
     };
 
+  // std::get<I> for volatile-qualified tuples
+  template<size_t _Ind, typename... _Tp>
+    inline auto
+    __volget(volatile tuple<_Tp...>& __tuple)
+    -> typename tuple_element<_Ind, tuple<_Tp...>>::type volatile&
+    { return std::get<_Ind>(const_cast<tuple<_Tp...>&>(__tuple)); }
+
+  // std::get<I> for const-volatile-qualified tuples
+  template<size_t _Ind, typename... _Tp>
+    inline auto
+    __volget(const volatile tuple<_Tp...>& __tuple)
+    -> typename tuple_element<_Ind, tuple<_Tp...>>::type const volatile&
+    { return std::get<_Ind>(const_cast<const tuple<_Tp...>&>(__tuple)); }
+
   /// Type of the function object returned from bind().
   template<typename _Signature>
     struct _Bind;
@@ -1109,7 +1120,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
     : public _Weak_result_type<_Functor>
     {
       typedef _Bind __self_type;
-      typedef typename _Build_index_tuple<sizeof...(_Bound_args)>::__type 
+      typedef typename _Build_index_tuple<sizeof...(_Bound_args)>::__type
         _Bound_indexes;
 
       _Functor _M_f;
@@ -1121,7 +1132,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
         __call(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>)
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (get<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as const
@@ -1130,10 +1141,9 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
         __call_c(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) const
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (get<_Indexes>(_M_bound_args), __args)...);
         }
 
-#if 0
       // Call as volatile
       template<typename _Result, typename... _Args, int... _Indexes>
         _Result
@@ -1141,7 +1151,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
 		 _Index_tuple<_Indexes...>) volatile
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (__volget<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as const volatile
@@ -1151,69 +1161,77 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
 		   _Index_tuple<_Indexes...>) const volatile
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (__volget<_Indexes>(_M_bound_args), __args)...);
         }
-#endif
 
      public:
-      explicit _Bind(_Functor __f, _Bound_args... __bound_args)
-      : _M_f(std::forward<_Functor>(__f)),
-	_M_bound_args(std::forward<_Bound_args>(__bound_args)...)
+      template<typename... _Args>
+        explicit _Bind(const _Functor& __f, _Args&&... __args)
+        : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...)
+        { }
+
+      template<typename... _Args>
+        explicit _Bind(_Functor&& __f, _Args&&... __args)
+        : _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...)
+        { }
+
+      _Bind(const _Bind&) = default;
+
+      _Bind(_Bind&& __b)
+      : _M_f(std::move(__b._M_f)), _M_bound_args(std::move(__b._M_bound_args))
       { }
 
       // Call unqualified
       template<typename... _Args, typename _Result
         = decltype( std::declval<_Functor>()(
               _Mu<_Bound_args>()( std::declval<_Bound_args&>(),
-				  std::declval<tuple<_Args...>&&>() )... ) )>
+				  std::declval<tuple<_Args...>&>() )... ) )>
         _Result
         operator()(_Args&&... __args)
         {
-          return this->__call<_Result>(tuple<_Args...>
-				       (std::forward<_Args>(__args)...),
-                                       _Bound_indexes());
+          return this->__call<_Result>(
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
+              _Bound_indexes());
         }
 
       // Call as const
       template<typename... _Args, typename _Result
         = decltype( std::declval<const _Functor>()(
 	      _Mu<_Bound_args>()( std::declval<const _Bound_args&>(),
-				  std::declval<tuple<_Args...>&&>() )... ) )>
+				  std::declval<tuple<_Args...>&>() )... ) )>
         _Result
         operator()(_Args&&... __args) const
         {
-          return this->__call_c<_Result>(tuple<_Args...>
-                                         (std::forward<_Args>(__args)...),
-                                         _Bound_indexes());
+          return this->__call_c<_Result>(
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
+              _Bound_indexes());
         }
 
-#if 0
       // Call as volatile
       template<typename... _Args, typename _Result
         = decltype( std::declval<volatile _Functor>()(
               _Mu<_Bound_args>()( std::declval<volatile _Bound_args&>(),
-                                  std::declval<tuple<_Args...>&&>() )... ) )>
+                                  std::declval<tuple<_Args...>&>() )... ) )>
         _Result
         operator()(_Args&&... __args) volatile
         {
-          return this->__call_v<_Result>(tuple<_Args...>
-                                         (std::forward<_Args>(__args)...),
-                                         _Bound_indexes());
+          return this->__call_v<_Result>(
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
+              _Bound_indexes());
         }
 
       // Call as const volatile
       template<typename... _Args, typename _Result
         = decltype( std::declval<const volatile _Functor>()(
               _Mu<_Bound_args>()( std::declval<const volatile _Bound_args&>(),
-                                  std::declval<tuple<_Args...>&&>() )... ) )>
+                                  std::declval<tuple<_Args...>&>() )... ) )>
         _Result
         operator()(_Args&&... __args) const volatile
         {
-          return this->__call_c_v<_Result>(tuple<_Args...>
-                                           (std::forward<_Args>(__args)...),
-                                           _Bound_indexes());
+          return this->__call_c_v<_Result>(
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
+              _Bound_indexes());
         }
-#endif
     };
 
   /// Type of the function object returned from bind<R>().
@@ -1243,7 +1261,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __disable_if_void<_Res>::type = 0)
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (get<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call unqualified, return void
@@ -1253,7 +1271,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __enable_if_void<_Res>::type = 0)
         {
           _M_f(_Mu<_Bound_args>()
-	       (get<_Indexes>(_M_bound_args), std::move(__args))...);
+	       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as const
@@ -1263,7 +1281,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __disable_if_void<_Res>::type = 0) const
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (get<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as const, return void
@@ -1273,7 +1291,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __enable_if_void<_Res>::type = 0) const
         {
           _M_f(_Mu<_Bound_args>()
-	       (get<_Indexes>(_M_bound_args),  std::move(__args))...);
+	       (get<_Indexes>(_M_bound_args),  __args)...);
         }
 
       // Call as volatile
@@ -1283,7 +1301,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __disable_if_void<_Res>::type = 0) volatile
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (__volget<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as volatile, return void
@@ -1293,7 +1311,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __enable_if_void<_Res>::type = 0) volatile
         {
           _M_f(_Mu<_Bound_args>()
-	       (get<_Indexes>(_M_bound_args), std::move(__args))...);
+	       (__volget<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as const volatile
@@ -1303,7 +1321,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __disable_if_void<_Res>::type = 0) const volatile
         {
           return _M_f(_Mu<_Bound_args>()
-                      (get<_Indexes>(_M_bound_args), std::move(__args))...);
+                      (__volget<_Indexes>(_M_bound_args), __args)...);
         }
 
       // Call as const volatile, return void
@@ -1314,16 +1332,26 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
             typename __enable_if_void<_Res>::type = 0) const volatile
         {
           _M_f(_Mu<_Bound_args>()
-	       (get<_Indexes>(_M_bound_args), std::move(__args))...);
+	       (__volget<_Indexes>(_M_bound_args), __args)...);
         }
 
     public:
       typedef _Result result_type;
 
-      explicit
-      _Bind_result(_Functor __f, _Bound_args... __bound_args)
-      : _M_f(std::forward<_Functor>(__f)),
-	_M_bound_args(std::forward<_Bound_args>(__bound_args)...)
+      template<typename... _Args>
+        explicit _Bind_result(const _Functor& __f, _Args&&... __args)
+        : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...)
+        { }
+
+      template<typename... _Args>
+        explicit _Bind_result(_Functor&& __f, _Args&&... __args)
+        : _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...)
+        { }
+
+      _Bind_result(const _Bind_result&) = default;
+
+      _Bind_result(_Bind_result&& __b)
+      : _M_f(std::move(__b._M_f)), _M_bound_args(std::move(__b._M_bound_args))
       { }
 
       // Call unqualified
@@ -1332,7 +1360,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
         operator()(_Args&&... __args)
         {
           return this->__call<_Result>(
-              tuple<_Args...>(std::forward<_Args>(__args)...),
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
               _Bound_indexes());
         }
 
@@ -1342,7 +1370,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
         operator()(_Args&&... __args) const
         {
           return this->__call<_Result>(
-              tuple<_Args...>(std::forward<_Args>(__args)...),
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
               _Bound_indexes());
         }
 
@@ -1352,7 +1380,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
         operator()(_Args&&... __args) volatile
         {
           return this->__call<_Result>(
-              tuple<_Args...>(std::forward<_Args>(__args)...),
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
               _Bound_indexes());
         }
 
@@ -1362,7 +1390,7 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
         operator()(_Args&&... __args) const volatile
         {
           return this->__call<_Result>(
-              tuple<_Args...>(std::forward<_Args>(__args)...),
+              std::forward_as_tuple(std::forward<_Args>(__args)...),
               _Bound_indexes());
         }
     };
@@ -1383,38 +1411,55 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
     struct is_bind_expression<_Bind_result<_Result, _Signature> >
     : public true_type { };
 
+  template<typename _Functor, typename... _ArgTypes>
+    struct _Bind_helper
+    {
+      typedef _Maybe_wrap_member_pointer<typename decay<_Functor>::type>
+        __maybe_type;
+      typedef typename __maybe_type::type __functor_type;
+      typedef _Bind<__functor_type(typename decay<_ArgTypes>::type...)> type;
+    };
+
   /**
    *  @brief Function template for std::bind.
    *  @ingroup binders
    */
   template<typename _Functor, typename... _ArgTypes>
     inline
-    _Bind<typename _Maybe_wrap_member_pointer<_Functor>::type(_ArgTypes...)>
-    bind(_Functor __f, _ArgTypes... __args)
+    typename _Bind_helper<_Functor, _ArgTypes...>::type
+    bind(_Functor&& __f, _ArgTypes&&... __args)
     {
-      typedef _Maybe_wrap_member_pointer<_Functor> __maybe_type;
-      typedef typename __maybe_type::type __functor_type;
-      typedef _Bind<__functor_type(_ArgTypes...)> __result_type;
-      return __result_type(__maybe_type::__do_wrap(__f),
+      typedef _Bind_helper<_Functor, _ArgTypes...> __helper_type;
+      typedef typename __helper_type::__maybe_type __maybe_type;
+      typedef typename __helper_type::type __result_type;
+      return __result_type(__maybe_type::__do_wrap(std::forward<_Functor>(__f)),
                            std::forward<_ArgTypes>(__args)...);
     } 
 
+  template<typename _Result, typename _Functor, typename... _ArgTypes>
+    struct _Bindres_helper
+    {
+      typedef _Maybe_wrap_member_pointer<typename decay<_Functor>::type>
+        __maybe_type;
+      typedef typename __maybe_type::type __functor_type;
+      typedef _Bind_result<_Result,
+                           __functor_type(typename decay<_ArgTypes>::type...)>
+        type;
+    };
+
   /**
-   *  @brief Function template for std::bind.
+   *  @brief Function template for std::bind<R>.
    *  @ingroup binders
    */
   template<typename _Result, typename _Functor, typename... _ArgTypes>
     inline
-    _Bind_result<_Result,
-		 typename _Maybe_wrap_member_pointer<_Functor>::type
-                            (_ArgTypes...)>
-    bind(_Functor __f, _ArgTypes... __args)
+    typename _Bindres_helper<_Result, _Functor, _ArgTypes...>::type
+    bind(_Functor&& __f, _ArgTypes&&... __args)
     {
-      typedef _Maybe_wrap_member_pointer<_Functor> __maybe_type;
-      typedef typename __maybe_type::type __functor_type;
-      typedef _Bind_result<_Result, __functor_type(_ArgTypes...)>
-	__result_type;
-      return __result_type(__maybe_type::__do_wrap(__f),
+      typedef _Bindres_helper<_Result, _Functor, _ArgTypes...> __helper_type;
+      typedef typename __helper_type::__maybe_type __maybe_type;
+      typedef typename __helper_type::type __result_type;
+      return __result_type(__maybe_type::__do_wrap(std::forward<_Functor>(__f)),
                            std::forward<_ArgTypes>(__args)...);
     }
 
Index: include/std/mutex
===================================================================
--- include/std/mutex	(revision 165130)
+++ include/std/mutex	(working copy)
@@ -690,7 +690,7 @@  namespace std
 
     template<typename _Callable, typename... _Args>
       friend void
-      call_once(once_flag& __once, _Callable __f, _Args&&... __args);
+      call_once(once_flag& __once, _Callable&& __f, _Args&&... __args);
   };
 
 #ifdef _GLIBCXX_HAVE_TLS
@@ -718,15 +718,17 @@  namespace std
   /// call_once
   template<typename _Callable, typename... _Args>
     void
-    call_once(once_flag& __once, _Callable __f, _Args&&... __args)
+    call_once(once_flag& __once, _Callable&& __f, _Args&&... __args)
     {
 #ifdef _GLIBCXX_HAVE_TLS
-      auto __bound_functor = std::bind<void>(__f, __args...);
+      auto __bound_functor = std::bind<void>(std::forward<_Callable>(__f),
+          std::forward<_Args>(__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<void>(__f, __args...);
+      __once_functor = std::bind<void>(std::forward<_Callable>(__f),
+          std::forward<_Args>(__args)...);
       __set_once_functor_lock_ptr(&__functor_lock);
 #endif
 
Index: include/std/thread
===================================================================
--- include/std/thread	(revision 165130)
+++ include/std/thread	(working copy)
@@ -126,16 +126,14 @@  namespace std
     thread(thread&& __t)
     { swap(__t); }
 
-    template<typename _Callable>
-      explicit thread(_Callable __f)
-      {
-	_M_start_thread(_M_make_routine<_Callable>
-			(std::forward<_Callable>(__f)));
-      }
-
     template<typename _Callable, typename... _Args>
+      explicit 
       thread(_Callable&& __f, _Args&&... __args)
-      { _M_start_thread(_M_make_routine(std::bind(__f, __args...))); }
+      {
+        _M_start_thread(_M_make_routine(std::bind<void>(
+                std::forward<_Callable>(__f),
+                std::forward<_Args>(__args)...)));
+      }
 
     ~thread()
     {
Index: include/std/future
===================================================================
--- include/std/future	(revision 165130)
+++ include/std/future	(working copy)
@@ -309,7 +309,7 @@  namespace std
         bool __set = __ignore_failure;
         // all calls to this function are serialized,
         // side-effects of invoking __res only happen once
-        call_once(_M_once, mem_fn(&_State::_M_do_set), this, ref(__res),
+        call_once(_M_once, &_State::_M_do_set, this, ref(__res),
             ref(__set));
         if (!__set)
           __throw_future_error(int(future_errc::promise_already_satisfied));
@@ -1155,7 +1155,7 @@  namespace std
       _M_run(_Args... __args)
       {
         // bound arguments decay so wrap lvalue references
-        auto __bound = std::bind<_Res>(_M_task,
+        auto __bound = std::bind<_Res>(std::ref(_M_task),
             _S_maybe_wrap_ref(std::forward<_Args>(__args))...);
         _Task_setter<_Task_state> __setter{ this, std::move(__bound) };
         _M_set_result(std::move(__setter));
Index: testsuite/20_util/bind/cv_quals.cc
===================================================================
--- testsuite/20_util/bind/cv_quals.cc	(revision 165130)
+++ testsuite/20_util/bind/cv_quals.cc	(working copy)
@@ -22,14 +22,24 @@ 
 #include <functional>
 #include <testsuite_hooks.h>
 
+// target must be invoked with cv-quals of call wrapper
+
 struct X
 {
   int operator()() { return 0; }
   int operator()() const { return 1; }
-  // int operator()() volatile { return 2; }
-  // int operator()() const volatile { return 3; }
+  int operator()() volatile { return 2; }
+  int operator()() const volatile { return 3; }
+
+  int operator()(int, int, int) { return 0; }
+  int operator()(int, int, int) const { return 1; }
+  int operator()(int, int, int) volatile { return 2; }
+  int operator()(int, int, int) const volatile { return 3; }
 };
 
+using std::placeholders::_1;
+using std::placeholders::_2;
+
 void test01()
 {
   bool test __attribute__((unused)) = true;
@@ -40,15 +50,70 @@  void test01()
   const auto b1 = std::bind(X());
   VERIFY( b1() == 1 );
 
-  // volatile auto b2 = std::bind(X());
-  // VERIFY( b2() == 2 );
+  volatile auto b2 = std::bind(X());
+  VERIFY( b2() == 2 );
+
+  const volatile auto b3 = std::bind(X());
+  VERIFY( b3() == 3 );
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+
+  auto b0 = std::bind<int>(X());
+  VERIFY( b0() == 0 );
+
+  const auto b1 = std::bind<int>(X());
+  VERIFY( b1() == 1 );
+
+  volatile auto b2 = std::bind<int>(X());
+  VERIFY( b2() == 2 );
+
+  const volatile auto b3 = std::bind<int>(X());
+  VERIFY( b3() == 3 );
+}
+
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  auto b0 = std::bind(X(), 0, _1, _2);
+  VERIFY( b0(0, 0) == 0 );
 
-  // const volatile auto b3 = std::bind(X());
-  // VERIFY( b3() == 3 );
+  const auto b1 = std::bind(X(), _1, 0, _2);
+  VERIFY( b1(0, 0) == 1 );
+
+  volatile auto b2 = std::bind(X(), _1, _2, 0);
+  VERIFY( b2(0, 0) == 2 );
+
+  const volatile auto b3 = std::bind(X(), _1, 0, _2);
+  VERIFY( b3(0, 0) == 3 );
 }
 
+void test04()
+{
+  bool test __attribute__((unused)) = true;
+
+  auto b0 = std::bind<int>(X(), 0, _1, _2);
+  VERIFY( b0(0, 0) == 0 );
+
+  const auto b1 = std::bind<int>(X(), _1, 0, _2);
+  VERIFY( b1(0, 0) == 1 );
+
+  volatile auto b2 = std::bind<int>(X(), _1, _2, 0);
+  VERIFY( b2(0, 0) == 2 );
+
+  const volatile auto b3 = std::bind<int>(X(), _1, 0, _2);
+  VERIFY( b3(0, 0) == 3 );
+}
+
+
 int main()
 {
   test01();
+  test02();
+  test03();
+  test04();
   return 0;
 }
Index: testsuite/20_util/bind/move.cc
===================================================================
--- testsuite/20_util/bind/move.cc	(revision 0)
+++ testsuite/20_util/bind/move.cc	(revision 0)
@@ -0,0 +1,58 @@ 
+// { dg-options "-std=gnu++0x" }
+
+// Copyright (C) 2010 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/>.
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// PR libstdc++/45924
+
+struct f
+{
+  f() : i(0) { }
+  f(f&& r) : i(1) { r.i = -1; }
+  f(const f&) = delete;
+  int operator()() { return i; }
+  int i;
+};
+
+void test01()
+{
+  auto b = std::bind(f());
+  VERIFY( b() == 1 );
+  auto bc(std::move(b));
+  VERIFY( bc() == 1 );
+  VERIFY( b() == -1 );
+}
+
+void test02()
+{
+  auto b = std::bind<int>(f());
+  VERIFY( b() == 1 );
+  auto bc(std::move(b));
+  VERIFY( bc() == 1 );
+  VERIFY( b() == -1 );
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
+