https://gcc.gnu.org/g:7249bc4aacc443faeb054d082d25e5d5cb819df9
commit r17-4250-g7249bc4aacc443faeb054d082d25e5d5cb819df9 Author: Patrick Palka <[email protected]> Date: Fri Aug 21 09:20:47 2026 -0400 libstdc++: Implement LWG 3749 changes to common_iterator A couple of backwards compatibility notes: Since iterator_traits is an empty type the new base class must depend on both the iterator and sentinel types so that two iterator_traits<_It, _Sent1> and iterator_traits<_It, _Sent2> subobjects continue to be potentially overlapping for _Sent1 != _Sent2. And it must be a public base so that iterator_traits<common_iterator> continues to be an aggregate type. libstdc++-v3/ChangeLog: * include/bits/stl_iterator.h (__detail::__common_iterator_iter_cat): New. (iterator_traits<common_iterator>): Use it to conditionally define iterator_category as per LWG 3749. * testsuite/24_iterators/common_iterator/1.cc (test_lwg3749): New test. Reviewed-by: Jonathan Wakely <[email protected]> Diff: --- libstdc++-v3/include/bits/stl_iterator.h | 37 +++++++++++++++------- .../testsuite/24_iterators/common_iterator/1.cc | 23 ++++++++++++++ 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index f5f2abbb8b6b..bcc22c50de57 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -2297,8 +2297,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using difference_type = iter_difference_t<_It>; }; + namespace __detail + { + template<typename _It, typename _Sent> + struct __common_iterator_iter_cat + { }; + + template<typename _It, typename _Sent> + requires integral<iter_difference_t<_It>> + struct __common_iterator_iter_cat<_It, _Sent> + { + static auto + _S_iter_cat() + { + if constexpr (requires { requires derived_from<__iter_category_t<_It>, + forward_iterator_tag>; }) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + using iterator_category = decltype(_S_iter_cat()); + }; + } // namespace __detail + template<input_iterator _It, typename _Sent> struct iterator_traits<common_iterator<_It, _Sent>> + : __detail::__common_iterator_iter_cat<_It, _Sent> { private: template<typename _Iter> @@ -2315,21 +2340,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using type = decltype(std::declval<const _CIter&>().operator->()); }; - static auto - _S_iter_cat() - { - if constexpr (requires { requires derived_from<__iter_category_t<_It>, - forward_iterator_tag>; }) - return forward_iterator_tag{}; - else - return input_iterator_tag{}; - } - public: using iterator_concept = __conditional_t<forward_iterator<_It>, forward_iterator_tag, input_iterator_tag>; - using iterator_category = decltype(_S_iter_cat()); + // iterator_category defined in base __common_iterator_iter_cat using value_type = iter_value_t<_It>; using difference_type = iter_difference_t<_It>; using pointer = typename __ptr<_It>::type; diff --git a/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc b/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc index 77ee33f8ee94..1f830766f912 100644 --- a/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc +++ b/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc @@ -18,6 +18,7 @@ // { dg-do run { target c++20 } } #include <iterator> +#include <ranges> #include <testsuite_hooks.h> void @@ -193,6 +194,28 @@ test_pr103992() static_assert( test_pr103992() ); +template<typename Iter> +concept has_iter_cat = requires { typename std::iterator_traits<Iter>::iterator_category; }; + +constexpr bool +test_lwg3749() +{ + // LWG 3749 - common_iterator should handle integer-class difference types +#if __SIZEOF_INT128__ + auto v = std::views::iota(__int128(0)); +#else + auto v = std::views::iota(0ll); +#endif + + using Iter = decltype(v.begin()); + static_assert( ! std::integral<std::iter_difference_t<Iter>> ); + static_assert( ! has_iter_cat<std::common_iterator<Iter, std::unreachable_sentinel_t>> ); + + return true; +} + +static_assert( test_lwg3749() ); + int main() {
