[PATCH] libstdc++: Implement LWG 3749 changes to common_iterator
Patrick Palka
ppalka@redhat.com
Fri Aug 21 13:20:47 GMT 2026
Tested on x86_64-pc-linux-gnu, does this look OK for trunk and later
backports?
-- >8 --
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.
---
libstdc++-v3/include/bits/stl_iterator.h | 37 +++++++++++++------
.../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()
{
--
2.55.0.618.g1a3e64c6c4
More information about the Libstdc++
mailing list