The first patch fixes an inconsistency between the return type and the
function body, as described in the PR.

The second patch removes the TR1 return type support from _Mu, because
it isn't necessary in C++11. The third patch is because the second one
accidentally removed a "volatile" (removing that is fine, because we
never create volatile _Mu, or even a const one, but no point removing
it on only one specialization and leaving it elsewhere).

Tested powerpc64le-linux.

I've committed both to trunk and will apply the first patch (but not
the second and third) to the branches too.
commit 430066b306ddcd35982a748a34bf3603261f9050
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Dec 15 12:20:01 2015 +0000

    Fix cv-qualifiers in std::bind invocation
    
        PR libstdc++/68912
        * include/std/functional (_Bind::operator()): Use lvalue functor to
        deduce return type.
        * testsuite/20_util/bind/68912.cc: New.

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 19caa96..8d39d62 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -1034,7 +1034,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
 
       // Call unqualified
       template<typename... _Args, typename _Result
-       = decltype( std::declval<_Functor>()(
+       = decltype( std::declval<_Functor&>()(
              _Mu<_Bound_args>()( std::declval<_Bound_args&>(),
                                  std::declval<tuple<_Args...>&>() )... ) )>
        _Result
@@ -1048,7 +1048,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
       // Call as const
       template<typename... _Args, typename _Result
        = decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
-                      typename add_const<_Functor>::type>::type>()(
+                      typename add_const<_Functor>::type&>::type>()(
              _Mu<_Bound_args>()( std::declval<const _Bound_args&>(),
                                  std::declval<tuple<_Args...>&>() )... ) )>
        _Result
@@ -1062,7 +1062,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
       // Call as volatile
       template<typename... _Args, typename _Result
        = decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
-                       typename add_volatile<_Functor>::type>::type>()(
+                       typename add_volatile<_Functor>::type&>::type>()(
              _Mu<_Bound_args>()( std::declval<volatile _Bound_args&>(),
                                  std::declval<tuple<_Args...>&>() )... ) )>
        _Result
@@ -1076,7 +1076,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
       // Call as const volatile
       template<typename... _Args, typename _Result
        = decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
-                       typename add_cv<_Functor>::type>::type>()(
+                       typename add_cv<_Functor>::type&>::type>()(
              _Mu<_Bound_args>()( std::declval<const volatile _Bound_args&>(),
                                  std::declval<tuple<_Args...>&>() )... ) )>
        _Result
diff --git a/libstdc++-v3/testsuite/20_util/bind/68912.cc 
b/libstdc++-v3/testsuite/20_util/bind/68912.cc
new file mode 100644
index 0000000..7a00b75
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bind/68912.cc
@@ -0,0 +1,53 @@
+// Copyright (C) 2015 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++11" }
+// { dg-do compile }
+
+#include<functional>
+
+struct Wrong {};
+struct A {};
+struct B {};
+struct C{};
+struct D{};
+
+struct X {
+  A operator()(int, double) & { return {}; }
+  Wrong operator()(int, double) && {return {}; }
+
+  B operator()(int, double) const & { return {}; }
+  Wrong operator()(int, double) const && {return {}; }
+
+  C operator()(int, double) volatile & { return {}; }
+  Wrong operator()(int, double) volatile && {return {}; }
+
+  D operator()(int, double) const volatile & { return {}; }
+  Wrong operator()(int, double) const volatile && {return {}; }
+};
+
+void test01()
+{
+  auto bound = std::bind(X{}, 5, std::placeholders::_1);
+  A res = bound(1.0);
+  const auto bound_c = bound;
+  B res_c = bound_c(1.0);
+  volatile auto bound_v = bound;
+  C res_v = bound_v(1.0);
+  volatile const auto bound_cv = bound;
+  D res_cv = bound_cv(1.0);
+}
commit 44698303952f8e1215756adf53f72ca72cf0c59d
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Dec 15 13:16:58 2015 +0000

    Remove vestigial traces of std::tr1::bind
    
        * include/std/functional (is_placeholder, is_bind_expression): Update
        comments.
        (_Safe_tuple_element): Replace with _Safe_tuple_element_t alias
        template.
        (_Mu): Remove vestigial TR1 return types and update coments.

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 8d39d62..99af29e 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -654,9 +654,11 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
     }
 
   /**
-   *  @brief Determines if the given type _Tp is a function object
+   *  @brief Determines if the given type _Tp is a function object that
    *  should be treated as a subexpression when evaluating calls to
-   *  function objects returned by bind(). [TR1 3.6.1]
+   *  function objects returned by bind().
+   *
+   *  C++11 [func.bind.isbind].
    *  @ingroup binders
    */
   template<typename _Tp>
@@ -665,7 +667,9 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
 
   /**
    *  @brief Determines if the given type _Tp is a placeholder in a
-   *  bind() expression and, if so, which placeholder it is. [TR1 3.6.2]
+   *  bind() expression and, if so, which placeholder it is.
+   *
+   *  C++11 [func.bind.isplace].
    *  @ingroup binders
    */
   template<typename _Tp>
@@ -740,45 +744,16 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
     : public integral_constant<int, _Num>
     { };
 
-  /**
-   * Used by _Safe_tuple_element to indicate that there is no tuple
-   * element at this position.
-   */
-  struct _No_tuple_element;
 
-  /**
-   * Implementation helper for _Safe_tuple_element. This primary
-   * template handles the case where it is safe to use @c
-   * tuple_element.
-   */
-  template<std::size_t __i, typename _Tuple, bool _IsSafe>
-    struct _Safe_tuple_element_impl
-    : tuple_element<__i, _Tuple> { };
-
-  /**
-   * Implementation helper for _Safe_tuple_element. This partial
-   * specialization handles the case where it is not safe to use @c
-   * tuple_element. We just return @c _No_tuple_element.
-   */
-  template<std::size_t __i, typename _Tuple>
-    struct _Safe_tuple_element_impl<__i, _Tuple, false>
-    {
-      typedef _No_tuple_element type;
-    };
-
-  /**
-   * Like tuple_element, but returns @c _No_tuple_element when
-   * tuple_element would return an error.
-   */
+  // Like tuple_element_t but SFINAE-friendly.
  template<std::size_t __i, typename _Tuple>
-   struct _Safe_tuple_element
-   : _Safe_tuple_element_impl<__i, _Tuple,
-                             (__i < tuple_size<_Tuple>::value)>
-   { };
+   using _Safe_tuple_element_t
+     = typename enable_if<(__i < tuple_size<_Tuple>::value),
+                         tuple_element<__i, _Tuple>>::type::type;
 
   /**
    *  Maps an argument to bind() into an actual argument to the bound
-   *  function object [TR1 3.6.3/5]. Only the first parameter should
+   *  function object [func.bind.bind]/10. Only the first parameter should
    *  be specified: the rest are used to determine among the various
    *  implementations. Note that, although this class is a function
    *  object, it isn't entirely normal because it takes only two
@@ -794,20 +769,19 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
 
   /**
    *  If the argument is reference_wrapper<_Tp>, returns the
-   *  underlying reference. [TR1 3.6.3/5 bullet 1]
+   *  underlying reference.
+   *  C++11 [func.bind.bind] p10 bullet 1.
    */
   template<typename _Tp>
     class _Mu<reference_wrapper<_Tp>, false, false>
     {
     public:
-      typedef _Tp& result_type;
-
       /* Note: This won't actually work for const volatile
        * reference_wrappers, because reference_wrapper::get() is const
        * but not volatile-qualified. This might be a defect in the TR.
        */
       template<typename _CVRef, typename _Tuple>
-       result_type
+       _Tp&
        operator()(_CVRef& __arg, _Tuple&) const volatile
        { return __arg.get(); }
     };
@@ -815,7 +789,8 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
   /**
    *  If the argument is a bind expression, we invoke the underlying
    *  function object with the same cv-qualifiers as we are given and
-   *  pass along all of our arguments (unwrapped). [TR1 3.6.3/5 bullet 2]
+   *  pass along all of our arguments (unwrapped).
+   *  C++11 [func.bind.bind] p10 bullet 2.
    */
   template<typename _Arg>
     class _Mu<_Arg, true, false>
@@ -849,58 +824,35 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
   /**
    *  If the argument is a placeholder for the Nth argument, returns
    *  a reference to the Nth argument to the bind function object.
-   *  [TR1 3.6.3/5 bullet 3]
+   *  C++11 [func.bind.bind] p10 bullet 3.
    */
   template<typename _Arg>
     class _Mu<_Arg, false, true>
     {
     public:
-      template<typename _Signature> class result;
-
-      template<typename _CVMu, typename _CVArg, typename _Tuple>
-       class result<_CVMu(_CVArg, _Tuple)>
-       {
-         // Add a reference, if it hasn't already been done for us.
-         // This allows us to be a little bit sloppy in constructing
-         // the tuple that we pass to result_of<...>.
-         typedef typename _Safe_tuple_element<(is_placeholder<_Arg>::value
-                                               - 1), _Tuple>::type
-           __base_type;
-
-       public:
-         typedef typename add_rvalue_reference<__base_type>::type type;
-       };
-
       template<typename _Tuple>
-       typename result<_Mu(_Arg, _Tuple)>::type
+       _Safe_tuple_element_t<(is_placeholder<_Arg>::value - 1), _Tuple>&&
        operator()(const volatile _Arg&, _Tuple& __tuple) const volatile
        {
-         return std::forward<typename result<_Mu(_Arg, _Tuple)>::type>(
+         using __type
+           = __tuple_element_t<(is_placeholder<_Arg>::value - 1), _Tuple>;
+         return std::forward<__type>(
              ::std::get<(is_placeholder<_Arg>::value - 1)>(__tuple));
        }
     };
 
   /**
    *  If the argument is just a value, returns a reference to that
-   *  value. The cv-qualifiers on the reference are the same as the
-   *  cv-qualifiers on the _Mu object. [TR1 3.6.3/5 bullet 4]
+   *  value. The cv-qualifiers on the reference are determined by the caller.
+   *  C++11 [func.bind.bind] p10 bullet 4.
    */
   template<typename _Arg>
     class _Mu<_Arg, false, false>
     {
     public:
-      template<typename _Signature> struct result;
-
-      template<typename _CVMu, typename _CVArg, typename _Tuple>
-       struct result<_CVMu(_CVArg, _Tuple)>
-       {
-         typedef typename add_lvalue_reference<_CVArg>::type 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
        { return std::forward<_CVArg>(__arg); }
     };
 
commit 59f967f86f9b06373e6a5b4e3703df234e61dd08
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Dec 15 14:23:43 2015 +0000

    Restore accidentally-removed volatile qualifier
    
        * include/std/functional (_Mu<_Arg, false, false>::operator()): Restore
        accidentally-removed volatile qualifier.

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 99af29e..ff29a57 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -852,7 +852,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
     public:
       template<typename _CVArg, typename _Tuple>
        _CVArg&&
-       operator()(_CVArg&& __arg, _Tuple&) const
+       operator()(_CVArg&& __arg, _Tuple&) const volatile
        { return std::forward<_CVArg>(__arg); }
     };
 

Reply via email to