[Bug libstdc++/120305] Cannot create a std::vector from a std::ranges::transform_view.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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