PR libstdc++/83427 detect weak result type from noexcept functions

Message ID 20171214172901.GA9983@redhat.com
State New
Headers show
Series
  • PR libstdc++/83427 detect weak result type from noexcept functions
Related show

Commit Message

Jonathan Wakely Dec. 14, 2017, 5:29 p.m.
Richard Smith pointed out that our "weak result type" implementation
(used by std::reference_wrapper and std::bind) doesn't work for
noexcept functions.

The simple fix is to adjust every partial specialization to include
noexcept deduction (which I'll do for gcc-7-branch), but I took the
opportunity to clean things up a bit on trunk. We already have the
required logic in _Mem_fn_traits, so I replaced all the partial
specializations for member function pointers with new helpers that use
_Mem_fn_traits. That adds support for ref-qualifiers as well, which
was missing.

I've also removed a number of useless partial specializations that can
never match anything. We don't need to support cv-qualified functions
types (so-called abominable function types) in std::bind, because you
can never call it with an argument of such a type, so I removed all
the _Weak_result_type_impl<R(Args...) cv> partial specializations. We
do need to support those types in std::reference_wrapper, but that
seems to be an obvious defect, so I've reported an issue to fix the
standard.  In the meanwhile I'm not adding noexcept deduction to those
specializations, because I want them to go away, not get fixed.
Finally, we also don't need _Weak_result_type_impl<R(&)(Args)> because
std::bind decays its functor, and reference_wrapper doesn't need a
weak result type for references to functions (and my defect report
might make them undefined anyway).

	PR libstdc++/83427
	* include/bits/refwrap.h (_Maybe_unary_or_binary_function): Move here
	from <bits/std_function.h>.
	(_Mem_fn_traits_base, _Mem_fn_traits): Move here, from <functional>.
	(_Weak_result_type_impl, _Reference_wrapper_base): Deduce noexcept
	for function types. Remove partial specializations for member
	functions.
	(_Weak_result_type_impl): Remove unused partial specializations for
	non-referenceable function types and for references to functions.
	(_Weak_result_type_memfun, _Reference_wrapper_base_memfun): New
	helpers to handle member functions via _Mem_fn_traits.
	(_Weak_result_type, reference_wrapper): Derive from new helpers.
	* include/bits/std_function.h (_Maybe_unary_or_binary_function): Move
	to <bits/refwrap.h>.
	* include/std/functional (_Pack, _AllConvertible, _NotSame): Remove.
	(_Mem_fn_traits_base, _Mem_fn_traits): Move to <bits/refwrap.h>.
	* testsuite/20_util/bind/83427.cc: New test.
	* testsuite/20_util/bind/refqual.cc: Add noexcept to functions and
	check for weak result types.
	* testsuite/20_util/reference_wrapper/83427.cc: New test.
        
Tested powerpc64le-linux, committed to trunk.
commit 0088fed20e8dadd79606876d896314e1dab19945
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Dec 14 16:07:15 2017 +0000

    PR libstdc++/83427 detect weak result type from noexcept functions
    
            PR libstdc++/83427
            * include/bits/refwrap.h (_Maybe_unary_or_binary_function): Move here
            from <bits/std_function.h>.
            (_Mem_fn_traits_base, _Mem_fn_traits): Move here, from <functional>.
            (_Weak_result_type_impl, _Reference_wrapper_base): Deduce noexcept
            for function types. Remove partial specializations for member
            functions.
            (_Weak_result_type_impl): Remove unused partial specializations for
            non-referenceable function types and for references to functions.
            (_Weak_result_type_memfun, _Reference_wrapper_base_memfun): New
            helpers to handle member functions via _Mem_fn_traits.
            (_Weak_result_type, reference_wrapper): Derive from new helpers.
            * include/bits/std_function.h (_Maybe_unary_or_binary_function): Move
            to <bits/refwrap.h>.
            * include/std/functional (_Pack, _AllConvertible, _NotSame): Remove.
            (_Mem_fn_traits_base, _Mem_fn_traits): Move to <bits/refwrap.h>.
            * testsuite/20_util/bind/83427.cc: New test.
            * testsuite/20_util/bind/refqual.cc: Add noexcept to functions and
            check for weak result types.
            * testsuite/20_util/reference_wrapper/83427.cc: New test.

Comments

Jonathan Wakely Dec. 14, 2017, 5:31 p.m. | #1
On 14/12/17 17:29 +0000, Jonathan Wakely wrote:
>Richard Smith pointed out that our "weak result type" implementation

>(used by std::reference_wrapper and std::bind) doesn't work for

>noexcept functions.

>

>The simple fix is to adjust every partial specialization to include

>noexcept deduction (which I'll do for gcc-7-branch), [...]


Here's the patch for the branch, which keeps all the partial
specializations for member functions, adding the deduction to them.

This doesn't remove the unused partial specializations, but also
doesn't "fix" them to detect noexcept.

Tested x86_64-linux, committed to trunk.
commit d12e6a7a3c605b95ee526bb6d11dbc286663492f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Dec 14 16:47:47 2017 +0000

    PR libstdc++/83427 detect weak result type from noexcept functions
    
            PR libstdc++/83427
            * include/bits/refwrap.h (_Weak_result_type_impl)
            (_Reference_wrapper_base): Deduce noexcept for function types.
            * testsuite/20_util/bind/83427.cc: New test.
            * testsuite/20_util/reference_wrapper/83427.cc: New test.

diff --git a/libstdc++-v3/include/bits/refwrap.h b/libstdc++-v3/include/bits/refwrap.h
index 124ee97bd2a..86260dac993 100644
--- a/libstdc++-v3/include/bits/refwrap.h
+++ b/libstdc++-v3/include/bits/refwrap.h
@@ -64,12 +64,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// Retrieve the result type for a function type.
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   template<typename _Res, typename... _ArgTypes>
@@ -106,50 +106,65 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { typedef _Res result_type; };
 
   /// Retrieve the result type for a function pointer.
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(*)(_ArgTypes...)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(*)(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(*)(_ArgTypes......)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(*)(_ArgTypes......)
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   /// Retrieve result type for a member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...)>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...)
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......)>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......)
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   /// Retrieve result type for a const member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...) const>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...) const
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......) const>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......) const
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   /// Retrieve result type for a volatile member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...) volatile>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...) volatile
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......) volatile>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......) volatile
+				  _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   /// Retrieve result type for a const volatile member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
     struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...)
