[libcxx-commits] [libcxx] [libc++] Validate exception throwing for vector mutators on max_size violation (PR #131953)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 19 07:46:23 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Peng Liu (winner245)

<details>
<summary>Changes</summary>

This patch ensures that `std::vector` and `vector<bool>` raise expected exceptions when vector's `size()` would otherwise exceed `max_size()` limit due to mutator operations. It also validates that the vector remains unchanged  when such exception is raised, ensuring the strong exception safety guarantee when conditions ([[vector.capacity]](https://eel.is/c++draft/vector.capacity#<!-- -->4), [[vector.modifiers]](https://eel.is/c++draft/vector.modifiers#<!-- -->2)) are met: 
- `reserve`, `resize`, `shrink_to_fit`: If an exception is thrown other than by the move constructor of a non-`Cpp17CopyInsertable` type, there are no effects.
- `{push, emplace}_back`: If an exception is thrown while inserting a single element at the end and T is `Cpp17CopyInsertable` or `is_nothrow_move_constructible_v<T>` is true, there are no effects.
- `emplace, insert, insert_range, append_range`: If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of `T` or by any `InputIterator` operation, there are no effects.

This patch focuses only on exceptions triggered when exceeding the `max_size()` limit, in order to fix issue #<!-- -->40963. However, a more extensive testing for other sources of exceptions—such as those caused by copy/move constructors, allocators, assignment operators, or reallocation scenarios—need to be added, which will be pursued as a further work.

---

Patch is 41.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/131953.diff


26 Files Affected:

- (modified) libcxx/test/std/containers/sequences/vector.bool/append_range.pass.cpp (-3) 
- (added) libcxx/test/std/containers/sequences/vector.bool/append_range_exceptions.pass.cpp (+59) 
- (modified) libcxx/test/std/containers/sequences/vector.bool/emplace.pass.cpp (+1-1) 
- (modified) libcxx/test/std/containers/sequences/vector.bool/emplace_back.pass.cpp (+1-1) 
- (added) libcxx/test/std/containers/sequences/vector.bool/emplace_back_exceptions.pass.cpp (+36) 
- (added) libcxx/test/std/containers/sequences/vector.bool/emplace_exceptions.pass.cpp (+65) 
- (added) libcxx/test/std/containers/sequences/vector.bool/insert_exceptions.pass.cpp (+108) 
- (modified) libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp (-3) 
- (added) libcxx/test/std/containers/sequences/vector.bool/insert_range_exceptions.pass.cpp (+72) 
- (added) libcxx/test/std/containers/sequences/vector.bool/push_back_exceptions.pass.cpp (+34) 
- (modified) libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp (-18) 
- (added) libcxx/test/std/containers/sequences/vector.bool/reserve_exceptions.pass.cpp (+68) 
- (added) libcxx/test/std/containers/sequences/vector.bool/resize_size_exceptions.pass.cpp (+68) 
- (added) libcxx/test/std/containers/sequences/vector.bool/resize_size_value_exceptions.pass.cpp (+71) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp (+10-3) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_exceptions.pass.cpp (+12-4) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_value_exceptions.pass.cpp (+8-2) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp (+4) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.modifiers/append_range.pass.cpp (-3) 
- (added) libcxx/test/std/containers/sequences/vector/vector.modifiers/append_range_exceptions.pass.cpp (+45) 
- (added) libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back_exception_safety.pass.cpp (+34) 
- (added) libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_exceptions.pass.cpp (+61) 
- (added) libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_exceptions.pass.cpp (+101) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp (-3) 
- (added) libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range_exceptions.pass.cpp (+69) 
- (modified) libcxx/test/std/containers/sequences/vector/vector.modifiers/push_back_exception_safety.pass.cpp (+14-1) 


``````````diff
diff --git a/libcxx/test/std/containers/sequences/vector.bool/append_range.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/append_range.pass.cpp
index 84047ea15c6cf..8dea772375490 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/append_range.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/append_range.pass.cpp
@@ -65,8 +65,5 @@ int main(int, char**) {
   test();
   static_assert(test());
 
-  // Note: `test_append_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
-  test_append_range_exception_safety_throwing_allocator<std::vector, bool>();
-
   return 0;
 }
diff --git a/libcxx/test/std/containers/sequences/vector.bool/append_range_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/append_range_exceptions.pass.cpp
new file mode 100644
index 0000000000000..63f23926f5f0e
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/append_range_exceptions.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// template<container-compatible-range<bool> R>
+//   constexpr void append_range(R&& rg); // C++23
+
+#include <cassert>
+#include <vector>
+
+#include "../insert_range_sequence_containers.h"
+#include "test_allocator.h"
+
+void test() {
+  // Note: `test_append_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
+  test_append_range_exception_safety_throwing_allocator<std::vector, bool>();
+
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size() - 2, true);
+    bool a[] = {false, true, false};
+    try {
+      v.append_range(a);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == v.max_size() - 2);
+      for (std::size_t i = 0; i < v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    std::vector<bool, limited_allocator<bool, 10> > v(10, true);
+    bool a[10 * 65536] = {};
+    try {
+      v.append_range(a);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == 10);
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/emplace.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/emplace.pass.cpp
index 810a1968605d8..e7f0d7f7eb12d 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/emplace.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/emplace.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, c++11
+// UNSUPPORTED: c++03
 // <vector>
 //  vector<bool>
 
diff --git a/libcxx/test/std/containers/sequences/vector.bool/emplace_back.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/emplace_back.pass.cpp
index 87da6fd9f6019..0bb2afa232914 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/emplace_back.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/emplace_back.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, c++11
+// UNSUPPORTED: c++03
 // <vector>
 //  vector.bool
 
diff --git a/libcxx/test/std/containers/sequences/vector.bool/emplace_back_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/emplace_back_exceptions.pass.cpp
new file mode 100644
index 0000000000000..27d1b3aa87f37
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/emplace_back_exceptions.pass.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// template <class... Args>
+//     reference emplace_back(Args&&... args); // reference in C++17
+
+#include <cassert>
+#include <vector>
+
+#include "test_allocator.h"
+
+int main(int, char**) {
+  using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+  Vec v(Vec().max_size(), true);
+  try {
+    v.emplace_back(true);
+    assert(false);
+  } catch (...) {
+    assert(v.size() == v.max_size());
+    for (std::size_t i = 0; i != v.size(); ++i)
+      assert(v[i] == true);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/emplace_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/emplace_exceptions.pass.cpp
new file mode 100644
index 0000000000000..5d6f18a4031fa
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/emplace_exceptions.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// template <class... Args> iterator emplace(const_iterator pos, Args&&... args);
+
+#include <cassert>
+#include <vector>
+
+#include "test_allocator.h"
+
+void test() {
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.emplace(v.begin(), true);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.emplace(v.end(), true);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.emplace(v.begin() + v.size() / 2, true);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/insert_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/insert_exceptions.pass.cpp
new file mode 100644
index 0000000000000..a9742ffe2a5a3
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/insert_exceptions.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// iterator insert(const_iterator position, const value_type& x);
+// iterator insert(const_iterator position, size_type n, const value_type& x);
+// iterator insert(const_iterator p, initializer_list<value_type> il);
+// template <class Iter>
+//   iterator insert(const_iterator position, Iter first, Iter last);
+
+#include <cassert>
+#include <vector>
+
+#include "test_allocator.h"
+#include "test_macros.h"
+
+void test() {
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.insert(v.begin(), false);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), false);
+    try {
+      v.insert(v.end(), 0);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == false);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.insert(v.begin() + v.size() / 2, false);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.insert(v.begin(), 1, false);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size() - 2, true);
+    bool a[] = {true, false, true};
+    try {
+      v.insert(v.begin() + v.size() / 2, std::begin(a), std::end(a));
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size() - 2);
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+#if TEST_STD_VER >= 11
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size() - 2, true);
+    try {
+      v.insert(v.begin(), {true, false, true});
+      assert(false);
+    } catch (...) {
+      assert(v.size() == v.max_size() - 2);
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+#endif
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp
index e9a84150feb82..486ffaf5ec56c 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp
@@ -84,9 +84,6 @@ int main(int, char**) {
   test();
   static_assert(test());
 
-  // Note: `test_insert_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
-  test_insert_range_exception_safety_throwing_allocator<std::vector, bool>();
-
 #ifndef TEST_HAS_NO_LOCALIZATION
   test_counted_istream_view();
 #endif
diff --git a/libcxx/test/std/containers/sequences/vector.bool/insert_range_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/insert_range_exceptions.pass.cpp
new file mode 100644
index 0000000000000..c521d91d26c1d
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/insert_range_exceptions.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// template<container-compatible-range<T> R>
+//   constexpr iterator insert_range(const_iterator position, R&& rg); // C++23
+
+#include <cassert>
+#include <vector>
+
+#include "../insert_range_sequence_containers.h"
+#include "test_allocator.h"
+
+void test() {
+  // Note: `test_insert_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw.
+  test_insert_range_exception_safety_throwing_allocator<std::vector, bool>();
+
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size() - 2, true);
+    bool a[] = {true, false, true};
+    try {
+      v.insert_range(v.end(), a);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == v.max_size() - 2);
+      for (std::size_t i = 0; i < v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size() - 2, false);
+    bool a[] = {true, false, true};
+    try {
+      v.insert_range(v.begin(), a);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == v.max_size() - 2);
+      for (std::size_t i = 0; i < v.size(); ++i)
+        assert(v[i] == false);
+    }
+  }
+  {
+    std::vector<bool, limited_allocator<bool, 10> > v(10, true);
+    bool a[10 * 65536] = {};
+    try {
+      v.insert_range(v.begin() + v.size() / 2, a);
+      assert(false);
+    } catch (...) {
+      assert(v.size() == 10);
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/push_back_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/push_back_exceptions.pass.cpp
new file mode 100644
index 0000000000000..272325bec1768
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/push_back_exceptions.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// void push_back(const value_type& x);
+
+#include <cassert>
+#include <vector>
+
+#include "test_allocator.h"
+
+int main(int, char**) {
+  using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+  Vec v(Vec().max_size(), true);
+  try {
+    v.push_back(true);
+    assert(false);
+  } catch (...) {
+    assert(v.size() == v.max_size());
+    for (std::size_t i = 0; i != v.size(); ++i)
+      assert(v[i] == true);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
index e0caeb0083fbb..ce51722d2a684 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
@@ -13,7 +13,6 @@
 
 #include <vector>
 #include <cassert>
-#include <stdexcept>
 
 #include "test_macros.h"
 #include "min_allocator.h"
@@ -57,23 +56,6 @@ TEST_CONSTEXPR_CXX20 bool tests() {
     assert(v.capacity() >= 150);
   }
 #endif
-#ifndef TEST_HAS_NO_EXCEPTIONS
-  if (!TEST_IS_CONSTANT_EVALUATED) {
-    std::vector<bool, limited_allocator<bool, 10> > v;
-    v.reserve(5);
-    try {
-      // A typical implementation would allocate chunks of bits.
-      // In libc++ the chunk has the same size as the machine word. It is
-      // reasonable to assume that in practice no implementation would use
-      // 64 kB or larger chunks.
-      v.reserve(10 * 65536);
-      assert(false);
-    } catch (const std::length_error&) {
-      // no-op
-    }
-    assert(v.capacity() >= 5);
-  }
-#endif
 
   return true;
 }
diff --git a/libcxx/test/std/containers/sequences/vector.bool/reserve_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/reserve_exceptions.pass.cpp
new file mode 100644
index 0000000000000..8dc31251bc73a
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/reserve_exceptions.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// void reserve(size_type n);
+
+#include <cassert>
+#include <stdexcept>
+#include <vector>
+
+#include "test_allocator.h"
+
+void test() {
+  {
+    std::vector<bool, limited_allocator<bool, 10> > v;
+    v.reserve(5);
+    try {
+      // A typical implementation would allocate chunks of bits.
+      // In libc++ the chunk has the same size as the machine word. It is
+      // reasonable to assume that in practice no implementation would use
+      // 64 kB or larger chunks.
+      v.reserve(10 * 65536);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.empty());
+      assert(v.capacity() >= 5);
+    }
+  }
+  {
+    using Vec = std::vector<bool, limited_allocator<bool, 10> >;
+    Vec v(Vec().max_size(), true);
+    try {
+      v.reserve(v.max_size() + 1);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == v.max_size());
+      for (std::size_t i = 0; i < v.size(); ++i)
+        assert(v[i] == true);
+    }
+  }
+  {
+    bool a[] = {true, false, true, false, true};
+    std::vector<bool> v(std::begin(a), std::end(a));
+    try {
+      v.reserve(v.max_size() + 1);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == 5);
+      assert(v.capacity() >= 5);
+      for (std::size_t i = 0; i < v.size(); ++i)
+        assert(v[i] == a[i]);
+    }
+  }
+}
+
+int main(int, char**) {
+  test();
+  return 0;
+}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/resize_size_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/resize_size_exceptions.pass.cpp
new file mode 100644
index 0000000000000..8a1539e40649c
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/resize_size_exceptions.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// <vector>
+// vector<bool>
+
+// void resize(size_type sz);
+
+#include <algorithm>
+#include <cassert>
+#include <stdexcept>
+#include <vector>
+
+#include "test_allocator.h"
+
+void test() {
+  {
+    std::vector<bool, limited_allocator<bool, 10> > v;
+    v.resize(5);
+    try {
+      // It is reasonable to assume that no vector<bool> implementation would use
+      // 64 kB or larger chunk size for the underlying bits storage.
+      v.resize(10 * 65536); // 10 * max_chunk_size
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == 5);
+      assert(v.capacity() >= 5);
+      for (std::size_t i = 0; i != v.size(); ++i)
+        assert(!v[i]);
+    }
+  }
+  {
+    std::vector<bool, limited_allocator<bool, 10> > v;
+    v.resize(v.max_size() / 2);
+    try {
+      v.resize(v.max_size() + 1);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == v.max_size() / 2);
+      for (std::size_t i = 0; i < v.size(); ++i)
+        assert(v[i] == false);
+    }
+  }
+  {
+    bool a[] = {true, false, true, false, true};
+    std::vector<bool> v(std::begin(a), std::end(a));
+    try {
+      v.resize(v.max_size() + 1);
+      assert(false);
+    } catch (const std::length_error&) {
+      assert(v.size() == 5);
+      assert(v.capacity() >= 5);
+      assert(std::equal(v.begin(), v...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/131953


More information about the libcxx-commits mailing list