[PATCH v2] libstdc++: Fix std::uninitialized_value_construct for arrays [PR120397]

Jonathan Wakely jwakely@redhat.com
Fri Jun 13 09:30:51 GMT 2025


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.

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



More information about the Libstdc++ mailing list