-				  const volatile>
+				  const volatile _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
+  template<typename _Res, typename _Class, typename... _ArgTypes
+	   _GLIBCXX_NOEXCEPT_PARM>
     struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......)
-				  const volatile>
+				  const volatile _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   /**
@@ -201,8 +216,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // - a function type (unary)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res(_T1)>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(_T1) _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<_T1, _Res>
     { };
 
@@ -222,8 +237,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // - a function type (binary)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res(_T1, _T2)>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(_T1, _T2) _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<_T1, _T2, _Res>
     { };
 
@@ -243,62 +258,62 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // - a function pointer type (unary)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res(*)(_T1)>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(*)(_T1) _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<_T1, _Res>
     { };
 
   // - a function pointer type (binary)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res(*)(_T1, _T2)>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(*)(_T1, _T2) _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<_T1, _T2, _Res>
     { };
 
   // - a pointer to member function type (unary, no qualifiers)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)()>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)() _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<_T1*, _Res>
     { };
 
   // - a pointer to member function type (binary, no qualifiers)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2)>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<_T1*, _T2, _Res>
     { };
 
   // - a pointer to member function type (unary, const)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)() const>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)() const _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<const _T1*, _Res>
     { };
 
   // - a pointer to member function type (binary, const)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<const _T1*, _T2, _Res>
     { };
 
   // - a pointer to member function type (unary, volatile)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)() volatile>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)() volatile _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<volatile _T1*, _Res>
     { };
 
   // - a pointer to member function type (binary, volatile)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) volatile>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) volatile _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<volatile _T1*, _T2, _Res>
     { };
 
   // - a pointer to member function type (unary, const volatile)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)() const volatile>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)() const volatile _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<const volatile _T1*, _Res>
     { };
 
   // - a pointer to member function type (binary, const volatile)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const volatile>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const volatile _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<const volatile _T1*, _T2, _Res>
     { };
 
diff --git a/libstdc++-v3/testsuite/20_util/bind/83427.cc b/libstdc++-v3/testsuite/20_util/bind/83427.cc
new file mode 100644
index 00000000000..3b8a6506966
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bind/83427.cc
@@ -0,0 +1,31 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <functional>
+
+// PR libstdc++/83427
+
+int f() noexcept { return 0; }
+auto b = std::bind(f);
+static_assert(std::is_same_v<decltype(b)::result_type, int>);
+
+struct X { long f() const noexcept { return 0L; } };
+auto b2 = std::bind(&X::f, X{});
+static_assert(std::is_same_v<decltype(b2)::result_type, long>);
diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/83427.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/83427.cc
new file mode 100644
index 00000000000..170caf92045
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/83427.cc
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <functional>
+
+// PR libstdc++/83427
+
+int f(short) noexcept { return 0; }
+std::reference_wrapper<decltype(f)> r(f);
+static_assert(std::is_same_v<decltype(r)::result_type, int>);
+static_assert(std::is_same_v<decltype(r)::argument_type, short>);
+
+auto* p = &f;
+std::reference_wrapper<decltype(&f)> r2(p);
+static_assert(std::is_same_v<decltype(r2)::result_type, int>);
+static_assert(std::is_same_v<decltype(r2)::argument_type, short>);
+
+struct X { long f() const noexcept { return 0L; } };
+auto m = &X::f;
+std::reference_wrapper<decltype(m)> r3(m);
+static_assert(std::is_same_v<decltype(r3)::result_type, long>);
+static_assert(std::is_same_v<decltype(r3)::argument_type, const X*>);

Patch

diff --git a/libstdc++-v3/include/bits/refwrap.h b/libstdc++-v3/include/bits/refwrap.h
index 5e5b61060e3..1b64cd8fbf5 100644
--- a/libstdc++-v3/include/bits/refwrap.h
+++ b/libstdc++-v3/include/bits/refwrap.h
@@ -44,6 +44,69 @@  namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  /**
+   * Derives from @c unary_function or @c binary_function, or perhaps
+   * nothing, depending on the number of arguments provided. The
+   * primary template is the basis case, which derives nothing.
+   */
+  template<typename _Res, typename... _ArgTypes>
+    struct _Maybe_unary_or_binary_function { };
+
+  /// Derives from @c unary_function, as appropriate.
+  template<typename _Res, typename _T1>
+    struct _Maybe_unary_or_binary_function<_Res, _T1>
+    : std::unary_function<_T1, _Res> { };
+
+  /// Derives from @c binary_function, as appropriate.
+  template<typename _Res, typename _T1, typename _T2>
+    struct _Maybe_unary_or_binary_function<_Res, _T1, _T2>
+    : std::binary_function<_T1, _T2, _Res> { };
+
+  template<typename _Signature>
+    struct _Mem_fn_traits;
+
+  template<typename _Res, typename _Class, typename... _ArgTypes>
+    struct _Mem_fn_traits_base
+    {
+      using __result_type = _Res;
+      using __maybe_type
+	= _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...>;
+      using __arity = integral_constant<size_t, sizeof...(_ArgTypes)>;
+    };
+
+#define _GLIBCXX_MEM_FN_TRAITS2(_CV, _REF, _LVAL, _RVAL)		\
+  template<typename _Res, typename _Class, typename... _ArgTypes>	\
+    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) _CV _REF>	\
+    : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...>		\
+    {									\
+      using __vararg = false_type;					\
+    };									\
+  template<typename _Res, typename _Class, typename... _ArgTypes>	\
+    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes... ...) _CV _REF>	\
+    : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...>		\
+    {									\
+      using __vararg = true_type;					\
+    };
+
+#define _GLIBCXX_MEM_FN_TRAITS(_REF, _LVAL, _RVAL)		\
+  _GLIBCXX_MEM_FN_TRAITS2(		, _REF, _LVAL, _RVAL)	\
+  _GLIBCXX_MEM_FN_TRAITS2(const		, _REF, _LVAL, _RVAL)	\
+  _GLIBCXX_MEM_FN_TRAITS2(volatile	, _REF, _LVAL, _RVAL)	\
+  _GLIBCXX_MEM_FN_TRAITS2(const volatile, _REF, _LVAL, _RVAL)
+
+_GLIBCXX_MEM_FN_TRAITS( , true_type, true_type)
+_GLIBCXX_MEM_FN_TRAITS(&, true_type, false_type)
+_GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
+
+#if __cplusplus > 201402L
+_GLIBCXX_MEM_FN_TRAITS(noexcept, true_type, true_type)
+_GLIBCXX_MEM_FN_TRAITS(& noexcept, true_type, false_type)
+_GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type)
+#endif
+
+#undef _GLIBCXX_MEM_FN_TRAITS
+#undef _GLIBCXX_MEM_FN_TRAITS2
+
   /// If we have found a result_type, extract it.
   template<typename _Functor, typename = __void_t<>>
     struct _Maybe_get_result_type
