diff --git a/llvm/include/llvm/ADT/ilist_base.h b/llvm/include/llvm/ADT/ilist_base.h index b8c098b951ade..000253a26012b 100644 --- a/llvm/include/llvm/ADT/ilist_base.h +++ b/llvm/include/llvm/ADT/ilist_base.h @@ -15,9 +15,9 @@ namespace llvm { /// Implementations of list algorithms using ilist_node_base. -template class ilist_base { +template class ilist_base { public: - using node_base_type = ilist_node_base; + using node_base_type = ilist_node_base; static void insertBeforeImpl(node_base_type &Next, node_base_type &N) { node_base_type &Prev = *Next.getPrev(); diff --git a/llvm/include/llvm/ADT/ilist_iterator.h b/llvm/include/llvm/ADT/ilist_iterator.h index 2393c4d2c403c..16a45b5beac50 100644 --- a/llvm/include/llvm/ADT/ilist_iterator.h +++ b/llvm/include/llvm/ADT/ilist_iterator.h @@ -50,14 +50,44 @@ template <> struct IteratorHelper : ilist_detail::NodeAccess { template static void decrement(T *&I) { I = Access::getNext(*I); } }; +/// Mixin class used to add a \a getNodeParent() function to iterators iff the +/// list uses \a ilist_parent, calling through to the node's \a getParent(). For +/// more details see \a ilist_node. +template +class iterator_parent_access; +template +class iterator_parent_access { +public: + inline const ParentPtrTy getNodeParent() const { + return static_cast(this)->NodePtr->getParent(); + } +}; +template +class iterator_parent_access { +public: + inline ParentPtrTy getNodeParent() { + return static_cast(this)->NodePtr->getParent(); + } +}; +template +class iterator_parent_access {}; +template +class iterator_parent_access {}; + } // end namespace ilist_detail /// Iterator for intrusive lists based on ilist_node. template -class ilist_iterator : ilist_detail::SpecificNodeAccess { +class ilist_iterator : ilist_detail::SpecificNodeAccess, + public ilist_detail::iterator_parent_access< + ilist_iterator, + typename OptionsT::parent_ptr_ty, IsConst> { friend ilist_iterator; friend ilist_iterator; friend ilist_iterator; + friend ilist_detail::iterator_parent_access< + ilist_iterator, + typename OptionsT::parent_ptr_ty, IsConst>; using Traits = ilist_detail::IteratorTraits; using Access = ilist_detail::SpecificNodeAccess; @@ -168,6 +198,8 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess { return tmp; } + bool isValid() const { return NodePtr; } + /// Get the underlying ilist_node. node_pointer getNodePtr() const { return static_cast(NodePtr); } @@ -179,10 +211,17 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess { /// but with the addition of two bits recording whether this position (when in /// a range) is half or fully open. template -class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess { +class ilist_iterator_w_bits + : ilist_detail::SpecificNodeAccess, + public ilist_detail::iterator_parent_access< + ilist_iterator_w_bits, + typename OptionsT::parent_ptr_ty, IsConst> { friend ilist_iterator_w_bits; friend ilist_iterator_w_bits; friend ilist_iterator; + friend ilist_detail::iterator_parent_access< + ilist_iterator_w_bits, + typename OptionsT::parent_ptr_ty, IsConst>; using Traits = ilist_detail::IteratorTraits; using Access = ilist_detail::SpecificNodeAccess; @@ -319,6 +358,8 @@ class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess { return tmp; } + bool isValid() const { return NodePtr; } + /// Get the underlying ilist_node. node_pointer getNodePtr() const { return static_cast(NodePtr); } diff --git a/llvm/include/llvm/ADT/ilist_node.h b/llvm/include/llvm/ADT/ilist_node.h index 3b6f0dcc7b5e9..209fd209167e8 100644 --- a/llvm/include/llvm/ADT/ilist_node.h +++ b/llvm/include/llvm/ADT/ilist_node.h @@ -24,6 +24,23 @@ namespace ilist_detail { struct NodeAccess; +/// Mixin base class that is used to add \a getParent() and +/// \a setParent(ParentPtrTy) methods to \a ilist_node_impl iff \a ilist_parent +/// has been set in the list options. +template class node_parent_access { +public: + inline const ParentPtrTy getParent() const { + return static_cast(this)->getNodeBaseParent(); + } + inline ParentPtrTy getParent() { + return static_cast(this)->getNodeBaseParent(); + } + void setParent(ParentPtrTy Parent) { + return static_cast(this)->setNodeBaseParent(Parent); + } +}; +template class node_parent_access {}; + } // end namespace ilist_detail template class ilist_iterator; @@ -51,7 +68,11 @@ class ilist_select_iterator_type { /// This is a wrapper around \a ilist_node_base whose main purpose is to /// provide type safety: you can't insert nodes of \a ilist_node_impl into the /// wrong \a simple_ilist or \a iplist. -template class ilist_node_impl : OptionsT::node_base_type { +template +class ilist_node_impl + : OptionsT::node_base_type, + public ilist_detail::node_parent_access< + ilist_node_impl, typename OptionsT::parent_ptr_ty> { using value_type = typename OptionsT::value_type; using node_base_type = typename OptionsT::node_base_type; using list_base_type = typename OptionsT::list_base_type; @@ -60,6 +81,8 @@ template class ilist_node_impl : OptionsT::node_base_type { friend struct ilist_detail::NodeAccess; friend class ilist_sentinel; + friend class ilist_detail::node_parent_access< + ilist_node_impl, typename OptionsT::parent_ptr_ty>; friend class ilist_iterator; friend class ilist_iterator; friend class ilist_iterator; @@ -171,6 +194,20 @@ template class ilist_node_impl : OptionsT::node_base_type { /// } /// \endexample /// +/// When the \a ilist_parent option is passed to an ilist_node and the +/// owning ilist, each node contains a pointer to the ilist's owner. This adds +/// \a getParent() and \a setParent(ParentTy*) methods to the ilist_node, which +/// will be used for node access by the ilist if the node class publicly +/// inherits from \a ilist_node_with_parent. By default, setParent() is not +/// automatically called by the ilist; a SymbolTableList will call setParent() +/// on inserted nodes, but the sentinel must still be manually set after the +/// list is created (e.g. SymTabList.end()->setParent(Parent)). +/// +/// The primary benefit of using ilist_parent is that a parent +/// pointer will be stored in the sentinel, meaning that you can safely use \a +/// ilist_iterator::getNodeParent() to get the node parent from any valid (i.e. +/// non-null) iterator, even one that points to a sentinel value. +/// /// See \a is_valid_option for steps on adding a new option. template class ilist_node diff --git a/llvm/include/llvm/ADT/ilist_node_base.h b/llvm/include/llvm/ADT/ilist_node_base.h index f6c518e6eed7a..caad87cdd4d71 100644 --- a/llvm/include/llvm/ADT/ilist_node_base.h +++ b/llvm/include/llvm/ADT/ilist_node_base.h @@ -13,40 +13,61 @@ namespace llvm { -/// Base class for ilist nodes. -/// -/// Optionally tracks whether this node is the sentinel. -template class ilist_node_base; +namespace ilist_detail { + +template class node_base_prevnext; -template <> class ilist_node_base { - ilist_node_base *Prev = nullptr; - ilist_node_base *Next = nullptr; +template class node_base_prevnext { + NodeBase *Prev = nullptr; + NodeBase *Next = nullptr; public: - void setPrev(ilist_node_base *Prev) { this->Prev = Prev; } - void setNext(ilist_node_base *Next) { this->Next = Next; } - ilist_node_base *getPrev() const { return Prev; } - ilist_node_base *getNext() const { return Next; } + void setPrev(NodeBase *Prev) { this->Prev = Prev; } + void setNext(NodeBase *Next) { this->Next = Next; } + NodeBase *getPrev() const { return Prev; } + NodeBase *getNext() const { return Next; } bool isKnownSentinel() const { return false; } void initializeSentinel() {} }; -template <> class ilist_node_base { - PointerIntPair PrevAndSentinel; - ilist_node_base *Next = nullptr; +template class node_base_prevnext { + PointerIntPair PrevAndSentinel; + NodeBase *Next = nullptr; public: - void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); } - void setNext(ilist_node_base *Next) { this->Next = Next; } - ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); } - ilist_node_base *getNext() const { return Next; } + void setPrev(NodeBase *Prev) { PrevAndSentinel.setPointer(Prev); } + void setNext(NodeBase *Next) { this->Next = Next; } + NodeBase *getPrev() const { return PrevAndSentinel.getPointer(); } + NodeBase *getNext() const { return Next; } bool isSentinel() const { return PrevAndSentinel.getInt(); } bool isKnownSentinel() const { return isSentinel(); } void initializeSentinel() { PrevAndSentinel.setInt(true); } }; +template class node_base_parent { + ParentPtrTy Parent = nullptr; + +public: + void setNodeBaseParent(ParentPtrTy Parent) { this->Parent = Parent; } + inline const ParentPtrTy getNodeBaseParent() const { return Parent; } + inline ParentPtrTy getNodeBaseParent() { return Parent; } +}; +template <> class node_base_parent {}; + +} // end namespace ilist_detail + +/// Base class for ilist nodes. +/// +/// Optionally tracks whether this node is the sentinel. +template +class ilist_node_base + : public ilist_detail::node_base_prevnext< + ilist_node_base, + EnableSentinelTracking>, + public ilist_detail::node_base_parent {}; + } // end namespace llvm #endif // LLVM_ADT_ILIST_NODE_BASE_H diff --git a/llvm/include/llvm/ADT/ilist_node_options.h b/llvm/include/llvm/ADT/ilist_node_options.h index e6e1068953e36..aa32162cd51e4 100644 --- a/llvm/include/llvm/ADT/ilist_node_options.h +++ b/llvm/include/llvm/ADT/ilist_node_options.h @@ -15,8 +15,8 @@ namespace llvm { -template class ilist_node_base; -template class ilist_base; +template class ilist_node_base; +template class ilist_base; /// Option to choose whether to track sentinels. /// @@ -39,6 +39,19 @@ template struct ilist_tag {}; /// iterator class to store that information. template struct ilist_iterator_bits {}; +/// Option to add a pointer to this list's owner in every node. +/// +/// This option causes the \a ilist_base_node for this list to contain a pointer +/// ParentTy *Parent, returned by \a ilist_base_node::getNodeBaseParent() and +/// set by \a ilist_base_node::setNodeBaseParent(ParentTy *Parent). The parent +/// value is not set automatically; the ilist owner should set itself as the +/// parent of the list sentinel, and the parent should be set on each node +/// inserted into the list. This value is also not used by +/// \a ilist_node_with_parent::getNodeParent(), but is used by \a +/// ilist_iterator::getNodeParent(), which allows the parent to be fetched from +/// any valid (non-null) iterator to this list, including the sentinel. +template struct ilist_parent {}; + namespace ilist_detail { /// Helper trait for recording whether an option is specified explicitly. @@ -114,6 +127,21 @@ template <> struct extract_iterator_bits<> : std::false_type, is_implicit {}; template struct is_valid_option> : std::true_type {}; +/// Extract node parent option. +/// +/// Look through \p Options for the \a ilist_parent option, pulling out the +/// custom parent type, using void as a default. +template struct extract_parent; +template +struct extract_parent, Options...> { + typedef ParentTy *type; +}; +template +struct extract_parent : extract_parent {}; +template <> struct extract_parent<> { typedef void type; }; +template +struct is_valid_option> : std::true_type {}; + /// Check whether options are valid. /// /// The conjunction of \a is_valid_option on each individual option. @@ -128,7 +156,7 @@ struct check_options /// /// This is usually computed via \a compute_node_options. template + class TagT, bool HasIteratorBits, class ParentPtrTy> struct node_options { typedef T value_type; typedef T *pointer; @@ -140,15 +168,18 @@ struct node_options { static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit; static const bool has_iterator_bits = HasIteratorBits; typedef TagT tag; - typedef ilist_node_base node_base_type; - typedef ilist_base list_base_type; + typedef ParentPtrTy parent_ptr_ty; + typedef ilist_node_base + node_base_type; + typedef ilist_base list_base_type; }; template struct compute_node_options { typedef node_options::value, extract_sentinel_tracking::is_explicit, typename extract_tag::type, - extract_iterator_bits::value> + extract_iterator_bits::value, + typename extract_parent::type> type; }; diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h index e1220966e7e6e..80067f2652a2b 100644 --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -59,7 +59,8 @@ class DbgMarker; class BasicBlock final : public Value, // Basic blocks are data objects also public ilist_node_with_parent { public: - using InstListType = SymbolTableList>; + using InstListType = SymbolTableList, + ilist_parent>; /// Flag recording whether or not this block stores debug-info in the form /// of intrinsic instructions (false) or non-instruction records (true). bool IsNewDbgInfoFormat; @@ -172,10 +173,11 @@ class BasicBlock final : public Value, // Basic blocks are data objects also friend BasicBlock::iterator Instruction::eraseFromParent(); friend BasicBlock::iterator Instruction::insertInto(BasicBlock *BB, BasicBlock::iterator It); - friend class llvm::SymbolTableListTraits>; + friend class llvm::SymbolTableListTraits< + llvm::Instruction, ilist_iterator_bits, ilist_parent>; friend class llvm::ilist_node_with_parent>; + ilist_iterator_bits, + ilist_parent>; // Friendly methods that need to access us for the maintenence of // debug-info attachments. diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h index 249be2799fa93..0b636fc7ceaa3 100644 --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -46,11 +46,13 @@ getDbgRecordRange(DbgMarker *); class Instruction : public User, public ilist_node_with_parent> { + ilist_iterator_bits, + ilist_parent> { public: - using InstListType = SymbolTableList>; + using InstListType = SymbolTableList, + ilist_parent>; + private: - BasicBlock *Parent; DebugLoc DbgLoc; // 'dbg' Metadata cache. /// Relative order of this instruction in its parent basic block. Used for @@ -149,9 +151,6 @@ class Instruction : public User, Instruction *user_back() { return cast(*user_begin());} const Instruction *user_back() const { return cast(*user_begin());} - inline const BasicBlock *getParent() const { return Parent; } - inline BasicBlock *getParent() { return Parent; } - /// Return the module owning the function this instruction belongs to /// or nullptr it the function does not have a module. /// @@ -980,7 +979,8 @@ class Instruction : public User, }; private: - friend class SymbolTableListTraits>; + friend class SymbolTableListTraits, + ilist_parent>; friend class BasicBlock; // For renumbering. // Shadow Value::setValueSubclassData with a private forwarding method so that @@ -993,8 +993,6 @@ class Instruction : public User, return Value::getSubclassDataFromValue(); } - void setParent(BasicBlock *P); - protected: // Instruction subclasses can stick up to 15 bits of stuff into the // SubclassData field of instruction with these members. diff --git a/llvm/include/llvm/IR/ValueSymbolTable.h b/llvm/include/llvm/IR/ValueSymbolTable.h index 6350f6a2435e4..cd1dbbe1688a1 100644 --- a/llvm/include/llvm/IR/ValueSymbolTable.h +++ b/llvm/include/llvm/IR/ValueSymbolTable.h @@ -28,6 +28,7 @@ class GlobalIFunc; class GlobalVariable; class Instruction; template struct ilist_iterator_bits; +template struct ilist_parent; template class SmallString; template class SymbolTableListTraits; @@ -42,7 +43,8 @@ class ValueSymbolTable { friend class SymbolTableListTraits; friend class SymbolTableListTraits; friend class SymbolTableListTraits; - friend class SymbolTableListTraits>; + friend class SymbolTableListTraits, + ilist_parent>; friend class Value; /// @name Types diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index 29f2cbf611fa3..b0caa97ed3918 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -175,8 +175,8 @@ template <> void llvm::invalidateParentIListOrdering(BasicBlock *BB) { // Explicit instantiation of SymbolTableListTraits since some of the methods // are not in the public header file... -template class llvm::SymbolTableListTraits>; +template class llvm::SymbolTableListTraits< + Instruction, ilist_iterator_bits, ilist_parent>; BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent, BasicBlock *InsertBefore) @@ -189,6 +189,7 @@ BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent, assert(!InsertBefore && "Cannot insert block before another block with no function!"); + end().getNodePtr()->setParent(this); setName(Name); if (NewParent) setIsNewDbgInfoFormat(NewParent->IsNewDbgInfoFormat); diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 29272e627a1d1..a5d95de033418 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -27,8 +27,7 @@ using namespace llvm; Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps, InstListType::iterator InsertBefore) - : User(ty, Value::InstructionVal + it, Ops, NumOps), Parent(nullptr) { - + : User(ty, Value::InstructionVal + it, Ops, NumOps) { // When called with an iterator, there must be a block to insert into. BasicBlock *BB = InsertBefore->getParent(); assert(BB && "Instruction to insert before is not in a basic block!"); @@ -37,7 +36,7 @@ Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps, Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps, Instruction *InsertBefore) - : User(ty, Value::InstructionVal + it, Ops, NumOps), Parent(nullptr) { + : User(ty, Value::InstructionVal + it, Ops, NumOps) { // If requested, insert this instruction into a basic block... if (InsertBefore) { @@ -49,15 +48,14 @@ Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps, Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps, BasicBlock *InsertAtEnd) - : User(ty, Value::InstructionVal + it, Ops, NumOps), Parent(nullptr) { - + : User(ty, Value::InstructionVal + it, Ops, NumOps) { // If requested, append this instruction into the basic block. if (InsertAtEnd) insertInto(InsertAtEnd, InsertAtEnd->end()); } Instruction::~Instruction() { - assert(!Parent && "Instruction still linked in the program!"); + assert(!getParent() && "Instruction still linked in the program!"); // Replace any extant metadata uses of this instruction with undef to // preserve debug info accuracy. Some alternatives include: @@ -76,10 +74,6 @@ Instruction::~Instruction() { setMetadata(LLVMContext::MD_DIAssignID, nullptr); } -void Instruction::setParent(BasicBlock *P) { - Parent = P; -} - const Module *Instruction::getModule() const { return getParent()->getModule(); } @@ -96,7 +90,7 @@ void Instruction::removeFromParent() { } void Instruction::handleMarkerRemoval() { - if (!Parent->IsNewDbgInfoFormat || !DebugMarker) + if (!getParent()->IsNewDbgInfoFormat || !DebugMarker) return; DebugMarker->removeMarker(); @@ -329,11 +323,12 @@ void Instruction::dropOneDbgRecord(DbgRecord *DVR) { } bool Instruction::comesBefore(const Instruction *Other) const { - assert(Parent && Other->Parent && + assert(getParent() && Other->getParent() && "instructions without BB parents have no order"); - assert(Parent == Other->Parent && "cross-BB instruction order comparison"); - if (!Parent->isInstrOrderValid()) - Parent->renumberInstructions(); + assert(getParent() == Other->getParent() && + "cross-BB instruction order comparison"); + if (!getParent()->isInstrOrderValid()) + const_cast(getParent())->renumberInstructions(); return Order < Other->Order; } diff --git a/llvm/unittests/ADT/IListBaseTest.cpp b/llvm/unittests/ADT/IListBaseTest.cpp index 1c55eac5c5312..bd915688b190d 100644 --- a/llvm/unittests/ADT/IListBaseTest.cpp +++ b/llvm/unittests/ADT/IListBaseTest.cpp @@ -16,8 +16,10 @@ namespace { // Test fixture. template class IListBaseTest : public ::testing::Test {}; +class Parent; + // Test variants with the same test. -typedef ::testing::Types, ilist_base> +typedef ::testing::Types, ilist_base, ilist_base, ilist_base> IListBaseTestTypes; TYPED_TEST_SUITE(IListBaseTest, IListBaseTestTypes, ); diff --git a/llvm/unittests/ADT/IListIteratorBitsTest.cpp b/llvm/unittests/ADT/IListIteratorBitsTest.cpp index 8ae73b1ed5f78..97c14265e6bcb 100644 --- a/llvm/unittests/ADT/IListIteratorBitsTest.cpp +++ b/llvm/unittests/ADT/IListIteratorBitsTest.cpp @@ -27,6 +27,11 @@ struct PlainNode : ilist_node { friend class dummy; }; +class Parent {}; +struct ParentNode + : ilist_node, ilist_parent> { +}; + TEST(IListIteratorBitsTest, DefaultConstructor) { simple_ilist>::iterator I; simple_ilist>::reverse_iterator RI; @@ -121,4 +126,22 @@ TEST(IListIteratorBitsTest, RangeIteration) { (void)N; } +TEST(IListIteratorBitsTest, GetParent) { + simple_ilist, ilist_parent> L; + Parent P; + ParentNode A; + + // Parents are not set automatically. + A.setParent(&P); + L.insert(L.end(), A); + L.end().getNodePtr()->setParent(&P); + + // Check we can get the node parent from all iterators, including for the + // sentinel. + EXPECT_EQ(&P, L.begin().getNodeParent()); + EXPECT_EQ(&P, L.end().getNodeParent()); + EXPECT_EQ(&P, L.rbegin().getNodeParent()); + EXPECT_EQ(&P, L.rend().getNodeParent()); +} + } // end namespace diff --git a/llvm/unittests/ADT/IListIteratorTest.cpp b/llvm/unittests/ADT/IListIteratorTest.cpp index bd638a8e22b22..fd420b9c82767 100644 --- a/llvm/unittests/ADT/IListIteratorTest.cpp +++ b/llvm/unittests/ADT/IListIteratorTest.cpp @@ -13,7 +13,10 @@ using namespace llvm; namespace { +class Parent {}; + struct Node : ilist_node {}; +struct ParentNode : ilist_node> {}; TEST(IListIteratorTest, DefaultConstructor) { simple_ilist::iterator I; @@ -168,4 +171,22 @@ TEST(IListIteratorTest, ReverseConstructor) { "unexpected implicit conversion"); } +TEST(IListIteratorTest, GetParent) { + simple_ilist> L; + Parent P; + ParentNode A; + + // Parents are not set automatically. + A.setParent(&P); + L.insert(L.end(), A); + L.end().getNodePtr()->setParent(&P); + + // Check we can get the node parent from all iterators, including for the + // sentinel. + EXPECT_EQ(&P, L.begin().getNodeParent()); + EXPECT_EQ(&P, L.end().getNodeParent()); + EXPECT_EQ(&P, L.rbegin().getNodeParent()); + EXPECT_EQ(&P, L.rend().getNodeParent()); +} + } // end namespace diff --git a/llvm/unittests/ADT/IListNodeBaseTest.cpp b/llvm/unittests/ADT/IListNodeBaseTest.cpp index 65f85fc3a237e..07f397d2ef0fe 100644 --- a/llvm/unittests/ADT/IListNodeBaseTest.cpp +++ b/llvm/unittests/ADT/IListNodeBaseTest.cpp @@ -13,8 +13,12 @@ using namespace llvm; namespace { -typedef ilist_node_base RawNode; -typedef ilist_node_base TrackingNode; +class Parent {}; + +typedef ilist_node_base RawNode; +typedef ilist_node_base TrackingNode; +typedef ilist_node_base ParentNode; +typedef ilist_node_base ParentTrackingNode; TEST(IListNodeBaseTest, DefaultConstructor) { RawNode A; @@ -27,6 +31,19 @@ TEST(IListNodeBaseTest, DefaultConstructor) { EXPECT_EQ(nullptr, TA.getNext()); EXPECT_FALSE(TA.isKnownSentinel()); EXPECT_FALSE(TA.isSentinel()); + + ParentNode PA; + EXPECT_EQ(nullptr, PA.getPrev()); + EXPECT_EQ(nullptr, PA.getNext()); + EXPECT_EQ(nullptr, PA.getNodeBaseParent()); + EXPECT_FALSE(PA.isKnownSentinel()); + + ParentTrackingNode PTA; + EXPECT_EQ(nullptr, PTA.getPrev()); + EXPECT_EQ(nullptr, PTA.getNext()); + EXPECT_EQ(nullptr, PTA.getNodeBaseParent()); + EXPECT_FALSE(PTA.isKnownSentinel()); + EXPECT_FALSE(PTA.isSentinel()); } TEST(IListNodeBaseTest, setPrevAndNext) { @@ -63,6 +80,41 @@ TEST(IListNodeBaseTest, setPrevAndNext) { EXPECT_EQ(nullptr, TB.getNext()); EXPECT_EQ(nullptr, TC.getPrev()); EXPECT_EQ(nullptr, TC.getNext()); + + ParentNode PA, PB, PC; + PA.setPrev(&PB); + EXPECT_EQ(&PB, PA.getPrev()); + EXPECT_EQ(nullptr, PA.getNext()); + EXPECT_EQ(nullptr, PB.getPrev()); + EXPECT_EQ(nullptr, PB.getNext()); + EXPECT_EQ(nullptr, PC.getPrev()); + EXPECT_EQ(nullptr, PC.getNext()); + + PA.setNext(&PC); + EXPECT_EQ(&PB, PA.getPrev()); + EXPECT_EQ(&PC, PA.getNext()); + EXPECT_EQ(nullptr, PB.getPrev()); + EXPECT_EQ(nullptr, PB.getNext()); + EXPECT_EQ(nullptr, PC.getPrev()); + EXPECT_EQ(nullptr, PC.getNext()); + + ParentTrackingNode PTA, PTB, PTC; + PTA.setPrev(&PTB); + EXPECT_EQ(&PTB, PTA.getPrev()); + EXPECT_EQ(nullptr, PTA.getNext()); + EXPECT_EQ(nullptr, PTB.getPrev()); + EXPECT_EQ(nullptr, PTB.getNext()); + EXPECT_EQ(nullptr, PTC.getPrev()); + EXPECT_EQ(nullptr, PTC.getNext()); + + PTA.setNext(&PTC); + EXPECT_EQ(&PTB, PTA.getPrev()); + EXPECT_EQ(&PTC, PTA.getNext()); + EXPECT_EQ(nullptr, PTB.getPrev()); + EXPECT_EQ(nullptr, PTB.getNext()); + EXPECT_EQ(nullptr, PTC.getPrev()); + EXPECT_EQ(nullptr, PTC.getNext()); + } TEST(IListNodeBaseTest, isKnownSentinel) { @@ -94,6 +146,48 @@ TEST(IListNodeBaseTest, isKnownSentinel) { EXPECT_TRUE(TA.isSentinel()); EXPECT_EQ(&TB, TA.getPrev()); EXPECT_EQ(&TB, TA.getNext()); + + // Without sentinel tracking (with Parent). + ParentNode PA, PB; + EXPECT_FALSE(PA.isKnownSentinel()); + PA.setPrev(&PB); + PA.setNext(&PB); + EXPECT_EQ(&PB, PA.getPrev()); + EXPECT_EQ(&PB, PA.getNext()); + EXPECT_FALSE(PA.isKnownSentinel()); + PA.initializeSentinel(); + EXPECT_FALSE(PA.isKnownSentinel()); + EXPECT_EQ(&PB, PA.getPrev()); + EXPECT_EQ(&PB, PA.getNext()); + + // With sentinel tracking (with Parent). + ParentTrackingNode PTA, PTB; + EXPECT_FALSE(PTA.isKnownSentinel()); + EXPECT_FALSE(PTA.isSentinel()); + PTA.setPrev(&PTB); + PTA.setNext(&PTB); + EXPECT_EQ(&PTB, PTA.getPrev()); + EXPECT_EQ(&PTB, PTA.getNext()); + EXPECT_FALSE(PTA.isKnownSentinel()); + EXPECT_FALSE(PTA.isSentinel()); + PTA.initializeSentinel(); + EXPECT_TRUE(PTA.isKnownSentinel()); + EXPECT_TRUE(PTA.isSentinel()); + EXPECT_EQ(&PTB, PTA.getPrev()); + EXPECT_EQ(&PTB, PTA.getNext()); +} + +TEST(IListNodeBaseTest, setNodeBaseParent) { + Parent Par; + ParentNode PA; + EXPECT_EQ(nullptr, PA.getNodeBaseParent()); + PA.setNodeBaseParent(&Par); + EXPECT_EQ(&Par, PA.getNodeBaseParent()); + + ParentTrackingNode PTA; + EXPECT_EQ(nullptr, PTA.getNodeBaseParent()); + PTA.setNodeBaseParent(&Par); + EXPECT_EQ(&Par, PTA.getNodeBaseParent()); } } // end namespace diff --git a/llvm/unittests/ADT/IListNodeTest.cpp b/llvm/unittests/ADT/IListNodeTest.cpp index 057eabb4e4ab7..0a5da12d7f30f 100644 --- a/llvm/unittests/ADT/IListNodeTest.cpp +++ b/llvm/unittests/ADT/IListNodeTest.cpp @@ -19,6 +19,8 @@ struct Node; struct TagA {}; struct TagB {}; +struct ParentA {}; +struct ParentB {}; TEST(IListNodeTest, Options) { static_assert( @@ -63,6 +65,18 @@ TEST(IListNodeTest, Options) { compute_node_options, ilist_sentinel_tracking>::type>, "order shouldn't matter with real tags"); + static_assert( + !std::is_same_v::type, + compute_node_options>::type>, + "void parent is different to no parent"); + static_assert( + !std::is_same_v>::type, + compute_node_options>::type>, + "ParentA is not void"); + static_assert( + !std::is_same_v>::type, + compute_node_options>::type>, + "ParentA is not ParentB"); } } // end namespace