Skip to content
Snippets Groups Projects
Commit 7daf5242 authored by Tom Stellard's avatar Tom Stellard
Browse files

Merging r323390:

------------------------------------------------------------------------
r323390 | ericwf | 2018-01-24 16:02:48 -0800 (Wed, 24 Jan 2018) | 9 lines

Fix PR35564 - std::list splice/erase incorrectly throw in debug mode.

There was a bug in the implementation of splice where the container
sizes were updated before decrementing one of the iterators. Afterwards,
the result of decrementing the iterator was flagged as UB by the debug
implementation because the container was reported to be empty.

This patch fixes that bug by delaying the updating of the container
sizes until after the iterators have been correctly constructed.
------------------------------------------------------------------------

llvm-svn: 334621
parent 4f031296
No related branches found
No related tags found
No related merge requests found
......@@ -2058,15 +2058,15 @@ list<_Tp, _Alloc>::splice(const_iterator __p, list& __c, const_iterator __f, con
#endif
if (__f != __l)
{
__link_pointer __first = __f.__ptr_;
--__l;
__link_pointer __last = __l.__ptr_;
if (this != &__c)
{
size_type __s = _VSTD::distance(__f, __l);
size_type __s = _VSTD::distance(__f, __l) + 1;
__c.__sz() -= __s;
base::__sz() += __s;
}
__link_pointer __first = __f.__ptr_;
--__l;
__link_pointer __last = __l.__ptr_;
base::__unlink_nodes(__first, __last);
__link_nodes(__p.__ptr_, __first, __last);
#if _LIBCPP_DEBUG_LEVEL >= 2
......
......@@ -42,6 +42,7 @@ public:
Base::run();
try {
FrontOnEmptyContainer();
if constexpr (CT != CT_ForwardList) {
AssignInvalidates();
BackOnEmptyContainer();
......@@ -50,6 +51,8 @@ public:
InsertIterIterIter();
EmplaceIterValue();
EraseIterIter();
} else {
SpliceFirstElemAfter();
}
if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
PopBack();
......@@ -57,12 +60,66 @@ public:
if constexpr (CT == CT_List || CT == CT_Deque) {
PopFront(); // FIXME: Run with forward list as well
}
if constexpr (CT == CT_List || CT == CT_ForwardList) {
RemoveFirstElem();
}
if constexpr (CT == CT_List) {
SpliceFirstElem();
}
} catch (...) {
assert(false && "uncaught debug exception");
}
}
private:
static void RemoveFirstElem() {
// See llvm.org/PR35564
CHECKPOINT("remove(<first-elem>)");
{
Container C = makeContainer(1);
auto FirstVal = *(C.begin());
C.remove(FirstVal);
assert(C.empty());
}
{
Container C = {1, 1, 1, 1};
auto FirstVal = *(C.begin());
C.remove(FirstVal);
assert(C.empty());
}
}
static void SpliceFirstElem() {
// See llvm.org/PR35564
CHECKPOINT("splice(<first-elem>)");
{
Container C = makeContainer(1);
Container C2;
C2.splice(C2.end(), C, C.begin(), ++C.begin());
}
{
Container C = makeContainer(1);
Container C2;
C2.splice(C2.end(), C, C.begin());
}
}
static void SpliceFirstElemAfter() {
// See llvm.org/PR35564
CHECKPOINT("splice(<first-elem>)");
{
Container C = makeContainer(1);
Container C2;
C2.splice_after(C2.begin(), C, C.begin(), ++C.begin());
}
{
Container C = makeContainer(1);
Container C2;
C2.splice_after(C2.begin(), C, C.begin());
}
}
static void AssignInvalidates() {
CHECKPOINT("assign(Size, Value)");
Container C(allocator_type{});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment