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)) - 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