[PATCH] libstdc++: Fix std::uninitialized_value_construct for arrays [PR120397]
Tomasz Kaminski
tkaminsk@redhat.com
Thu Jun 12 10:29:10 GMT 2025
On Thu, Jun 12, 2025 at 12:13 AM Jonathan Wakely <jwakely@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.
> *
> testsuite/20_util/specialized_algorithms/uninitialized_default_construct/120397.cc:
> New test.
> *
> testsuite/20_util/specialized_algorithms/uninitialized_value_construct/120397.cc:
> New test.
> ---
>
> Tested x86_64-linux.
>
> libstdc++-v3/include/bits/stl_uninitialized.h | 19 ++++++++++++++++++-
> .../uninitialized_default_construct/120397.cc | 19 +++++++++++++++++++
> .../uninitialized_value_construct/120397.cc | 19 +++++++++++++++++++
> 3 files changed, 56 insertions(+), 1 deletion(-)
> 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 9372e5a01847..19d784bed4fc 100644
> --- a/libstdc++-v3/include/bits/stl_uninitialized.h
> +++ b/libstdc++-v3/include/bits/stl_uninitialized.h
> @@ -117,7 +117,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> ~_UninitDestroyGuard()
> {
> if (__builtin_expect(_M_cur != 0, 0))
>
I would find this more understandable, if we would do it as follows:
#if __cplusplus >= 20
std::destroy(_M_first, _M_cur);
else
_S_destroy(_M_first, *_M_cur)
And then _S_destroy is defined only in C++17.
> - std::_Destroy(_M_first, *_M_cur);
> + _S_destroy(_M_first, *_M_cur);
> }
>
> _GLIBCXX20_CONSTEXPR
> @@ -128,6 +128,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> private:
> _UninitDestroyGuard(const _UninitDestroyGuard&);
> +
> + template<typename _Iter>
> + _GLIBCXX20_CONSTEXPR
> + static void
> + _S_destroy(_Iter __first, _Iter __last)
> + {
> +#if __cplusplus == 201703L
> + // std::uninitialized_{value,default}{,_n} can construct array
> types,
> + // but std::_Destroy cannot handle them until C++20 (PR 120397).
> + 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
> +#endif
> + std::_Destroy(__first, __last);
>
+ }
> };
>
> // 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250612/2175f5b9/attachment.htm>
More information about the Libstdc++
mailing list