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

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
      Known to work|                            |4.8.5
            Version|unknown                     |7.0
            Summary|std::search with binary     |[5/6/7 Regression]
                   |comparison predicate uses   |std::search with binary
                   |invalid reference           |comparison predicate uses
                   |                            |invalid reference
      Known to fail|                            |4.9.4, 5.4.0, 6.3.0, 7.0

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Actually, std::includes() doesn't use the problematic function objects that
store a reference, so there's no bug.

We do have a regression for this standalone testcase, which violates the
ForwardIterator requirements, but worked previously:

#include <algorithm>

struct bad_iterator
{
  typedef std::forward_iterator_tag iterator_category;
  typedef int value_type;
  typedef value_type const* pointer;
  typedef value_type const& reference;
  typedef std::ptrdiff_t difference_type;

  bad_iterator() : ptr(), stash() { }
  bad_iterator(pointer p) : ptr(p), stash() { update(); }
  bad_iterator(const bad_iterator& i) : ptr(i.ptr), stash() { update(); }
  ~bad_iterator() { ptr = 0; update(); }

  bad_iterator& operator=(const bad_iterator& i)
  {
    ptr = i.ptr;
    update();
    return *this;
  }

  bad_iterator& operator++() { ++ptr; update(); return *this; }
  bad_iterator operator++(int) { bad_iterator i = *this; ++*this; return i; }
  reference operator*() const { return *stash; }
  pointer operator->() const { return stash; }

  bool operator==(const bad_iterator& i) const { return ptr == i.ptr; }
  bool operator!=(const bad_iterator& i) const { return !(*this == i); }

private:
  void update()
  {
#ifdef VALID_FWD_ITER
    stash = ptr;
#else
    pointer p = 0;
    if (ptr)
      p = new value_type(*ptr);
    delete stash;
    stash = p;
#endif
  }

  pointer ptr;
  pointer stash;
};

int main() {
  int s[] = { 0, 1, 2, 3, 4, 5 };
  std::search(s, s+3, bad_iterator(s), bad_iterator(s+4));
}

This stopped working with GCC 4.9.0 when we added the __iter_comp_iter stuff
that stores the reference.

Technically this is invalid, but I think we can support it without too much
difficulty. That's reasonable given that std::filesystem::path::iterator also
violates the ForwardIterator requirements, and the Ranges TS removes the
reference-quality requirement anyway.

Reply via email to