[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-07-11 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305
Bug 120305 depends on bug 96710, which changed state.

Bug 96710 Summary: __int128 vs 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96710

   What|Removed |Added

 Status|ASSIGNED|RESOLVED
 Resolution|--- |FIXED

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-17 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #17 from aneris  ---
Alright, I understand. Thank you again.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-17 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #16 from Jonathan Wakely  ---
(In reply to aneris from comment #13)
> (In reply to Jonathan Wakely from comment #12)
> > tl;dr if you want to compile with strict -std=c++20 -pedantic settings, you
> > need to strictly follow the rules of the standard.
> 
> I understand, though, at the very least, couldn't this be made a warning for
> -pedantic? I think that would be immensely useful.

I don't see how. The library code is just C++ code, it doesn't know what your
intention was when writing the code, or whether you wanted to use __int128
without warnings or not. And I don't think there's any preprocessor macro that
the library can even check to see if you used -pedantic or not.

> On another note, this code does compile with Clang. Apparently godbolt
> defaults to libstdc++ for clang instead of libc++ and that caused all the
> confusion.

Yes, we've been asking them to make that more obvious for years:
https://github.com/compiler-explorer/compiler-explorer/issues/3682

> Here: https://godbolt.org/z/j6fYMdjeo
> 
> I did some digging and this is because std::is_integral_v<__int128_t> is
> unconditionally true in libc++, unlike in libstdc++ where it's only true
> when the GNU extensions are enabled.

Yes, which is not conforming to the C++20 (and earlier) standards. It is
allowed by C++23 though, and I plan to treat that as a DR for earlier
standards. That's the topic of PR 96710.

> So I was wondering, is it really out of the question to promote __int128_t
> to an integer type by default like Clang? It'd make some code more
> compatible.

That's PR 96710. It was not allowed by the standard, but we fixed that:
https://cplusplus.github.io/LWG/issue3828
(I reported that issue myself, specifically because I want to resolve this
problem).

(In reply to aneris from comment #14)
> (In reply to aneris from comment #13)
> 
> > I did some digging and this is because std::is_integral_v<__int128_t> is
> > unconditionally true in libc++, unlike in libstdc++ where it's only true
> > when the GNU extensions are enabled.
> 
> Ok this is not it at all.
> 
> looks like libc++ defaults to a long long unsigned as the difference type
> for an iota_view with long unsigned.

Right, for libc++ std::integral<__int128> is always true, but it also looks
like they chose not to use the mechanisms introduced by 
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1522r1.pdf for
iota_view, so that range_difference_t> cannot represent the
size of some views.

https://godbolt.org/z/3M7sxh5qn

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-17 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #15 from aneris  ---
(In reply to aneris from comment #14)
> (In reply to aneris from comment #13)

> So I was wondering, is it really out of the question to promote __int128_t to 
> an integer type by default like Clang? It'd make some code more compatible.

I missed that you have tagged 96710 in "Depends on", sorry.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-17 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #14 from aneris  ---
(In reply to aneris from comment #13)

> I did some digging and this is because std::is_integral_v<__int128_t> is
> unconditionally true in libc++, unlike in libstdc++ where it's only true
> when the GNU extensions are enabled.

Ok this is not it at all.

looks like libc++ defaults to a long long unsigned as the difference type for
an iota_view with long unsigned.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-17 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #13 from aneris  ---
(In reply to Jonathan Wakely from comment #12)
> tl;dr if you want to compile with strict -std=c++20 -pedantic settings, you
> need to strictly follow the rules of the standard.

I understand, though, at the very least, couldn't this be made a warning for
-pedantic? I think that would be immensely useful.

On another note, this code does compile with Clang. Apparently godbolt defaults
to libstdc++ for clang instead of libc++ and that caused all the confusion.

Here: https://godbolt.org/z/j6fYMdjeo

I did some digging and this is because std::is_integral_v<__int128_t> is
unconditionally true in libc++, unlike in libstdc++ where it's only true when
the GNU extensions are enabled.

So I was wondering, is it really out of the question to promote __int128_t to
an integer type by default like Clang? It'd make some code more compatible.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #12 from Jonathan Wakely  ---
tl;dr if you want to compile with strict -std=c++20 -pedantic settings, you
need to strictly follow the rules of the standard.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #11 from Jonathan Wakely  ---
Specifically, we have these concepts used to select a partial specialization of
std::iterator_traits:

template
  concept __cpp17_iterator = requires(_Iter __it)
{
  { *__it } -> __can_reference;
  { ++__it } -> same_as<_Iter&>;
  { *__it++ } -> __can_reference;
} && copyable<_Iter>;

template
  concept __cpp17_input_iterator = __cpp17_iterator<_Iter>
&& equality_comparable<_Iter>
&& requires(_Iter __it)
{
  typename incrementable_traits<_Iter>::difference_type;
  typename indirectly_readable_traits<_Iter>::value_type;
  typename common_reference_t&&,
   typename indirectly_readable_traits<_Iter>::value_type&>;
  typename common_reference_t::value_type&>;
  requires signed_integral<
typename incrementable_traits<_Iter>::difference_type>;
};

That last signed_integral requirement is the problem.

signed_integral<__int128> is satisfied for -std=gnu++20 and not for -std=c++20.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #10 from Jonathan Wakely  ---
(In reply to Jonathan Wakely from comment #7)
> An iota_view with unsigned long elements (i.e. 64-bit integers) must use
> something wider than 64 bits for the difference_type of its iterators. The
> C++20 standard allows that to be an integer type or an integer-like class
> type.
> 
> In strict standard-conforming mode, we do not use the non-standard __int128
> type for iota_view iterators, so we use an integer-like class type.

Sorry, I slightly misremembered the details and this is not quite correct. We
use __int128 for the difference_type even in strict mode. 

The problem is that the Cpp17InputIterator requirements require the iterator's
difference_type to be a standard integer type, and in struct modes __int128 is
not considered a standard integer type (it's a non-standard extension).

In non-strict -std=gnu++20 mode we consider __int128 to be a standard integer
type, and so iota iterators meet the Cpp17InputIterator requirements. 

So the end result is the same, the difference is just in the precise details of
*why* iota view iterators do not meet the Cpp17InputIterator requirements.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #9 from aneris  ---
Hmm, alright.

Thank you very much for your time.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #8 from Jonathan Wakely  ---
N.B. this has nothing to do with ranges::transform_view, the problem is
entirely due to iota_view

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1522r1.pdf has the
background on integer-like class types.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #3 from aneris  ---
(In reply to Andrew Pinski from comment #2)
> The difference is int128_t support.

Could you elaborate a bit? I am afraid I don't follow.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #7 from Jonathan Wakely  ---
(In reply to aneris from comment #0)
> The code compiles correctly if you replace all the long unsigned with just
> unsigned though, which I find very peculiar, the code also compiles with
> gnu++20 as the standard.

An iota_view with unsigned elements (i.e. 32-bit integers) can use 64-bit
integer for the difference_type of its iterators.

An iota_view with unsigned long elements (i.e. 64-bit integers) must use
something wider than 64 bits for the difference_type of its iterators. The
C++20 standard allows that to be an integer type or an integer-like class type.

In strict standard-conforming mode, we do not use the non-standard __int128
type for iota_view iterators, so we use an integer-like class type.

The Cpp17InputIterator requirements do not allow an integer-like class type to
be used, which means that in strict conformance mode, an iota_view with 64-bit
elements has iterators which do not meet the Cpp17InputIterator requirements.

You should not be assuming that C++20 ranges can be used in code that expects
class STL-style iterators. C++20 iterators and classic STL-style iterators are
not fully compatible with each other.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

Jonathan Wakely  changed:

   What|Removed |Added

 Status|UNCONFIRMED |RESOLVED
 Resolution|--- |INVALID

--- Comment #6 from Jonathan Wakely  ---
(In reply to aneris from comment #0)
> auto triangularNums = std::ranges::views::iota(1lu, N + 1) |
> std::views::transform([](long unsigned a){return (a * (a + 1))/2;}); 
> return std::vector{triangularNums.begin(),
> triangularNums.end()};

This is not a bug. The std::vector(InputIterator, InputIterator) constructor
requires arguments that meet the Cpp17InputIterator requirements.
ranges::iota_view iterators do not meet those requirements.

The correct way to do this is:

  return std::ranges::to>(triangularNums);

You can also directly use the constructor that std::ranges::to uses:

  return std::vector{std::from_range, triangularNums);

The std::ranges::to solution works since GCC 14, the std::from_range
constructor is only supported since GCC 15.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread pinskia at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #4 from Andrew Pinski  ---
(In reply to aneris from comment #3)
> (In reply to Andrew Pinski from comment #2)
> > The difference is int128_t support.
> 
> Could you elaborate a bit? I am afraid I don't follow.

I am saying why `-std=c++20 -pedantic` fails but `-std=gnu++20 -pedantic`
works. it seems related to int128_t support in libstdc++. I have not looked
further than that.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #5 from aneris  ---
(In reply to Andrew Pinski from comment #4)
> (In reply to aneris from comment #3)
> > (In reply to Andrew Pinski from comment #2)
> > > The difference is int128_t support.
> > 
> > Could you elaborate a bit? I am afraid I don't follow.
> 
> I am saying why `-std=c++20 -pedantic` fails but `-std=gnu++20 -pedantic`
> works. it seems related to int128_t support in libstdc++. I have not looked
> further than that.

Ah, okay!

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread pinskia at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

--- Comment #2 from Andrew Pinski  ---
The difference is int128_t support.

[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.

2025-05-16 Thread aneris at disroot dot org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120305

aneris  changed:

   What|Removed |Added

 CC||aneris at disroot dot org

--- Comment #1 from aneris  ---
Created attachment 61440
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61440&action=edit
the ii file produced by the compiler