diff --git a/llvm/include/llvm/ADT/ilist_iterator.h b/llvm/include/llvm/ADT/ilist_iterator.h
index d106d0c62215..1a883364421a 100644
--- a/llvm/include/llvm/ADT/ilist_iterator.h
+++ b/llvm/include/llvm/ADT/ilist_iterator.h
@@ -27,27 +27,28 @@ 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 <bool IsReverse> struct IteratorHelper;
+template <> struct IteratorHelper<false> : ilist_detail::NodeAccess {
+  typedef ilist_detail::NodeAccess Access;
+  template <class T> static void increment(T *&I) { I = Access::getNext(*I); }
+  template <class T> static void decrement(T *&I) { I = 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);
-  }
+template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
+  typedef ilist_detail::NodeAccess Access;
+  template <class T> static void increment(T *&I) { I = Access::getPrev(*I); }
+  template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
 };
 
 } // end namespace ilist_detail
 
 /// Iterator for intrusive lists  based on ilist_node.
-template <typename NodeTy, bool IsReverse> class ilist_iterator {
+template <typename NodeTy, bool IsReverse>
+class ilist_iterator : ilist_detail::SpecificNodeAccess<
+                           typename std::remove_const<NodeTy>::type> {
+  typedef ilist_detail::SpecificNodeAccess<
+      typename std::remove_const<NodeTy>::type>
+      Access;
+
 public:
   typedef NodeTy value_type;
   typedef value_type *pointer;
@@ -69,10 +70,8 @@ public:
   /// Create from an ilist_node.
   explicit ilist_iterator(node_reference N) : NodePtr(&N) {}
 
-  explicit ilist_iterator(pointer NP)
-      : NodePtr(ilist_node_access::getNodePtr(NP)) {}
-  explicit ilist_iterator(reference NR)
-      : NodePtr(ilist_node_access::getNodePtr(&NR)) {}
+  explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {}
+  explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {}
   ilist_iterator() : NodePtr(nullptr) {}
 
   // This is templated so that we can allow constructing a const iterator from
@@ -108,7 +107,7 @@ public:
   // Accessors...
   reference operator*() const {
     assert(!NodePtr->isKnownSentinel());
-    return *ilist_node_access::getValuePtr(NodePtr);
+    return *Access::getValuePtr(NodePtr);
   }
   pointer operator->() const { return &operator*(); }
 
diff --git a/llvm/include/llvm/ADT/ilist_node.h b/llvm/include/llvm/ADT/ilist_node.h
index a5e2f5ed5b7f..8bcbec2dc8c9 100644
--- a/llvm/include/llvm/ADT/ilist_node.h
+++ b/llvm/include/llvm/ADT/ilist_node.h
@@ -19,17 +19,20 @@
 
 namespace llvm {
 
+namespace ilist_detail {
+struct NodeAccess;
+} // end namespace ilist_detail
+
 template<typename NodeTy>
 struct ilist_traits;
 
-struct ilist_node_access;
 template <typename NodeTy, bool IsReverse = false> class ilist_iterator;
 template <typename NodeTy> class ilist_sentinel;
 
 /// Templated wrapper class.
 template <typename NodeTy> class ilist_node : ilist_node_base {
   friend class ilist_base;
-  friend struct ilist_node_access;
+  friend struct ilist_detail::NodeAccess;
   friend struct ilist_traits<NodeTy>;
   friend class ilist_iterator<NodeTy, false>;
   friend class ilist_iterator<NodeTy, true>;
@@ -65,13 +68,15 @@ public:
   using ilist_node_base::isKnownSentinel;
 };
 
+namespace ilist_detail {
 /// An access class for ilist_node private API.
 ///
 /// 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.
 ///
 /// Using this class outside of the ilist implementation is unsupported.
-struct ilist_node_access {
+struct NodeAccess {
+protected:
   template <typename T> static ilist_node<T> *getNodePtr(T *N) { return N; }
   template <typename T> static const ilist_node<T> *getNodePtr(const T *N) {
     return N;
@@ -99,6 +104,27 @@ struct ilist_node_access {
   }
 };
 
+template <class T> struct SpecificNodeAccess : NodeAccess {
+protected:
+  typedef T *pointer;
+  typedef const T *const_pointer;
+  typedef ilist_node<T> node_type;
+
+  static node_type *getNodePtr(pointer N) {
+    return NodeAccess::getNodePtr<T>(N);
+  }
+  static const ilist_node<T> *getNodePtr(const_pointer N) {
+    return NodeAccess::getNodePtr<T>(N);
+  }
+  static pointer getValuePtr(node_type *N) {
+    return NodeAccess::getValuePtr<T>(N);
+  }
+  static const_pointer getValuePtr(const node_type *N) {
+    return NodeAccess::getValuePtr<T>(N);
+  }
+};
+} // end namespace ilist_detail
+
 template <typename NodeTy> class ilist_sentinel : public ilist_node<NodeTy> {
 public:
   ilist_sentinel() {
diff --git a/llvm/include/llvm/ADT/simple_ilist.h b/llvm/include/llvm/ADT/simple_ilist.h
index 6db10fb7320b..698cad052631 100644
--- a/llvm/include/llvm/ADT/simple_ilist.h
+++ b/llvm/include/llvm/ADT/simple_ilist.h
@@ -46,7 +46,8 @@ namespace llvm {
 /// eraseAndDispose(), and \a clearAndDispose().  These have different names
 /// because the extra semantic is otherwise non-obvious.  They are equivalent
 /// to calling \a std::for_each() on the range to be discarded.
-template <typename T> class simple_ilist : ilist_base, ilist_node_access {
+template <typename T>
+class simple_ilist : ilist_base, ilist_detail::SpecificNodeAccess<T> {
   typedef ilist_base list_base_type;
   ilist_sentinel<T> Sentinel;
 
diff --git a/llvm/unittests/ADT/IListSentinelTest.cpp b/llvm/unittests/ADT/IListSentinelTest.cpp
index 533421e85040..55571efc9c25 100644
--- a/llvm/unittests/ADT/IListSentinelTest.cpp
+++ b/llvm/unittests/ADT/IListSentinelTest.cpp
@@ -16,10 +16,15 @@ namespace {
 
 class Node : public ilist_node<Node> {};
 
+struct LocalAccess : ilist_detail::NodeAccess {
+  using NodeAccess::getPrev;
+  using NodeAccess::getNext;
+};
+
 TEST(IListSentinelTest, DefaultConstructor) {
   ilist_sentinel<Node> S;
-  EXPECT_EQ(&S, ilist_node_access::getPrev(S));
-  EXPECT_EQ(&S, ilist_node_access::getNext(S));
+  EXPECT_EQ(&S, LocalAccess::getPrev(S));
+  EXPECT_EQ(&S, LocalAccess::getNext(S));
 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
   EXPECT_TRUE(S.isKnownSentinel());
 #else
@@ -29,8 +34,8 @@ TEST(IListSentinelTest, DefaultConstructor) {
 
 TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) {
   Node N;
-  EXPECT_EQ(nullptr, ilist_node_access::getPrev(N));
-  EXPECT_EQ(nullptr, ilist_node_access::getNext(N));
+  EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
+  EXPECT_EQ(nullptr, LocalAccess::getNext(N));
   EXPECT_FALSE(N.isKnownSentinel());
 }
 
diff --git a/llvm/unittests/ADT/IListTest.cpp b/llvm/unittests/ADT/IListTest.cpp
index 5fe225b8874b..472d97c365c6 100644
--- a/llvm/unittests/ADT/IListTest.cpp
+++ b/llvm/unittests/ADT/IListTest.cpp
@@ -218,7 +218,7 @@ TEST(IListTest, addNodeToList) {
 }
 
 struct PrivateNode : private ilist_node<PrivateNode> {
-  friend struct llvm::ilist_node_access;
+  friend struct llvm::ilist_detail::NodeAccess;
 
   int Value = 0;