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

commit r16-2746-gd49d359b0c5266b314bcf31405746909d99927a1
Author: Tomasz Kamiński <tkami...@redhat.com>
Date:   Fri Aug 1 09:21:27 2025 +0200

    libstdc++: Fix dereferencing of std::indirect xvalues [PR121128]
    
    Forr rvalues the _Self parameter deduces a non-reference type. Consequently,
    ((_Self)__self) moved the object to a temporary, which then destroyed on
    function exit.
    
    This patch fixes this by using a C-style cast __self to (const indirect&).
    This not only resolves the above issue but also correctly handles types that
    are derived (publicly and privately) from indirect. Allocator requirements 
in
    [allocator.requirements.general] p22 guarantee that dereferencing const 
_M_objp
    works with equivalent semantics to dereferencing _M_objp.
    
            PR libstdc++/121128
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/indirect.h (indirect::operator*):
            Cast __self to approparietly qualified indirect.
            * testsuite/std/memory/indirect/access.cc: New test.
            * testsuite/std/memory/polymorphic/access.cc: New test.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/indirect.h               |  7 ++-
 .../testsuite/std/memory/indirect/access.cc        | 58 ++++++++++++++++++++++
 .../testsuite/std/memory/polymorphic/access.cc     | 53 ++++++++++++++++++++
 3 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/indirect.h 
b/libstdc++-v3/include/bits/indirect.h
index e8000d7c0243..89fa8c874fbd 100644
--- a/libstdc++-v3/include/bits/indirect.h
+++ b/libstdc++-v3/include/bits/indirect.h
@@ -286,8 +286,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr auto&&
       operator*(this _Self&& __self) noexcept
       {
-       __glibcxx_assert(__self._M_objp != nullptr);
-       return std::forward_like<_Self>(*((_Self)__self)._M_objp);
+       // n.b. [allocator.requirements.general] p22 implies
+       // dereferencing const pointer is same as pointer
+       const indirect& __iself = (const indirect&)__self;
+       __glibcxx_assert(__iself._M_objp != nullptr);
+       return std::forward_like<_Self>(*__iself._M_objp);
       }
 
       constexpr const_pointer
diff --git a/libstdc++-v3/testsuite/std/memory/indirect/access.cc 
b/libstdc++-v3/testsuite/std/memory/indirect/access.cc
new file mode 100644
index 000000000000..cf21275a115b
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/indirect/access.cc
@@ -0,0 +1,58 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <vector>
+
+#include <testsuite_hooks.h>
+
+template<template<typename> class Indirect>
+constexpr void
+test_access()
+{
+  const std::vector<int> src{1, 2, 3, 4, 5};
+  Indirect<std::vector<int>> i(src);
+  auto const& ci = i;
+  VERIFY( *i == src );
+  VERIFY( *ci == src );
+  VERIFY( *std::move(ci) == src );
+
+  std::vector<int>&& vr = *std::move(i);
+  VERIFY( vr == src );
+  VERIFY( *i == src );
+
+  std::vector<int> vc = *std::move(i);
+  VERIFY( vc == src );
+  VERIFY( vr.empty() );
+  VERIFY( i->empty() );
+  VERIFY( ci->empty() );
+}
+
+template<typename T>
+struct PublicBase : std::indirect<T>
+{
+  using std::indirect<T>::indirect;
+};
+
+template<typename T>
+class PrivateBase : std::indirect<T>
+{
+public:        
+  using std::indirect<T>::indirect;
+  using std::indirect<T>::operator*;
+  using std::indirect<T>::operator->;
+};
+
+constexpr bool
+test_all()
+{
+  test_access<std::indirect>();
+  test_access<PublicBase>();
+  test_access<PrivateBase>();
+  return true;
+}
+
+int main()
+{
+  test_all();
+  static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/access.cc 
b/libstdc++-v3/testsuite/std/memory/polymorphic/access.cc
new file mode 100644
index 000000000000..7b95bb192631
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/access.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <vector>
+
+#include <testsuite_hooks.h>
+
+template<template<typename> class Polymorhpic>
+constexpr void
+test_access()
+{
+  const std::vector<int> src{1, 2, 3, 4, 5};
+  Polymorhpic<std::vector<int>> i(src);
+  auto const& ci = i;
+  VERIFY( *i == src );
+  VERIFY( *ci == src );
+  VERIFY( *std::move(ci) == src );
+
+  auto&& vr = *std::move(i);
+  static_assert( std::is_same_v<decltype(vr), std::vector<int>&> );
+  VERIFY( vr == src );
+  VERIFY( *i == src );
+}
+
+template<typename T>
+struct PublicBase : std::polymorphic<T>
+{
+  using std::polymorphic<T>::polymorphic;
+};
+
+template<typename T>
+class PrivateBase : std::polymorphic<T>
+{
+public:        
+  using std::polymorphic<T>::polymorphic;
+  using std::polymorphic<T>::operator*;
+  using std::polymorphic<T>::operator->;
+};
+
+constexpr bool
+test_all()
+{
+  test_access<std::polymorphic>();
+  test_access<PublicBase>();
+  test_access<PrivateBase>();
+  return true;
+}
+
+int main()
+{
+  test_all();
+//  static_assert(test_all());
+}

Reply via email to