Hi,
the below is what I have for the issue: see 23.2.2.3/1. Probably,
resolving libstdc++/21772 will obsolete the basic testing allocator
provided by submitter, but for the time being seems sufficient for
the job.
Anyway, looks fine to everyone? Anything simpler? Otherwise I will go
ahead for mainline. After a bit of testing seems suited also for
4_1-branch.
Paolo.
///////////////////
2005-12-09 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/25288
* include/bits/stl_list.h (list<>::_M_insert_dispatch(__false_type),
_M_fill_insert): If _M_create_node throws, erase the elements just
inserted.
* testsuite/23_containers/list/modifiers/insert/25288.cc: New.
* testsuite/testsuite_allocator.h (class throw_allocator):
Add.Index: include/bits/stl_list.h
===================================================================
--- include/bits/stl_list.h (revision 108226)
+++ include/bits/stl_list.h (working copy)
@@ -1113,8 +1113,23 @@
_InputIterator __first, _InputIterator __last,
__false_type)
{
- for (; __first != __last; ++__first)
- _M_insert(__pos, *__first);
+ iterator __tmp(__pos);
+ try
+ {
+ if (__first != __last)
+ {
+ __tmp = insert(__pos, *__first);
+ ++__first;
+ }
+
+ for (; __first != __last; ++__first)
+ _M_insert(__pos, *__first);
+ }
+ catch(...)
+ {
+ erase(__tmp, __pos);
+ __throw_exception_again;
+ }
}
// Called by insert(p,n,x), and the range insert when it
turns out
@@ -1122,8 +1137,23 @@
void
_M_fill_insert(iterator __pos, size_type __n, const
value_type& __x)
{
- for (; __n > 0; --__n)
- _M_insert(__pos, __x);
+ iterator __tmp(__pos);
+ try
+ {
+ if (__n)
+ {
+ __tmp = insert(__pos, __x);
+ --__n;
+ }
+
+ for (; __n > 0; --__n)
+ _M_insert(__pos, __x);
+ }
+ catch(...)
+ {
+ erase(__tmp, __pos);
+ __throw_exception_again;
+ }
}
Index: testsuite/23_containers/list/modifiers/insert/25288.cc
===================================================================
--- testsuite/23_containers/list/modifiers/insert/25288.cc
(revision 0)
+++ testsuite/23_containers/list/modifiers/insert/25288.cc
(revision 0)
@@ -0,0 +1,92 @@
+// Copyright (C) 2005 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 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without Pred 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 COPYING. If not, write to the
Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301,
+// USA.
+
+// 23.2.2.3 list modifiers [lib.list.modifiers]
+
+#include <list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+// libstdc++/25288
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+
+ typedef __gnu_test::throw_allocator<int> my_alloc;
+ typedef std::list<int, my_alloc > my_list;
+
+ for (int j = 0; j < 10; ++j)
+ for (int i = 0; i < 10; ++i)
+ {
+ my_alloc alloc1(j + i);
+ my_list list1(alloc1);
+
+ for (int k = 0; k < j; ++k)
+ list1.push_back(-(k + 1));
+
+ try
+ {
+ list1.insert(list1.begin(), 10, 99);
+ VERIFY( false );
+ }
+ catch (std::bad_alloc&)
+ {
+ VERIFY( true );
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
+
+ VERIFY( list1.size() == my_list::size_type(j) );
+ VERIFY( list1.size() == 0 || list1.back() == -j );
+ VERIFY( list1.size() == 0 || list1.front() == -1 );
+
+ my_alloc alloc2(j + i);
+ my_list list2(alloc2);
+
+ const int data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ for (int k = 0; k < j; ++k)
+ list2.push_back(-(k + 1));
+
+ try
+ {
+ list2.insert(list2.begin(), data, data + 10);
+ VERIFY( false );
+ }
+ catch (std::bad_alloc&)
+ {
+ VERIFY( true );
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
+
+ VERIFY( list2.size() == my_list::size_type(j) );
+ VERIFY( list2.size() == 0 || list2.back() == -j );
+ VERIFY( list2.size() == 0 || list2.front() == -1 );
+ }
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: testsuite/testsuite_allocator.h
===================================================================
--- testsuite/testsuite_allocator.h (revision 108226)
+++ testsuite/testsuite_allocator.h (working copy)
@@ -1,7 +1,7 @@
// -*- C++ -*-
// Testing allocator for the C++ library testsuite.
//
-// Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+// Copyright (C) 2002, 2003, 2004, 2005 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
@@ -229,6 +229,81 @@
}
throw;
}
+
+ template<typename Tp>
+ class throw_allocator
+ {
+ public:
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef Tp* pointer;
+ typedef const Tp* const_pointer;
+ typedef Tp& reference;
+ typedef const Tp& const_reference;
+ typedef Tp value_type;
+
+ template<typename Tp1>
+ struct rebind
+ { typedef throw_allocator<Tp1> other; };
+
+ throw_allocator() throw()
+ : count(size_type(-1)) { }
+
+ throw_allocator(size_type c) throw()
+ : count(c) { }
+
+ template<typename Tp1>
+ throw_allocator(const throw_allocator<Tp1>& b) throw()
+ : count(b.get_count()) { }
+
+ size_type get_count() const { return count; }
+
+ pointer
+ address(reference x) const { return &x; }
+
+ const_pointer
+ address(const_reference x) const { return &x; }
+
+ pointer
+ allocate(size_type n, const void* = 0)
+ {
+ if (count == 0)
+ throw std::bad_alloc();
+
+ if (count != size_type(-1))
+ --count;
+
+ return static_cast<Tp*>(::operator new(n * sizeof(Tp)));
+ }
+
+ void
+ deallocate(pointer p, size_type)
+ { ::operator delete(p); }
+
+ size_type
+ max_size() const throw()
+ { return size_type(-1) / sizeof(Tp); }
+
+ void
+ construct(pointer p, const Tp& val)
+ { ::new(p) Tp(val); }
+
+ void
+ destroy(pointer p) { p->~Tp(); }
+
+ private:
+ template<typename Tp1>
+ friend inline bool
+ operator==(const throw_allocator&, const
throw_allocator<Tp1>&)
+ { return true; }
+
+ template<typename Tp1>
+ friend inline bool
+ operator!=(const throw_allocator&, const
throw_allocator<Tp1>&)
+ { return false; }
+
+ size_type count;
+ };
}; // namespace __gnu_test
#endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H