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