Bug 93267 - std::ranges::begin|end do not work for iota_view when the element and bound type are the same
Summary: std::ranges::begin|end do not work for iota_view when the element and bound t...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 10.0
Assignee: Jonathan Wakely
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2020-01-14 15:29 UTC by Pilar Latiesa
Modified: 2020-01-15 17:50 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-01-14 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Pilar Latiesa 2020-01-14 15:29:42 UTC
The following testcase emits errors at the specified locations:

#include <cstddef>
#include <ranges>

int main()
{
std::size_t const Zero = 0u;
std::size_t const Size = 10u;

auto const Test1 = std::ranges::views::iota(0, Size);
auto beginTest1 = std::ranges::begin(Test1); // OK

auto const Test2 = std::ranges::views::iota(Zero, Size);
auto beginTest2 = std::ranges::begin(Test2); // Error

std::ranges::iota_view const Test3(Zero, Size);
auto beginTest3 = std::ranges::begin(Test3); // Error

std::ranges::iota_view<std::size_t, std::size_t> const Test4(0, Size);
auto beginTest4 = std::ranges::begin(Test4); // Error

std::ranges::iota_view<int, std::size_t> const Test5(0, Size);
auto beginTest4 = std::ranges::begin(Test5); // OK
}

The error reads:

error: no match for call to '(const std::ranges::__cust_access::_Begin) (const std::ranges::iota_view<long unsigned int, long unsigned int>&)'

 
/home/pililatiesa/gcc-trunk-20200114/include/c++/10.0.0/bits/range_access.h:420:2: note: candidate: 'constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const [with _Tp = const std::ranges::iota_view<long unsigned int, long unsigned int>&]'

  420 |  operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())

      |  ^~~~~~~~

/home/pililatiesa/gcc-trunk-20200114/include/c++/10.0.0/bits/range_access.h:420:2: note: constraints not satisfied

<source>: In instantiation of 'constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const [with _Tp = const std::ranges::iota_view<long unsigned int, long unsigned int>&]':

<source>:10:34:   required from here

/home/pililatiesa/gcc-trunk-20200114/include/c++/10.0.0/bits/range_access.h:420:2:   required by the constraints of 'template<class _Tp>  requires (__maybe_safe_range<_Tp>) && ((is_array_v<typename std::remove_reference<_Tp>::remove_reference_t>) || (__member_begin<_Tp>) || (__adl_begin<_Tp>)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&&) const'

/home/pililatiesa/gcc-trunk-20200114/include/c++/10.0.0/bits/range_access.h:418:4: note: neither operand of the disjunction is satisfied

  418 |    || __adl_begin<_Tp>
Comment 1 Jonathan Wakely 2020-01-14 15:43:23 UTC
Please provide the output of 'gcc -v' as requested by https://gcc.gnu.org/bugs/
Comment 2 Jonathan Wakely 2020-01-14 15:44:11 UTC
Your testcase is invalid:

iota.cc: In function 'int main()':
iota.cc:22:6: error: conflicting declaration 'auto beginTest4'
   22 | auto beginTest4 = std::ranges::begin(Test5); // OK
      |      ^~~~~~~~~~
iota.cc:19:6: note: previous declaration as 'std::ranges::iota_view<long unsigned int, long unsigned int>::_Iterator beginTest4'
   19 | auto beginTest4 = std::ranges::begin(Test4); // Error
      |      ^~~~~~~~~~


