On Fri, Jun 13, 2025 at 11:31 AM Jonathan Wakely <jwak...@redhat.com> wrote:
> 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. > --- > > v2: Only define+use _S_destroy for C++17, at Tomasz's request. > LGTM. Thanks. The previous version required understanding subtleties of _Destroy, that is sometimes forwards to std::destroy_at. Now, I can understand it just by looking on the file. > > Tested x86_64-linux. > > libstdc++-v3/include/bits/stl_uninitialized.h | 21 +++++++++++++++++++ > .../uninitialized_default_construct/120397.cc | 19 +++++++++++++++++ > .../uninitialized_value_construct/120397.cc | 19 +++++++++++++++++ > 3 files changed, 59 insertions(+) > create mode 100644 > libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc > create mode 100644 > libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc > > diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h > b/libstdc++-v3/include/bits/stl_uninitialized.h > index bde787c2beaa..4b3f81604606 100644 > --- a/libstdc++-v3/include/bits/stl_uninitialized.h > +++ b/libstdc++-v3/include/bits/stl_uninitialized.h > @@ -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,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > private: > _UninitDestroyGuard(const _UninitDestroyGuard&); > + > +#if __cplusplus == 201703L > + template<typename _Iter> > + _GLIBCXX20_CONSTEXPR > + 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. > diff --git > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc > new file mode 100644 > index 000000000000..7aa05d7d12f4 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc > @@ -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); > +} > diff --git > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc > new file mode 100644 > index 000000000000..f4d9fce20213 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc > @@ -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); > +} > -- > 2.49.0 > >