mirror of git://gcc.gnu.org/git/gcc.git
libstdc++: Fix std::uninitialized_value_construct for arrays [PR120397]
The std::uninitialized_{value,default}_construct{,_n} algorithms should
be able to create arrays, but that currently fails because when an
exception happens they clean up using std::_Destroy and in C++17 that
doesn't support destroying arrays. (For C++20 and later, std::destroy
does handle destroying arrays.)
This commit adjusts the _UninitDestroyGuard RAII type used by those
algos so that in C++17 mode it recursively destroys each rank of an
array type, only using std::_Destroy for the last rank when it's
destroying non-array objects.
libstdc++-v3/ChangeLog:
PR libstdc++/120397
* include/bits/stl_uninitialized.h (_UninitDestroyGuard<I,void>):
Add new member function _S_destroy and call it from the
destructor (for C++17 only).
* testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc:
New test.
* testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc:
New test.
Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
parent
33e3139f5d
commit
3af71d4ac8
|
|
@ -118,7 +118,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
~_UninitDestroyGuard()
|
||||
{
|
||||
if (__builtin_expect(_M_cur != 0, 0))
|
||||
#if __cplusplus == 201703L
|
||||
// std::uninitialized_{value,default}{,_n} can construct array types,
|
||||
// but std::_Destroy cannot handle them until C++20 (PR 120397).
|
||||
_S_destroy(_M_first, *_M_cur);
|
||||
#else
|
||||
std::_Destroy(_M_first, *_M_cur);
|
||||
#endif
|
||||
}
|
||||
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
|
|
@ -129,6 +135,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
private:
|
||||
_UninitDestroyGuard(const _UninitDestroyGuard&);
|
||||
|
||||
#if __cplusplus == 201703L
|
||||
template<typename _Iter>
|
||||
static void
|
||||
_S_destroy(_Iter __first, _Iter __last)
|
||||
{
|
||||
using _ValT = typename iterator_traits<_Iter>::value_type;
|
||||
if constexpr (is_array<_ValT>::value)
|
||||
for (; __first != __last; ++__first)
|
||||
_S_destroy(*__first, *__first + extent<_ValT>::value);
|
||||
else
|
||||
std::_Destroy(__first, __last);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// This is the default implementation of std::uninitialized_copy.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// { dg-do compile { target c++17 } }
|
||||
|
||||
#include <memory>
|
||||
|
||||
// PR libstdc++/120397
|
||||
// std::uninitialized_value_construct cannot create arrays of non-trivially
|
||||
// destructible types
|
||||
|
||||
struct X { X() { } ~X() { } };
|
||||
|
||||
void def(X (*x)[1])
|
||||
{
|
||||
std::uninitialized_default_construct(x, x+1);
|
||||
}
|
||||
|
||||
void def_n(X (*x)[1])
|
||||
{
|
||||
std::uninitialized_default_construct_n(x, 1);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// { dg-do compile { target c++17 } }
|
||||
|
||||
#include <memory>
|
||||
|
||||
// PR libstdc++/120397
|
||||
// std::uninitialized_value_construct cannot create arrays of non-trivially
|
||||
// destructible types
|
||||
|
||||
struct X { X() { } ~X() { } };
|
||||
|
||||
void val(X (*x)[1])
|
||||
{
|
||||
std::uninitialized_value_construct(x, x+1);
|
||||
}
|
||||
|
||||
void val_n(X (*x)[1])
|
||||
{
|
||||
std::uninitialized_value_construct_n(x, 1);
|
||||
}
|
||||
Loading…
Reference in New Issue