@@ -64,101 +127,52 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// Retrieve the result type for a function type.
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes...) volatile>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes......) volatile>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes...) const volatile>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(_ArgTypes......) const volatile>
-    { typedef _Res result_type; };
-
-  /// Retrieve the result type for a function reference.
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(&)(_ArgTypes...)>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(&)(_ArgTypes......)>
+  /// Retrieve the result type for a varargs function type.
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
   /// Retrieve the result type for a function pointer.
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(*)(_ArgTypes...)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct _Weak_result_type_impl<_Res(*)(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res(*)(_ArgTypes......)>
+  /// Retrieve the result type for a varargs function pointer.
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct
+    _Weak_result_type_impl<_Res(*)(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
     { typedef _Res result_type; };
 
-  /// Retrieve result type for a member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...)>
-    { typedef _Res result_type; };
+  // Let _Weak_result_type_impl perform the real work.
+  template<typename _Functor,
+	   bool = is_member_function_pointer<_Functor>::value>
+    struct _Weak_result_type_memfun
+    : _Weak_result_type_impl<_Functor>
+    { };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......)>
-    { typedef _Res result_type; };
+  // A pointer to member function has a weak result type.
+  template<typename _MemFunPtr>
+    struct _Weak_result_type_memfun<_MemFunPtr, true>
+    {
+      using result_type = typename _Mem_fn_traits<_MemFunPtr>::__result_type;
+    };
 
-  /// Retrieve result type for a const member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...) const>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......) const>
-    { typedef _Res result_type; };
-
-  /// Retrieve result type for a volatile member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...) volatile>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......) volatile>
-    { typedef _Res result_type; };
-
-  /// Retrieve result type for a const volatile member function pointer.
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes...)
-				  const volatile>
-    { typedef _Res result_type; };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Weak_result_type_impl<_Res (_Class::*)(_ArgTypes......)
-				  const volatile>
-    { typedef _Res result_type; };
+  // A pointer to data member doesn't have a weak result type.
+  template<typename _Func, typename _Class>
+    struct _Weak_result_type_memfun<_Func _Class::*, false>
+    { };
 
   /**
    *  Strip top-level cv-qualifiers from the function object and let
-   *  _Weak_result_type_impl perform the real work.
+   *  _Weak_result_type_memfun perform the real work.
   */
   template<typename _Functor>
     struct _Weak_result_type
