https://gcc.gnu.org/g:7239744d25dadf39f431dfe38f3c03942acdb979
commit r17-810-g7239744d25dadf39f431dfe38f3c03942acdb979 Author: Tomasz Kamiński <[email protected]> Date: Fri Apr 24 05:26:13 2026 +0200 libstdc++: Make ref_view<R> statically sized if R has static size This patch introduces ranges::__static_size<_Range> helper functions, that returns ranges::size(__rg) for __statically_sized_range. This function is then used for ref_view<R>::size if R has static size, avoiding dereference of pointer value that is not known at compile time. Similarly for ref_view<R>::empty() we compare the size with zero, if it is known statically. This implements relevant part of P3928R0: static_sized_range by Hewill Kang. As standard does not specify when constexpr functions are usable at compile time, such implementation are allowed (but not mandated) by current draft. libstdc++-v3/ChangeLog: * include/bits/ranges_base.h (ranges::__static_size): Define. * include/std/ranges (ref_view::size()): For ranges with static size return ranges::__static_size<_Range>. (ref_view::empty): For ranges with static size, compare size against zero. * testsuite/23_containers/inplace_vector/cons/from_iota_neg.cc: Expect errors from ref_view uses. * testsuite/23_containers/inplace_vector/cons/from_range_neg.cc: Expect errors from ref_view uses. Reviewed-by: Jonathan Wakely <[email protected]> Reviewed-by: Patrick Palka <[email protected]> Signed-off-by: Tomasz Kamiński <[email protected]> Diff: --- libstdc++-v3/include/bits/ranges_base.h | 14 ++++++++++++++ libstdc++-v3/include/std/ranges | 18 ++++++++++++++++-- .../23_containers/inplace_vector/cons/from_iota_neg.cc | 6 ++---- .../inplace_vector/cons/from_range_neg.cc | 10 ++++------ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index fea4100eb09e..ce1c40fc17f6 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -562,6 +562,20 @@ namespace ranges template<typename _Tp> concept __static_sized_range = sized_range<_Tp> && requires (_Tp& __t) { static_cast<char(*)[size_t(ranges::size(__t) >= 0)]>(nullptr); }; + + template<__static_sized_range _Range> + consteval range_size_t<_Range> + __static_size() + { + auto __conjure = [](_Range& __r) + { + if constexpr (ranges::size(__r) <= size_t(-1)) + return integral_constant<size_t, size_t(ranges::size(__r))>{}; + else + return integral_constant<range_size_t<_Range>, ranges::size(__r)>{}; + }; + return range_size_t<_Range>(decltype(__conjure(std::declval<_Range&>()))::value); + } #endif // C++26 template<typename _Derived> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 7d8b37f8c5cf..2f11cc2336f7 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1382,11 +1382,25 @@ namespace views::__adaptor constexpr bool empty() const requires requires { ranges::empty(*_M_r); } - { return ranges::empty(*_M_r); } + { +#if __cplusplus > 202302L + if constexpr (__static_sized_range<_Range>) + return ranges::__static_size<_Range>() == 0; + else +#endif + return ranges::empty(*_M_r); + } constexpr auto size() const requires sized_range<_Range> - { return ranges::size(*_M_r); } + { +#if __cplusplus > 202302L + if constexpr (__static_sized_range<_Range>) + return ranges::__static_size<_Range>(); + else +#endif + return ranges::size(*_M_r); + } constexpr auto data() const requires contiguous_range<_Range> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_iota_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_iota_neg.cc index ae0b96175b7d..6b66b5d97ed9 100644 --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_iota_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_iota_neg.cc @@ -33,14 +33,12 @@ test_all() std::inplace_vector<int, 15> tr1(std::from_range, ref_view(m12)); std::inplace_vector<int, 10> tm2(std::from_range, m12); // { dg-error "(from here|expansion of)" } - // ref_view is not statically sized due pointer dereference - std::inplace_vector<int, 10> tr2(std::from_range, ref_view(m12)); + std::inplace_vector<int, 10> tr2(std::from_range, ref_view(m12)); // { dg-error "(from here|expansion of)" } StaticIota<__int128, 0> mm; std::inplace_vector<int, 10> tm3(std::from_range, mm); // { dg-error "(from here|expansion of)" } - // ref_view is not statically sized due pointer dereference - std::inplace_vector<int, 10> tr3(std::from_range, ref_view(mm)); + std::inplace_vector<int, 10> tr3(std::from_range, ref_view(mm)); // { dg-error "(from here|expansion of)" } } // { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range_neg.cc index 48d5b4c56f59..ea187761e5e7 100644 --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range_neg.cc @@ -62,16 +62,14 @@ test_all() test_one(a1); // { dg-error "from here" } test_one(s1); // { dg-error "from here" } - // ref_view is not statically sized due pointer dereference - test_one(ref_view(a1)); - test_one(a5 | std::views::adjacent<7> | std::views::elements<0>); + test_one(ref_view(a1)); // { dg-error "from here" } + test_one(a5 | std::views::adjacent<5> | std::views::elements<0>); // { dg-error "from here" } test_one(s5 | std::views::adjacent<5> | std::views::elements<0>); // { dg-error "from here" } test_five(a5); // { dg-error "from here" } test_five(s5); // { dg-error "from here" } - // ref_view is not statically sized due pointer dereference - test_five(ref_view(a5)); - test_five(a7 | std::views::adjacent<3> | std::views::elements<0>); + test_five(ref_view(a5)); // { dg-error "from here" } + test_five(a7 | std::views::adjacent<3> | std::views::elements<0>); // { dg-error "from here" } test_five(s7 | std::views::adjacent<3> | std::views::elements<0>); // { dg-error "from here" } }
