Index: llvm/trunk/include/llvm/ADT/ilist.h =================================================================== --- llvm/trunk/include/llvm/ADT/ilist.h +++ llvm/trunk/include/llvm/ADT/ilist.h @@ -65,9 +65,8 @@ void addNodeToList(NodeTy *) {} void removeNodeFromList(NodeTy *) {} - /// Callback before transferring nodes to this list. - /// - /// \pre \c this!=&OldList + /// Callback before transferring nodes to this list. The nodes may already be + /// in this same list. template void transferNodesFromList(ilist_callback_traits &OldList, Iterator /*first*/, Iterator /*last*/) { @@ -286,8 +285,8 @@ if (position == last) return; - if (this != &L2) // Notify traits we moved the nodes... - this->transferNodesFromList(L2, first, last); + // Notify traits we moved the nodes... + this->transferNodesFromList(L2, first, last); base_list_type::splice(position, L2, first, last); } Index: llvm/trunk/include/llvm/CodeGen/MachineFunction.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineFunction.h +++ llvm/trunk/include/llvm/CodeGen/MachineFunction.h @@ -85,7 +85,7 @@ template void transferNodesFromList(ilist_callback_traits &OldList, Iterator, Iterator) { - llvm_unreachable("Never transfer between lists"); + assert(this == &OldList && "never transfer MBBs between functions"); } }; Index: llvm/trunk/lib/CodeGen/MachineBasicBlock.cpp =================================================================== --- llvm/trunk/lib/CodeGen/MachineBasicBlock.cpp +++ llvm/trunk/lib/CodeGen/MachineBasicBlock.cpp @@ -132,8 +132,12 @@ instr_iterator First, instr_iterator Last) { assert(Parent->getParent() == FromList.Parent->getParent() && - "MachineInstr parent mismatch!"); - assert(this != &FromList && "Called without a real transfer..."); + "cannot transfer MachineInstrs between MachineFunctions"); + + // If it's within the same BB, there's nothing to do. + if (this == &FromList) + return; + assert(Parent != FromList.Parent && "Two lists have the same parent?"); // If splicing between two blocks within the same function, just update the Index: llvm/trunk/lib/IR/SymbolTableListTraitsImpl.h =================================================================== --- llvm/trunk/lib/IR/SymbolTableListTraitsImpl.h +++ llvm/trunk/lib/IR/SymbolTableListTraitsImpl.h @@ -83,7 +83,8 @@ SymbolTableListTraits &L2, iterator first, iterator last) { // We only have to do work here if transferring instructions between BBs ItemParentClass *NewIP = getListOwner(), *OldIP = L2.getListOwner(); - assert(NewIP != OldIP && "Expected different list owners"); + if (NewIP == OldIP) + return; // We only have to update symbol table entries if we are transferring the // instructions to a different symtab object... Index: llvm/trunk/unittests/ADT/IListTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/IListTest.cpp +++ llvm/trunk/unittests/ADT/IListTest.cpp @@ -207,6 +207,12 @@ } // end namespace namespace llvm { +// These nodes are stack-allocated for testing purposes, so don't let the ilist +// own or delete them. +template <> struct ilist_alloc_traits { + static void deleteNode(NodeWithCallback *) {} +}; + template <> struct ilist_callback_traits { void addNodeToList(NodeWithCallback *N) { N->IsInList = true; } void removeNodeFromList(NodeWithCallback *N) { N->IsInList = false; } @@ -247,6 +253,30 @@ ASSERT_TRUE(N.WasTransferred); } +TEST(IListTest, sameListSplice) { + NodeWithCallback N1(1); + NodeWithCallback N2(2); + ASSERT_FALSE(N1.WasTransferred); + ASSERT_FALSE(N2.WasTransferred); + + ilist L1; + L1.insert(L1.end(), &N1); + L1.insert(L1.end(), &N2); + ASSERT_EQ(2u, L1.size()); + ASSERT_EQ(&N1, &L1.front()); + ASSERT_FALSE(N1.WasTransferred); + ASSERT_FALSE(N2.WasTransferred); + + // Swap the nodes with splice inside the same list. Check that we get the + // transfer callback. + L1.splice(L1.begin(), L1, std::next(L1.begin()), L1.end()); + ASSERT_EQ(2u, L1.size()); + ASSERT_EQ(&N1, &L1.back()); + ASSERT_EQ(&N2, &L1.front()); + ASSERT_FALSE(N1.WasTransferred); + ASSERT_TRUE(N2.WasTransferred); +} + struct PrivateNode : private ilist_node { friend struct llvm::ilist_detail::NodeAccess;