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<bool> 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 
25*8dfdcc7bSNikolas Klauser   template <class U>
AllocatorAllocator26*8dfdcc7bSNikolas Klauser   Allocator(const Allocator<U>&) {}
27*8dfdcc7bSNikolas Klauser 
AllocatorAllocator28*8dfdcc7bSNikolas Klauser   Allocator(bool should_throw = true) {
29*8dfdcc7bSNikolas Klauser     if (should_throw)
30*8dfdcc7bSNikolas Klauser       throw 0;
31*8dfdcc7bSNikolas Klauser   }
32*8dfdcc7bSNikolas Klauser 
allocateAllocator33*8dfdcc7bSNikolas Klauser   T* allocate(int n) { return std::allocator<T>().allocate(n); }
deallocateAllocator34*8dfdcc7bSNikolas Klauser   void deallocate(T* ptr, int n) { std::allocator<T>().deallocate(ptr, n); }
35*8dfdcc7bSNikolas Klauser 
operator ==(const Allocator &,const Allocator &)36*8dfdcc7bSNikolas Klauser   friend bool operator==(const Allocator&, const Allocator&) { return false; }
37*8dfdcc7bSNikolas Klauser };
38*8dfdcc7bSNikolas Klauser 
39*8dfdcc7bSNikolas Klauser template <class IterCat>
40*8dfdcc7bSNikolas Klauser struct Iterator {
41*8dfdcc7bSNikolas Klauser   using iterator_category = IterCat;
42*8dfdcc7bSNikolas Klauser   using difference_type   = std::ptrdiff_t;
43*8dfdcc7bSNikolas Klauser   using value_type        = bool;
44*8dfdcc7bSNikolas Klauser   using reference         = bool&;
45*8dfdcc7bSNikolas Klauser   using pointer           = bool*;
46*8dfdcc7bSNikolas Klauser 
47*8dfdcc7bSNikolas Klauser   int i_;
48*8dfdcc7bSNikolas Klauser   bool b_ = true;
IteratorIterator49*8dfdcc7bSNikolas Klauser   Iterator(int i = 0) : i_(i) {}
operator *Iterator50*8dfdcc7bSNikolas Klauser   bool& operator*() {
51*8dfdcc7bSNikolas Klauser     if (i_ == 1)
52*8dfdcc7bSNikolas Klauser       throw 1;
53*8dfdcc7bSNikolas Klauser     return b_;
54*8dfdcc7bSNikolas Klauser   }
55*8dfdcc7bSNikolas Klauser 
operator ==(const Iterator & lhs,const Iterator & rhs)56*8dfdcc7bSNikolas Klauser   friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ == rhs.i_; }
57*8dfdcc7bSNikolas Klauser 
operator !=(const Iterator & lhs,const Iterator & rhs)58*8dfdcc7bSNikolas Klauser   friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ != rhs.i_; }
59*8dfdcc7bSNikolas Klauser 
operator ++Iterator60*8dfdcc7bSNikolas Klauser   Iterator& operator++() {
61*8dfdcc7bSNikolas Klauser     ++i_;
62*8dfdcc7bSNikolas Klauser     return *this;
63*8dfdcc7bSNikolas Klauser   }
64*8dfdcc7bSNikolas Klauser 
operator ++Iterator65*8dfdcc7bSNikolas Klauser   Iterator operator++(int) {
66*8dfdcc7bSNikolas Klauser     auto tmp = *this;
67*8dfdcc7bSNikolas Klauser     ++i_;
68*8dfdcc7bSNikolas Klauser     return tmp;
69*8dfdcc7bSNikolas Klauser   }
70*8dfdcc7bSNikolas Klauser };
71*8dfdcc7bSNikolas Klauser 
check_new_delete_called()72*8dfdcc7bSNikolas Klauser void check_new_delete_called() {
73*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.new_called == globalMemCounter.delete_called);
74*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called);
75*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called);
76*8dfdcc7bSNikolas Klauser   assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
77*8dfdcc7bSNikolas Klauser }
78*8dfdcc7bSNikolas Klauser 
main(int,char **)79*8dfdcc7bSNikolas Klauser int main(int, char**) {
80*8dfdcc7bSNikolas Klauser   using AllocVec = std::vector<bool, Allocator<bool> >;
81*8dfdcc7bSNikolas Klauser 
82*8dfdcc7bSNikolas Klauser #if TEST_STD_VER >= 14
83*8dfdcc7bSNikolas Klauser   try { // Throw in vector(size_type, const allocator_type&) from allocator
84*8dfdcc7bSNikolas Klauser     Allocator<bool> alloc(false);
85*8dfdcc7bSNikolas Klauser     AllocVec get_alloc(0, alloc);
86*8dfdcc7bSNikolas Klauser   } catch (int) {
87*8dfdcc7bSNikolas Klauser   }
88*8dfdcc7bSNikolas Klauser   check_new_delete_called();
89*8dfdcc7bSNikolas Klauser #endif  // TEST_STD_VER >= 14
90*8dfdcc7bSNikolas Klauser 
91*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator) from input iterator
92*8dfdcc7bSNikolas Klauser     std::vector<bool> vec((Iterator<std::input_iterator_tag>()), Iterator<std::input_iterator_tag>(2));
93*8dfdcc7bSNikolas Klauser   } catch (int) {
94*8dfdcc7bSNikolas Klauser   }
95*8dfdcc7bSNikolas Klauser   check_new_delete_called();
96*8dfdcc7bSNikolas Klauser 
97*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator) from forward iterator
98*8dfdcc7bSNikolas Klauser     std::vector<bool> vec((Iterator<std::forward_iterator_tag>()), Iterator<std::forward_iterator_tag>(2));
99*8dfdcc7bSNikolas Klauser   } catch (int) {
100*8dfdcc7bSNikolas Klauser   }
101*8dfdcc7bSNikolas Klauser   check_new_delete_called();
102*8dfdcc7bSNikolas Klauser 
103*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator) from allocator
104*8dfdcc7bSNikolas Klauser     int a[] = {1, 2};
105*8dfdcc7bSNikolas Klauser     AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2));
106*8dfdcc7bSNikolas Klauser   } catch (int) {
107*8dfdcc7bSNikolas Klauser   }
108*8dfdcc7bSNikolas Klauser   check_new_delete_called();
109*8dfdcc7bSNikolas Klauser 
110*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator
111*8dfdcc7bSNikolas Klauser     std::allocator<bool> alloc;
112*8dfdcc7bSNikolas Klauser     std::vector<bool> vec(Iterator<std::input_iterator_tag>(), Iterator<std::input_iterator_tag>(2), alloc);
113*8dfdcc7bSNikolas Klauser   } catch (int) {
114*8dfdcc7bSNikolas Klauser   }
115*8dfdcc7bSNikolas Klauser   check_new_delete_called();
116*8dfdcc7bSNikolas Klauser 
117*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator
118*8dfdcc7bSNikolas Klauser     std::allocator<bool> alloc;
119*8dfdcc7bSNikolas Klauser     std::vector<bool> vec(Iterator<std::forward_iterator_tag>(), Iterator<std::forward_iterator_tag>(2), alloc);
120*8dfdcc7bSNikolas Klauser   } catch (int) {
121*8dfdcc7bSNikolas Klauser   }
122*8dfdcc7bSNikolas Klauser   check_new_delete_called();
123*8dfdcc7bSNikolas Klauser 
124*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
125*8dfdcc7bSNikolas Klauser     bool a[] = {true, false};
126*8dfdcc7bSNikolas Klauser     Allocator<bool> alloc(false);
127*8dfdcc7bSNikolas Klauser     AllocVec vec(cpp17_input_iterator<bool*>(a), cpp17_input_iterator<bool*>(a + 2), alloc);
128*8dfdcc7bSNikolas Klauser   } catch (int) {
129*8dfdcc7bSNikolas Klauser   }
130*8dfdcc7bSNikolas Klauser   check_new_delete_called();
131*8dfdcc7bSNikolas Klauser 
132*8dfdcc7bSNikolas Klauser   try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
133*8dfdcc7bSNikolas Klauser     bool a[] = {true, false};
134*8dfdcc7bSNikolas Klauser     Allocator<bool> alloc(false);
135*8dfdcc7bSNikolas Klauser     AllocVec vec(forward_iterator<bool*>(a), forward_iterator<bool*>(a + 2), alloc);
136*8dfdcc7bSNikolas Klauser   } catch (int) {
137*8dfdcc7bSNikolas Klauser   }
138*8dfdcc7bSNikolas Klauser   check_new_delete_called();
139*8dfdcc7bSNikolas Klauser 
140*8dfdcc7bSNikolas Klauser   return 0;
141*8dfdcc7bSNikolas Klauser }
142