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