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 <class Iterator>
void transferNodesFromList(ilist_callback_traits &OldList, Iterator /*first*/,
Iterator /*last*/) {
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);
}
template <class Iterator>
void transferNodesFromList(ilist_callback_traits &OldList, Iterator, Iterator) {
- llvm_unreachable("Never transfer between lists");
+ assert(this == &OldList && "never transfer MBBs between functions");
}
};
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
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...
} // 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<NodeWithCallback> {
+ static void deleteNode(NodeWithCallback *) {}
+};
+
template <> struct ilist_callback_traits<NodeWithCallback> {
void addNodeToList(NodeWithCallback *N) { N->IsInList = true; }
void removeNodeFromList(NodeWithCallback *N) { N->IsInList = false; }
ASSERT_TRUE(N.WasTransferred);
}
+TEST(IListTest, sameListSplice) {
+ NodeWithCallback N1(1);
+ NodeWithCallback N2(2);
+ ASSERT_FALSE(N1.WasTransferred);
+ ASSERT_FALSE(N2.WasTransferred);
+
+ ilist<NodeWithCallback> 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<PrivateNode> {
friend struct llvm::ilist_detail::NodeAccess;