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 | // (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 |
13 | |
14 | #include <cstddef> |
15 | #include <memory> |
16 | #include <type_traits> |
17 | #include <vector> |
18 | |
19 | #include "../vector/common.h" |
20 | #include "count_new.h" |
21 | #include "test_iterators.h" |
22 | |
23 | int main(int, char**) { |
24 | using AllocVec = std::vector<bool, throwing_allocator<bool> >; |
25 | |
26 | try { // Throw in vector() from allocator |
27 | AllocVec vec; |
28 | } catch (int) { |
29 | } |
30 | check_new_delete_called(); |
31 | |
32 | #if TEST_STD_VER >= 14 |
33 | try { // Throw in vector(size_type, const allocator_type&) from allocator |
34 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); |
35 | AllocVec get_alloc(0, alloc); |
36 | } catch (int) { |
37 | } |
38 | check_new_delete_called(); |
39 | #endif // TEST_STD_VER >= 14 |
40 | |
41 | try { // Throw in vector(size_type, const value_type&, const allocator_type&) from allocator |
42 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); |
43 | AllocVec get_alloc(0, true, alloc); |
44 | } catch (int) { |
45 | } |
46 | check_new_delete_called(); |
47 | |
48 | try { // Throw in vector(InputIterator, InputIterator) from input iterator |
49 | std::vector<bool> vec( |
50 | throwing_iterator<bool, std::input_iterator_tag>(), throwing_iterator<bool, std::input_iterator_tag>(2)); |
51 | } catch (int) { |
52 | } |
53 | check_new_delete_called(); |
54 | |
55 | try { // Throw in vector(InputIterator, InputIterator) from forward iterator |
56 | std::vector<bool> vec( |
57 | throwing_iterator<bool, std::forward_iterator_tag>(), throwing_iterator<bool, std::forward_iterator_tag>(2)); |
58 | } catch (int) { |
59 | } |
60 | check_new_delete_called(); |
61 | |
62 | try { // Throw in vector(InputIterator, InputIterator) from allocator |
63 | bool a[] = {true, true}; |
64 | AllocVec vec(cpp17_input_iterator<bool*>(a), cpp17_input_iterator<bool*>(a + 2)); |
65 | } catch (int) { |
66 | } |
67 | check_new_delete_called(); |
68 | |
69 | try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator |
70 | std::allocator<bool> alloc; |
71 | std::vector<bool> vec( |
72 | throwing_iterator<bool, std::input_iterator_tag>(), throwing_iterator<bool, std::input_iterator_tag>(2), alloc); |
73 | } catch (int) { |
74 | } |
75 | check_new_delete_called(); |
76 | |
77 | try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator |
78 | std::allocator<bool> alloc; |
79 | std::vector<bool> vec(throwing_iterator<bool, std::forward_iterator_tag>(), |
80 | throwing_iterator<bool, std::forward_iterator_tag>(2), |
81 | alloc); |
82 | } catch (int) { |
83 | } |
84 | check_new_delete_called(); |
85 | |
86 | try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator |
87 | bool a[] = {true, false}; |
88 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); |
89 | AllocVec vec(cpp17_input_iterator<bool*>(a), cpp17_input_iterator<bool*>(a + 2), alloc); |
90 | } catch (int) { |
91 | } |
92 | check_new_delete_called(); |
93 | |
94 | try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator |
95 | bool a[] = {true, false}; |
96 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); |
97 | AllocVec vec(forward_iterator<bool*>(a), forward_iterator<bool*>(a + 2), alloc); |
98 | } catch (int) { |
99 | } |
100 | check_new_delete_called(); |
101 | |
102 | #if TEST_STD_VER >= 11 |
103 | try { // Throw in vector(const vector&, const allocator_type&) from allocator |
104 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ false); |
105 | AllocVec vec(alloc); |
106 | vec.push_back(true); |
107 | alloc.throw_on_copy_ = true; |
108 | AllocVec vec2(vec, alloc); |
109 | } catch (int) { |
110 | } |
111 | check_new_delete_called(); |
112 | |
113 | try { // Throw in vector(vector&&, const allocator_type&) from allocator |
114 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ false); |
115 | AllocVec vec(alloc); |
116 | vec.push_back(true); |
117 | alloc.throw_on_copy_ = true; |
118 | AllocVec vec2(std::move(vec), alloc); |
119 | } catch (int) { |
120 | } |
121 | check_new_delete_called(); |
122 | |
123 | try { // Throw in vector(initializer_list<value_type>, const allocator_type&) constructor from allocator |
124 | throwing_allocator<bool> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); |
125 | AllocVec vec({true, true}, alloc); |
126 | } catch (int) { |
127 | } |
128 | check_new_delete_called(); |
129 | #endif // TEST_STD_VER >= 11 |
130 | |
131 | return 0; |
132 | } |
133 | |