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

            Bug ID: 122903
           Summary: [16 Regression] gjs-1.86.0 fails to build since
                    r16-4100-gaaeca77a79a9a8
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: slyfox at gcc dot gnu.org
  Target Milestone: ---

I'm not sure if it's a regression or an intentional change. But since
r16-4100-gaaeca77a79a9a8 (bisected) `gjs-1.86.0` started failing to build.

I proposed the upstream fix as:
https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/1046

But I'm not sure if the API change is intentional and whether iterator `gjs`
implements is correct. Filing the bug just in case.

Here is the extracted reproducer from `gjs`:

// $ cat a.cc
#include <algorithm>
#include <iterator>

// gjs calls it OwnedInfo
class T {
  T() = delete;
 public:
  explicit T(const T&);
  T(T && o);

  T& operator=(const T&);
  T& operator=(T&&);
};

// gjs calls it `class InfoIterator`
struct I {
  bool operator==(const class I &) const;
  bool operator!=(const class I &) const;
  I& operator++();

  T operator*(); // Note, not the `T&` reference!

  typedef std::input_iterator_tag iterator_category;
  typedef int difference_type;
  typedef T value_type;
  typedef value_type* pointer;
  typedef value_type& reference;
};

bool struct_is_simple(I b, I e) {
    return std::all_of(b, e, [](T) { return false; });
}

gcc-14, work as is:

$ g++-14 -c a.cc -std=c++11
# ok

gcc-master fails:
$ g++ -c a.cc -std=c++11

In file included from
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/stl_algobase.h:71,
                 from
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/algorithm:62,
                 from a.cc:1:
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/predefined_ops.h:
In instantiation of 'bool
__gnu_cxx::__ops::_Unary_negate<_Func>::operator()(_Tp&&) [with _Tp = T; _Func
= struct_is_simple(I, I)::<lambda(T)>]':
required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with
_Iterator = I; _Predicate = __gnu_cxx::__ops::_Unary_negate<struct_is_simple(I,
I)::<lambda(T)> >]'
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/stl_algobase.h:2103:42:
 2103 |       while (__first != __last && !__pred(*__first))
      |                                    ~~~~~~^~~~~~~~~~
required from '_InputIterator std::__find_if_not(_InputIterator,
_InputIterator, _Predicate) [with _InputIterator = I; _Predicate =
struct_is_simple(I, I)::<lambda(T)>]'
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/stl_algo.h:115:28:
  115 |       return std::__find_if(__first, __last,
      |              ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
  116 |                             __gnu_cxx::__ops::not1(__pred));
      |                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
required from '_IIter std::find_if_not(_IIter, _IIter, _Predicate) [with _IIter
= I; _Predicate = struct_is_simple(I, I)::<lambda(T)>]'
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/stl_algo.h:473:32:
  473 |       return std::__find_if_not(__first, __last, __pred);
      |              ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
required from 'bool std::all_of(_IIter, _IIter, _Predicate) [with _IIter = I;
_Predicate = struct_is_simple(I, I)::<lambda(T)>]'
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/stl_algo.h:413:40:
  413 |     { return __last == std::find_if_not(__first, __last, __pred); }
      |                        ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
required from here
a.cc:31:23:
   31 |     return std::all_of(b, e, [](T) { return false; });
      |            ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/<<NIX>>/gcc-16.0.0.99999999/include/c++/16.0.0.99999999/bits/predefined_ops.h:105:47:
error: cannot bind rvalue reference of type 'T&&' to lvalue of type 'T'
  105 |         operator()(_Tp&& __arg) { return !_M_f(__arg); }
      |                                           ~~~~^~~~~~~
a.cc:9:10: note: initializing argument 1 of 'T::T(T&&)'
    9 |   T(T && o);
      |     ~~~~~^
a.cc:31:30: note: initializing argument 1 of 'struct_is_simple(I,
I)::<lambda(T)>'
   31 |     return std::all_of(b, e, [](T) { return false; });
      |                              ^

Note that dereference iterator returns a value, not a reference: `T
operator*(); // Note, not the `T&` reference!`. If I change it to `T
operator*();` then both `gcc-14` and `gcc-master` start matching behaviour.

A few questions:

1. Is it expected that `gcc-14` / `gcc-master` differ in handling this code?
2. Is `T operator*();` a reasonable iterator implementaiton?

Thanks!

Reply via email to