-    : _Weak_result_type_impl<typename remove_cv<_Functor>::type>
+    : _Weak_result_type_memfun<typename remove_cv<_Functor>::type>
     { };
 
   // Detect nested argument_type.
@@ -201,8 +215,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // - a function type (unary)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res(_T1)>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(_T1) _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<_T1, _Res>
     { };
 
@@ -222,8 +236,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // - a function type (binary)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res(_T1, _T2)>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(_T1, _T2) _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<_T1, _T2, _Res>
     { };
 
@@ -243,64 +257,28 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   // - a function pointer type (unary)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res(*)(_T1)>
+  template<typename _Res, typename _T1 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(*)(_T1) _GLIBCXX_NOEXCEPT_QUAL>
     : unary_function<_T1, _Res>
     { };
 
   // - a function pointer type (binary)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res(*)(_T1, _T2)>
+  template<typename _Res, typename _T1, typename _T2 _GLIBCXX_NOEXCEPT_PARM>
+    struct _Reference_wrapper_base<_Res(*)(_T1, _T2) _GLIBCXX_NOEXCEPT_QUAL>
     : binary_function<_T1, _T2, _Res>
     { };
 
-  // - a pointer to member function type (unary, no qualifiers)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)()>
-    : unary_function<_T1*, _Res>
+  template<typename _Tp, bool = is_member_function_pointer<_Tp>::value>
+    struct _Reference_wrapper_base_memfun
+    : _Reference_wrapper_base<_Tp>
     { };
 
