Index: llvm/include/llvm/ADT/iterator.h =================================================================== --- llvm/include/llvm/ADT/iterator.h +++ llvm/include/llvm/ADT/iterator.h @@ -35,6 +35,21 @@ /// terms of addition of one. These aren't equivalent for all iterator /// categories, and respecting that adds a lot of complexity for little gain. /// +/// Iterators are expected to have const rules analogous to pointers, with a +/// single, const-qualified operator*() that returns ReferenceT. This matches +/// the second and third pointers in the following example: +/// \code +/// int Value; +/// { int *I = &Value; } // ReferenceT 'int&' +/// { int *const I = &Value; } // ReferenceT 'int&'; const +/// { const int *I = &Value; } // ReferenceT 'const int&' +/// { const int *const I = &Value; } // ReferenceT 'const int&'; const +/// \endcode +/// 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 handle itself, the field can be declared +/// mutable or use const_cast. +/// /// Classes wishing to use `iterator_facade_base` should implement the following /// methods: /// @@ -187,17 +202,9 @@ return !(static_cast(*this) < RHS); } - PointerProxy operator->() { - return static_cast(this)->operator*(); - } PointerProxy operator->() const { return static_cast(this)->operator*(); } - ReferenceProxy operator[](DifferenceTypeT n) { - static_assert(IsRandomAccess, - "Subscripting is only defined for random access iterators."); - return static_cast(this)->operator+(n); - } ReferenceProxy operator[](DifferenceTypeT n) const { static_assert(IsRandomAccess, "Subscripting is only defined for random access iterators."); Index: llvm/unittests/ADT/IteratorTest.cpp =================================================================== --- llvm/unittests/ADT/IteratorTest.cpp +++ llvm/unittests/ADT/IteratorTest.cpp @@ -78,6 +78,14 @@ using IntProxyIterator = PointerProxyWrapper; using ConstIntProxyIterator = PointerProxyWrapper; +// There should only be a single (const-qualified) operator*, operator->, and +// operator[]. This test confirms that there isn't a non-const overload. Rather +// than adding those, users should double-check that T, PointerT, and ReferenceT +// have the right constness, and/or make fields mutable. +static_assert(&IntIterator::operator* == &IntIterator::operator*, ""); +static_assert(&IntIterator::operator-> == &IntIterator::operator->, ""); +static_assert(&IntIterator::operator[] == &IntIterator::operator[], ""); + template ::value, bool> = false> constexpr bool canAssignFromInt(T &&) {