It compiles for me if I fix that.
Comment 3 Pilar Latiesa 2020-01-14 16:05:10 UTC
(In reply to Jonathan Wakely from comment #1)
> Please provide the output of 'gcc -v' as requested by
> https://gcc.gnu.org/bugs/

Using built-in specs.
COLLECT_GCC=g++
Target: x86_64-linux-gnu
Configured with: ../gcc-trunk-20200114/configure --prefix=/usr --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap --with-abi=m64 --enable-clocale=gnu --enable-languages=c,c++,fortran --enable-ld=yes --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-linker-build-id --enable-lto --enable-plugins --enable-threads=posix --enable-libatomic --enable-libcilkrts --enable-libgomp 
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.0.0 20200111 (experimental)
Comment 4 Pilar Latiesa 2020-01-14 16:08:10 UTC
(In reply to Jonathan Wakely from comment #1)
> Please provide the output of 'gcc -v' as requested by
> https://gcc.gnu.org/bugs/

Using built-in specs.
COLLECT_GCC=g++
Target: x86_64-linux-gnu
Configured with: ../gcc-trunk-20200114/configure --prefix=/usr --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap --with-abi=m64 --enable-clocale=gnu --enable-languages=c,c++,fortran --enable-ld=yes --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-linker-build-id --enable-lto --enable-plugins --enable-threads=posix --enable-libatomic --enable-libcilkrts --enable-libgomp 
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.0.0 20200111 (experimental)

(In reply to Jonathan Wakely from comment #2)
> Your testcase is invalid:
> 
> iota.cc: In function 'int main()':
> iota.cc:22:6: error: conflicting declaration 'auto beginTest4'
>    22 | auto beginTest4 = std::ranges::begin(Test5); // OK
>       |      ^~~~~~~~~~
> iota.cc:19:6: note: previous declaration as 'std::ranges::iota_view<long
> unsigned int, long unsigned int>::_Iterator beginTest4'
>    19 | auto beginTest4 = std::ranges::begin(Test4); // Error
>       |      ^~~~~~~~~~

Sorry. I composed the testcase from several pieces but didn't test the whole.
 
> It compiles for me if I fix that.

Strange. I see the same errors on Compiler Explorer: https://godbolt.org/z/pcq7fS
Comment 5 Pilar Latiesa 2020-01-14 16:52:46 UTC
It compiles with -std=gnu++2a but not with -std=c++2a. Hope this helps.
Comment 6 Jonathan Wakely 2020-01-14 17:07:44 UTC
(In reply to Pilar Latiesa from comment #5)
> It compiles with -std=gnu++2a but not with -std=c++2a. Hope this helps.

This is why you're supposed to provide the command, and 'gcc -v' info etc.
Comment 7 Jonathan Wakely 2020-01-14 17:17:57 UTC
The problem happens when the first template argument is an integer with no larger integer type available. I try to use __int128 but that's not usable with -std=c++2a.

#include <ranges>

int main()
{
  std::ranges::iota_view<long, int> i(0, 3);
  std::ranges::begin(i);
}
Comment 8 Jonathan Wakely 2020-01-15 14:26:58 UTC
The problem is that std::weakly_incrementable only allows signed integers, not integer-like types. I have a fix.
Comment 9 GCC Commits 2020-01-15 17:01:32 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:2a0f6c61b4db19535c632be68bddad74b6adb6cf

commit r10-5985-g2a0f6c61b4db19535c632be68bddad74b6adb6cf
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jan 15 14:09:35 2020 +0000

    libstdc++: Fix weakly_incrementable to allow __int128 (PR 93267)
    
    The __iota_diff_t alias can be the type __int128, but that does not
    satisfy the signed_integral and __is_signed_integer_like concepts when
    __STRICT_ANSI__ is defined (which is true for -std=c++2a).
    
    Because weakly_incrementable is defined in terms of signed_integral, it
    is not satisfied by __int128, which means iota_view's iterator doesn't
    always satisfy input_or_output_iterator and so iota_view is not always a
    range.
    
    The solution is to define __max_size_type and __max_diff_type using
    __int128, so that __is_signed_integer_like allows __int128, and then
    make weakly_incrementable use __is_signed_integer_like instead of
    signed_integral.
    
    	PR libstdc++/93267
    	* include/bits/iterator_concepts.h (__max_diff_type, __max_size_type):
    	Move here from <bits/range_access.h> and define using __int128 when
    	available.
    	(__is_integer_like, __is_signed_integer_like): Move here from
    	<bits/range_access.h>.
    	(weakly_incrementable): Use __is_signed_integer_like.
    	* include/bits/range_access.h (__max_diff_type, __max_size_type)
    	(__is_integer_like, __is_signed_integer_like): Move to
    	<bits/iterator_concepts.h>.
    	(__make_unsigned_like_t): Move here from <ranges>.
    	* include/std/ranges (__make_unsigned_like_t): Move to
    	<bits/range_access.h>.
    	(iota_view): Replace using-directive with using-declarations.
    	* testsuite/std/ranges/iota/93267.cc: New test.
    	* testsuite/std/ranges/iota_view.cc: Move to new 'iota' sub-directory.
Comment 10 Jonathan Wakely 2020-01-15 17:50:52 UTC
Fixed, thanks for the report.