-  // - a pointer to member function type (binary, no qualifiers)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2)>
-    : binary_function<_T1*, _T2, _Res>
-    { };
-
-  // - a pointer to member function type (unary, const)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)() const>
-    : unary_function<const _T1*, _Res>
-    { };
-
-  // - a pointer to member function type (binary, const)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const>
-    : binary_function<const _T1*, _T2, _Res>
-    { };
-
-  // - a pointer to member function type (unary, volatile)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)() volatile>
-    : unary_function<volatile _T1*, _Res>
-    { };
-
-  // - a pointer to member function type (binary, volatile)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) volatile>
-    : binary_function<volatile _T1*, _T2, _Res>
-    { };
-
-  // - a pointer to member function type (unary, const volatile)
-  template<typename _Res, typename _T1>
-    struct _Reference_wrapper_base<_Res (_T1::*)() const volatile>
-    : unary_function<const volatile _T1*, _Res>
-    { };
-
-  // - a pointer to member function type (binary, const volatile)
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Reference_wrapper_base<_Res (_T1::*)(_T2) const volatile>
-    : binary_function<const volatile _T1*, _T2, _Res>
-    { };
+  template<typename _MemFunPtr>
+    struct _Reference_wrapper_base_memfun<_MemFunPtr, true>
+    : _Mem_fn_traits<_MemFunPtr>::__maybe_type
+    {
+      using result_type = typename _Mem_fn_traits<_MemFunPtr>::__result_type;
+    };
 
   /**
    *  @brief Primary class template for reference_wrapper.
@@ -309,7 +287,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
    */
   template<typename _Tp>
     class reference_wrapper
