re PR libstdc++/41316 ([C++0x] forward_list::sort violates strict aliasing rules)

2009-09-11  Paolo Carlini  <paolo.carlini@oracle.com>

	PR libstdc++/41316
	* include/bits/forward_list.h (_Fwd_list_node_base<>::_M_sort_after):
	Remove.
	(forward_list<>::sort(_Comp)): Only declare.
	(forward_list<>::sort()): Forward to the latter.
	* include/bits/forward_list.tcc (_Fwd_list_node_base<>::_M_sort_after):
	Remove definition.
	(forward_list<>::sort(_Comp)): Define.
	* testsuite/23_containers/forward_list/requirements/dr438/
	assign_neg.cc: Adjust dg-error line number.
	* testsuite/23_containers/forward_list/requirements/dr438/
	insert_neg.cc: Likewise.
	* testsuite/23_containers/forward_list/requirements/dr438/
	constructor_1_neg.cc: Likewise.
	* testsuite/23_containers/forward_list/requirements/dr438/
	constructor_2_neg.cc: Likewise.

From-SVN: r151635
This commit is contained in:
Paolo Carlini 2009-09-11 13:47:36 +00:00 committed by Paolo Carlini
parent db689ed6ab
commit fc52f99da8
7 changed files with 130 additions and 124 deletions

View File

@ -1,3 +1,22 @@
2009-09-11 Paolo Carlini <paolo.carlini@oracle.com>
PR libstdc++/41316
* include/bits/forward_list.h (_Fwd_list_node_base<>::_M_sort_after):
Remove.
(forward_list<>::sort(_Comp)): Only declare.
(forward_list<>::sort()): Forward to the latter.
* include/bits/forward_list.tcc (_Fwd_list_node_base<>::_M_sort_after):
Remove definition.
(forward_list<>::sort(_Comp)): Define.
* testsuite/23_containers/forward_list/requirements/dr438/
assign_neg.cc: Adjust dg-error line number.
* testsuite/23_containers/forward_list/requirements/dr438/
insert_neg.cc: Likewise.
* testsuite/23_containers/forward_list/requirements/dr438/
constructor_1_neg.cc: Likewise.
* testsuite/23_containers/forward_list/requirements/dr438/
constructor_2_neg.cc: Likewise.
2009-09-11 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
* src/Makefile.am (libstdc___la_LINK): New.

View File

