https://gcc.gnu.org/g:f22677a48b644e15304cf28f79b156c127f3df81

commit f22677a48b644e15304cf28f79b156c127f3df81
Author: Patrick Palka <ppa...@redhat.com>
Date:   Thu Jul 25 09:02:13 2024 -0400

    libstdc++: fix uses of explicit object parameter [PR116038]
    
    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 <jwak...@redhat.com>

Diff:
---
 libstdc++-v3/include/std/functional                |  4 +--
 libstdc++-v3/include/std/ranges                    | 11 +++++---
 .../20_util/function_objects/bind_back/116038.cc   | 27 ++++++++++++++++++++
 .../20_util/function_objects/bind_front/116038.cc  | 27 ++++++++++++++++++++
 .../testsuite/std/ranges/adaptors/116038.cc        | 29 ++++++++++++++++++++++
 5 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 99364286a72e..7788a9637578 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -944,7 +944,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
                                        __like_t<_Self, _BoundArgs>..., 
_CallArgs...>)
        {
-         return _S_call(std::forward<_Self>(__self), _BoundIndices(),
+         return _S_call(__like_t<_Self, _Bind_front>(__self), _BoundIndices(),
                         std::forward<_CallArgs>(__call_args)...);
        }
 #else
@@ -1072,7 +1072,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
                                        _CallArgs..., __like_t<_Self, 
_BoundArgs>...>)
        {
-         return _S_call(std::forward<_Self>(__self), _BoundIndices(),
+         return _S_call(__like_t<_Self, _Bind_back>(__self), _BoundIndices(),
                         std::forward<_CallArgs>(__call_args)...);
        }
 
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 3f335b95a086..b7c7aa36ddc4 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1033,7 +1033,7 @@ namespace views::__adaptor
            return _Adaptor{}(std::forward<_Range>(__r),
                              std::forward<decltype(__args)>(__args)...);
          };
-         return std::apply(__forwarder, std::forward<_Self>(__self)._M_args);
+         return std::apply(__forwarder, __like_t<_Self, 
_Partial>(__self)._M_args);
        }
 #else
       template<typename _Range>
@@ -1082,7 +1082,10 @@ namespace views::__adaptor
        requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Arg>>
        constexpr auto
        operator()(this _Self&& __self, _Range&& __r)
-       { return _Adaptor{}(std::forward<_Range>(__r), 
std::forward<_Self>(__self)._M_arg); }
+       {
+         return _Adaptor{}(std::forward<_Range>(__r),
+                           __like_t<_Self, _Partial>(__self)._M_arg);
+       }
 #else
       template<typename _Range>
        requires __adaptor_invocable<_Adaptor, _Range, const _Arg&>
@@ -1185,8 +1188,8 @@ namespace views::__adaptor
        constexpr auto
        operator()(this _Self&& __self, _Range&& __r)
        {
-         return (std::forward<_Self>(__self)._M_rhs
-                 (std::forward<_Self>(__self)._M_lhs
+         return (__like_t<_Self, _Pipe>(__self)._M_rhs
+                 (__like_t<_Self, _Pipe>(__self)._M_lhs
                   (std::forward<_Range>(__r))));
        }
 #else
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/116038.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/116038.cc
new file mode 100644
index 000000000000..ed392b1434e7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/116038.cc
@@ -0,0 +1,27 @@
+// PR libstdc++/116038
+// { dg-do compile { target c++23 } }
+
+#include <functional>
+#include <utility>
+
+struct A { };
+struct B { };
+
+template<class... Ts>
+struct overloaded : private Ts... {
+  overloaded(Ts...);
+  using Ts::operator()...;
+};
+
+int apply_a(A, int);
+int apply_b(B, int);
+
+int main() {
+  overloaded o = { std::bind_back(apply_a, 1),
+                  std::bind_back(apply_b, 2) };
+  A a;
+  o(a);
+  std::as_const(o)(a);
+  std::move(o)(a);
+  std::move(std::as_const(o))(a);
+}
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/116038.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/116038.cc
new file mode 100644
index 000000000000..3bf1226375b7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/116038.cc
@@ -0,0 +1,27 @@
+// PR libstdc++/116038
+// { dg-do compile { target c++20 } }
+
+#include <functional>
+#include <utility>
+
+struct A { };
+struct B { };
+
+template<class... Ts>
+struct overloaded : private Ts... {
+  overloaded(Ts...);
+  using Ts::operator()...;
+};
+
+int apply_a(int, A);
+int apply_b(int, B);
+
+int main() {
+  overloaded o = { std::bind_front(apply_a, 1),
+                  std::bind_front(apply_b, 2) };
+  A a;
+  o(a);
+  std::as_const(o)(a);
+  std::move(o)(a);
+  std::move(std::as_const(o))(a);
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/116038.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/116038.cc
new file mode 100644
index 000000000000..1afdf3d06d12
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/116038.cc
@@ -0,0 +1,29 @@
+// PR libstdc++/116038
+// { dg-do compile { target c++20 } }
+
+#include <ranges>
+#include <utility>
+
+struct A { };
+struct B { };
+
+template<class... Ts>
+struct overloaded : private Ts... {
+  overloaded(Ts...);
+  using Ts::operator()...;
+};
+
+int x[5];
+struct integralish { operator int() const; } i;
+
+int main() {
+  overloaded o1 = { std::views::drop(i) };
+  o1(x);
+  std::move(o1)(x);
+  std::as_const(o1)(x);
+
+  overloaded o2 = { std::views::drop(i) | std::views::take(i) };
+  o2(x);
+  std::move(o2)(x);
+  std::as_const(o1)(x);
+}

Reply via email to