1*8dfdcc7bSNikolas Klauser //===----------------------------------------------------------------------===//
2*8dfdcc7bSNikolas Klauser //
3*8dfdcc7bSNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8dfdcc7bSNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5*8dfdcc7bSNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8dfdcc7bSNikolas Klauser //
7*8dfdcc7bSNikolas Klauser //===----------------------------------------------------------------------===//
8*8dfdcc7bSNikolas Klauser 
9*8dfdcc7bSNikolas Klauser // UNSUPPORTED: no-exceptions
10*8dfdcc7bSNikolas Klauser 
11*8dfdcc7bSNikolas Klauser // (bug report: https://llvm.org/PR58392)
12*8dfdcc7bSNikolas Klauser // Check that vector constructors don't leak memory when an operation inside the constructor throws an exception
13*8dfdcc7bSNikolas Klauser 
14*8dfdcc7bSNikolas Klauser #include <type_traits>
15*8dfdcc7bSNikolas Klauser #include <vector>
16*8dfdcc7bSNikolas Klauser 
17*8dfdcc7bSNikolas Klauser #include "count_new.h"
18*8dfdcc7bSNikolas Klauser #include "test_iterators.h"
19*8dfdcc7bSNikolas Klauser 
20*8dfdcc7bSNikolas Klauser template <class T>
21*8dfdcc7bSNikolas Klauser struct Allocator {
22*8dfdcc7bSNikolas Klauser   using value_type      = T;
23*8dfdcc7bSNikolas Klauser   using is_always_equal = std::false_type;
24*8dfdcc7bSNikolas Klauser 
AllocatorAllocator25*8dfdcc7bSNikolas Klauser   Allocator(bool should_throw = true) {
26*8dfdcc7bSNikolas Klauser     if (should_throw)
27*8dfdcc7bSNikolas Klauser       throw 0;
28*8dfdcc7bSNikolas Klauser   }
29*8dfdcc7bSNikolas Klauser 
allocateAllocator30*8dfdcc7bSNikolas Klauser   T* allocate(int n) { return std::allocator<T>().allocate(n); }
deallocateAllocator31*8dfdcc7bSNikolas Klauser   void deallocate(T* ptr, int n) { std::allocator<T>().deallocate(ptr, n); }
32*8dfdcc7bSNikolas Klauser 
operator ==(const Allocator &,const Allocator &)33*8dfdcc7bSNikolas Klauser   friend bool operator==(const Allocator&, const Allocator&) { return false; }
34*8dfdcc7bSNikolas Klauser };
35*8dfdcc7bSNikolas Klauser 
36*8dfdcc7bSNikolas Klauser struct ThrowingT {
37*8dfdcc7bSNikolas Klauser   int* throw_after_n_ = nullptr;
ThrowingTThrowingT38*8dfdcc7bSNikolas Klauser   ThrowingT() { throw 0; }
39*8dfdcc7bSNikolas Klauser 
ThrowingTThrowingT40*8dfdcc7bSNikolas Klauser   ThrowingT(int& throw_after_n) : throw_after_n_(&throw_after_n) {
41*8dfdcc7bSNikolas Klauser     if (throw_after_n == 0)
42*8dfdcc7bSNikolas Klauser       throw 0;
43*8dfdcc7bSNikolas Klauser     --throw_after_n;
44*8dfdcc7bSNikolas Klauser   }
45*8dfdcc7bSNikolas Klauser 
ThrowingTThrowingT46*8dfdcc7bSNikolas Klauser   ThrowingT(const ThrowingT&) {
47*8dfdcc7bSNikolas Klauser     if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
48*8dfdcc7bSNikolas Klauser       throw 1;
49*8dfdcc7bSNikolas Klauser     --*throw_after_n_;
50*8dfdcc7bSNikolas Klauser   }
51*8dfdcc7bSNikolas Klauser 
operator =ThrowingT52*8dfdcc7bSNikolas Klauser   ThrowingT& operator=(const ThrowingT&) {
53*8dfdcc7bSNikolas Klauser     if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
54*8dfdcc7bSNikolas Klauser       throw 1;
55*8dfdcc7bSNikolas Klauser     --*throw_after_n_;
56*8dfdcc7bSNikolas Klauser     return *this;
57*8dfdcc7bSNikolas Klauser   }
58*8dfdcc7bSNikolas Klauser };
59*8dfdcc7bSNikolas Klauser 
60*8dfdcc7bSNikolas Klauser template <class IterCat>
61*8dfdcc7bSNikolas Klauser struct Iterator {
62*8dfdcc7bSNikolas Klauser   using iterator_category = IterCat;
63*8dfdcc7bSNikolas Klauser   using difference_type   = std::ptrdiff_t;
64*8dfdcc7bSNikolas Klauser   using value_type        = int;
65*8dfdcc7bSNikolas Klauser   using reference         = int&;
66*8dfdcc7bSNikolas Klauser   using pointer           = int*;
67*8dfdcc7bSNikolas Klauser 
68*8dfdcc7bSNikolas Klauser   int i_;
IteratorIterator69*8dfdcc7bSNikolas Klauser   Iterator(int i = 0) : i_(i) {}
operator *Iterator70*8dfdcc7bSNikolas Klauser   int& operator*() {
71*8dfdcc7bSNikolas Klauser     if (i_ == 1)
72*8dfdcc7bSNikolas Klauser       throw 1;
73*8dfdcc7bSNikolas Klauser     return i_;
74*8dfdcc7bSNikolas Klauser   }
75*8dfdcc7bSNikolas Klauser 
operator ==(const Iterator & lhs,const Iterator & rhs)76*8dfdcc7bSNikolas Klauser   friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ == rhs.i_; }
77*8dfdcc7bSNikolas Klauser 
operator !=(const Iterator & lhs,const Iterator & rhs)78*8dfdcc7bSNikolas Klauser   friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ != rhs.i_; }
79*8dfdcc7bSNikolas Klauser 
operator ++Iterator80*8dfdcc7bSNikolas Klauser   Iterator& operator++() {
81*8dfdcc7bSNikolas Klauser     ++i_;
82*8dfdcc7bSNikolas Klauser     return *this;
83*8dfdcc7bSNikolas Klauser   }
84*8dfdcc7bSNikolas Klauser 
operator ++Iterator85*8dfdcc7bSNikolas Klauser   Iterator operator++(int) {
86*8dfdcc7bSNikolas Klauser     auto tmp = *this;
87*8dfdcc7bSNikolas Klauser     ++i_;
88*8dfdcc7bSNikolas Klauser     return tmp;
89*8dfdcc7bSNikolas Klauser   }
90*8dfdcc7bSNikolas Klauser };
91*8dfdcc7bSNikolas Klauser 
check_new_delete_called()92*8dfdcc7bSNikolas Klauser void check_new_delete_called() {
93*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.new_called == globalMemCounter.delete_called);
94*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called);
95*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called);
96*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
97*8dfdcc7bSNikolas Klauser }
98*8dfdcc7bSNikolas Klauser 
main(int,char **)99*8dfdcc7bSNikolas Klauser int main(int, char**) {
100*8dfdcc7bSNikolas Klauser   using AllocVec = std::vector<int, Allocator<int> >;
101*8dfdcc7bSNikolas Klauser   try { // vector()
102*8dfdcc7bSNikolas Klauser     AllocVec vec;
103*8dfdcc7bSNikolas Klauser   } catch (int) {
104*8dfdcc7bSNikolas Klauser   }
105*8dfdcc7bSNikolas Klauser   check_new_delete_called();
106*8dfdcc7bSNikolas Klauser 
107*8dfdcc7bSNikolas Klauser   try { // Throw in vector(size_type) from type
108*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> get_alloc(1);
109*8dfdcc7bSNikolas Klauser   } catch (int) {
110*8dfdcc7bSNikolas Klauser   }
111*8dfdcc7bSNikolas Klauser   check_new_delete_called();
112*8dfdcc7bSNikolas Klauser 
113*8dfdcc7bSNikolas Klauser #if TEST_STD_VER >= 14
114*8dfdcc7bSNikolas Klauser   try { // Throw in vector(size_type, value_type) from type
115*8dfdcc7bSNikolas Klauser     int throw_after = 1;
116*8dfdcc7bSNikolas Klauser     ThrowingT v(throw_after);
117*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> get_alloc(1, v);
118*8dfdcc7bSNikolas Klauser   } catch (int) {
119*8dfdcc7bSNikolas Klauser   }
120*8dfdcc7bSNikolas Klauser   check_new_delete_called();
121*8dfdcc7bSNikolas Klauser 
122*8dfdcc7bSNikolas Klauser   try { // Throw in vector(size_type, const allocator_type&) from allocator
123*8dfdcc7bSNikolas Klauser     Allocator<int> alloc(false);
124*8dfdcc7bSNikolas Klauser     AllocVec get_alloc(0, alloc);
125*8dfdcc7bSNikolas Klauser   } catch (int) {
126*8dfdcc7bSNikolas Klauser   }
127*8dfdcc7bSNikolas Klauser   check_new_delete_called();
128*8dfdcc7bSNikolas Klauser 
129*8dfdcc7bSNikolas Klauser   try { // Throw in vector(size_type, const allocator_type&) from the type
130*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> vec(1, std::allocator<ThrowingT>());
131*8dfdcc7bSNikolas Klauser   } catch (int) {
132*8dfdcc7bSNikolas Klauser   }
133*8dfdcc7bSNikolas Klauser   check_new_delete_called();
134*8dfdcc7bSNikolas Klauser #endif  // TEST_STD_VER >= 14
135*8dfdcc7bSNikolas Klauser 
136*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator) from input iterator
137*8dfdcc7bSNikolas Klauser     std::vector<int> vec((Iterator<std::input_iterator_tag>()), Iterator<std::input_iterator_tag>(2));
138*8dfdcc7bSNikolas Klauser   } catch (int) {
139*8dfdcc7bSNikolas Klauser   }
140*8dfdcc7bSNikolas Klauser   check_new_delete_called();
141*8dfdcc7bSNikolas Klauser 
142*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator) from forward iterator
143*8dfdcc7bSNikolas Klauser     std::vector<int> vec((Iterator<std::forward_iterator_tag>()), Iterator<std::forward_iterator_tag>(2));
144*8dfdcc7bSNikolas Klauser   } catch (int) {
145*8dfdcc7bSNikolas Klauser   }
146*8dfdcc7bSNikolas Klauser   check_new_delete_called();
147*8dfdcc7bSNikolas Klauser 
148*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator) from allocator
149*8dfdcc7bSNikolas Klauser     int a[] = {1, 2};
150*8dfdcc7bSNikolas Klauser     AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2));
151*8dfdcc7bSNikolas Klauser   } catch (int) {
152*8dfdcc7bSNikolas Klauser   }
153*8dfdcc7bSNikolas Klauser   check_new_delete_called();
154*8dfdcc7bSNikolas Klauser 
155*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator
156*8dfdcc7bSNikolas Klauser     std::allocator<int> alloc;
157*8dfdcc7bSNikolas Klauser     std::vector<int> vec(Iterator<std::input_iterator_tag>(), Iterator<std::input_iterator_tag>(2), alloc);
158*8dfdcc7bSNikolas Klauser   } catch (int) {
159*8dfdcc7bSNikolas Klauser   }
160*8dfdcc7bSNikolas Klauser   check_new_delete_called();
161*8dfdcc7bSNikolas Klauser 
162*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator
163*8dfdcc7bSNikolas Klauser     std::allocator<int> alloc;
164*8dfdcc7bSNikolas Klauser     std::vector<int> vec(Iterator<std::forward_iterator_tag>(), Iterator<std::forward_iterator_tag>(2), alloc);
165*8dfdcc7bSNikolas Klauser   } catch (int) {
166*8dfdcc7bSNikolas Klauser   }
167*8dfdcc7bSNikolas Klauser   check_new_delete_called();
168*8dfdcc7bSNikolas Klauser 
169*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
170*8dfdcc7bSNikolas Klauser     int a[] = {1, 2};
171*8dfdcc7bSNikolas Klauser     Allocator<int> alloc(false);
172*8dfdcc7bSNikolas Klauser     AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2), alloc);
173*8dfdcc7bSNikolas Klauser   } catch (int) {
174*8dfdcc7bSNikolas Klauser   }
175*8dfdcc7bSNikolas Klauser   check_new_delete_called();
176*8dfdcc7bSNikolas Klauser 
177*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
178*8dfdcc7bSNikolas Klauser     int a[] = {1, 2};
179*8dfdcc7bSNikolas Klauser     Allocator<int> alloc(false);
180*8dfdcc7bSNikolas Klauser     AllocVec vec(forward_iterator<int*>(a), forward_iterator<int*>(a + 2), alloc);
181*8dfdcc7bSNikolas Klauser   } catch (int) {
182*8dfdcc7bSNikolas Klauser   }
183*8dfdcc7bSNikolas Klauser   check_new_delete_called();
184*8dfdcc7bSNikolas Klauser 
185*8dfdcc7bSNikolas Klauser   try { // Throw in vector(const vector&) from type
186*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> vec;
187*8dfdcc7bSNikolas Klauser     int throw_after = 0;
188*8dfdcc7bSNikolas Klauser     vec.emplace_back(throw_after);
189*8dfdcc7bSNikolas Klauser     auto vec2 = vec;
190*8dfdcc7bSNikolas Klauser   } catch (int) {
191*8dfdcc7bSNikolas Klauser   }
192*8dfdcc7bSNikolas Klauser   check_new_delete_called();
193*8dfdcc7bSNikolas Klauser 
194*8dfdcc7bSNikolas Klauser   try { // Throw in vector(const vector&, const allocator_type&) from type
195*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> vec;
196*8dfdcc7bSNikolas Klauser     int throw_after = 1;
197*8dfdcc7bSNikolas Klauser     vec.emplace_back(throw_after);
198*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> vec2(vec, std::allocator<int>());
199*8dfdcc7bSNikolas Klauser   } catch (int) {
200*8dfdcc7bSNikolas Klauser   }
201*8dfdcc7bSNikolas Klauser   check_new_delete_called();
202*8dfdcc7bSNikolas Klauser 
203*8dfdcc7bSNikolas Klauser   try { // Throw in vector(vector&&, const allocator_type&) from type
204*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT, Allocator<ThrowingT> > vec(Allocator<ThrowingT>(false));
205*8dfdcc7bSNikolas Klauser     int throw_after = 1;
206*8dfdcc7bSNikolas Klauser     vec.emplace_back(throw_after);
207*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT, Allocator<ThrowingT> > vec2(std::move(vec), Allocator<ThrowingT>(false));
208*8dfdcc7bSNikolas Klauser   } catch (int) {
209*8dfdcc7bSNikolas Klauser   }
210*8dfdcc7bSNikolas Klauser   check_new_delete_called();
211*8dfdcc7bSNikolas Klauser 
212*8dfdcc7bSNikolas Klauser #if TEST_STD_VER >= 11
213*8dfdcc7bSNikolas Klauser   try { // Throw in vector(initializer_list<value_type>) from type
214*8dfdcc7bSNikolas Klauser     int throw_after = 1;
215*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> vec({ThrowingT(throw_after)});
216*8dfdcc7bSNikolas Klauser   } catch (int) {
217*8dfdcc7bSNikolas Klauser   }
218*8dfdcc7bSNikolas Klauser   check_new_delete_called();
219*8dfdcc7bSNikolas Klauser 
220*8dfdcc7bSNikolas Klauser   try { // Throw in vector(initializer_list<value_type>, const allocator_type&) constructor from type
221*8dfdcc7bSNikolas Klauser     int throw_after = 1;
222*8dfdcc7bSNikolas Klauser     std::vector<ThrowingT> vec({ThrowingT(throw_after)}, std::allocator<ThrowingT>());
223*8dfdcc7bSNikolas Klauser   } catch (int) {
224*8dfdcc7bSNikolas Klauser   }
225*8dfdcc7bSNikolas Klauser   check_new_delete_called();
226*8dfdcc7bSNikolas Klauser #endif // TEST_STD_VER >= 11
227*8dfdcc7bSNikolas Klauser 
228*8dfdcc7bSNikolas Klauser   return 0;
229*8dfdcc7bSNikolas Klauser }
230