-
Patrick Palka authored
The type of an implicit object parameter is always the current class. For an explicit object parameter however, its deduced type can be a derived class of the current class. So when combining multiple implicit-object overloads into a single explicit-object overload we need to account for this possibility. For example when accessing a member of the current class through an explicit object parameter, it may now be a derived class from which the member is not accessible, as in the below testcases. This pitfall is discussed[1] in the deducing this paper. The general solution is to cast the explicit object parameter to (a reference to) the current class rather than e.g. using std::forward which preserves the deduced type. This patch corrects the existing problematic uses of explicit object parameters in the library, all of which forward the parameter via std::forward, to instead cast the parameter to the current class via our __like_t alias template. Note that unlike the paper's like_t, ours always returns a reference so we can just write __like_t<Self, B>(self) instead of (_like_t<Self, B>&&)self as the paper does. [1]: https://wg21.link/P0847#name-lookup-within-member-functions (and the section after that) PR libstdc++/116038 libstdc++-v3/ChangeLog: * include/std/functional (_Bind_front::operator()): Use __like_t instead of std::forward when forwarding __self. (_Bind_back::operator()): Likewise. * include/std/ranges (_Partial::operator()): Likewise. (_Pipe::operator()): Likewise. * testsuite/20_util/function_objects/bind_back/116038.cc: New test. * testsuite/20_util/function_objects/bind_front/116038.cc: New test. * testsuite/std/ranges/adaptors/116038.cc: New test. Reviewed-by:
Jonathan Wakely <jwakely@redhat.com>
Patrick Palka authoredThe type of an implicit object parameter is always the current class. For an explicit object parameter however, its deduced type can be a derived class of the current class. So when combining multiple implicit-object overloads into a single explicit-object overload we need to account for this possibility. For example when accessing a member of the current class through an explicit object parameter, it may now be a derived class from which the member is not accessible, as in the below testcases. This pitfall is discussed[1] in the deducing this paper. The general solution is to cast the explicit object parameter to (a reference to) the current class rather than e.g. using std::forward which preserves the deduced type. This patch corrects the existing problematic uses of explicit object parameters in the library, all of which forward the parameter via std::forward, to instead cast the parameter to the current class via our __like_t alias template. Note that unlike the paper's like_t, ours always returns a reference so we can just write __like_t<Self, B>(self) instead of (_like_t<Self, B>&&)self as the paper does. [1]: https://wg21.link/P0847#name-lookup-within-member-functions (and the section after that) PR libstdc++/116038 libstdc++-v3/ChangeLog: * include/std/functional (_Bind_front::operator()): Use __like_t instead of std::forward when forwarding __self. (_Bind_back::operator()): Likewise. * include/std/ranges (_Partial::operator()): Likewise. (_Pipe::operator()): Likewise. * testsuite/20_util/function_objects/bind_back/116038.cc: New test. * testsuite/20_util/function_objects/bind_front/116038.cc: New test. * testsuite/std/ranges/adaptors/116038.cc: New test. Reviewed-by:
Jonathan Wakely <jwakely@redhat.com>