1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: no-exceptions
11 // (bug report: https://llvm.org/PR58392)
12 // Check that vector<bool> constructors don't leak memory when an operation inside the constructor throws an exception
15 #include <type_traits>
19 #include "count_new.h"
20 #include "test_iterators.h"
25 using is_always_equal
= std::false_type
;
28 Allocator(const Allocator
<U
>&) {}
30 Allocator(bool should_throw
= true) {
35 T
* allocate(std::size_t n
) { return std::allocator
<T
>().allocate(n
); }
36 void deallocate(T
* ptr
, std::size_t n
) { std::allocator
<T
>().deallocate(ptr
, n
); }
39 friend bool operator==(const Allocator
&, const Allocator
<U
>&) { return true; }
42 template <class IterCat
>
44 using iterator_category
= IterCat
;
45 using difference_type
= std::ptrdiff_t;
46 using value_type
= bool;
47 using reference
= bool&;
48 using pointer
= bool*;
52 Iterator(int i
= 0) : i_(i
) {}
59 friend bool operator==(const Iterator
& lhs
, const Iterator
& rhs
) { return lhs
.i_
== rhs
.i_
; }
61 friend bool operator!=(const Iterator
& lhs
, const Iterator
& rhs
) { return lhs
.i_
!= rhs
.i_
; }
63 Iterator
& operator++() {
68 Iterator
operator++(int) {
75 void check_new_delete_called() {
76 assert(globalMemCounter
.new_called
== globalMemCounter
.delete_called
);
77 assert(globalMemCounter
.new_array_called
== globalMemCounter
.delete_array_called
);
78 assert(globalMemCounter
.aligned_new_called
== globalMemCounter
.aligned_delete_called
);
79 assert(globalMemCounter
.aligned_new_array_called
== globalMemCounter
.aligned_delete_array_called
);
82 int main(int, char**) {
83 using AllocVec
= std::vector
<bool, Allocator
<bool> >;
85 #if TEST_STD_VER >= 14
86 try { // Throw in vector(size_type, const allocator_type&) from allocator
87 Allocator
<bool> alloc(false);
88 AllocVec
get_alloc(0, alloc
);
91 check_new_delete_called();
92 #endif // TEST_STD_VER >= 14
94 try { // Throw in vector(InputIterator, InputIterator) from input iterator
95 std::vector
<bool> vec((Iterator
<std::input_iterator_tag
>()), Iterator
<std::input_iterator_tag
>(2));
98 check_new_delete_called();
100 try { // Throw in vector(InputIterator, InputIterator) from forward iterator
101 std::vector
<bool> vec((Iterator
<std::forward_iterator_tag
>()), Iterator
<std::forward_iterator_tag
>(2));
104 check_new_delete_called();
106 try { // Throw in vector(InputIterator, InputIterator) from allocator
108 AllocVec
vec(cpp17_input_iterator
<int*>(a
), cpp17_input_iterator
<int*>(a
+ 2));
111 check_new_delete_called();
113 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator
114 std::allocator
<bool> alloc
;
115 std::vector
<bool> vec(Iterator
<std::input_iterator_tag
>(), Iterator
<std::input_iterator_tag
>(2), alloc
);
118 check_new_delete_called();
120 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator
121 std::allocator
<bool> alloc
;
122 std::vector
<bool> vec(Iterator
<std::forward_iterator_tag
>(), Iterator
<std::forward_iterator_tag
>(2), alloc
);
125 check_new_delete_called();
127 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
128 bool a
[] = {true, false};
129 Allocator
<bool> alloc(false);
130 AllocVec
vec(cpp17_input_iterator
<bool*>(a
), cpp17_input_iterator
<bool*>(a
+ 2), alloc
);
133 check_new_delete_called();
135 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
136 bool a
[] = {true, false};
137 Allocator
<bool> alloc(false);
138 AllocVec
vec(forward_iterator
<bool*>(a
), forward_iterator
<bool*>(a
+ 2), alloc
);
141 check_new_delete_called();