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+ // <vector>
12+
13+ // Make sure elements are destroyed when exceptions thrown in __construct_at_end
14+
15+ #include < cassert>
16+ #include < cstddef>
17+ #include < memory>
18+ #include < vector>
19+
20+ #include " test_macros.h"
21+ #if TEST_STD_VER >= 20
22+ # include < ranges>
23+ #endif
24+
25+ #include " common.h"
26+ #include " count_new.h"
27+
28+ struct throw_context {
29+ static int num;
30+ static int limit;
31+
32+ throw_context (int lim = 2 ) {
33+ num = 0 ;
34+ limit = lim;
35+ }
36+
37+ static void inc () {
38+ ++num;
39+ if (num >= limit) {
40+ --num;
41+ throw 1 ;
42+ }
43+ }
44+
45+ static void dec () { --num; }
46+ };
47+
48+ int throw_context::num = 0 ;
49+ int throw_context::limit = 0 ;
50+
51+ int debug = 0 ;
52+
53+ class throw_element {
54+ public:
55+ throw_element () : data(new int (1 )) {
56+ try {
57+ throw_context::inc ();
58+ } catch (int ) {
59+ delete data;
60+ throw ;
61+ }
62+ }
63+
64+ throw_element ([[maybe_unused]] throw_element const & other) : data(new int (1 )) {
65+ try {
66+ throw_context::inc ();
67+ } catch (int ) {
68+ delete data;
69+ throw ;
70+ }
71+ }
72+
73+ ~throw_element () {
74+ if (data) {
75+ delete data;
76+ throw_context::dec ();
77+ if (debug)
78+ printf (" dctor\n " );
79+ }
80+ }
81+
82+ throw_element& operator =([[maybe_unused]] throw_element const & other) {
83+ // nothing to do
84+ return *this ;
85+ }
86+
87+ private:
88+ int * data;
89+ };
90+
91+ int main (int , char *[]) {
92+ using AllocType = std::allocator<throw_element>;
93+
94+ // vector(size_type __n)
95+ {
96+ throw_context ctx;
97+ try {
98+ std::vector<throw_element> v (3 );
99+ } catch (int ) {
100+ }
101+ check_new_delete_called ();
102+ }
103+
104+ // vector(size_type __n, const allocator_type& __a)
105+ {
106+ throw_context ctx;
107+ AllocType alloc;
108+ try {
109+ std::vector<throw_element> v (3 , alloc);
110+ } catch (int ) {
111+ }
112+ check_new_delete_called ();
113+ }
114+
115+ // vector(size_type __n, const value_type& __x)
116+ {
117+ throw_context ctx (3 );
118+ try {
119+ throw_element e;
120+ std::vector<throw_element> v (3 , e);
121+ } catch (int ) {
122+ }
123+ check_new_delete_called ();
124+ }
125+
126+ // vector(size_type __n, const value_type& __x, const allocator_type& __a)
127+ {
128+ throw_context ctx (3 );
129+ try {
130+ throw_element e;
131+ AllocType alloc;
132+ std::vector<throw_element> v (4 , e, alloc);
133+ } catch (int ) {
134+ }
135+ check_new_delete_called ();
136+ }
137+
138+ // vector(_ForwardIterator __first, _ForwardIterator __last)
139+ {
140+ throw_context ctx (4 );
141+ try {
142+ std::vector<throw_element> v1 (2 );
143+ std::vector<throw_element> v2 (v1.begin (), v1.end ());
144+ } catch (int ) {
145+ }
146+ check_new_delete_called ();
147+ }
148+
149+ // vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
150+ {
151+ throw_context ctx (4 );
152+ AllocType alloc;
153+ try {
154+ std::vector<throw_element> v1 (2 );
155+ std::vector<throw_element> v2 (v1.begin (), v1.end (), alloc);
156+ } catch (int ) {
157+ }
158+ check_new_delete_called ();
159+ }
160+
161+ #if _LIBCPP_STD_VER >= 23
162+ // vector(from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type())
163+ {
164+ throw_context ctx (4 );
165+ try {
166+ std::vector<throw_element> r (2 );
167+ std::vector<throw_element> v (std::from_range, std::views::counted (r.begin (), 2 ));
168+ } catch (int ) {
169+ }
170+ check_new_delete_called ();
171+ }
172+ #endif
173+
174+ // vector(const vector& __x)
175+ {
176+ throw_context ctx (4 );
177+ try {
178+ std::vector<throw_element> v1 (2 );
179+ std::vector<throw_element> v2 (v1);
180+ } catch (int ) {
181+ }
182+ check_new_delete_called ();
183+ }
184+
185+ // vector(initializer_list<value_type> __il)
186+ {
187+ throw_context ctx (6 );
188+ try {
189+ throw_element e;
190+ std::vector<throw_element> v ({e, e, e});
191+ } catch (int ) {
192+ }
193+ check_new_delete_called ();
194+ }
195+
196+ // vector(initializer_list<value_type> __il, const allocator_type& __a)
197+ {
198+ throw_context ctx (6 );
199+ AllocType alloc;
200+ try {
201+ throw_element e;
202+ std::vector<throw_element> v ({e, e, e}, alloc);
203+ } catch (int ) {
204+ }
205+ check_new_delete_called ();
206+ }
207+
208+ // void resize(size_type __sz)
209+ {
210+ // cap < size
211+ throw_context ctx;
212+ std::vector<throw_element> v;
213+ v.reserve (1 );
214+ try {
215+ v.resize (4 );
216+ } catch (int ) {
217+ }
218+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
219+ }
220+ check_new_delete_called ();
221+
222+ // void resize(size_type __sz, const_reference __x)
223+ {
224+ // cap < size
225+ throw_context ctx (3 );
226+ std::vector<throw_element> v;
227+ v.reserve (1 );
228+ try {
229+ throw_element e;
230+ v.resize (4 , e);
231+ } catch (int ) {
232+ }
233+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
234+ }
235+ check_new_delete_called ();
236+
237+ // void assign(_ForwardIterator __first, _ForwardIterator __last)
238+ {
239+ // new size <= cap && new size > size
240+ throw_context ctx (4 );
241+ std::vector<throw_element> v;
242+ v.reserve (3 );
243+ try {
244+ std::vector<throw_element> data (2 );
245+ v.assign (data.begin (), data.end ());
246+ } catch (int ) {
247+ }
248+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
249+ }
250+ check_new_delete_called ();
251+
252+ {
253+ // new size > cap
254+ throw_context ctx (4 );
255+ std::vector<throw_element> v;
256+ try {
257+ std::vector<throw_element> data (2 );
258+ v.assign (data.begin (), data.end ());
259+ } catch (int ) {
260+ }
261+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
262+ }
263+ check_new_delete_called ();
264+
265+ #if _LIBCPP_STD_VER >= 23
266+ // void assign_range(_Range&& __range)
267+ {
268+ throw_context ctx (5 );
269+ std::vector<throw_element> v;
270+ try {
271+ std::vector<throw_element> r (3 );
272+ v.assign_range (r);
273+ } catch (int ) {
274+ }
275+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
276+ }
277+ check_new_delete_called ();
278+ #endif
279+
280+ // vector& operator=(initializer_list<value_type> __il)
281+ {
282+ throw_context ctx (5 );
283+ std::vector<throw_element> v;
284+ try {
285+ throw_element e;
286+ v = {e, e};
287+ } catch (int ) {
288+ }
289+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
290+ }
291+ check_new_delete_called ();
292+
293+ // vector<_Tp, _Allocator>& vector<_Tp, _Allocator>::operator=(const vector& __x)
294+ {
295+ throw_context ctx (4 );
296+ std::vector<throw_element> v;
297+ try {
298+ std::vector<throw_element> data (2 );
299+ v = data;
300+ } catch (int ) {
301+ }
302+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
303+ }
304+ check_new_delete_called ();
305+
306+ // iterator insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last)
307+ {
308+ throw_context ctx (6 );
309+ std::vector<throw_element> v;
310+ v.reserve (10 );
311+ try {
312+ std::vector<throw_element> data (3 );
313+ v.insert (v.begin (), data.begin (), data.end ());
314+ } catch (int ) {
315+ }
316+ assert (globalMemCounter.new_called == globalMemCounter.delete_called + 1 );
317+ }
318+ check_new_delete_called ();
319+
320+ #if _LIBCPP_STD_VER >= 23
321+ // iterator insert_range(const_iterator __position, _Range&& __range)
322+ {
323+ throw_context ctx (3 );
324+ std::vector<throw_element> v;
325+ try {
326+ std::vector<throw_element> data (2 );
327+ v.insert_range (v.begin (), data);
328+ } catch (int ) {
329+ }
330+ check_new_delete_called ();
331+ }
332+ #endif
333+
334+ return 0 ;
335+ }
0 commit comments