[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