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

Jonathan Wakely jwakely@redhat.com
Thu Dec 14 17:29:00 GMT 2017


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.

-------------- next part --------------
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.

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*>);


More information about the Libstdc++ mailing list