Skip to content

Commit c88a7a7

Browse files
committed
[llvm][ADT] Fix invalid reference type of depth-first, breadth-first and post order iterators
C++s iterator concept requires operator* to return the same type as is specified by the iterators reference type. This functionality is especially important for older generic code that did not yet make use of auto. An example from within LLVM is iterator_adaptor_base which uses the reference type of the iterator it is wrapping as its return type for operator* (this class is used as base for a lot of other functionality like filter iterators and so on). Using any of the graph traversal iterators listed above with it would previously fail to compile due to reference being non-const while operator* returned a const reference. This patch fixes that by correctly specifying reference and using it as the return type of operator* explicitly to prevent further issues in the future. Differential Revision: https://reviews.llvm.org/D151198
1 parent d4d96c4 commit c88a7a7

File tree

6 files changed

+19
-6
lines changed

6 files changed

+19
-6
lines changed

llvm/include/llvm/ADT/BreadthFirstIterator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class bf_iterator : public bf_iterator_storage<SetType> {
5050
using value_type = typename GT::NodeRef;
5151
using difference_type = std::ptrdiff_t;
5252
using pointer = value_type *;
53-
using reference = value_type &;
53+
using reference = const value_type &;
5454

5555
private:
5656
using NodeRef = typename GT::NodeRef;
@@ -123,7 +123,7 @@ class bf_iterator : public bf_iterator_storage<SetType> {
123123

124124
bool operator!=(const bf_iterator &RHS) const { return !(*this == RHS); }
125125

126-
const NodeRef &operator*() const { return VisitQueue.front()->first; }
126+
reference operator*() const { return VisitQueue.front()->first; }
127127

128128
// This is a nonstandard operator-> that dereferences the pointer an extra
129129
// time so that you can actually call methods on the node, because the

llvm/include/llvm/ADT/DepthFirstIterator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class df_iterator : public df_iterator_storage<SetType, ExtStorage> {
8888
using value_type = typename GT::NodeRef;
8989
using difference_type = std::ptrdiff_t;
9090
using pointer = value_type *;
91-
using reference = value_type &;
91+
using reference = const value_type &;
9292

9393
private:
9494
using NodeRef = typename GT::NodeRef;
@@ -165,7 +165,7 @@ class df_iterator : public df_iterator_storage<SetType, ExtStorage> {
165165
}
166166
bool operator!=(const df_iterator &x) const { return !(*this == x); }
167167

168-
const NodeRef &operator*() const { return VisitStack.back().first; }
168+
reference operator*() const { return VisitStack.back().first; }
169169

170170
// This is a nonstandard operator-> that dereferences the pointer an extra
171171
// time... so that you can actually call methods ON the Node, because

llvm/include/llvm/ADT/PostOrderIterator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class po_iterator : public po_iterator_storage<SetType, ExtStorage> {
100100
using value_type = typename GT::NodeRef;
101101
using difference_type = std::ptrdiff_t;
102102
using pointer = value_type *;
103-
using reference = value_type &;
103+
using reference = const value_type &;
104104

105105
private:
106106
using NodeRef = typename GT::NodeRef;
@@ -161,7 +161,7 @@ class po_iterator : public po_iterator_storage<SetType, ExtStorage> {
161161
}
162162
bool operator!=(const po_iterator &x) const { return !(*this == x); }
163163

164-
const NodeRef &operator*() const { return std::get<0>(VisitStack.back()); }
164+
reference operator*() const { return std::get<0>(VisitStack.back()); }
165165

166166
// This is a nonstandard operator-> that dereferences the pointer an extra
167167
// time... so that you can actually call methods ON the BasicBlock, because

llvm/unittests/ADT/BreadthFirstIteratorTest.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,8 @@ TEST(BreadthFristIteratorTest, Cycle) {
7070
EXPECT_EQ(It, End);
7171
}
7272

73+
static_assert(
74+
std::is_convertible_v<decltype(*std::declval<bf_iterator<Graph<3>>>()),
75+
typename bf_iterator<Graph<3>>::reference>);
76+
7377
} // end namespace llvm

llvm/unittests/ADT/DepthFirstIteratorTest.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@ TEST(DepthFirstIteratorTest, ActuallyUpdateIterator) {
5050

5151
EXPECT_EQ(3, S.InsertVisited);
5252
}
53+
54+
static_assert(
55+
std::is_convertible_v<decltype(*std::declval<df_iterator<Graph<3>>>()),
56+
typename df_iterator<Graph<3>>::reference>);
57+
5358
}

llvm/unittests/ADT/PostOrderIteratorTest.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ TEST(PostOrderIteratorTest, Compiles) {
3636
PIExt.insertEdge(std::optional<BasicBlock *>(), NullBB);
3737
}
3838

39+
static_assert(
40+
std::is_convertible_v<decltype(*std::declval<po_iterator<Graph<3>>>()),
41+
typename po_iterator<Graph<3>>::reference>);
42+
3943
// Test post-order and reverse post-order traversals for simple graph type.
4044
TEST(PostOrderIteratorTest, PostOrderAndReversePostOrderTraverrsal) {
4145
Graph<6> G;

0 commit comments

Comments
 (0)