diff --git a/stl/inc/deque b/stl/inc/deque index 1b3e0329237..84bfc1d5be7 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1219,6 +1219,31 @@ public: return begin() + static_cast(_Off); } +private: + enum class _Pop_direction : bool { + _Front, + _Back, + }; + + template <_Pop_direction _Direction> + struct _NODISCARD _Restore_old_size_guard { + deque* _Container; + const size_type _Oldsize; + + ~_Restore_old_size_guard() { // restore old size, at least + if (_Container) { + while (_Oldsize < _Container->_Mysize()) { + if constexpr (_Direction == _Pop_direction::_Front) { + _Container->pop_front(); + } else { + _Container->pop_back(); + } + } + } + } + }; + +public: template , int> = 0> iterator insert(const_iterator _Where, _Iter _First, _Iter _Last) { // insert [_First, _Last) at _Where, input iterators @@ -1236,37 +1261,25 @@ public: if (_UFirst != _ULast) { if (_Off <= _Mysize() / 2) { // closer to front, push to front then rotate - _TRY_BEGIN + _Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize}; for (; _UFirst != _ULast; ++_UFirst) { emplace_front(*_UFirst); // prepend flipped } - _CATCH_ALL - while (_Oldsize < _Mysize()) { - pop_front(); // restore old size, at least - } - - _RERAISE; - _CATCH_END + _Guard._Container = nullptr; size_type _Num = _Mysize() - _Oldsize; _STD reverse(begin(), begin() + static_cast(_Num)); // flip new stuff in place _STD rotate(begin(), begin() + static_cast(_Num), begin() + static_cast(_Num + _Off)); } else { // closer to back - _TRY_BEGIN _Orphan_all(); + _Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize}; for (; _UFirst != _ULast; ++_UFirst) { _Emplace_back_internal(*_UFirst); } - _CATCH_ALL - while (_Oldsize < _Mysize()) { - pop_back(); // restore old size, at least - } - - _RERAISE; - _CATCH_END + _Guard._Container = nullptr; _STD rotate(begin() + static_cast(_Off), begin() + static_cast(_Oldsize), end()); @@ -1361,7 +1374,7 @@ private: #endif // _ITERATOR_DEBUG_LEVEL == 2 if (_Off < _Rem) { // closer to front - _TRY_BEGIN + _Restore_old_size_guard<_Pop_direction::_Front> _Guard{this, _Oldsize}; if (_Off < _Count) { // insert longer than prefix for (_Num = _Count - _Off; 0 < _Num; --_Num) { push_front(_Val); // push excess values @@ -1384,15 +1397,9 @@ private: _STD fill(begin() + static_cast(_Off), _Mid + static_cast(_Off), _Tmp._Get_value()); // fill in values } - _CATCH_ALL - while (_Oldsize < _Mysize()) { - pop_front(); // restore old size, at least - } - - _RERAISE; - _CATCH_END + _Guard._Container = nullptr; } else { // closer to back - _TRY_BEGIN + _Restore_old_size_guard<_Pop_direction::_Back> _Guard{this, _Oldsize}; if (_Rem < _Count) { // insert longer than suffix _Orphan_all(); for (_Num = _Count - _Rem; 0 < _Num; --_Num) { @@ -1417,10 +1424,7 @@ private: _STD fill(_Mid, _Mid + static_cast(_Count), _Tmp._Get_value()); // fill in values } - _CATCH_ALL - _Erase_last_n(_Mysize() - _Oldsize); - _RERAISE; - _CATCH_END + _Guard._Container = nullptr; } } diff --git a/tests/std/test.lst b/tests/std/test.lst index 695faf3d5bf..2cc70b68f8f 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -192,6 +192,7 @@ tests\GH_002039_byte_is_not_trivially_swappable tests\GH_002058_debug_iterator_race tests\GH_002120_streambuf_seekpos_and_seekoff tests\GH_002299_implicit_sfinae_constraints +tests\GH_002307_usual_scope_guard tests\GH_002488_promise_not_default_constructible_types tests\GH_002581_common_reference_workaround tests\LWG2597_complex_branch_cut diff --git a/tests/std/tests/GH_002307_usual_scope_guard/env.lst b/tests/std/tests/GH_002307_usual_scope_guard/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_002307_usual_scope_guard/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_002307_usual_scope_guard/test.cpp b/tests/std/tests/GH_002307_usual_scope_guard/test.cpp new file mode 100644 index 00000000000..e1d4a95bb77 --- /dev/null +++ b/tests/std/tests/GH_002307_usual_scope_guard/test.cpp @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; + +struct countdown { + int val; + + static int count; + + void tick() { + if (count == 0) { + throw runtime_error{"GO"}; + } else { + --count; + } + } + + explicit countdown(const int init) : val(init) { + tick(); + } + + countdown(const countdown& other) : val(other.val) { + tick(); + } + + countdown& operator=(const countdown& other) { + tick(); + val = other.val; + return *this; + } + + bool operator==(int other) const { + return val == other; + } +}; + +int countdown::count = 0; + +constexpr int init_data[] = {1, 2, 3, 4, 5, 6, 7}; +constexpr int more_data[] = {10, 11, 12, 13, 14}; + +template +void check(const Container& c) { + assert(equal(c.begin(), c.end(), begin(init_data), end(init_data))); +} + +void check_exception(const runtime_error& ex) { + assert(strcmp(ex.what(), "GO") == 0); +} + +void test_deque() { + countdown::count = 8; + + deque dq(begin(init_data), end(init_data)); + + try { + countdown::count = 3; + dq.insert(dq.end() - 2, begin(more_data), end(more_data)); + assert(false); // Should have thrown an exception + } catch (const runtime_error& ex) { + check_exception(ex); + check(dq); + } + + try { + countdown::count = 3; + dq.insert(dq.begin() + 2, begin(more_data), end(more_data)); + assert(false); // Should have thrown an exception + } catch (const runtime_error& ex) { + check_exception(ex); + check(dq); + } + + try { + countdown::count = 3; + dq.insert(dq.end() - 2, 6, countdown{10}); + assert(false); // Should have thrown an exception + } catch (const runtime_error& ex) { + check_exception(ex); + check(dq); + } + + try { + countdown::count = 3; + dq.insert(dq.begin() + 2, 6, countdown{11}); + assert(false); // Should have thrown an exception + } catch (const runtime_error& ex) { + check_exception(ex); + check(dq); + } +} + +int main() { + test_deque(); +}