@ -92,10 +92,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
: _Fwd_list_node_base<_Alloc>(),
_M_value(std::forward<_Args>(__args)...) { }
template<typename _Comp>
void
_M_sort_after(_Comp __comp);
_Tp _M_value;
};
@ -1149,7 +1145,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
*/
void
merge(forward_list&& __list)
{ this->merge(std::forward<forward_list>(__list), std::less<_Tp>()); }
{ this->merge(std::move(__list), std::less<_Tp>()); }
/**
* @brief Merge sorted lists according to comparison function.
@ -1174,10 +1170,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
*/
void
sort()
{
_Node* __tmp = __static_pointer_cast<_Node*>(&this->_M_impl._M_head);
__tmp->_M_sort_after(std::less<_Tp>());
}
{ this->sort(std::less<_Tp>()); }
/**
* @brief Sort the forward_list using a comparison function.
@ -1187,11 +1180,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
*/
template<typename _Comp>
void
sort(_Comp __comp)
{
_Node* __tmp = __static_pointer_cast<_Node*>(&this->_M_impl._M_head);
__tmp->_M_sort_after(__comp);
}
sort(_Comp __comp);
/**
* @brief Reverse the elements in list.
@ -1285,7 +1274,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
template<typename _Tp, typename _Alloc>
inline void
swap(forward_list<_Tp, _Alloc>& __lx,
forward_list<_Tp, _Alloc>& __ly)
forward_list<_Tp, _Alloc>& __ly)
{ __lx.swap(__ly); }
_GLIBCXX_END_NAMESPACE // namespace std

View File

@ -75,111 +75,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
}
}
/**
* @brief Sort the singly linked list starting after this node.
* This node is assumed to be an empty head node (of type
* _Fwd_list_node_base).
*/
template<typename _Tp, class _Alloc>
template<typename _Comp>
void
_Fwd_list_node<_Tp, _Alloc>::
_M_sort_after(_Comp __comp)
{
// If `next' is 0, return immediately.
_Pointer __list = __static_pointer_cast<_Pointer>(this->_M_next);
if (!__list)
return;
unsigned long __insize = 1;
while (1)
{
_Pointer __p = __list;
__list = 0;
_Pointer __tail = 0;
// Count number of merges we do in this pass.
unsigned long __nmerges = 0;
while (__p)
{
++__nmerges;
// There exists a merge to be done.
// Step `insize' places along from p.
_Pointer __q = __p;
unsigned long __psize = 0;
for (unsigned long __i = 0; __i < __insize; ++__i)
{
++__psize;
__q = __static_pointer_cast<_Pointer>(__q->_M_next);
if (!__q)
break;
}
// If q hasn't fallen off end, we have two lists to merge.
unsigned long __qsize = __insize;
// Now we have two lists; merge them.
while (__psize > 0 || (__qsize > 0 && __q))
{
// Decide whether next node of merge comes from p or q.
_Pointer __e;
if (__psize == 0)
{
// p is empty; e must come from q.
__e = __q;
__q = __static_pointer_cast<_Pointer>(__q->_M_next);
--__qsize;
}
else if (__qsize == 0 || !__q)
{
// q is empty; e must come from p.
__e = __p;
__p = __static_pointer_cast<_Pointer>(__p->_M_next);
--__psize;
}
else if (__comp(__p->_M_value, __q->_M_value))
{
// First node of p is lower; e must come from p.
__e = __p;
__p = __static_pointer_cast<_Pointer>(__p->_M_next);
--__psize;
}
else
{
// First node of q is lower; e must come from q.
__e = __q;
__q = __static_pointer_cast<_Pointer>(__q->_M_next);
--__qsize;
}
// Add the next node to the merged list.
if (__tail)
__tail->_M_next = __e;
else
__list = __e;
__tail = __e;
}
// Now p has stepped `insize' places along, and q has too.
__p = __q;
}
__tail->_M_next = 0;
// If we have done only one merge, we're finished.
// Allow for nmerges == 0, the empty list case.
if (__nmerges <= 1)
{
this->_M_next = __list;
return;
}
// Otherwise repeat, merging lists twice the size.
__insize *= 2;
}
}
template<typename _Tp, typename _Alloc>
_Fwd_list_base<_Tp, _Alloc>::
_Fwd_list_base(const _Fwd_list_base& __lst, const _Alloc& __a)
@ -472,6 +367,109 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
return false;
}
template<typename _Tp, class _Alloc>
template<typename _Comp>
void
forward_list<_Tp, _Alloc>::
sort(_Comp __comp)
{
typedef typename _Node::_Pointer _Pointer;
// If `next' is 0, return immediately.
_Pointer __list =
__static_pointer_cast<_Pointer>(this->_M_impl._M_head._M_next);
if (!__list)
return;
unsigned long __insize = 1;
while (1)
{
_Pointer __p = __list;
__list = 0;
_Pointer __tail = 0;
// Count number of merges we do in this pass.
unsigned long __nmerges = 0;
while (__p)
{
++__nmerges;
// There exists a merge to be done.
// Step `insize' places along from p.
_Pointer __q = __p;
unsigned long __psize = 0;
for (unsigned long __i = 0; __i < __insize; ++__i)
{
++__psize;
__q = __static_pointer_cast<_Pointer>(__q->_M_next);
if (!__q)
break;
}
// If q hasn't fallen off end, we have two lists to merge.
unsigned long __qsize = __insize;
// Now we have two lists; merge them.
while (__psize > 0 || (__qsize > 0 && __q))
{
// Decide whether next node of merge comes from p or q.
_Pointer __e;
if (__psize == 0)
{
// p is empty; e must come from q.
__e = __q;
__q = __static_pointer_cast<_Pointer>(__q->_M_next);
--__qsize;
}
else if (__qsize == 0 || !__q)
{
// q is empty; e must come from p.
__e = __p;
__p = __static_pointer_cast<_Pointer>(__p->_M_next);
--__psize;
}
else if (__comp(__p->_M_value, __q->_M_value))
{
// First node of p is lower; e must come from p.
__e = __p;
__p = __static_pointer_cast<_Pointer>(__p->_M_next);
--__psize;
}
else
{
// First node of q is lower; e must come from q.
__e = __q;
__q = __static_pointer_cast<_Pointer>(__q->_M_next);
--__qsize;
}
// Add the next node to the merged list.
if (__tail)
__tail->_M_next = __e;
else
__list = __e;
__tail = __e;
}
// Now p has stepped `insize' places along, and q has too.
__p = __q;
}
__tail->_M_next = 0;
// If we have done only one merge, we're finished.
// Allow for nmerges == 0, the empty list case.
if (__nmerges <= 1)
{
this->_M_impl._M_head._M_next = __list;
return;
}
// Otherwise repeat, merging lists twice the size.
__insize *= 2;
}
}
_GLIBCXX_END_NAMESPACE // namespace std
#endif /* _FORWARD_LIST_TCC */

View File

@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-std=gnu++0x" }
// { dg-error "no matching" "" { target *-*-* } 1209 }
// { dg-error "no matching" "" { target *-*-* } 1198 }
// { dg-excess-errors "" }
// Copyright (C) 2009 Free Software Foundation

View File

@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-std=gnu++0x" }
// { dg-error "no matching" "" { target *-*-* } 1209 }
// { dg-error "no matching" "" { target *-*-* } 1198 }
// { dg-excess-errors "" }
// Copyright (C) 2009 Free Software Foundation

View File

@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-std=gnu++0x" }
// { dg-error "no matching" "" { target *-*-* } 1209 }
// { dg-error "no matching" "" { target *-*-* } 1198 }
// { dg-excess-errors "" }
// Copyright (C) 2009 Free Software Foundation

View File

@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-std=gnu++0x" }
// { dg-error "no matching" "" { target *-*-* } 1209 }
// { dg-error "no matching" "" { target *-*-* } 1198 }
// { dg-excess-errors "" }
// Copyright (C) 2009 Free Software Foundation