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 constructors don't leak memory when an operation inside the constructor throws an exception 13 14 // XFAIL: FROZEN-CXX03-HEADERS-FIXME 15 16 #include <cstddef> 17 #include <memory> 18 #include <type_traits> 19 #include <vector> 20 21 #include "../common.h" 22 #include "count_new.h" 23 #include "test_allocator.h" 24 #include "test_iterators.h" 25 26 int main(int, char**) { 27 using AllocVec = std::vector<int, throwing_allocator<int> >; 28 try { // vector() 29 AllocVec vec; 30 } catch (int) { 31 } 32 check_new_delete_called(); 33 34 try { // Throw in vector(size_type) from type 35 std::vector<throwing_t> get_alloc(1); 36 } catch (int) { 37 } 38 check_new_delete_called(); 39 40 #if TEST_STD_VER >= 14 41 try { // Throw in vector(size_type, value_type) from type 42 int throw_after = 1; 43 throwing_t v(throw_after); 44 std::vector<throwing_t> get_alloc(1, v); 45 } catch (int) { 46 } 47 check_new_delete_called(); 48 49 try { // Throw in vector(size_type, const allocator_type&) from allocator 50 throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); 51 AllocVec get_alloc(0, alloc); 52 } catch (int) { 53 } 54 check_new_delete_called(); 55 56 try { // Throw in vector(size_type, const allocator_type&) from the type 57 std::vector<throwing_t> vec(1, std::allocator<throwing_t>()); 58 } catch (int) { 59 } 60 check_new_delete_called(); 61 #endif // TEST_STD_VER >= 14 62 63 try { // Throw in vector(size_type, value_type, const allocator_type&) from the type 64 int throw_after = 1; 65 throwing_t v(throw_after); 66 std::vector<throwing_t> vec(1, v, std::allocator<throwing_t>()); 67 } catch (int) { 68 } 69 check_new_delete_called(); 70 71 try { // Throw in vector(InputIterator, InputIterator) from input iterator 72 std::vector<int> vec( 73 (throwing_iterator<int, std::input_iterator_tag>()), throwing_iterator<int, std::input_iterator_tag>(2)); 74 } catch (int) { 75 } 76 check_new_delete_called(); 77 78 try { // Throw in vector(InputIterator, InputIterator) from forward iterator 79 std::vector<int> vec( 80 (throwing_iterator<int, std::forward_iterator_tag>()), throwing_iterator<int, std::forward_iterator_tag>(2)); 81 } catch (int) { 82 } 83 check_new_delete_called(); 84 85 try { // Throw in vector(InputIterator, InputIterator) from allocator 86 int a[] = {1, 2}; 87 AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2)); 88 } catch (int) { 89 } 90 check_new_delete_called(); 91 92 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator 93 std::allocator<int> alloc; 94 std::vector<int> vec( 95 throwing_iterator<int, std::input_iterator_tag>(), throwing_iterator<int, std::input_iterator_tag>(2), alloc); 96 } catch (int) { 97 } 98 check_new_delete_called(); 99 100 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator 101 std::allocator<int> alloc; 102 std::vector<int> vec(throwing_iterator<int, std::forward_iterator_tag>(), 103 throwing_iterator<int, std::forward_iterator_tag>(2), 104 alloc); 105 } catch (int) { 106 } 107 check_new_delete_called(); 108 109 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator 110 int a[] = {1, 2}; 111 throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); 112 AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2), alloc); 113 } catch (int) { 114 } 115 check_new_delete_called(); 116 117 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator 118 int a[] = {1, 2}; 119 throwing_allocator<int> alloc(/*throw_on_ctor = */ false, /*throw_on_copy = */ true); 120 AllocVec vec(forward_iterator<int*>(a), forward_iterator<int*>(a + 2), alloc); 121 } catch (int) { 122 } 123 check_new_delete_called(); 124 125 try { // Throw in vector(const vector&) from type 126 std::vector<throwing_t> vec; 127 int throw_after = 1; 128 vec.emplace_back(throw_after); 129 auto vec2 = vec; 130 } catch (int) { 131 } 132 check_new_delete_called(); 133 134 try { // Throw in vector(const vector&, const allocator_type&) from type 135 std::vector<throwing_t> vec; 136 int throw_after = 1; 137 vec.emplace_back(throw_after); 138 std::vector<throwing_t> vec2(vec, std::allocator<int>()); 139 } catch (int) { 140 } 141 check_new_delete_called(); 142 143 try { // Throw in vector(vector&&, const allocator_type&) from type during element-wise move 144 std::vector<throwing_t, test_allocator<throwing_t> > vec(test_allocator<throwing_t>(1)); 145 int throw_after = 10; 146 throwing_t v(throw_after); 147 vec.insert(vec.end(), 6, v); 148 std::vector<throwing_t, test_allocator<throwing_t> > vec2(std::move(vec), test_allocator<throwing_t>(2)); 149 } catch (int) { 150 } 151 check_new_delete_called(); 152 153 #if TEST_STD_VER >= 11 154 try { // Throw in vector(initializer_list<value_type>) from type 155 int throw_after = 1; 156 std::vector<throwing_t> vec({throwing_t(throw_after)}); 157 } catch (int) { 158 } 159 check_new_delete_called(); 160 161 try { // Throw in vector(initializer_list<value_type>, const allocator_type&) constructor from type 162 int throw_after = 1; 163 std::vector<throwing_t> vec({throwing_t(throw_after)}, std::allocator<throwing_t>()); 164 } catch (int) { 165 } 166 check_new_delete_called(); 167 #endif // TEST_STD_VER >= 11 168 169 return 0; 170 } 171