From: Jonathan Wakely Date: Fri, 11 Dec 2015 21:45:51 +0000 (+0000) Subject: Fix std::invoke support for reference_wrappers X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f3d7dd52a6e8c379f7f90cb547e2cd186fa07653;p=gcc.git Fix std::invoke support for reference_wrappers PR libstdc++/59768 * include/std/functional (_Unwrap, __invfwd): Define. (__invoke_impl): Remove reference_wrapper overloads and use __invfwd. * include/std/type_traits (__result_of_memobj, __result_of_memfun): Add partial specializations for const reference_wrappers and simplify. * testsuite/20_util/bind/ref_neg.cc: Use dg-excess-errors. * testsuite/20_util/function_objects/invoke/59768.cc: New. From-SVN: r231574 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f982946a757..ae1bbc0fc58 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,13 @@ +2015-12-11 Jonathan Wakely + + PR libstdc++/59768 + * include/std/functional (_Unwrap, __invfwd): Define. + (__invoke_impl): Remove reference_wrapper overloads and use __invfwd. + * include/std/type_traits (__result_of_memobj, __result_of_memfun): + Add partial specializations for const reference_wrappers and simplify. + * testsuite/20_util/bind/ref_neg.cc: Use dg-excess-errors. + * testsuite/20_util/function_objects/invoke/59768.cc: New. + 2015-12-11 Ville Voutilainen PR libstdc++/68139 diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index f1dc8393af8..19caa96b08a 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -184,6 +184,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Weak_result_type_impl::type> { }; + template::type> + struct _Unwrap + { + using type = _Tp&&; + + // Equivalent to std::forward<_Tp> + static constexpr _Tp&& + _S_fwd(_Tp& __t) noexcept { return static_cast<_Tp&&>(__t); } + }; + + template + struct _Unwrap<_Tp, reference_wrapper<_Up>> + { + using type = _Up&; + + // Get an lvalue-reference from a reference_wrapper. + static _Up& + _S_fwd(const _Tp& __t) noexcept { __t.get(); } + }; + + // Used by __invoke_impl instead of std::forward<_Tp> so that a + // reference_wrapper is converted to an lvalue-reference. + template + typename _Unwrap<_Tp>::type + __invfwd(typename remove_reference<_Tp>::type& __t) noexcept + { return _Unwrap<_Tp>::_S_fwd(__t); } + template inline _Res __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) @@ -194,15 +221,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline _Res __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, _Args&&... __args) - noexcept(noexcept((forward<_Tp>(__t).*__f)(forward<_Args>(__args)...))) - { return (forward<_Tp>(__t).*__f)(forward<_Args>(__args)...); } - - template - inline _Res - __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, - reference_wrapper<_Tp> __t, _Args&&... __args) - noexcept(noexcept((__t.get().*__f)(forward<_Args>(__args)...))) - { return (__t.get().*__f)(forward<_Args>(__args)...); } + noexcept(noexcept((__invfwd<_Tp>(__t).*__f)(forward<_Args>(__args)...))) + { return (__invfwd<_Tp>(__t).*__f)(forward<_Args>(__args)...); } template inline _Res @@ -214,15 +234,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template inline _Res __invoke_impl(__invoke_memobj_ref, _MemFun&& __f, _Tp&& __t) - noexcept(noexcept(forward<_Tp>(__t).*__f)) - { return forward<_Tp>(__t).*__f; } - - template - inline _Res - __invoke_impl(__invoke_memobj_ref, _MemFun&& __f, - reference_wrapper<_Tp> __t) - noexcept(noexcept(__t.get().*__f)) - { return __t.get().*__f; } + noexcept(noexcept(__invfwd<_Tp>(__t).*__f)) + { return __invfwd<_Tp>(__t).*__f; } template inline _Res diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index e5102def906..5b4d073add1 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2391,44 +2391,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2219. INVOKE-ing a pointer to member with a reference_wrapper // as the object expression - template struct reference_wrapper; template struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> - : __result_of_memobj<_Res _Class::*, _Arg> - { - typedef typename - __result_of_memobj_ref<_Res _Class::*, _Arg&>::type type; - }; + : __result_of_memobj_ref<_Res _Class::*, _Arg&> + { }; template struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>&> - : __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> + { }; + + template + struct __result_of_memobj<_Res _Class::*, const reference_wrapper<_Arg>&> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> { }; template struct __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>&&> - : __result_of_memobj<_Res _Class::*, reference_wrapper<_Arg>> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> + { }; + + template + struct __result_of_memobj<_Res _Class::*, const reference_wrapper<_Arg>&&> + : __result_of_memobj_ref<_Res _Class::*, _Arg&> { }; template struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> - : __result_of_memfun<_Res _Class::*, _Arg&, _Args...> - { - typedef typename - __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...>::type type; - }; + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> + { }; template struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>&, _Args...> - : __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> + { }; + + template + struct __result_of_memfun<_Res _Class::*, const reference_wrapper<_Arg>&, + _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> { }; template struct __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>&&, _Args...> - : __result_of_memfun<_Res _Class::*, reference_wrapper<_Arg>, _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> + { }; + + template + struct __result_of_memfun<_Res _Class::*, const reference_wrapper<_Arg>&&, + _Args...> + : __result_of_memfun_ref<_Res _Class::*, _Arg&, _Args...> { }; template diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index a09788a29e0..d1edfbf9678 100644 --- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc +++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc @@ -46,14 +46,9 @@ void test02() const int dummy = 0; std::bind(Inc(), _1)(dummy); // { dg-error "no match" } std::bind(&Inc::f, Inc(), std::ref(dummy))(); // { dg-error "no match" } - // { dg-error "no match" "" { target *-*-* } 594 } - // { dg-error "no type" "" { target *-*-* } 237 } } -// { dg-error "rvalue|const" "" { target *-*-* } 1024 } -// { dg-error "rvalue|const" "" { target *-*-* } 1038 } -// { dg-error "rvalue|const" "" { target *-*-* } 1052 } -// { dg-error "rvalue|const" "" { target *-*-* } 1066 } +// { dg-excess-errors "reasons for deduction/substitution failures" } int main() { diff --git a/libstdc++-v3/testsuite/20_util/function_objects/invoke/59768.cc b/libstdc++-v3/testsuite/20_util/function_objects/invoke/59768.cc new file mode 100644 index 00000000000..44f1418e241 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/function_objects/invoke/59768.cc @@ -0,0 +1,43 @@ +// 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 +// . + +// { dg-options "-std=gnu++1z" } +// { dg-do compile } + +#include + +struct A { + void foo(int n) { } +}; + +void +test01() +{ + A a; + auto ref = std::ref(a); + std::invoke(&A::foo, ref, 100); // lvalue + std::invoke(&A::foo, std::move(ref), 100); // rvalue + const auto refc = std::ref(a); + std::invoke(&A::foo, refc, 100); // const lvalue + std::invoke(&A::foo, std::move(refc), 100); // const rvalue +} + +int +main() +{ + test01(); +}