Skip to content

Commit 6b9b86d

Browse files
committed
ADT: Fix const-correctness of iterator facade
Fix the const-ness of `iterator_facade_base::operator->` and `iterator_facade_base::operator[]`. This is a follow-up to 1b651be, which fixed const-ness of various iterator adaptors. Iterators, like the pointers that they generalize, have two types of `const`. - The `const` qualifier on members indicates whether the iterator itself can be changed. This is analagous to `int *const`. - The `const` qualifier on return values of `operator*()`, `operator[]()`, and `operator->()` controls whether the the pointed-to value can be changed. This is analogous to `const int*`. If an iterator facade returns a handle to its own state, then T (and PointerT and ReferenceT) should usually be const-qualified. Otherwise, if clients are expected to modify the state itself, the field can be declared mutable or a const_cast can be used.
1 parent 75c86c9 commit 6b9b86d

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

llvm/include/llvm/ADT/iterator.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ namespace llvm {
3535
/// terms of addition of one. These aren't equivalent for all iterator
3636
/// categories, and respecting that adds a lot of complexity for little gain.
3737
///
38+
/// Iterators are expected to have const rules analogous to pointers, with a
39+
/// single, const-qualified operator*() that returns ReferenceT. This matches
40+
/// the second and third pointers in the following example:
41+
/// \code
42+
/// int Value;
43+
/// { int *I = &Value; } // ReferenceT 'int&'
44+
/// { int *const I = &Value; } // ReferenceT 'int&'; const
45+
/// { const int *I = &Value; } // ReferenceT 'const int&'
46+
/// { const int *const I = &Value; } // ReferenceT 'const int&'; const
47+
/// \endcode
48+
/// If an iterator facade returns a handle to its own state, then T (and
49+
/// PointerT and ReferenceT) should usually be const-qualified. Otherwise, if
50+
/// clients are expected to modify the handle itself, the field can be declared
51+
/// mutable or use const_cast.
52+
///
3853
/// Classes wishing to use `iterator_facade_base` should implement the following
3954
/// methods:
4055
///
@@ -187,17 +202,9 @@ class iterator_facade_base {
187202
return !(static_cast<const DerivedT &>(*this) < RHS);
188203
}
189204

190-
PointerProxy operator->() {
191-
return static_cast<DerivedT *>(this)->operator*();
192-
}
193205
PointerProxy operator->() const {
194206
return static_cast<const DerivedT *>(this)->operator*();
195207
}
196-
ReferenceProxy operator[](DifferenceTypeT n) {
197-
static_assert(IsRandomAccess,
198-
"Subscripting is only defined for random access iterators.");
199-
return static_cast<DerivedT *>(this)->operator+(n);
200-
}
201208
ReferenceProxy operator[](DifferenceTypeT n) const {
202209
static_assert(IsRandomAccess,
203210
"Subscripting is only defined for random access iterators.");

llvm/unittests/ADT/IteratorTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ using ConstIntIterator = PointerWrapper<const int>;
7878
using IntProxyIterator = PointerProxyWrapper<int, IntProxy>;
7979
using ConstIntProxyIterator = PointerProxyWrapper<const int, ConstIntProxy>;
8080

81+
// There should only be a single (const-qualified) operator*, operator->, and
82+
// operator[]. This test confirms that there isn't a non-const overload. Rather
83+
// than adding those, users should double-check that T, PointerT, and ReferenceT
84+
// have the right constness, and/or make fields mutable.
85+
static_assert(&IntIterator::operator* == &IntIterator::operator*, "");
86+
static_assert(&IntIterator::operator-> == &IntIterator::operator->, "");
87+
static_assert(&IntIterator::operator[] == &IntIterator::operator[], "");
88+
8189
template <class T,
8290
std::enable_if_t<std::is_assignable<T, int>::value, bool> = false>
8391
constexpr bool canAssignFromInt(T &&) {

0 commit comments

Comments
 (0)