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); } _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: public:
@ -633,7 +633,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual void* virtual void*
_M_get_deleter(const std::type_info& __ti) noexcept override _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 // 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 // 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, // 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) _Sp_make_shared_tag::_S_eq(__ti)
#endif #endif
) )
return __ptr; return _M_ptr();
return nullptr; 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; _Impl _M_impl;
}; };
@ -674,13 +674,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
[[no_unique_address]] _Alloc _M_alloc; [[no_unique_address]] _Alloc _M_alloc;
union { union {
_Tp _M_obj; remove_cv_t<_Tp> _M_obj;
char _M_unused; char _M_unused;
}; };
friend class __shared_count<_Lp>; // To be able to call _M_ptr(). 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: public:
using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>; 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, __shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a,
_Args&&... __args) _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); typename _Sp_cp_type::__allocator_type __a2(__a._M_a);
auto __guard = std::__allocate_guarded(__a2); auto __guard = std::__allocate_guarded(__a2);
_Sp_cp_type* __mem = __guard.get(); _Sp_cp_type* __mem = __guard.get();

View File

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

View File

@ -1261,7 +1261,7 @@ namespace __expected
{ } { }
union { union {
_Tp _M_val; remove_cv_t<_Tp> _M_val;
_Er _M_unex; _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*" ); "const_pointer is const void*" );
#endif // C++20 #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 int
main() main()
{ {
test01(); test01();
test02();
} }