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

            Bug ID: 118209
           Summary: ranges::sort doesn't use iter_move, cannot sort zip of
                    move-only type
           Product: gcc
           Version: 14.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: arthur.j.odwyer at gmail dot com
  Target Milestone: ---

Bug #105609 is related, i.e. it's about using std::move(*it) where ADL
iter_move(it) is required; but I think this new one differs enough to file it
separately. This one transitively affects make_heap and partial_sort.

This initially came from StackOverflow:
https://stackoverflow.com/questions/12227474/can-iter-swap-be-specialised/75535132?noredirect=1#comment139852610_75535132

// https://godbolt.org/z/jqYE9Tnqe

#include <algorithm>
#include <ranges>
#include <vector>
struct F {
  int a = -1;
  explicit F(int d) : a(d) { }
  F(const F&) = delete;
  F(F&& o) : a(o.a) { }
  void operator=(const F&) = delete;
  F& operator=(F&& o) {
    a = o.a;
    return *this;
  }
  auto operator<=>(const F&) const = default;
};
int main() {
  int a[] = {3,2,1};
  std::vector<F> v(a, a+3);

  // sorting v is OK
  std::ranges::sort(v);

  // sorting zip(v) doesn't compile
  std::ranges::sort(std::views::zip(v));
}


include/c++/15.0.0/bits/stl_heap.h:355:15: error: no viable conversion from
'typename std::remove_reference<tuple<F &>>::type' (aka 'std::tuple<F &>') to
'_ValueType' (aka 'std::tuple<F>')
  355 |           _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
      |                      ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This happens inside __make_heap, called from __partial_sort.
The problem is that it's calling `std::move(*iter)` to get an xvalue
zip_view::reference, which then converts to an lvalue F, which can't be copied
because F is move-only. What we need instead is to call zip_view::iterator's
ADL `iter_move(iter)`, to give us an xvalue F directly.

libc++ and MS STL both handle this OK.

Reply via email to