[libcxx-commits] [libcxx] [libc++] [test] Container exception-safety for default and inplace constructions (PR #202468)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 19 08:03:07 PDT 2026


https://github.com/halbi2 updated https://github.com/llvm/llvm-project/pull/202468

>From c7bb1403282a0c0d89b1bae0cccdadecf9c70345 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Fri, 19 Jun 2026 10:55:49 -0400
Subject: [PATCH 1/2] [libc++] Add missing constructor for forward_list

Fixes #204843
---
 libcxx/include/forward_list                                 | 6 +-----
 .../sequences/forwardlist/forwardlist.cons/size.pass.cpp    | 2 +-
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index 6d86f7a8e5975..d963fea6084ca 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -37,7 +37,7 @@ public:
         noexcept(is_nothrow_default_constructible<allocator_type>::value);
     explicit forward_list(const allocator_type& a);
     explicit forward_list(size_type n);
-    explicit forward_list(size_type n, const allocator_type& a); // C++14
+    explicit forward_list(size_type n, const allocator_type& a);
     forward_list(size_type n, const value_type& v);
     forward_list(size_type n, const value_type& v, const allocator_type& a);
     template <class InputIterator>
@@ -664,9 +664,7 @@ public:
       _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value) {} // = default;
   _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit forward_list(const allocator_type& __a);
   _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit forward_list(size_type __n);
-#  if _LIBCPP_STD_VER >= 14
   _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit forward_list(size_type __n, const allocator_type& __a);
-#  endif
   _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v);
 
   template <__enable_if_t<__is_allocator_v<_Alloc>, int> = 0>
@@ -941,7 +939,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type
   }
 }
 
-#  if _LIBCPP_STD_VER >= 14
 template <class _Tp, class _Alloc>
 _LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type __n, const allocator_type& __base_alloc)
     : __base(__base_alloc) {
@@ -952,7 +949,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type
     }
   }
 }
