From 44284cde6d74a8c0a849f9f30feb23a37a796820 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Sun, 24 Aug 2025 13:44:49 +0300 Subject: [PATCH 1/3] [libc++][ranges] LWG3610: iota_view::size sometimes rejects integer-class types Fixes #104948 - https://wg21.link/LWG3610 --- libcxx/docs/Status/Cxx23Issues.csv | 2 +- libcxx/include/__ranges/iota_view.h | 2 +- .../range.iota.view/size.pass.cpp | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv index 189f8452e0678..38571dabae463 100644 --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -143,7 +143,7 @@ "`LWG3598 `__","``system_category().default_error_condition(0)`` is underspecified","2022-02 (Virtual)","","","" "`LWG3601 `__","common_iterator's postfix-proxy needs ``indirectly_readable`` ","2022-02 (Virtual)","","","" "`LWG3607 `__","``contiguous_iterator`` should not be allowed to have custom ``iter_move`` and ``iter_swap`` behavior","2022-02 (Virtual)","|Nothing To Do|","","" -"`LWG3610 `__","``iota_view::size`` sometimes rejects integer-class types","2022-02 (Virtual)","","","" +"`LWG3610 `__","``iota_view::size`` sometimes rejects integer-class types","2022-02 (Virtual)","|Complete|","22","" "`LWG3612 `__","Inconsistent pointer alignment in ``std::format`` ","2022-02 (Virtual)","|Complete|","14","" "`LWG3616 `__","LWG 3498 seems to miss the non-member ``swap`` for ``basic_syncbuf`` ","2022-02 (Virtual)","|Complete|","18","" "`LWG3618 `__","Unnecessary ``iter_move`` for ``transform_view::iterator`` ","2022-02 (Virtual)","|Complete|","19","" diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h index 4b84585258b91..cf401a4665fcd 100644 --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -348,7 +348,7 @@ class iota_view : public view_interface> { _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires(same_as<_Start, _BoundSentinel> && __advanceable<_Start>) || - (integral<_Start> && integral<_BoundSentinel>) || sized_sentinel_for<_BoundSentinel, _Start> + (__integer_like<_Start> && __integer_like<_BoundSentinel>) || sized_sentinel_for<_BoundSentinel, _Start> { if constexpr (__integer_like<_Start> && __integer_like<_BoundSentinel>) { return (__value_ < 0) diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp index b894bc542be10..90afec2fba177 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp @@ -16,8 +16,21 @@ #include #include "test_macros.h" +#define TEST_HAS_NO_INT128 +#include "type_algorithms.h" #include "types.h" +template +concept HasSize = requires(const T t) { t.size(); }; + +struct CheckForSize { + template + constexpr void operator()() { + static_assert(HasSize>); + static_assert(HasSize>); + } +}; + constexpr bool test() { // Both are integer like and both are less than zero. { @@ -99,6 +112,11 @@ constexpr bool test() { assert(sz == 10); } + // LWG3610: `iota_view::size` sometimes rejects integer-class types + { + types::for_each(types::integer_types{}, CheckForSize{}); + } + return true; } From bee2ac2a7a4da6b6f234106cbb3070577bf49a96 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 25 Aug 2025 11:28:26 +0300 Subject: [PATCH 2/3] Updated test --- .../ranges/range.factories/range.iota.view/size.pass.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp index 90afec2fba177..315e581aed577 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp @@ -24,10 +24,11 @@ template concept HasSize = requires(const T t) { t.size(); }; struct CheckForSize { - template + template constexpr void operator()() { - static_assert(HasSize>); - static_assert(HasSize>); + types::for_each(types::integer_types{}, []() { + static_assert(HasSize>); + }); } }; From 1575d9566e5e65411561e60b928092055ed1ee80 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 25 Aug 2025 14:26:11 +0300 Subject: [PATCH 3/3] Added `__int128_t` support --- libcxx/include/__ranges/iota_view.h | 6 ++++++ .../ranges/range.factories/range.iota.view/begin.pass.cpp | 4 ++++ .../ranges/range.factories/range.iota.view/end.pass.cpp | 8 ++++++++ .../iterator/member_typedefs.compile.pass.cpp | 8 ++++++++ .../range.iota.view/iterator/star.pass.cpp | 6 ++++++ .../range.iota.view/iterator/subscript.pass.cpp | 6 ++++++ .../ranges/range.factories/range.iota.view/size.pass.cpp | 1 - 7 files changed, 38 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h index cf401a4665fcd..275694a054057 100644 --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -57,11 +57,17 @@ struct __get_wider_signed { return type_identity{}; else if constexpr (sizeof(_Int) < sizeof(long)) return type_identity{}; + else if constexpr (sizeof(_Int) < sizeof(long long)) + return type_identity{}; else +# if _LIBCPP_HAS_INT128 + return type_identity<__int128_t>{}; +# else return type_identity{}; static_assert( sizeof(_Int) <= sizeof(long long), "Found integer-like type that is bigger than largest integer like type."); +# endif } using type = typename decltype(__call())::type; diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp index 06419c1b14ee0..dbe052ea18287 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp @@ -40,6 +40,10 @@ constexpr void testType() { constexpr bool test() { testType(); +#ifndef TEST_HAS_NO_INT128 + testType<__int128_t>(); + testType<__uint128_t>(); +#endif testType(); testType(); testType(); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp index 6abbef55b6ba7..d12079fdb5eec 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp @@ -61,6 +61,14 @@ constexpr void testType(U u) { constexpr bool test() { testType(SomeInt(10)); testType(IntComparableWith(SomeInt(10))); +#ifndef TEST_HAS_NO_INT128 + testType<__int128_t>(__int128_t(10)); + testType<__uint128_t>(__uint128_t(10)); +#endif + testType(10LL); + testType(10ULL); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); testType(IntComparableWith(10)); testType(IntComparableWith(10)); testType(IntComparableWith(10)); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp index c2f7fd14042a8..2cd7105adad4b 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp @@ -106,7 +106,11 @@ void test() { // Same as below, if there is no type larger than long, we can just use that. static_assert(sizeof(Iter::difference_type) >= sizeof(long)); static_assert(std::is_signed_v); +#ifdef TEST_HAS_NO_INT128 LIBCPP_STATIC_ASSERT(std::same_as); +#else + LIBCPP_STATIC_ASSERT(std::same_as); +#endif } { const std::ranges::iota_view io(0); @@ -118,7 +122,11 @@ void test() { // https://eel.is/c++draft/range.iota.view#1.3 static_assert(sizeof(Iter::difference_type) >= sizeof(long long)); static_assert(std::is_signed_v); +#ifdef TEST_HAS_NO_INT128 LIBCPP_STATIC_ASSERT(std::same_as); +#else + LIBCPP_STATIC_ASSERT(std::same_as); +#endif } { const std::ranges::iota_view io; diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp index 570c74e29c686..b776d90c5e5e3 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp @@ -81,6 +81,12 @@ constexpr void testType() { constexpr bool test() { testType(); testType(); +#ifndef TEST_HAS_NO_INT128 + testType<__int128_t>(); + testType<__uint128_t>(); +#endif + testType(); + testType(); testType(); testType(); testType(); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp index 0e5aca0dd554c..786b63dfeedee 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp @@ -47,6 +47,12 @@ constexpr void testType() { constexpr bool test() { testType(); +#ifndef TEST_HAS_NO_INT128 + testType<__int128_t>(); + testType<__uint128_t>(); +#endif + testType(); + testType(); testType(); testType(); testType(); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp index 315e581aed577..bb8215339b2bd 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp @@ -16,7 +16,6 @@ #include #include "test_macros.h" -#define TEST_HAS_NO_INT128 #include "type_algorithms.h" #include "types.h"