[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