diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index 3a431bb9536..95027f0c29e 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -50,20 +50,64 @@ namespace llvm { template class iplist; template class ilist_iterator; -/// ilist_nextprev_traits - A fragment for template traits for intrusive list -/// that provides default next/prev implementations for common operations. +/// An access class for next/prev on ilist_nodes. /// -template -struct ilist_nextprev_traits { - static NodeTy *getPrev(NodeTy *N) { return N->getPrev(); } - static NodeTy *getNext(NodeTy *N) { return N->getNext(); } - static const NodeTy *getPrev(const NodeTy *N) { return N->getPrev(); } - static const NodeTy *getNext(const NodeTy *N) { return N->getNext(); } +/// This gives access to the private parts of ilist nodes. Nodes for an ilist +/// should friend this class if they inherit privately from ilist_node. +/// +/// It's strongly discouraged to *use* this class outside of ilist +/// implementation. +struct ilist_node_access { + template static NodeTy *getPrev(NodeTy *N) { + return N->getPrev(); + } + template static NodeTy *getNext(NodeTy *N) { + return N->getNext(); + } + template static const NodeTy *getPrev(const NodeTy *N) { + return N->getPrev(); + } + template static const NodeTy *getNext(const NodeTy *N) { + return N->getNext(); + } - static void setPrev(NodeTy *N, NodeTy *Prev) { N->setPrev(Prev); } - static void setNext(NodeTy *N, NodeTy *Next) { N->setNext(Next); } + template static void setPrev(NodeTy *N, NodeTy *Prev) { + N->setPrev(Prev); + } + template static void setNext(NodeTy *N, NodeTy *Next) { + N->setNext(Next); + } + template static void setPrev(NodeTy *N, std::nullptr_t) { + N->setPrev(nullptr); + } + template static void setNext(NodeTy *N, std::nullptr_t) { + N->setNext(nullptr); + } }; +namespace ilist_detail { + +template T &make(); + +/// Type trait to check for a traits class that has a getNext member (as a +/// canary for any of the ilist_nextprev_traits API). +template struct HasGetNext { + typedef char Yes[1]; + typedef char No[2]; + template struct SFINAE {}; + + template + static Yes &hasGetNext( + SFINAE(make().getNext(&make())))> + * = 0); + template static No &hasGetNext(...); + + static const bool value = + sizeof(hasGetNext(nullptr)) == sizeof(Yes); +}; + +} // end namespace ilist_detail + template struct ilist_traits; @@ -93,15 +137,15 @@ struct ilist_sentinel_traits { if (!Head) { Head = ilist_traits::createSentinel(); ilist_traits::noteHead(Head, Head); - ilist_traits::setNext(Head, nullptr); + ilist_node_access::setNext(Head, nullptr); return Head; } - return ilist_traits::getPrev(Head); + return ilist_node_access::getPrev(Head); } /// noteHead - stash the sentinel into its default location static void noteHead(NodeTy *NewHead, NodeTy *Sentinel) { - ilist_traits::setPrev(NewHead, Sentinel); + ilist_node_access::setPrev(NewHead, Sentinel); } }; @@ -187,11 +231,9 @@ struct ilist_node_traits { /// By inheriting from this, you can easily use default implementations /// for all common operations. /// -template -struct ilist_default_traits : public ilist_nextprev_traits, - public ilist_sentinel_traits, - public ilist_node_traits { -}; +template +struct ilist_default_traits : public ilist_sentinel_traits, + public ilist_node_traits {}; // Template traits for intrusive list. By specializing this template class, you // can change what next/prev fields are used to store the links... @@ -218,7 +260,6 @@ template class ilist_iterator : public std::iterator { public: - typedef ilist_traits Traits; typedef std::iterator super; @@ -279,12 +320,12 @@ public: // Increment and decrement operators... ilist_iterator &operator--() { - NodePtr = Traits::getPrev(NodePtr); + NodePtr = ilist_node_access::getPrev(NodePtr); assert(NodePtr && "--'d off the beginning of an ilist!"); return *this; } ilist_iterator &operator++() { - NodePtr = Traits::getNext(NodePtr); + NodePtr = ilist_node_access::getNext(NodePtr); return *this; } ilist_iterator operator--(int) { @@ -348,8 +389,11 @@ template struct simplify_type > { /// and the successor pointer for the sentinel (which always stays at the /// end of the list) is always null. /// -template > -class iplist : public Traits { +template > +class iplist : public Traits, ilist_node_access { + static_assert(!ilist_detail::HasGetNext::value, + "ilist next and prev links are not customizable!"); + mutable NodeTy *Head; // Use the prev node pointer of 'head' as the tail pointer. This is really a diff --git a/include/llvm/ADT/ilist_node.h b/include/llvm/ADT/ilist_node.h index 7e5a0e0e5ad..afac2f33f70 100644 --- a/include/llvm/ADT/ilist_node.h +++ b/include/llvm/ADT/ilist_node.h @@ -36,17 +36,13 @@ protected: ilist_half_node() : Prev(nullptr) {} }; -template -struct ilist_nextprev_traits; - +struct ilist_node_access; template class ilist_iterator; -/// ilist_node - Base class that provides next/prev services for nodes -/// that use ilist_nextprev_traits or ilist_default_traits. -/// +/// Base class that provides next/prev services for ilist nodes. template class ilist_node : private ilist_half_node { - friend struct ilist_nextprev_traits; + friend struct ilist_node_access; friend struct ilist_traits; friend struct ilist_half_embedded_sentinel_traits; friend struct ilist_embedded_sentinel_traits; diff --git a/include/llvm/IR/SymbolTableListTraits.h b/include/llvm/IR/SymbolTableListTraits.h index 60e04e2f9ec..42320a96f39 100644 --- a/include/llvm/IR/SymbolTableListTraits.h +++ b/include/llvm/IR/SymbolTableListTraits.h @@ -69,8 +69,7 @@ template class SymbolTableList; // template class SymbolTableListTraits - : public ilist_nextprev_traits, - public SymbolTableListSentinelTraits, + : public SymbolTableListSentinelTraits, public ilist_node_traits { typedef SymbolTableList ListTy; typedef