mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-25 05:52:53 +02:00
bc2ac24566
Re-implement `ilist_node::getNextNode()` and `getPrevNode()` without relying on the sentinel having a "next" pointer. Instead, get access to the owning list and compare against the `begin()` and `end()` iterators. This only works when the node *can* get access to the owning list. The new support is in `ilist_node_with_parent<>`, and any class `Ty` inheriting from `ilist_node<NodeTy>` that wants `getNextNode()` and/or `getPrevNode()` should inherit from `ilist_node_with_parent<NodeTy, ParentTy>` instead. The requirements: - `NodeTy` must have a `getParent()` function that returns the parent. - `ParentTy` must have a `getSublistAccess()` static that, given a(n ignored) `NodeTy*` (to determine which list), returns a member field pointer to the appropriate `ilist<>`. This isn't the cleanest way to get access to the owning list, but it leverages the API already used in the IR hierarchy (see, e.g., `Instruction::getSublistAccess()`). If anyone feels like ripping out the calls to `getNextNode()` and `getPrevNode()` and replacing with direct iterator logic, they can also remove the access function, etc., but as an incremental step, I'm maintaining the API where it's currently used in tree. If these requirements are *not* met, call sites with access to the ilist can call `iplist<NodeTy>::getNextNode(NodeTy*)` directly, as in ilistTest.cpp. Why rewrite this? The old code was broken, calling `getNext()` on a sentinel that possibly didn't have a "next" pointer at all! The new code avoids that particular flavour of UB (see the commit message for r252538 for more details about the "lucky" memory layout that made this function so interesting). There's still some UB here: the end iterator gets downcast to `NodeTy*`, even when it's a sentinel (which is typically `ilist_half_node<NodeTy*>`). I'll tackle that in follow-up commits. See this llvm-dev thread for more details: http://lists.llvm.org/pipermail/llvm-dev/2015-October/091115.html What's the danger? There might be some code that relies on `getNextNode()` or `getPrevNode()` *never* returning `nullptr` -- i.e., that relies on them being broken when the sentinel is an `ilist_half_node<NodeTy>`. I tried to root out those cases with the audits I did leading up to r252380, but it's possible I missed one or two. I hope not. (If (1) you have out-of-tree code, (2) you've reverted r252380 temporarily, and (3) you get some weird crashes with this commit, then I recommend un-reverting r252380 and auditing the compile errors looking for "strange" implicit conversions.) llvm-svn: 252694
124 lines
4.2 KiB
C++
124 lines
4.2 KiB
C++
//==-- llvm/ADT/ilist_node.h - Intrusive Linked List Helper ------*- C++ -*-==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the ilist_node class template, which is a convenient
|
|
// base class for creating classes that can be used with ilists.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_ADT_ILIST_NODE_H
|
|
#define LLVM_ADT_ILIST_NODE_H
|
|
|
|
namespace llvm {
|
|
|
|
template<typename NodeTy>
|
|
struct ilist_traits;
|
|
template <typename NodeTy> struct ilist_embedded_sentinel_traits;
|
|
template <typename NodeTy> struct ilist_half_embedded_sentinel_traits;
|
|
|
|
/// ilist_half_node - Base class that provides prev services for sentinels.
|
|
///
|
|
template<typename NodeTy>
|
|
class ilist_half_node {
|
|
friend struct ilist_traits<NodeTy>;
|
|
friend struct ilist_half_embedded_sentinel_traits<NodeTy>;
|
|
NodeTy *Prev;
|
|
protected:
|
|
NodeTy *getPrev() { return Prev; }
|
|
const NodeTy *getPrev() const { return Prev; }
|
|
void setPrev(NodeTy *P) { Prev = P; }
|
|
ilist_half_node() : Prev(nullptr) {}
|
|
};
|
|
|
|
template<typename NodeTy>
|
|
struct ilist_nextprev_traits;
|
|
|
|
template <typename NodeTy> class ilist_iterator;
|
|
|
|
/// ilist_node - Base class that provides next/prev services for nodes
|
|
/// that use ilist_nextprev_traits or ilist_default_traits.
|
|
///
|
|
template<typename NodeTy>
|
|
class ilist_node : private ilist_half_node<NodeTy> {
|
|
friend struct ilist_nextprev_traits<NodeTy>;
|
|
friend struct ilist_traits<NodeTy>;
|
|
friend struct ilist_half_embedded_sentinel_traits<NodeTy>;
|
|
friend struct ilist_embedded_sentinel_traits<NodeTy>;
|
|
NodeTy *Next;
|
|
NodeTy *getNext() { return Next; }
|
|
const NodeTy *getNext() const { return Next; }
|
|
void setNext(NodeTy *N) { Next = N; }
|
|
protected:
|
|
ilist_node() : Next(nullptr) {}
|
|
|
|
public:
|
|
ilist_iterator<NodeTy> getIterator() {
|
|
// FIXME: Stop downcasting to create the iterator (potential UB).
|
|
return ilist_iterator<NodeTy>(static_cast<NodeTy *>(this));
|
|
}
|
|
ilist_iterator<const NodeTy> getIterator() const {
|
|
// FIXME: Stop downcasting to create the iterator (potential UB).
|
|
return ilist_iterator<const NodeTy>(static_cast<const NodeTy *>(this));
|
|
}
|
|
};
|
|
|
|
/// An ilist node that can access its parent list.
|
|
///
|
|
/// Requires \c NodeTy to have \a getParent() to find the parent node, and the
|
|
/// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
|
|
template <typename NodeTy, typename ParentTy>
|
|
class ilist_node_with_parent : public ilist_node<NodeTy> {
|
|
protected:
|
|
ilist_node_with_parent() = default;
|
|
|
|
private:
|
|
/// Forward to NodeTy::getParent().
|
|
///
|
|
/// Note: do not use the name "getParent()". We want a compile error
|
|
/// (instead of recursion) when the subclass fails to implement \a
|
|
/// getParent().
|
|
const ParentTy *getNodeParent() const {
|
|
return static_cast<const NodeTy *>(this)->getParent();
|
|
}
|
|
|
|
public:
|
|
/// @name Adjacent Node Accessors
|
|
/// @{
|
|
/// \brief Get the previous node, or \c nullptr for the list head.
|
|
NodeTy *getPrevNode() {
|
|
// Should be separated to a reused function, but then we couldn't use auto
|
|
// (and would need the type of the list).
|
|
const auto &List =
|
|
getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
|
|
return List.getPrevNode(*static_cast<NodeTy *>(this));
|
|
}
|
|
/// \brief Get the previous node, or \c nullptr for the list head.
|
|
const NodeTy *getPrevNode() const {
|
|
return const_cast<ilist_node_with_parent *>(this)->getPrevNode();
|
|
}
|
|
|
|
/// \brief Get the next node, or \c nullptr for the list tail.
|
|
NodeTy *getNextNode() {
|
|
// Should be separated to a reused function, but then we couldn't use auto
|
|
// (and would need the type of the list).
|
|
const auto &List =
|
|
getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
|
|
return List.getNextNode(*static_cast<NodeTy *>(this));
|
|
}
|
|
/// \brief Get the next node, or \c nullptr for the list tail.
|
|
const NodeTy *getNextNode() const {
|
|
return const_cast<ilist_node_with_parent *>(this)->getNextNode();
|
|
}
|
|
/// @}
|
|
};
|
|
|
|
} // End llvm namespace
|
|
|
|
#endif
|