1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: no-exceptions
10
11// (bug report: https://llvm.org/PR58392)
12// Check that vector constructors don't leak memory when an operation inside the constructor throws an exception
13
14// XFAIL: FROZEN-CXX03-HEADERS-FIXME
15
16#include <cstddef>
17#include <memory>
18#include <type_traits>
19#include <vector>
20
21#include "../common.h"
22#include "count_new.h"
23#include "test_allocator.h"
24#include "test_iterators.h"
25
26int main(int, char**) {
27 using AllocVec = std::vector<int, throwing_allocator<int> >;
28 try { // vector()
29 AllocVec vec;
30 } catch (int) {
31 }
32 check_new_delete_called();
33
34 try { // Throw in vector(size_type) from type
35 std::vector<throwing_t> get_alloc(1);
36 } catch (int) {
37 }
38 check_new_delete_called();
39
40#if TEST_STD_VER >= 14
41 try { // Throw in vector(size_type, value_type) from type
42 int throw_after = 1;
43 throwing_t v(throw_after);
44 std::vector<throwing_t> get_alloc(1, v);
45 } catch (int) {
46 }
47 check_new_delete_called();
48
49 try { // Throw in vector(size_type, const allocator_type&) from allocator
50 throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true);
51 AllocVec get_alloc(0, alloc);
52 } catch (int) {
53 }
54 check_new_delete_called();
55
56 try { // Throw in vector(size_type, const allocator_type&) from the type
57 std::vector<throwing_t> vec(1, std::allocator<throwing_t>());
58 } catch (int) {
59 }
60 check_new_delete_called();
61#endif // TEST_STD_VER >= 14
62
63 try { // Throw in vector(size_type, value_type, const allocator_type&) from the type
64 int throw_after = 1;
65 throwing_t v(throw_after);
66 std::vector<throwing_t> vec(1, v, std::allocator<throwing_t>());
67 } catch (int) {
68 }
69 check_new_delete_called();
70
71 try { // Throw in vector(InputIterator, InputIterator) from input iterator
72 std::vector<int> vec(
73 (throwing_iterator<int, std::input_iterator_tag>()), throwing_iterator<int, std::input_iterator_tag>(2));
74 } catch (int) {
75 }
76 check_new_delete_called();
77
78 try { // Throw in vector(InputIterator, InputIterator) from forward iterator
79 std::vector<int> vec(
80 (throwing_iterator<int, std::forward_iterator_tag>()), throwing_iterator<int, std::forward_iterator_tag>(2));
81 } catch (int) {
82 }
83 check_new_delete_called();
84
85 try { // Throw in vector(InputIterator, InputIterator) from allocator
86 int a[] = {1, 2};
87 AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2));
88 } catch (int) {
89 }
90 check_new_delete_called();
91
92 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator
93 std::allocator<int> alloc;
94 std::vector<int> vec(
95 throwing_iterator<int, std::input_iterator_tag>(), throwing_iterator<int, std::input_iterator_tag>(2), alloc);
96 } catch (int) {
97 }
98 check_new_delete_called();
99
100 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator
101 std::allocator<int> alloc;
102 std::vector<int> vec(throwing_iterator<int, std::forward_iterator_tag>(),
103 throwing_iterator<int, std::forward_iterator_tag>(2),
104 alloc);
105 } catch (int) {
106 }
107 check_new_delete_called();
108
109 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
110 int a[] = {1, 2};
111 throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true);
112 AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2), alloc);
113 } catch (int) {
114 }
115 check_new_delete_called();
116
117 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
118 int a[] = {1, 2};
119 throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true);
120 AllocVec vec(forward_iterator<int*>(a), forward_iterator<int*>(a + 2), alloc);
121 } catch (int) {
122 }
123 check_new_delete_called();
124
125 try { // Throw in vector(const vector&) from type
126 std::vector<throwing_t> vec;
127 int throw_after = 1;
128 vec.emplace_back(args&: throw_after);
129 auto vec2 = vec;
130 } catch (int) {
131 }
132 check_new_delete_called();
133
134 try { // Throw in vector(const vector&, const allocator_type&) from type
135 std::vector<throwing_t> vec;
136 int throw_after = 1;
137 vec.emplace_back(args&: throw_after);
138 std::vector<throwing_t> vec2(vec, std::allocator<int>());
139 } catch (int) {
140 }
141 check_new_delete_called();
142
143 try { // Throw in vector(vector&&, const allocator_type&) from type during element-wise move
144 std::vector<throwing_t, test_allocator<throwing_t> > vec(test_allocator<throwing_t>(1));
145 int throw_after = 10;
146 throwing_t v(throw_after);
147 vec.insert(vec.end(), 6, v);
148 std::vector<throwing_t, test_allocator<throwing_t> > vec2(std::move(vec), test_allocator<throwing_t>(2));
149 } catch (int) {
150 }
151 check_new_delete_called();
152
153#if TEST_STD_VER >= 11
154 try { // Throw in vector(initializer_list<value_type>) from type
155 int throw_after = 1;
156 std::vector<throwing_t> vec({throwing_t(throw_after)});
157 } catch (int) {
158 }
159 check_new_delete_called();
160
161 try { // Throw in vector(initializer_list<value_type>, const allocator_type&) constructor from type
162 int throw_after = 1;
163 std::vector<throwing_t> vec({throwing_t(throw_after)}, std::allocator<throwing_t>());
164 } catch (int) {
165 }
166 check_new_delete_called();
167#endif // TEST_STD_VER >= 11
168
169 return 0;
170}
171

source code of libcxx/test/std/containers/sequences/vector/vector.cons/exceptions.pass.cpp