diff options
-rw-r--r-- | llvm/include/llvm/ADT/ilist.h | 55 | ||||
-rw-r--r-- | llvm/include/llvm/ADT/ilist_node.h | 5 | ||||
-rw-r--r-- | llvm/include/llvm/CodeGen/MachineBasicBlock.h | 17 | ||||
-rw-r--r-- | llvm/include/llvm/CodeGen/MachineFunction.h | 4 | ||||
-rw-r--r-- | llvm/include/llvm/IR/SymbolTableListTraits.h | 12 | ||||
-rw-r--r-- | llvm/lib/CodeGen/MachinePipeliner.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/Target/X86/X86FixupSetCC.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/LoopRerollPass.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp | 11 | ||||
-rw-r--r-- | llvm/unittests/ADT/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/ADT/IListIteratorTest.cpp | 149 |
13 files changed, 230 insertions, 54 deletions
diff --git a/llvm/include/llvm/ADT/ilist.h b/llvm/include/llvm/ADT/ilist.h index 9ee5a283fed..1a8f67fd470 100644 --- a/llvm/include/llvm/ADT/ilist.h +++ b/llvm/include/llvm/ADT/ilist.h @@ -35,7 +35,7 @@ namespace llvm { template<typename NodeTy, typename Traits> class iplist; -template<typename NodeTy> class ilist_iterator; +template <typename NodeTy, bool IsReverse> class ilist_iterator; /// An access class for ilist_node private API. /// @@ -146,12 +146,30 @@ template <class NodeTy> struct ConstCorrectNodeType { template <class NodeTy> struct ConstCorrectNodeType<const NodeTy> { typedef const ilist_node<NodeTy> type; }; + +template <bool IsReverse = false> struct IteratorHelper { + template <class T> static void increment(T *&I) { + I = ilist_node_access::getNext(*I); + } + template <class T> static void decrement(T *&I) { + I = ilist_node_access::getPrev(*I); + } +}; +template <> struct IteratorHelper<true> { + template <class T> static void increment(T *&I) { + IteratorHelper<false>::decrement(I); + } + template <class T> static void decrement(T *&I) { + IteratorHelper<false>::increment(I); + } +}; + } // end namespace ilist_detail //===----------------------------------------------------------------------===// // Iterator for intrusive list. // -template <typename NodeTy> +template <typename NodeTy, bool IsReverse> class ilist_iterator : public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> { public: @@ -185,7 +203,7 @@ public: // a nonconst iterator... template <class node_ty> ilist_iterator( - const ilist_iterator<node_ty> &RHS, + const ilist_iterator<node_ty, IsReverse> &RHS, typename std::enable_if<std::is_convertible<node_ty *, NodeTy *>::value, void *>::type = nullptr) : NodePtr(RHS.getNodePtr()) {} @@ -193,11 +211,22 @@ public: // This is templated so that we can allow assigning to a const iterator from // a nonconst iterator... template <class node_ty> - const ilist_iterator &operator=(const ilist_iterator<node_ty> &RHS) { + const ilist_iterator & + operator=(const ilist_iterator<node_ty, IsReverse> &RHS) { NodePtr = RHS.getNodePtr(); return *this; } + /// Convert from an iterator to its reverse. + /// + /// TODO: Roll this into the implicit constructor once we're sure that no one + /// is relying on the std::reverse_iterator off-by-one semantics. + ilist_iterator<NodeTy, !IsReverse> getReverse() const { + if (NodePtr) + return ilist_iterator<NodeTy, !IsReverse>(*NodePtr); + return ilist_iterator<NodeTy, !IsReverse>(); + } + void reset(pointer NP) { NodePtr = NP; } // Accessors... @@ -217,12 +246,11 @@ public: // Increment and decrement operators... ilist_iterator &operator--() { - NodePtr = ilist_node_access::getPrev(*NodePtr); - assert(NodePtr && "--'d off the beginning of an ilist!"); + ilist_detail::IteratorHelper<IsReverse>::decrement(NodePtr); return *this; } ilist_iterator &operator++() { - NodePtr = ilist_node_access::getNext(*NodePtr); + ilist_detail::IteratorHelper<IsReverse>::increment(NodePtr); return *this; } ilist_iterator operator--(int) { @@ -356,8 +384,8 @@ public: typedef ilist_iterator<const NodeTy> const_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; + typedef ilist_iterator<const NodeTy, true> const_reverse_iterator; + typedef ilist_iterator<NodeTy, true> reverse_iterator; iplist() = default; ~iplist() { clear(); } @@ -369,11 +397,10 @@ public: const_iterator end() const { return const_iterator(Sentinel); } // reverse iterator creation methods. - reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin());} - + reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); } + const_reverse_iterator rbegin() const{ return ++const_reverse_iterator(Sentinel); } + reverse_iterator rend() { return reverse_iterator(Sentinel); } + const_reverse_iterator rend() const { return const_reverse_iterator(Sentinel); } // Miscellaneous inspection routines. size_type max_size() const { return size_type(-1); } diff --git a/llvm/include/llvm/ADT/ilist_node.h b/llvm/include/llvm/ADT/ilist_node.h index a817b4b4a18..0e4bd972292 100644 --- a/llvm/include/llvm/ADT/ilist_node.h +++ b/llvm/include/llvm/ADT/ilist_node.h @@ -51,7 +51,7 @@ public: }; struct ilist_node_access; -template <typename NodeTy> class ilist_iterator; +template <typename NodeTy, bool IsReverse = false> class ilist_iterator; template <typename NodeTy> class ilist_sentinel; /// Templated wrapper class. @@ -59,7 +59,8 @@ template <typename NodeTy> class ilist_node : ilist_node_base { friend class ilist_base; friend struct ilist_node_access; friend struct ilist_traits<NodeTy>; - friend class ilist_iterator<NodeTy>; + friend class ilist_iterator<NodeTy, false>; + friend class ilist_iterator<NodeTy, true>; friend class ilist_sentinel<NodeTy>; protected: diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h index 68a6ef33442..60268b1aafd 100644 --- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h +++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h @@ -150,9 +150,8 @@ public: typedef Instructions::iterator instr_iterator; typedef Instructions::const_iterator const_instr_iterator; - typedef std::reverse_iterator<instr_iterator> reverse_instr_iterator; - typedef - std::reverse_iterator<const_instr_iterator> const_reverse_instr_iterator; + typedef Instructions::reverse_iterator reverse_instr_iterator; + typedef Instructions::const_reverse_iterator const_reverse_instr_iterator; typedef MachineInstrBundleIterator<MachineInstr> iterator; typedef MachineInstrBundleIterator<const MachineInstr> const_iterator; @@ -193,10 +192,14 @@ public: const_iterator begin() const { return instr_begin(); } iterator end () { return instr_end(); } const_iterator end () const { return instr_end(); } - reverse_iterator rbegin() { return instr_rbegin(); } - const_reverse_iterator rbegin() const { return instr_rbegin(); } - reverse_iterator rend () { return instr_rend(); } - const_reverse_iterator rend () const { return instr_rend(); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } /// Support for MachineInstr::getNextNode(). static Instructions MachineBasicBlock::*getSublistAccess(MachineInstr *) { diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index e14614ca757..b6c1a08c98e 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -445,8 +445,8 @@ public: // Provide accessors for the MachineBasicBlock list... typedef BasicBlockListType::iterator iterator; typedef BasicBlockListType::const_iterator const_iterator; - typedef std::reverse_iterator<const_iterator> const_reverse_iterator; - typedef std::reverse_iterator<iterator> reverse_iterator; + typedef BasicBlockListType::const_reverse_iterator const_reverse_iterator; + typedef BasicBlockListType::reverse_iterator reverse_iterator; /// Support for MachineBasicBlock::getNextNode(). static BasicBlockListType MachineFunction::* diff --git a/llvm/include/llvm/IR/SymbolTableListTraits.h b/llvm/include/llvm/IR/SymbolTableListTraits.h index f0f8ba3ae4d..87364aa32cd 100644 --- a/llvm/include/llvm/IR/SymbolTableListTraits.h +++ b/llvm/include/llvm/IR/SymbolTableListTraits.h @@ -30,10 +30,6 @@ namespace llvm { class ValueSymbolTable; -template <typename NodeTy> class ilist_iterator; -template <typename NodeTy, typename Traits> class iplist; -template <typename Ty> struct ilist_traits; - /// Template metafunction to get the parent type for a symbol table list. /// /// Implementations create a typedef called \c type so that we only need a @@ -66,6 +62,7 @@ template <typename NodeTy> class SymbolTableList; template <typename ValueSubClass> class SymbolTableListTraits : public ilist_node_traits<ValueSubClass> { typedef SymbolTableList<ValueSubClass> ListTy; + typedef ilist_iterator<ValueSubClass, false> iterator; typedef typename SymbolTableListParentType<ValueSubClass>::type ItemParentClass; @@ -94,10 +91,9 @@ private: public: void addNodeToList(ValueSubClass *V); void removeNodeFromList(ValueSubClass *V); - void transferNodesFromList(SymbolTableListTraits &L2, - ilist_iterator<ValueSubClass> first, - ilist_iterator<ValueSubClass> last); -//private: + void transferNodesFromList(SymbolTableListTraits &L2, iterator first, + iterator last); + // private: template<typename TPtr> void setSymTabObject(TPtr *, TPtr); static ValueSymbolTable *toPtr(ValueSymbolTable *P) { return P; } diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index 0eff6e603d2..9648fd8d35d 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -2880,8 +2880,7 @@ void SwingSchedulerDAG::removeDeadInstructions(MachineBasicBlock *KernelBB, used = false; } if (!used) { - MI->eraseFromParent(); - ME = (*MBB)->instr_rend(); + MI++->eraseFromParent(); continue; } ++MI; diff --git a/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp b/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp index e0798bf4482..be940904922 100644 --- a/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp +++ b/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp @@ -105,7 +105,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { // RET is generated as part of epilogue generation and hence we know // what the two instructions preceding it are and that it is safe to // insert RET above them. - MachineBasicBlock::reverse_instr_iterator RI(I); + MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse(); assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() && RI->getOperand(0).getReg() == Lanai::FP && RI->getOperand(1).isReg() && @@ -117,8 +117,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { RI->getOperand(0).getReg() == Lanai::SP && RI->getOperand(1).isReg() && RI->getOperand(1).getReg() == Lanai::FP); - ++RI; - MachineBasicBlock::instr_iterator FI(RI.base()); + MachineBasicBlock::instr_iterator FI = RI.getReverse(); MBB.splice(std::next(I), &MBB, FI, I); FilledSlots += 2; } else { @@ -154,14 +153,14 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB, bool SawLoad = false; bool SawStore = false; - for (MachineBasicBlock::reverse_instr_iterator I(Slot); I != MBB.instr_rend(); - ++I) { + for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse(); + I != MBB.instr_rend(); ++I) { // skip debug value if (I->isDebugValue()) continue; // Convert to forward iterator. - MachineBasicBlock::instr_iterator FI(std::next(I).base()); + MachineBasicBlock::instr_iterator FI = I.getReverse(); if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() || FI == LastFiller || I->isPseudo()) diff --git a/llvm/lib/Target/X86/X86FixupSetCC.cpp b/llvm/lib/Target/X86/X86FixupSetCC.cpp index fb317da9535..cf3d43132cb 100644 --- a/llvm/lib/Target/X86/X86FixupSetCC.cpp +++ b/llvm/lib/Target/X86/X86FixupSetCC.cpp @@ -99,7 +99,8 @@ bool X86FixupSetCCPass::isSetCCr(unsigned Opcode) { MachineInstr * X86FixupSetCCPass::findFlagsImpDef(MachineBasicBlock *MBB, MachineBasicBlock::reverse_iterator MI) { - auto MBBStart = MBB->instr_rend(); + // FIXME: Should this be instr_rend(), and MI be reverse_instr_iterator? + auto MBBStart = MBB->rend(); for (int i = 0; (i < SearchBound) && (MI != MBBStart); ++i, ++MI) for (auto &Op : MI->implicit_operands()) if ((Op.getReg() == X86::EFLAGS) && (Op.isDef())) diff --git a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp index 4e9fdf86344..6523674b3f6 100644 --- a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp @@ -1412,13 +1412,12 @@ bool LoopReroll::DAGRootTracker::validate(ReductionTracker &Reductions) { void LoopReroll::DAGRootTracker::replace(const SCEV *IterCount) { BasicBlock *Header = L->getHeader(); // Remove instructions associated with non-base iterations. - for (BasicBlock::reverse_iterator J = Header->rbegin(); - J != Header->rend();) { + for (BasicBlock::reverse_iterator J = Header->rbegin(), JE = Header->rend(); + J != JE;) { unsigned I = Uses[&*J].find_first(); if (I > 0 && I < IL_All) { - Instruction *D = &*J; - DEBUG(dbgs() << "LRR: removing: " << *D << "\n"); - D->eraseFromParent(); + DEBUG(dbgs() << "LRR: removing: " << *J << "\n"); + J++->eraseFromParent(); continue; } diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index 6726e0e9642..eafdb46b384 100644 --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -2578,8 +2578,8 @@ static void findLiveSetAtInst(Instruction *Inst, GCPtrLivenessData &Data, // call result is not live (normal), nor are it's arguments // (unless they're used again later). This adjustment is // specifically what we need to relocate - BasicBlock::reverse_iterator rend(Inst->getIterator()); - computeLiveInValues(BB->rbegin(), rend, LiveOut); + computeLiveInValues(BB->rbegin(), ++Inst->getIterator().getReverse(), + LiveOut); LiveOut.remove(Inst); Out.insert(LiveOut.begin(), LiveOut.end()); } diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index d9915d3ba9f..83e65094d7f 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -1868,9 +1868,9 @@ int BoUpSLP::getSpillCost() { ); // Now find the sequence of instructions between PrevInst and Inst. - BasicBlock::reverse_iterator InstIt(Inst->getIterator()), - PrevInstIt(PrevInst->getIterator()); - --PrevInstIt; + BasicBlock::reverse_iterator InstIt = ++Inst->getIterator().getReverse(), + PrevInstIt = + PrevInst->getIterator().getReverse(); while (InstIt != PrevInstIt) { if (PrevInstIt == PrevInst->getParent()->rend()) { PrevInstIt = Inst->getParent()->rbegin(); @@ -3036,9 +3036,10 @@ bool BoUpSLP::BlockScheduling::extendSchedulingRegion(Value *V) { } // Search up and down at the same time, because we don't know if the new // instruction is above or below the existing scheduling region. - BasicBlock::reverse_iterator UpIter(ScheduleStart->getIterator()); + BasicBlock::reverse_iterator UpIter = + ++ScheduleStart->getIterator().getReverse(); BasicBlock::reverse_iterator UpperEnd = BB->rend(); - BasicBlock::iterator DownIter(ScheduleEnd); + BasicBlock::iterator DownIter = ScheduleEnd->getIterator(); BasicBlock::iterator LowerEnd = BB->end(); for (;;) { if (++ScheduleRegionSize > ScheduleRegionSizeLimit) { diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt index ed008a34ae6..4026a0758ef 100644 --- a/llvm/unittests/ADT/CMakeLists.txt +++ b/llvm/unittests/ADT/CMakeLists.txt @@ -19,6 +19,7 @@ set(ADTSources HashingTest.cpp ilistTestTemp.cpp IListBaseTest.cpp + IListIteratorTest.cpp IListNodeBaseTest.cpp IListSentinelTest.cpp ImmutableMapTest.cpp diff --git a/llvm/unittests/ADT/IListIteratorTest.cpp b/llvm/unittests/ADT/IListIteratorTest.cpp new file mode 100644 index 00000000000..1a87a270a67 --- /dev/null +++ b/llvm/unittests/ADT/IListIteratorTest.cpp @@ -0,0 +1,149 @@ +//===- unittests/ADT/IListIteratorTest.cpp - ilist_iterator unit tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ilist.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +struct Node : ilist_node<Node> {}; + +TEST(IListIteratorTest, DefaultConstructor) { + iplist<Node>::iterator I; + iplist<Node>::reverse_iterator RI; + iplist<Node>::const_iterator CI; + iplist<Node>::const_reverse_iterator CRI; + EXPECT_EQ(nullptr, I.getNodePtr()); + EXPECT_EQ(nullptr, CI.getNodePtr()); + EXPECT_EQ(nullptr, RI.getNodePtr()); + EXPECT_EQ(nullptr, CRI.getNodePtr()); + EXPECT_EQ(I, I); + EXPECT_EQ(I, CI); + EXPECT_EQ(CI, I); + EXPECT_EQ(CI, CI); + EXPECT_EQ(RI, RI); + EXPECT_EQ(RI, CRI); + EXPECT_EQ(CRI, RI); + EXPECT_EQ(CRI, CRI); + EXPECT_EQ(I, RI.getReverse()); + EXPECT_EQ(RI, I.getReverse()); +} + +TEST(IListIteratorTest, Empty) { + iplist<Node> L; + + // Check iterators of L. + EXPECT_EQ(L.begin(), L.end()); + EXPECT_EQ(L.rbegin(), L.rend()); + + // Reverse of end should be rend (since the sentinel sits on both sides). + EXPECT_EQ(L.end(), L.rend().getReverse()); + EXPECT_EQ(L.rend(), L.end().getReverse()); + + // Iterators shouldn't match default constructors. + iplist<Node>::iterator I; + iplist<Node>::reverse_iterator RI; + EXPECT_NE(I, L.begin()); + EXPECT_NE(I, L.end()); + EXPECT_NE(RI, L.rbegin()); + EXPECT_NE(RI, L.rend()); + + // Don't delete nodes. + L.clearAndLeakNodesUnsafely(); +} + +TEST(IListIteratorTest, OneNodeList) { + iplist<Node> L; + Node A; + L.insert(L.end(), &A); + + // Check address of reference. + EXPECT_EQ(&A, &*L.begin()); + EXPECT_EQ(&A, &*L.rbegin()); + + // Check that the handle matches. + EXPECT_EQ(L.rbegin().getNodePtr(), L.begin().getNodePtr()); + + // Check iteration. + EXPECT_EQ(L.end(), ++L.begin()); + EXPECT_EQ(L.begin(), --L.end()); + EXPECT_EQ(L.rend(), ++L.rbegin()); + EXPECT_EQ(L.rbegin(), --L.rend()); + + // Check conversions. + EXPECT_EQ(L.rbegin(), L.begin().getReverse()); + EXPECT_EQ(L.begin(), L.rbegin().getReverse()); + + // Don't delete nodes. + L.clearAndLeakNodesUnsafely(); +} + +TEST(IListIteratorTest, TwoNodeList) { + iplist<Node> L; + Node A, B; + L.insert(L.end(), &A); + L.insert(L.end(), &B); + + // Check order. + EXPECT_EQ(&A, &*L.begin()); + EXPECT_EQ(&B, &*++L.begin()); + EXPECT_EQ(L.end(), ++++L.begin()); + EXPECT_EQ(&B, &*L.rbegin()); + EXPECT_EQ(&A, &*++L.rbegin()); + EXPECT_EQ(L.rend(), ++++L.rbegin()); + + // Check conversions. + EXPECT_EQ(++L.rbegin(), L.begin().getReverse()); + EXPECT_EQ(L.rbegin(), (++L.begin()).getReverse()); + EXPECT_EQ(++L.begin(), L.rbegin().getReverse()); + EXPECT_EQ(L.begin(), (++L.rbegin()).getReverse()); + + // Don't delete nodes. + L.clearAndLeakNodesUnsafely(); +} + +TEST(IListIteratorTest, CheckEraseForward) { + iplist<Node> L; + Node A, B; + L.insert(L.end(), &A); + L.insert(L.end(), &B); + + // Erase nodes. + auto I = L.begin(); + EXPECT_EQ(&A, &*I); + EXPECT_EQ(&A, L.remove(I++)); + EXPECT_EQ(&B, &*I); + EXPECT_EQ(&B, L.remove(I++)); + EXPECT_EQ(L.end(), I); + + // Don't delete nodes. + L.clearAndLeakNodesUnsafely(); +} + +TEST(IListIteratorTest, CheckEraseReverse) { + iplist<Node> L; + Node A, B; + L.insert(L.end(), &A); + L.insert(L.end(), &B); + + // Erase nodes. + auto RI = L.rbegin(); + EXPECT_EQ(&B, &*RI); + EXPECT_EQ(&B, L.remove(&*RI++)); + EXPECT_EQ(&A, &*RI); + EXPECT_EQ(&A, L.remove(&*RI++)); + EXPECT_EQ(L.rend(), RI); + + // Don't delete nodes. + L.clearAndLeakNodesUnsafely(); +} + +} // end namespace |