diff --git a/stl/inc/ranges b/stl/inc/ranges index 38289d7320a..49b69fa59e9 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -4216,12 +4216,11 @@ namespace ranges { using _Decayed = decay_t<_It>; _STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Decayed>); if constexpr (contiguous_iterator<_Decayed>) { - return {_St::_Span, - noexcept(span(_STD to_address(_STD declval<_It>()), iter_difference_t<_Decayed>{}))}; + return {_St::_Span, true}; } else if constexpr (random_access_iterator<_Decayed>) { return {_St::_Subrange, noexcept(subrange(_STD declval<_It>(), _STD declval<_It>() + iter_difference_t<_Decayed>{}))}; - } else if constexpr (constructible_from<_Decayed, _It>) { + } else if constexpr (is_convertible_v<_It, _Decayed>) { return {_St::_Subrange_counted, noexcept(subrange( counted_iterator(_STD declval<_It>(), iter_difference_t<_Decayed>{}), default_sentinel))}; diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 056b84b2982..96b44d2616a 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -964,7 +964,12 @@ namespace test { requires std::signed_integral && requires { typename std::iterator_traits::iterator_category; } struct redifference_iterator_category_base { using iterator_category = std::iterator_traits::iterator_category; - using iterator_concept = decltype([] { + }; + + template + class redifference_iterator : public redifference_iterator_category_base { + public: + using iterator_concept = decltype([] { if constexpr (std::contiguous_iterator) { return std::contiguous_iterator_tag{}; } else if constexpr (std::random_access_iterator) { @@ -977,13 +982,8 @@ namespace test { return std::input_iterator_tag{}; } }()); - }; - - template - class redifference_iterator : public redifference_iterator_category_base { - public: - using value_type = std::iter_value_t; - using difference_type = Diff; + using value_type = std::iter_value_t; + using difference_type = Diff; redifference_iterator() = default; constexpr explicit redifference_iterator(It it) : i_{std::move(it)} {} @@ -1052,22 +1052,22 @@ namespace test { return i.i_ == j.i_; } - [[nodiscard]] friend constexpr redifference_iterator operator+( - const redifference_iterator& it, std::same_as auto n) + template I> // TRANSITION, DevCom-10735214, should be abbreviated + [[nodiscard]] friend constexpr redifference_iterator operator+(const redifference_iterator& it, I n) requires std::random_access_iterator { return redifference_iterator{it.i_ + static_cast>(n)}; } - [[nodiscard]] friend constexpr redifference_iterator operator+( - std::same_as auto n, const redifference_iterator& it) + template I> // TRANSITION, DevCom-10735214, should be abbreviated + [[nodiscard]] friend constexpr redifference_iterator operator+(I n, const redifference_iterator& it) requires std::random_access_iterator { return redifference_iterator{it.i_ + static_cast>(n)}; } - [[nodiscard]] friend constexpr redifference_iterator operator-( - const redifference_iterator& it, std::same_as auto n) + template I> // TRANSITION, DevCom-10735214, should be abbreviated + [[nodiscard]] friend constexpr redifference_iterator operator-(const redifference_iterator& it, I n) requires std::random_access_iterator { return redifference_iterator{it.i_ - static_cast>(n)}; diff --git a/tests/std/tests/P0896R4_views_counted/test.cpp b/tests/std/tests/P0896R4_views_counted/test.cpp index a033fb72643..e20d1177c26 100644 --- a/tests/std/tests/P0896R4_views_counted/test.cpp +++ b/tests/std/tests/P0896R4_views_counted/test.cpp @@ -14,6 +14,12 @@ template concept Countable = requires { typename iter_difference_t>; } && requires(I&& i, iter_difference_t> n) { views::counted(forward(i), n); }; +template +concept CanConstructCountedSubrange = requires { typename iter_difference_t>; } + && requires(I&& i, iter_difference_t> n) { + ranges::subrange(counted_iterator(forward(i), n), default_sentinel); + }; + template struct convertible_difference { constexpr convertible_difference(const int _val_) noexcept : _val(_val_) {} @@ -31,8 +37,7 @@ struct instantiator { template static constexpr void call() { - using ranges::contiguous_range, ranges::equal, ranges::iterator_t, ranges::random_access_range, ranges::size, - ranges::subrange; + using ranges::equal, ranges::size, ranges::subrange; int input[] = {13, 42, 1729, -1, -1}; static_assert(Countable); @@ -41,6 +46,10 @@ struct instantiator { auto result = ranges::views::counted(Iter{input}, convertible_difference{3}); if constexpr (contiguous_iterator) { static_assert(same_as>, dynamic_extent>>); + + const test::redifference_iterator<_Signed128, Iter> rediff_it{Iter{input}}; + ranges::contiguous_range auto rediff_result = ranges::views::counted(rediff_it, _Signed128{4}); + assert(size(rediff_result) == 4); } else if constexpr (random_access_iterator) { static_assert(same_as>); } else { @@ -53,6 +62,37 @@ struct instantiator { } }; +// Also test GH-5183: ": views::counted::_Choose() misses difference casting for contiguous_iterator case" +struct ExplicitCopyCtorIter { + using difference_type = int; + + ExplicitCopyCtorIter() = default; + ExplicitCopyCtorIter(ExplicitCopyCtorIter&&) = default; + ExplicitCopyCtorIter& operator=(ExplicitCopyCtorIter&&) = default; + explicit ExplicitCopyCtorIter(const ExplicitCopyCtorIter&) = default; + int operator*(); + ExplicitCopyCtorIter& operator++(); + void operator++(int); +}; +static_assert(!Countable); +static_assert(!CanConstructCountedSubrange); + +struct ImplicitCopyOnlyIter { + using difference_type = int; + + ImplicitCopyOnlyIter() = default; + ImplicitCopyOnlyIter(ImplicitCopyOnlyIter&&) = default; + ImplicitCopyOnlyIter& operator=(ImplicitCopyOnlyIter&&) = default; + explicit ImplicitCopyOnlyIter(const ImplicitCopyOnlyIter&) = delete; + template + ImplicitCopyOnlyIter(const ImplicitCopyOnlyIter&); + int operator*(); + ImplicitCopyOnlyIter& operator++(); + void operator++(int); +}; +static_assert(Countable); +static_assert(CanConstructCountedSubrange); + int main() { static_assert(with_writable_iterators::call()); with_writable_iterators::call();