Currently, basic_const_iterator::operator== is defined as a friend function:
template<sentinel_for<Iterator> S> friend constexpr bool operator==(const basic_const_iterator& x, const S& s);
which only requires S to model sentinel_for<Iterator>, and since basic_const_iterator has a conversion constructor that accepts I, this will result in infinite constraint checks when comparing basic_const_iterator<int*> with int* (online example):
#include <iterator>
template<std::input_iterator I>
struct basic_const_iterator {
basic_const_iterator() = default;
basic_const_iterator(I);
template<std::sentinel_for<I> S>
friend bool operator==(const basic_const_iterator&, const S&);
};
static_assert(std::sentinel_for<basic_const_iterator<int*>, int*>); // infinite meta-recursion
That is, sentinel_for ends with weakly-equality-comparable-with and instantiates operator==, which in turn rechecks sentinel_for and instantiates the same operator==, making the circle closed.
The proposed resolution is to change operator== to be a member function so that S is no longer accidentally instantiated as basic_const_iterator. The same goes for basic_const_iterator::operator-.