mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 03:46:53 -05:00
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 <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
@@ -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
|
||||
|
||||
58
libstdc++-v3/testsuite/std/memory/indirect/access.cc
Normal file
58
libstdc++-v3/testsuite/std/memory/indirect/access.cc
Normal file
@@ -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());
|
||||
}
|
||||
53
libstdc++-v3/testsuite/std/memory/polymorphic/access.cc
Normal file
53
libstdc++-v3/testsuite/std/memory/polymorphic/access.cc
Normal file
@@ -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());
|
||||
}
|
||||
Reference in New Issue
Block a user