// 300. list::merge() specification incomplete
if (this != std::__addressof(__x))
{
- _M_check_equal_allocators(__x);
+ _M_check_equal_allocators(__x);
iterator __first1 = begin();
iterator __last1 = end();
iterator __first2 = __x.begin();
iterator __last2 = __x.end();
- while (__first1 != __last1 && __first2 != __last2)
- if (*__first2 < *__first1)
- {
- iterator __next = __first2;
- _M_transfer(__first1, __first2, ++__next);
- __first2 = __next;
- }
- else
- ++__first1;
- if (__first2 != __last2)
- _M_transfer(__last1, __first2, __last2);
+ const size_t __orig_size = __x.size();
+ __try {
+ while (__first1 != __last1 && __first2 != __last2)
+ if (*__first2 < *__first1)
+ {
+ iterator __next = __first2;
+ _M_transfer(__first1, __first2, ++__next);
+ __first2 = __next;
+ }
+ else
+ ++__first1;
+ if (__first2 != __last2)
+ _M_transfer(__last1, __first2, __last2);
- this->_M_inc_size(__x._M_get_size());
- __x._M_set_size(0);
+ this->_M_inc_size(__x._M_get_size());
+ __x._M_set_size(0);
+ }
+ __catch(...)
+ {
+ size_t __dist = std::distance(__first2, __last2);
+ this->_M_inc_size(__dist);
+ __x._M_set_size(__orig_size - __dist);
+ __throw_exception_again;
+ }
}
}
iterator __last1 = end();
iterator __first2 = __x.begin();
iterator __last2 = __x.end();
- while (__first1 != __last1 && __first2 != __last2)
- if (__comp(*__first2, *__first1))
- {
- iterator __next = __first2;
- _M_transfer(__first1, __first2, ++__next);
- __first2 = __next;
- }
- else
- ++__first1;
- if (__first2 != __last2)
- _M_transfer(__last1, __first2, __last2);
-
- this->_M_inc_size(__x._M_get_size());
- __x._M_set_size(0);
+ const size_t __orig_size = __x.size();
+ __try
+ {
+ while (__first1 != __last1 && __first2 != __last2)
+ if (__comp(*__first2, *__first1))
+ {
+ iterator __next = __first2;
+ _M_transfer(__first1, __first2, ++__next);
+ __first2 = __next;
+ }
+ else
+ ++__first1;
+ if (__first2 != __last2)
+ _M_transfer(__last1, __first2, __last2);
+
+ this->_M_inc_size(__x._M_get_size());
+ __x._M_set_size(0);
+ }
+ __catch(...)
+ {
+ size_t __dist = std::distance(__first2, __last2);
+ this->_M_inc_size(__dist);
+ __x._M_set_size(__orig_size - __dist);
+ __throw_exception_again;
+ }
}
}
list __tmp[64];
list * __fill = __tmp;
list * __counter;
-
- do
+ __try
{
- __carry.splice(__carry.begin(), *this, begin());
-
- for(__counter = __tmp;
- __counter != __fill && !__counter->empty();
- ++__counter)
+ do
{
- __counter->merge(__carry);
+ __carry.splice(__carry.begin(), *this, begin());
+
+ for(__counter = __tmp;
+ __counter != __fill && !__counter->empty();
+ ++__counter)
+ {
+ __counter->merge(__carry);
+ __carry.swap(*__counter);
+ }
__carry.swap(*__counter);
+ if (__counter == __fill)
+ ++__fill;
}
- __carry.swap(*__counter);
- if (__counter == __fill)
- ++__fill;
- }
- while ( !empty() );
+ while ( !empty() );
- for (__counter = __tmp + 1; __counter != __fill; ++__counter)
- __counter->merge(*(__counter - 1));
- swap( *(__fill - 1) );
+ for (__counter = __tmp + 1; __counter != __fill; ++__counter)
+ __counter->merge(*(__counter - 1));
+ swap( *(__fill - 1) );
+ }
+ __catch(...)
+ {
+ this->splice(this->end(), __carry);
+ for (int i = 0; i < sizeof(__tmp)/sizeof(__tmp[0]); ++i)
+ this->splice(this->end(), __tmp[i]);
+ __throw_exception_again;
+ }
}
}
list __tmp[64];
list * __fill = __tmp;
list * __counter;
-
- do
+ __try
{
- __carry.splice(__carry.begin(), *this, begin());
-
- for(__counter = __tmp;
- __counter != __fill && !__counter->empty();
- ++__counter)
+ do
{
- __counter->merge(__carry, __comp);
+ __carry.splice(__carry.begin(), *this, begin());
+
+ for(__counter = __tmp;
+ __counter != __fill && !__counter->empty();
+ ++__counter)
+ {
+ __counter->merge(__carry, __comp);
+ __carry.swap(*__counter);
+ }
__carry.swap(*__counter);
+ if (__counter == __fill)
+ ++__fill;
}
- __carry.swap(*__counter);
- if (__counter == __fill)
- ++__fill;
- }
- while ( !empty() );
+ while ( !empty() );
- for (__counter = __tmp + 1; __counter != __fill; ++__counter)
- __counter->merge(*(__counter - 1), __comp);
- swap(*(__fill - 1));
+ for (__counter = __tmp + 1; __counter != __fill; ++__counter)
+ __counter->merge(*(__counter - 1), __comp);
+ swap(*(__fill - 1));
+ }
+ __catch(...)
+ {
+ this->splice(this->end(), __carry);
+ for (int i = 0; i < sizeof(__tmp)/sizeof(__tmp[0]); ++i)
+ this->splice(this->end(), __tmp[i]);
+ __throw_exception_again;
+ }
}
}
--- /dev/null
+// { dg-do run { target c++11 } }
+
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 23.2.2.4 list operations [lib.list.ops]
+
+#include <testsuite_hooks.h>
+
+#include <list>
+
+struct ThrowingComparator
+{
+ unsigned int throw_after = 0;
+ unsigned int count = 0;
+ bool operator()(int, int) {
+ if (++count >= throw_after) {
+ throw 666;
+ }
+ return true;
+ }
+};
+
+struct X
+{
+ X() = default;
+ X(int) {}
+};
+
+unsigned int throw_after_X = 0;
+unsigned int count_X = 0;
+
+bool operator<(const X&, const X&) {
+ if (++count_X >= throw_after_X) {
+ throw 666;
+ }
+ return true;
+}
+
+
+int main()
+{
+ std::list<int> a{1, 2, 3, 4};
+ std::list<int> b{5, 6, 7, 8, 9, 10, 11, 12};
+ try {
+ a.merge(b, ThrowingComparator{5});
+ } catch (...) {
+ }
+ VERIFY(a.size() == 8 && b.size() == 4);
+ std::list<X> ax{1, 2, 3, 4};
+ std::list<X> bx{5, 6, 7, 8, 9, 10, 11, 12};
+ throw_after_X = 5;
+ try {
+ ax.merge(bx);
+ } catch (...) {
+ }
+ VERIFY(ax.size() == 8 && bx.size() == 4);
+ std::list<int> ay{5, 6, 7, 8, 9, 10, 11, 12};
+ try {
+ ay.sort(ThrowingComparator{5});
+ } catch (...) {
+ }
+ VERIFY(ay.size() == 8);
+ std::list<X> az{5, 6, 7, 8, 9, 10, 11, 12};
+ throw_after_X = 5;
+ try {
+ az.sort();
+ } catch (...) {
+ }
+ VERIFY(az.size() == 8);
+}