[Bug libstdc++/94354] New: std::reverse_iterator comparison operators defined incorrectly

redi at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Fri Mar 27 10:01:56 GMT 2020


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94354

            Bug ID: 94354
           Summary: std::reverse_iterator comparison operators defined
                    incorrectly
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Keywords: rejects-valid
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

We define the comparison operators for reverse_iterator slightly differently to
how the standard specifies them, which means we incorrectly reject this:

#include <iterator>

struct Iter
{
  using iterator_category = std::random_access_iterator_tag;
  using value_type = int;
  using pointer = int*;
  using reference = int&;
  using difference_type = std::ptrdiff_t;

  Iter();

  Iter& operator++();
  Iter operator++(int);
  Iter& operator--();
  Iter operator--(int);
  int& operator*() const;
  int* operator->() const;

  int& operator[](difference_type) const;

  Iter& operator+=(difference_type);
  Iter& operator-=(difference_type);

  friend Iter operator+(Iter, difference_type);
  friend Iter operator+(difference_type, Iter);
  friend Iter operator-(Iter, difference_type);
  friend difference_type operator-(Iter, Iter);

  friend bool operator==(Iter, Iter);
  friend bool operator!=(Iter, Iter);
  friend bool operator<(Iter, Iter);
  friend bool operator>(Iter, Iter);
  friend bool operator<=(Iter, Iter);
  friend bool operator>=(Iter, Iter);
};

bool operator!=(Iter, long*);

std::reverse_iterator<Iter> l{Iter()};
std::reverse_iterator<long*> r{nullptr};

#if __cplusplus > 201703L
static_assert( std::random_access_iterator<Iter> );
static_assert( std::random_access_iterator<long*> );
#endif

bool b1 = l.base() != r.base();  // OK

bool b2 = l != r;


reviter.cc:50:13:   in 'constexpr' expansion of 'std::operator!=<Iter, long
int*>(l, r)'
/home/jwakely/gcc/10/include/c++/10.0.1/bits/stl_iterator.h:375:25: error: no
match for 'operator==' (operand types are
'std::reverse_iterator<Iter>::iterator_type' {aka 'Iter'} and
'std::reverse_iterator<long int*>::iterator_type' {aka 'long int*'})
  375 |     { return __x.base() == __y.base(); }
      |              ~~~~~~~~~~~^~~~~~~~~~~~~


The reverse_iterator's preconditions are met (both Iter and long* are random
access iterators) and so is the constraint for operator!=

Constraints: x.base() != y.base() is well-formed and convertible to bool.

But it fails because we define operator!= as !(l == r) which uses == on the
base iterator types, and they only support !=

I think the testcase should be valid for C++11 and later, as per
https://cplusplus.github.io/LWG/lwg-defects.html#280
(and also C++98 if we treat that as a DR).


More information about the Gcc-bugs mailing list