libstdc++: Do not cast away const-ness in std::construct_at (LWG 3870)

This change also requires implementing the proposed resolution of LWG
3216 so that std::make_shared and std::allocate_shared still work, and
the proposed resolution of LWG 3891 so that std::expected still works.

libstdc++-v3/ChangeLog:

	* include/bits/shared_ptr_base.h: Remove cv-qualifiers from
	type managed by _Sp_counted_ptr_inplace, as per LWG 3210.
	* include/bits/stl_construct.h: Do not cast away cv-qualifiers
	when passing pointer to placement new.
	* include/std/expected: Use remove_cv_t for union member, as per
	LWG 3891.
	* testsuite/20_util/allocator/void.cc: Do not test construction
	via const pointer.
This commit is contained in:
Jonathan Wakely 2024-07-11 20:38:05 +01:00 committed by Jonathan Wakely
parent 993deb3a9a
commit 2eaae1bd69
No known key found for this signature in database
4 changed files with 12 additions and 26 deletions

View File

@ -591,7 +591,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }
__gnu_cxx::__aligned_buffer<_Tp> _M_storage;
__gnu_cxx::__aligned_buffer<__remove_cv_t<_Tp>> _M_storage;
};
public:
@ -633,7 +633,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual void*
_M_get_deleter(const std::type_info& __ti) noexcept override
{
auto __ptr = const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
// Check for the fake type_info first, so we don't try to access it
// as a real type_info object. Otherwise, check if it's the real
// type_info for this class. With RTTI enabled we can check directly,
@ -646,11 +645,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Sp_make_shared_tag::_S_eq(__ti)
#endif
)
return __ptr;
return _M_ptr();
return nullptr;
}
_Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }
__remove_cv_t<_Tp>*
_M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }
_Impl _M_impl;
};
@ -674,13 +674,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
[[no_unique_address]] _Alloc _M_alloc;
union {
_Tp _M_obj;
remove_cv_t<_Tp> _M_obj;
char _M_unused;
};
friend class __shared_count<_Lp>; // To be able to call _M_ptr().
_Tp* _M_ptr() noexcept { return std::__addressof(_M_obj); }
auto _M_ptr() noexcept { return std::__addressof(_M_obj); }
public:
using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;
@ -962,7 +962,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a,
_Args&&... __args)
{
typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
using _Tp2 = __remove_cv_t<_Tp>;
using _Sp_cp_type = _Sp_counted_ptr_inplace<_Tp2, _Alloc, _Lp>;
typename _Sp_cp_type::__allocator_type __a2(__a._M_a);
auto __guard = std::__allocate_guarded(__a2);
_Sp_cp_type* __mem = __guard.get();

View File

@ -96,7 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
construct_at(_Tp* __location, _Args&&... __args)
noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
{
void* __loc = const_cast<remove_cv_t<_Tp>*>(__location);
void* __loc = __location;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 3436. std::construct_at should support arrays
if constexpr (is_array_v<_Tp>)
@ -130,7 +130,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return;
}
#endif
::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
}
#else
template<typename _T1, typename _T2>
@ -146,7 +146,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _T1>
inline void
_Construct_novalue(_T1* __p)
{ ::new((void*)__p) _T1; }
{ ::new(static_cast<void*>(__p)) _T1; }
template<typename _ForwardIterator>
_GLIBCXX20_CONSTEXPR void

View File

@ -1261,7 +1261,7 @@ namespace __expected
{ }
union {
_Tp _M_val;
remove_cv_t<_Tp> _M_val;
_Er _M_unex;
};

View File

@ -88,23 +88,8 @@ static_assert( std::is_same<std::allocator<void>::const_pointer, const void*>(),
"const_pointer is const void*" );
#endif // C++20
void
test02()
{
std::allocator<void> av;
int* p = std::allocator<int>().allocate(1);
const int* c = p;
std::allocator_traits<std::allocator<void>>::construct(av, c, 0);
volatile int* v = p;
std::allocator_traits<std::allocator<void>>::construct(av, v, 0);
const volatile int* cv = p;
std::allocator_traits<std::allocator<void>>::construct(av, cv, 0);
std::allocator<int>().deallocate(p, 1);
}
int
main()
{
test01();
test02();
}