-#  endif
 
 template <class _Tp, class _Alloc>
 _LIBCPP_CONSTEXPR_SINCE_CXX26 forward_list<_Tp, _Alloc>::forward_list(size_type __n, const value_type& __v) {
diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp
index 206854560c19f..2cfd829a1eb23 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/size.pass.cpp
@@ -21,7 +21,7 @@
 
 template <class T, class Allocator>
 void check_allocator(unsigned n, Allocator const& alloc = Allocator()) {
-#if TEST_STD_VER > 11
+#if TEST_STD_VER >= 11
   typedef std::forward_list<T, Allocator> C;
   C d(n, alloc);
   assert(d.get_allocator() == alloc);

>From 236195106fa5999ddd8fa59809e09866339f517d Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Mon, 8 Jun 2026 20:06:28 -0400
Subject: [PATCH 2/2] [libc++] [test] Container exception-safety for default
 and inplace construction

The prior commit to these tests omitted these constructor definitions.
Now every throwing constructor is tested except for the allocator-extended
move constructor that can copy when the allocators mismatch.
---
 .../std/containers/exception_safety_helpers.h | 15 ++++++
 .../forwardlist/exception_safety.pass.cpp     | 27 +++++++++-
 .../sequences/list/exception_safety.pass.cpp  | 52 +++++++++++++++++--
 3 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/std/containers/exception_safety_helpers.h b/libcxx/test/std/containers/exception_safety_helpers.h
index 6e463304cce4f..243c7f1fb48d4 100644
--- a/libcxx/test/std/containers/exception_safety_helpers.h
+++ b/libcxx/test/std/containers/exception_safety_helpers.h
@@ -103,6 +103,21 @@ using ThrowingCopy = ThrowingBase<0, 0, N, 0>;
 template <int N>
 using ThrowingMove = ThrowingBase<0, 0, 0, N>;
 
+template <int ThrowOn, int Size, class Func>
+void test_exception_safety_throwing_default(Func&& func) {
+  using T = ThrowingDefault<ThrowOn>;
+  T::reset();
+
+  try {
+    func(Size);
+    assert(false); // The function call above should throw.
+
+  } catch (int) {
+    assert(T::default_constructed == ThrowOn);
+    assert(T::destroyed == ThrowOn - 1); // No destructor call for the partially-constructed element.
+  }
+}
+
 template <int ThrowOn, int Size, class Func>
 void test_exception_safety_throwing_copy(Func&& func) {
   using T = ThrowingCopy<ThrowOn>;
diff --git a/libcxx/test/std/containers/sequences/forwardlist/exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/exception_safety.pass.cpp
index a345665634276..b2fed121b55ac 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/exception_safety.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/exception_safety.pass.cpp
@@ -10,6 +10,11 @@
 
 // UNSUPPORTED: c++03, no-exceptions
 
+// TODO:
+// - forward_list(forward_list&&, const allocator_type&)
+
+// forward_list(size_type n);
+// forward_list(size_type n, const allocator_type& a);
 // forward_list(size_type n, const value_type& v);
 // forward_list(size_type n, const value_type& v, const allocator_type& a);
 // template <class InputIterator>
@@ -91,6 +96,25 @@ int main(int, char**) {
     });
   }
 
+  {
+    constexpr int ThrowOn = 3;
+    constexpr int Size    = 5;
+    using T               = ThrowingDefault<ThrowOn>;
+    using Alloc           = std::allocator<T>;
+
+    // forward_list(size_type n);
+    test_exception_safety_throwing_default<ThrowOn, Size>([](size_t n) {
+      std::forward_list<T> c(n);
+      (void)c;
+    });
+
+    // forward_list(size_type n, const allocator_type& a);
+    test_exception_safety_throwing_default<ThrowOn, Size>([](size_t n) {
+      std::forward_list<T> c(n, Alloc());
+      (void)c;
+    });
+  }
+
   {
     constexpr int ThrowOn = 1;
     constexpr int Size    = 1;
@@ -142,7 +166,7 @@ int main(int, char**) {
     using C               = std::forward_list<T>;
     using Alloc           = std::allocator<T>;
 
-    std::initializer_list<T> il{1, 2, 3, 4, 5};
+    std::initializer_list<T> il = {1, 2, 3, 4, 5};
 
     // forward_list(size_type n, const value_type& v);
     test_exception_safety_throwing_copy<ThrowOn, Size>([](T* from, T*) {
@@ -290,6 +314,7 @@ int main(int, char**) {
 
     { // void resize(size_type n);
       using X = ThrowingDefault<ThrowOn>;
+      X::reset();
       std::forward_list<X> c0{X{1}, X{2}, X{3}};
       std::forward_list<X> c = c0;
       try {
diff --git a/libcxx/test/std/containers/sequences/list/exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/list/exception_safety.pass.cpp
index 9820792f748c2..2d9d93b1a45bf 100644
--- a/libcxx/test/std/containers/sequences/list/exception_safety.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/exception_safety.pass.cpp
@@ -11,10 +11,10 @@
 // UNSUPPORTED: c++03, no-exceptions
 
 // TODO:
-// - throwing upon moving;
-// - initializer lists;
-// - throwing when constructing the element in place.
+// - list(list&&, const allocator_type&)
 
+// list(size_type n);
+// list(size_type n, const allocator_type& a);
 // list(size_type n, const value_type& v);
 // list(size_type n, const value_type& v, const allocator_type& a);
 // template <class InputIterator>
@@ -86,6 +86,25 @@ int main(int, char**) {
     });
   }
 
+  {
+    constexpr int ThrowOn = 3;
+    constexpr int Size    = 5;
+    using T               = ThrowingDefault<ThrowOn>;
+    using Alloc           = std::allocator<T>;
+
+    // list(size_type n);
+    test_exception_safety_throwing_default<ThrowOn, Size>([](size_t n) {
+      std::list<T> c(n);
+      (void)c;
+    });
+
+    // list(size_type n, const allocator_type& a);
+    test_exception_safety_throwing_default<ThrowOn, Size>([](size_t n) {
+      std::list<T> c(n, Alloc());
+      (void)c;
+    });
+  }
+
   {
     constexpr int ThrowOn = 3;
     constexpr int Size    = 5;
@@ -93,6 +112,8 @@ int main(int, char**) {
     using C               = std::list<T>;
     using Alloc           = std::allocator<T>;
 
+    std::initializer_list<T> il = {1, 2, 3, 4, 5};
+
     // list(size_type n, const value_type& v);
     test_exception_safety_throwing_copy<ThrowOn, Size>([](T* from, T*) {
       std::list<T> c(Size, *from);
@@ -135,6 +156,13 @@ int main(int, char**) {
     });
 #endif
 
+    // template <class InputIterator>
+    //     list(InputIterator first, InputIterator last, const allocator_type& a);
+    test_exception_safety_throwing_copy<ThrowOn, Size>([](T* from, T* to) {
+      std::list<T> c(from, to, Alloc());
+      (void)c;
+    });
+
     // list(const list& x);
     test_exception_safety_throwing_copy_container<C, ThrowOn, Size>([](C&& in) {
       std::list<T> c(in);
@@ -147,12 +175,30 @@ int main(int, char**) {
       (void)c;
     });
 
+    // list(initializer_list<value_type> il);
+    test_exception_safety_throwing_copy<ThrowOn, Size>([&il](T*, T*) {
+      std::list<T> c(il);
+      (void)c;
+    });
+
+    // list(initializer_list<value_type> il, const allocator_type& a);
+    test_exception_safety_throwing_copy<ThrowOn, Size>([&il](T*, T*) {
+      std::list<T> c(il, Alloc());
+      (void)c;
+    });
+
     // list& operator=(const list& x);
     test_exception_safety_throwing_copy_container<C, ThrowOn, Size>([](C&& in) {
       std::list<T> c;
       c = in;
     });
 
+    // list& operator=(initializer_list<value_type> il);
+    test_exception_safety_throwing_copy<ThrowOn, Size>([&il](T*, T*) {
+      std::list<T> c;
+      c = il;
+    });
+
     // template <class InputIterator>
     //     void assign(InputIterator first, InputIterator last);
     test_exception_safety_throwing_copy<ThrowOn, Size>([](T* from, T* to) {



More information about the libcxx-commits mailing list