-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][test] Add exception tests for vector capacity operations #118141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
a5c7be2
to
8119fc8
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
d673cc8
to
2595c3c
Compare
44f8a0b
to
1950489
Compare
@llvm/pr-subscribers-libcxx Author: Peng Liu (winner245) ChangesAs a follow-up to #117662, this PR provides a comprehensive set of exception tests for the following capacity-related functions in
Previously, the exception safety tests for these functions were either missing or inadequate. We need a thorough coverage of exception tests to validate that these operations provide strong exception guarantees under various exceptional scenarios. Patch is 59.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/118141.diff 7 Files Affected:
diff --git a/libcxx/test/std/containers/sequences/vector/common.h b/libcxx/test/std/containers/sequences/vector/common.h
index ff8147ef6b838b..fb8db972f1d23e 100644
--- a/libcxx/test/std/containers/sequences/vector/common.h
+++ b/libcxx/test/std/containers/sequences/vector/common.h
@@ -11,10 +11,15 @@
#include <cassert>
#include <cstddef>
+#include <cstdlib>
#include <memory>
+#include <string>
#include <type_traits>
+#include <utility>
+#include <vector>
#include "count_new.h"
+#include "test_macros.h"
struct throwing_t {
int* throw_after_n_ = nullptr;
@@ -48,6 +53,95 @@ struct throwing_t {
}
};
+#if TEST_STD_VER >= 11
+
+template <typename T>
+struct move_only_throwing_t {
+ T data_;
+ int* throw_after_n_ = nullptr;
+ bool moved_from_ = false;
+
+ move_only_throwing_t() = default;
+
+ explicit move_only_throwing_t(const T& data, int& throw_after_n) : data_(data), throw_after_n_(&throw_after_n) {
+ if (throw_after_n == 0)
+ throw 1;
+ --throw_after_n;
+ }
+
+ explicit move_only_throwing_t(T&& data, int& throw_after_n) : data_(std::move(data)), throw_after_n_(&throw_after_n) {
+ if (throw_after_n == 0)
+ throw 1;
+ --throw_after_n;
+ }
+
+ move_only_throwing_t(const move_only_throwing_t&) = delete;
+ move_only_throwing_t& operator=(const move_only_throwing_t&) = delete;
+
+ move_only_throwing_t(move_only_throwing_t&& rhs) : data_(std::move(rhs.data_)), throw_after_n_(rhs.throw_after_n_) {
+ rhs.throw_after_n_ = nullptr;
+ rhs.moved_from_ = true;
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ }
+
+ move_only_throwing_t& operator=(move_only_throwing_t&& rhs) {
+ if (this == &rhs)
+ return *this;
+ data_ = std::move(rhs.data_);
+ throw_after_n_ = rhs.throw_after_n_;
+ rhs.moved_from_ = true;
+ rhs.throw_after_n_ = nullptr;
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ return *this;
+ }
+
+ friend bool operator==(const move_only_throwing_t& lhs, const move_only_throwing_t& rhs) {
+ return lhs.data_ == rhs.data_;
+ }
+ friend bool operator!=(const move_only_throwing_t& lhs, const move_only_throwing_t& rhs) {
+ return lhs.data_ != rhs.data_;
+ }
+};
+
+#endif
+
+template <typename T>
+struct throwing_data {
+ T data_;
+ int* throw_after_n_ = nullptr;
+ throwing_data() { throw 0; }
+
+ throwing_data(const T& data, int& throw_after_n) : data_(data), throw_after_n_(&throw_after_n) {
+ if (throw_after_n == 0)
+ throw 0;
+ --throw_after_n;
+ }
+
+ throwing_data(const throwing_data& rhs) : data_(rhs.data_), throw_after_n_(rhs.throw_after_n_) {
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ }
+
+ throwing_data& operator=(const throwing_data& rhs) {
+ data_ = rhs.data_;
+ throw_after_n_ = rhs.throw_after_n_;
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ return *this;
+ }
+
+ friend bool operator==(const throwing_data& lhs, const throwing_data& rhs) {
+ return lhs.data_ == rhs.data_ && lhs.throw_after_n_ == rhs.throw_after_n_;
+ }
+ friend bool operator!=(const throwing_data& lhs, const throwing_data& rhs) { return !(lhs == rhs); }
+};
+
template <class T>
struct throwing_allocator {
using value_type = T;
@@ -125,4 +219,43 @@ inline void check_new_delete_called() {
assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
}
+class Rnd {
+public:
+ static void initializeSeed(unsigned int seed = 12345) { std::srand(seed); }
+
+ static std::vector<int> getRandomIntegerInputs(std::size_t N) {
+ std::vector<int> v;
+ v.reserve(N);
+ for (std::size_t i = 0; i < N; ++i)
+ v.push_back(std::rand());
+ return v;
+ }
+
+ static std::vector<std::string> getRandomStringInputsWithLength(std::size_t N, std::size_t len) {
+ std::vector<std::string> v;
+ v.reserve(N);
+ for (std::size_t i = 0; i < N; ++i)
+ v.push_back(getRandomString(len));
+ return v;
+ }
+
+private:
+ static const char Letters[];
+ static const std::size_t LettersSize;
+
+ static std::string getRandomString(std::size_t len) {
+ std::string s;
+ s.reserve(len);
+ for (std::size_t i = 0; i < len; ++i)
+ s += Letters[std::rand() % LettersSize];
+ return s;
+ }
+};
+
+const char Rnd::Letters[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
+ 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+const std::size_t Rnd::LettersSize = sizeof(Rnd::Letters) / sizeof(Rnd::Letters[0]);
+
#endif // TEST_STD_CONTAINERS_SEQUENCES_VECTOR_COMMON_H
diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
index b8548ad72d4376..38e969335e0adb 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
@@ -19,126 +19,76 @@
#include "asan_testing.h"
TEST_CONSTEXPR_CXX20 bool tests() {
- {
- std::vector<int> v;
- v.reserve(10);
- assert(v.capacity() >= 10);
- assert(is_contiguous_container_asan_correct(v));
- }
- {
- std::vector<int> v(100);
- assert(v.capacity() == 100);
- v.reserve(50);
- assert(v.size() == 100);
- assert(v.capacity() == 100);
- v.reserve(150);
- assert(v.size() == 100);
- assert(v.capacity() == 150);
- assert(is_contiguous_container_asan_correct(v));
- }
- {
- // Add 1 for implementations that dynamically allocate a container proxy.
- std::vector<int, limited_allocator<int, 250 + 1> > v(100);
- assert(v.capacity() == 100);
- v.reserve(50);
- assert(v.size() == 100);
- assert(v.capacity() == 100);
- v.reserve(150);
- assert(v.size() == 100);
- assert(v.capacity() == 150);
- assert(is_contiguous_container_asan_correct(v));
- }
-#ifndef TEST_HAS_NO_EXCEPTIONS
- if (!TEST_IS_CONSTANT_EVALUATED) {
- std::vector<int> v;
- std::size_t sz = v.max_size() + 1;
-
- try {
- v.reserve(sz);
- assert(false);
- } catch (const std::length_error&) {
- assert(v.size() == 0);
- assert(v.capacity() == 0);
- }
- }
- if (!TEST_IS_CONSTANT_EVALUATED) {
- std::vector<int> v(10, 42);
- int* previous_data = v.data();
- std::size_t previous_capacity = v.capacity();
- std::size_t sz = v.max_size() + 1;
-
- try {
- v.reserve(sz);
- assert(false);
- } catch (std::length_error&) {
- assert(v.size() == 10);
- assert(v.capacity() == previous_capacity);
- assert(v.data() == previous_data);
-
- for (int i = 0; i < 10; ++i) {
- assert(v[i] == 42);
- }
- }
- }
-#endif
+ {
+ std::vector<int> v;
+ v.reserve(10);
+ assert(v.capacity() >= 10);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<int> v(100);
+ assert(v.capacity() == 100);
+ v.reserve(50);
+ assert(v.size() == 100);
+ assert(v.capacity() == 100);
+ v.reserve(150);
+ assert(v.size() == 100);
+ assert(v.capacity() == 150);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ // Add 1 for implementations that dynamically allocate a container proxy.
+ std::vector<int, limited_allocator<int, 250 + 1> > v(100);
+ assert(v.capacity() == 100);
+ v.reserve(50);
+ assert(v.size() == 100);
+ assert(v.capacity() == 100);
+ v.reserve(150);
+ assert(v.size() == 100);
+ assert(v.capacity() == 150);
+ assert(is_contiguous_container_asan_correct(v));
+ }
#if TEST_STD_VER >= 11
- {
- std::vector<int, min_allocator<int>> v;
- v.reserve(10);
- assert(v.capacity() >= 10);
- assert(is_contiguous_container_asan_correct(v));
- }
- {
- std::vector<int, min_allocator<int>> v(100);
- assert(v.capacity() == 100);
- v.reserve(50);
- assert(v.size() == 100);
- assert(v.capacity() == 100);
- v.reserve(150);
- assert(v.size() == 100);
- assert(v.capacity() == 150);
- assert(is_contiguous_container_asan_correct(v));
- }
- {
- std::vector<int, safe_allocator<int>> v;
- v.reserve(10);
- assert(v.capacity() >= 10);
- assert(is_contiguous_container_asan_correct(v));
- }
- {
- std::vector<int, safe_allocator<int>> v(100);
- assert(v.capacity() == 100);
- v.reserve(50);
- assert(v.size() == 100);
- assert(v.capacity() == 100);
- v.reserve(150);
- assert(v.size() == 100);
- assert(v.capacity() == 150);
- assert(is_contiguous_container_asan_correct(v));
- }
-#endif
-#ifndef TEST_HAS_NO_EXCEPTIONS
- if (!TEST_IS_CONSTANT_EVALUATED) {
- std::vector<int, limited_allocator<int, 100> > v;
- v.reserve(50);
- assert(v.capacity() == 50);
- assert(is_contiguous_container_asan_correct(v));
- try {
- v.reserve(101);
- assert(false);
- } catch (const std::length_error&) {
- // no-op
- }
- assert(v.capacity() == 50);
- assert(is_contiguous_container_asan_correct(v));
- }
+ {
+ std::vector<int, min_allocator<int>> v;
+ v.reserve(10);
+ assert(v.capacity() >= 10);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<int, min_allocator<int>> v(100);
+ assert(v.capacity() == 100);
+ v.reserve(50);
+ assert(v.size() == 100);
+ assert(v.capacity() == 100);
+ v.reserve(150);
+ assert(v.size() == 100);
+ assert(v.capacity() == 150);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<int, safe_allocator<int>> v;
+ v.reserve(10);
+ assert(v.capacity() >= 10);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<int, safe_allocator<int>> v(100);
+ assert(v.capacity() == 100);
+ v.reserve(50);
+ assert(v.size() == 100);
+ assert(v.capacity() == 100);
+ v.reserve(150);
+ assert(v.size() == 100);
+ assert(v.capacity() == 150);
+ assert(is_contiguous_container_asan_correct(v));
+ }
#endif
- return true;
+ return true;
}
-int main(int, char**)
-{
+int main(int, char**) {
tests();
#if TEST_STD_VER > 17
diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
new file mode 100644
index 00000000000000..0f21746e80f626
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
@@ -0,0 +1,314 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// This test file validates that std::vector<T>::reserve provides a strong exception guarantee if T is
+// Cpp17MoveInsertible and no exception is thrown by the move constructor of T during the reserve call.
+// It also checks that if T's move constructor is not noexcept, reserve provides only a basic exception
+// guarantee.
+
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include "../common.h"
+#include "MoveOnly.h"
+#include "count_new.h"
+#include "increasing_allocator.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <typename T, typename Alloc>
+void test_allocation_exception_for_strong_guarantee(
+ std::vector<T, Alloc>& v, const std::vector<T>& values, std::size_t new_cap) {
+ assert(v.size() == values.size());
+ T* old_data = v.data();
+ std::size_t old_size = v.size();
+ std::size_t old_cap = v.capacity();
+
+ try {
+ v.reserve(new_cap);
+ } catch (...) { // std::length_error, std::bad_alloc
+ assert(v.data() == old_data);
+ assert(v.size() == old_size);
+ assert(v.capacity() == old_cap);
+ for (std::size_t i = 0; i < v.size(); ++i)
+ assert(v[i] == values[i]);
+ }
+}
+
+template <typename T, typename Alloc>
+void test_copy_ctor_exception_for_strong_guarantee(std::vector<throwing_data<T>, Alloc>& v,
+ const std::vector<T>& values) {
+ assert(v.empty() && !values.empty());
+ int throw_after = values.size() + values.size() / 2; // Trigger an exception halfway through reallocation
+ v.reserve(values.size());
+ for (std::size_t i = 0; i < values.size(); ++i)
+ v.emplace_back(values[i], throw_after);
+
+ throwing_data<T>* old_data = v.data();
+ std::size_t old_size = v.size();
+ std::size_t old_cap = v.capacity();
+ std::size_t new_cap = 2 * old_cap;
+
+ try {
+ v.reserve(new_cap);
+ } catch (...) {
+ assert(v.data() == old_data);
+ assert(v.size() == old_size);
+ assert(v.capacity() == old_cap);
+ for (std::size_t i = 0; i < v.size(); ++i)
+ assert(v[i].data_ == values[i]);
+ }
+}
+
+#if TEST_STD_VER >= 11
+
+template <typename T, typename Alloc>
+void test_move_ctor_exception_for_basic_guarantee(std::vector<move_only_throwing_t<T>, Alloc>& v,
+ const std::vector<T>& values) {
+ assert(v.empty() && !values.empty());
+ int throw_after = values.size() + values.size() / 2; // Trigger an exception halfway through reallocation
+ v.reserve(values.size());
+ for (std::size_t i = 0; i < values.size(); ++i)
+ v.emplace_back(values[i], throw_after);
+
+ try {
+ v.reserve(2 * v.capacity());
+ } catch (...) {
+ // After a failure during element-wise move, the vector elements are left in a valid but unspecified state.
+ for (std::size_t i = 0; i < v.size(); ++i) {
+ assert(((void)v[i],
+ (void)v[i].data_,
+ (void)v[i].throw_after_n_,
+ (void)(v[i] == v[i]),
+ v[i].moved_from_ || v[i].data_ == values[i]));
+ }
+ }
+}
+
+#endif
+
+// Check the strong exception guarantee during reallocation failures
+void test_allocation_exceptions() {
+ //
+ // Tests for std::length_error during reallocation failures
+ //
+ {
+ std::vector<int> v;
+ test_allocation_exception_for_strong_guarantee(v, std::vector<int>(), v.max_size() + 1);
+ }
+ check_new_delete_called();
+
+ {
+ int a[] = {1, 2, 3, 4, 5};
+ std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
+ std::vector<int> v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
+ }
+ check_new_delete_called();
+
+ {
+ int a[] = {1, 2, 3, 4, 5};
+ std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
+ std::vector<int, min_allocator<int> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
+ }
+ check_new_delete_called();
+
+ {
+ int a[] = {1, 2, 3, 4, 5};
+ std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
+ std::vector<int, safe_allocator<int> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
+ }
+ check_new_delete_called();
+
+ {
+ int a[] = {1, 2, 3, 4, 5};
+ std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
+ std::vector<int, test_allocator<int> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int> in(10, 42);
+ std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
+ }
+ check_new_delete_called();
+
+#if TEST_STD_VER >= 23
+ {
+ std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ std::vector<int, increasing_allocator<int>> v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
+ }
+ check_new_delete_called();
+#endif
+
+ //
+ // Tests for std::bad_alloc during reallocation failures
+ //
+ {
+ std::vector<int> in(10, 42);
+ std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, 91);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int> in(10, 42);
+ std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end());
+ v.reserve(30);
+ test_allocation_exception_for_strong_guarantee(v, in, 61);
+ }
+ check_new_delete_called();
+
+#if TEST_STD_VER >= 11
+ {
+ std::vector<MoveOnly> in(10);
+ std::vector<MoveOnly, limited_allocator<MoveOnly, 100> > v(10);
+ test_allocation_exception_for_strong_guarantee(v, in, 91);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<MoveOnly> in(10);
+ in.insert(in.cbegin() + 5, MoveOnly(42));
+ std::vector<MoveOnly, limited_allocator<MoveOnly, 100> > v(10);
+ v.reserve(30);
+ v.insert(v.cbegin() + 5, MoveOnly(42));
+ test_allocation_exception_for_strong_guarantee(v, in, 61);
+ }
+ check_new_delete_called();
+#endif
+
+ { // Practical example: Testing with 100 randomly generated integers.
+ auto in = Rnd::getRandomIntegerInputs(100);
+ std::vector<int, limited_allocator<int, 299> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, 200);
+ }
+ check_new_delete_called();
+
+ { // Practical example: Testing with 100 randomly generated strings, each 256 characters long.
+ std::vector<std::string> in = Rnd::getRandomStringInputsWithLength(100, 256);
+ std::vector<std::string, limited_allocator<std::string, 299> > v(in.begin(), in.end());
+ test_allocation_exception_for_strong_guarantee(v, in, 200);
+ }
+ check_new_delete_called();
+}
+
+// Check the strong exception guarantee during copy-constructor failures
+void test_copy_ctor_exceptions() {
+ {
+ int a[] = {1, 2, 3, 4, 5};
+ std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
+ std::vector<throwing_data<int> > v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ int a[] = {1, 2, 3, 4, 5};
+ std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
+ std::vector<throwing_data<int>, min_allocator<throwing_data<int> > > v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int> in(10, 42);
+ std::vector<throwing_data<int>, safe_allocator<throwing_data<int> > > v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int> in(10, 42);
+ std::vector<throwing_data<int>, test_allocator<throwing_data<int> > > v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int> in(10, 42);
+ std::vector<throwing_data<int>, limited_allocator<throwing_data<int>, 100> > v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+
+#if TEST_STD_VER >= 23
+ {
+ std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ std::vector<throwing_data<int>, increasing_allocator<throwing_data<int>>> v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+#endif
+
+ { // Practical example: Testing with 100 randomly generated integers.
+ auto in = Rnd::getRandomIntegerInputs(100);
+ std::vector<throwing_data<int> > v;
+ test_copy_ctor_exception_for_strong_guarantee(v, in);
+ }
+ check_new_delete_called();
+
+ { // Practical example: Testing with 100 randomly generated strings, each 256 characters long.
+ std::vector<std::string> i...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I had reviewed this earlier but forgot to press "send" on my comments.
libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp
Show resolved
Hide resolved
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
Outdated
Show resolved
Hide resolved
a94d839
to
7159e0d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note that I will be OOO from Dec 21st to Jan 6th, so you should expect no reviews from me until I'm back!
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
Show resolved
Hide resolved
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
Outdated
Show resolved
Hide resolved
7159e0d
to
2f6ad14
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, this LGTM!
As a follow-up to #117662, this PR provides a comprehensive set of exception tests for the following capacity-related functions in
std::vector
. Specifically, it includes tests for the following functions:reserve(size_type)
resize(size_type)
andresize(size_type, const_reference)
shrink_to_fit()
Previously, the exception safety tests for these functions were either missing or inadequate. We need a thorough coverage of exception tests to validate that these operations provide strong exception guarantees under various exceptional scenarios.