From c5a2375241372f3c2106878a91843c3285fb72be Mon Sep 17 00:00:00 2001
From: Jonathan Wakely <jwakely.gcc@gmail.com>
Date: Thu, 24 Dec 2009 14:54:33 +0000
Subject: [PATCH] functional (bind): Avoid invalid instantiations for
 bind<void>.

2009-12-24  Jonathan Wakely  <jwakely.gcc@gmail.com>

	* include/std/functional (bind): Avoid invalid instantiations
	for bind<void>.
	* testsuite/20_util/bind/conv_result.cc: New.

From-SVN: r155457
---
 libstdc++-v3/ChangeLog                        |  6 ++
 libstdc++-v3/include/std/functional           | 87 ++++++++++++++++---
 .../testsuite/20_util/bind/conv_result.cc     | 49 +++++++++++
 3 files changed, 128 insertions(+), 14 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/20_util/bind/conv_result.cc

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 4ca96b2878aa..ad2d892c83ab 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,9 @@
+2009-12-24  Jonathan Wakely  <jwakely.gcc@gmail.com>
+
+	* include/std/functional (bind): Avoid invalid instantiations
+	for bind<void>.
+	* testsuite/20_util/bind/conv_result.cc: New.
+
 2009-12-24  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	* include/bits/stl_deque.h (copy_backward(_Deque_iterator,
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 19503bdf05e0..3be8ed76c3ec 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -1130,6 +1130,16 @@ namespace std
       { return type(__pm); }
     };
 
+  // Specialization needed to prevent "forming reference to void" errors when
+  // bind<void>() is called, because argument deduction instantiates
+  // _Maybe_wrap_member_pointer<void> outside the immediate context where
+  // SFINAE applies.
+  template<>
+    struct _Maybe_wrap_member_pointer<void>
+    {
+      typedef void type;
+    };
+
   /// Type of the function object returned from bind().
   template<typename _Signature>
     struct _Bind;
@@ -1262,44 +1272,93 @@ namespace std
       _Functor _M_f;
       tuple<_Bound_args...> _M_bound_args;
 
+      // sfinae types
+      template<typename _Res>
+        struct __enable_if_void : enable_if<is_void<_Res>::value, int> { };
+      template<typename _Res>
+        struct __disable_if_void : enable_if<!is_void<_Res>::value, int> { };
+
       // Call unqualified
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>)
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0)
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call unqualified, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0)
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
       // Call as const
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>) const
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0) const
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call as const, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0) const
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
       // Call as volatile
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, 
-               _Index_tuple<_Indexes...>) volatile
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0) volatile
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call as volatile, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0) volatile
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
       // Call as const volatile
-      template<typename... _Args, int... _Indexes>
+      template<typename _Res, typename... _Args, int... _Indexes>
         _Result
-        __call(const tuple<_Args...>& __args, 
-               _Index_tuple<_Indexes...>) const volatile
+        __call(const tuple<_Args...>& __args, _Index_tuple<_Indexes...>,
+            typename __disable_if_void<_Res>::type = 0) const volatile
         {
           return _M_f(_Mu<_Bound_args>()
                       (get<_Indexes>(_M_bound_args), __args)...);
         }
 
+      // Call as const volatile, return void
+      template<typename _Res, typename... _Args, int... _Indexes>
+        void
+        __call(const tuple<_Args...>& __args, 
+               _Index_tuple<_Indexes...>,
+            typename __enable_if_void<_Res>::type = 0) const volatile
+        {
+          _M_f(_Mu<_Bound_args>()
+                      (get<_Indexes>(_M_bound_args), __args)...);
+        }
+
     public:
       typedef _Result result_type;
 
@@ -1312,7 +1371,7 @@ namespace std
         result_type
         operator()(_Args&... __args)
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
 
       // Call as const
@@ -1320,7 +1379,7 @@ namespace std
         result_type
         operator()(_Args&... __args) const
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
 
       // Call as volatile
@@ -1328,7 +1387,7 @@ namespace std
         result_type
         operator()(_Args&... __args) volatile
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
 
       // Call as const volatile
@@ -1336,7 +1395,7 @@ namespace std
         result_type
         operator()(_Args&... __args) const volatile
         {
-          return this->__call(tie(__args...), _Bound_indexes());
+          return this->__call<_Result>(tie(__args...), _Bound_indexes());
         }
     };
 
diff --git a/libstdc++-v3/testsuite/20_util/bind/conv_result.cc b/libstdc++-v3/testsuite/20_util/bind/conv_result.cc
new file mode 100644
index 000000000000..440a5276bdfc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bind/conv_result.cc
@@ -0,0 +1,49 @@
+// { dg-options "-std=gnu++0x" }
+// Copyright (C) 2009 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/>.
+
+// 20.7.11 Function template bind
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct X
+{
+  typedef int result_type;
+  int operator()(int i) const { return i+1; }
+  bool b;
+};
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  using std::bind;
+  using std::ref;
+  ::X x = { true };
+
+  // test bind<R> form
+  bind<void>(ref(x), 1)();
+  VERIFY( bind<long>(ref(x), 1)() == 2 );
+  bind<void>(&::X::b, ref(x))();
+  VERIFY( bind<int>(&::X::b, ref(x))() == 1 );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
-- 
GitLab