-    : public _Reference_wrapper_base<typename remove_cv<_Tp>::type>
+    : public _Reference_wrapper_base_memfun<typename remove_cv<_Tp>::type>
     {
       _Tp* _M_data;
 
diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h
index a9ba7567b33..94b7ee99067 100644
--- a/libstdc++-v3/include/bits/std_function.h
+++ b/libstdc++-v3/include/bits/std_function.h
@@ -49,25 +49,6 @@  namespace std _GLIBCXX_VISIBILITY(default)
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /**
-   * Derives from @c unary_function or @c binary_function, or perhaps
-   * nothing, depending on the number of arguments provided. The
-   * primary template is the basis case, which derives nothing.
-   */
-  template<typename _Res, typename... _ArgTypes>
-    struct _Maybe_unary_or_binary_function { };
-
-  /// Derives from @c unary_function, as appropriate.
-  template<typename _Res, typename _T1>
-    struct _Maybe_unary_or_binary_function<_Res, _T1>
-    : std::unary_function<_T1, _Res> { };
-
-  /// Derives from @c binary_function, as appropriate.
-  template<typename _Res, typename _T1, typename _T2>
-    struct _Maybe_unary_or_binary_function<_Res, _T1, _T2>
-    : std::binary_function<_T1, _T2, _Res> { };
-
-
-  /**
    *  @brief Exception class thrown when class template function's
    *  operator() is called with an empty target.
    *  @ingroup exceptions
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index a6d121bb150..f94c63b213e 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -55,7 +55,8 @@ 
 #include <type_traits>
 #include <bits/functional_hash.h>
 #include <bits/invoke.h>
-#include <bits/std_function.h>
+#include <bits/refwrap.h>	// std::reference_wrapper and _Mem_fn_traits
+#include <bits/std_function.h>	// std::function
 #if __cplusplus > 201402L
 # include <unordered_map>
 # include <vector>
@@ -82,68 +83,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 #endif
 
-  template<typename... _Types>
-    struct _Pack : integral_constant<size_t, sizeof...(_Types)>
-    { };
-
-  template<typename _From, typename _To, bool = _From::value == _To::value>
-    struct _AllConvertible : false_type
-    { };
-
-  template<typename... _From, typename... _To>
-    struct _AllConvertible<_Pack<_From...>, _Pack<_To...>, true>
-    : __and_<is_convertible<_From, _To>...>
-    { };
-
-  template<typename _Tp1, typename _Tp2>
-    using _NotSame = __not_<is_same<typename std::decay<_Tp1>::type,
-				    typename std::decay<_Tp2>::type>>;
-
-  template<typename _Signature>
-    struct _Mem_fn_traits;
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits_base
-    {
-      using __result_type = _Res;
-      using __maybe_type
-	= _Maybe_unary_or_binary_function<_Res, _Class*, _ArgTypes...>;
-      using __arity = integral_constant<size_t, sizeof...(_ArgTypes)>;
-    };
-
-#define _GLIBCXX_MEM_FN_TRAITS2(_CV, _REF, _LVAL, _RVAL)		\
-  template<typename _Res, typename _Class, typename... _ArgTypes>	\
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) _CV _REF>	\
-    : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...>		\
-    {									\
-      using __vararg = false_type;					\
-    };									\
-  template<typename _Res, typename _Class, typename... _ArgTypes>	\
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes... ...) _CV _REF>	\
-    : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...>		\
-    {									\
-      using __vararg = true_type;					\
-    };
-
-#define _GLIBCXX_MEM_FN_TRAITS(_REF, _LVAL, _RVAL)		\
-  _GLIBCXX_MEM_FN_TRAITS2(		, _REF, _LVAL, _RVAL)	\
-  _GLIBCXX_MEM_FN_TRAITS2(const		, _REF, _LVAL, _RVAL)	\
-  _GLIBCXX_MEM_FN_TRAITS2(volatile	, _REF, _LVAL, _RVAL)	\
-  _GLIBCXX_MEM_FN_TRAITS2(const volatile, _REF, _LVAL, _RVAL)
-
-_GLIBCXX_MEM_FN_TRAITS( , true_type, true_type)
-_GLIBCXX_MEM_FN_TRAITS(&, true_type, false_type)
-_GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
-
-#if __cplusplus > 201402L
-_GLIBCXX_MEM_FN_TRAITS(noexcept, true_type, true_type)
-_GLIBCXX_MEM_FN_TRAITS(& noexcept, true_type, false_type)
-_GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type)
-#endif
-
-#undef _GLIBCXX_MEM_FN_TRAITS
-#undef _GLIBCXX_MEM_FN_TRAITS2
-
   template<typename _MemFunPtr,
 	   bool __is_mem_fn = is_member_function_pointer<_MemFunPtr>::value>
     class _Mem_fn_base
diff --git a/libstdc++-v3/testsuite/20_util/bind/83427.cc b/libstdc++-v3/testsuite/20_util/bind/83427.cc
new file mode 100644
index 00000000000..e96841435f2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bind/83427.cc
@@ -0,0 +1,31 @@ 
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <functional>
+
+// PR libstdc++/83427
+
+int f() noexcept { return 0; }
+auto b = std::bind(f);
+static_assert(std::is_same_v<decltype(b)::result_type, int>);
+
+struct X { long f() const & noexcept { return 0L; } };
+auto b2 = std::bind(&X::f, X{});
+static_assert(std::is_same_v<decltype(b2)::result_type, long>);
diff --git a/libstdc++-v3/testsuite/20_util/bind/refqual.cc b/libstdc++-v3/testsuite/20_util/bind/refqual.cc
index e7088746607..09fe6d52d37 100644
--- a/libstdc++-v3/testsuite/20_util/bind/refqual.cc
+++ b/libstdc++-v3/testsuite/20_util/bind/refqual.cc
@@ -22,8 +22,8 @@ 
 
 struct X
 {
-  int f() const& { return 0; }
-  int g(int i, ...)& { return i; }
+  int f() const& noexcept { return 0; }
+  int g(int i, ...)& noexcept { return i; }
 };
 
 void
@@ -34,6 +34,10 @@  test01()
   VERIFY( b() == 0 );
   auto bb = std::bind(&X::g, &x, 1, 2);
   VERIFY( bb() == 1 );
+
+  // Check for weak result types:
+  using T1 = decltype(b)::result_type;
+  using T2 = decltype(bb)::result_type;
 }
 
 int
diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/83427.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/83427.cc
new file mode 100644
index 00000000000..c4b360f0bb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/83427.cc
@@ -0,0 +1,39 @@ 
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <functional>
+
+// PR libstdc++/83427
+
+int f(short) noexcept { return 0; }
+std::reference_wrapper<decltype(f)> r(f);
+static_assert(std::is_same_v<decltype(r)::result_type, int>);
+static_assert(std::is_same_v<decltype(r)::argument_type, short>);
+
+auto* p = &f;
+std::reference_wrapper<decltype(&f)> r2(p);
+static_assert(std::is_same_v<decltype(r2)::result_type, int>);
+static_assert(std::is_same_v<decltype(r2)::argument_type, short>);
+
+struct X { long f() const & noexcept { return 0L; } };
+auto m = &X::f;
+std::reference_wrapper<decltype(m)> r3(m);
+static_assert(std::is_same_v<decltype(r3)::result_type, long>);
+static_assert(std::is_same_v<decltype(r3)::argument_type, const X*>);