[libcxx-commits] [libcxx] [libc++] Fix __segmented_iterator_traits for implicit template instantiation in SFINAE (PR #134304)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Thu Apr 3 13:32:34 PDT 2025


https://github.com/winner245 created https://github.com/llvm/llvm-project/pull/134304

The general template `__segmented_iterator_traits<_Iterator>` is only declared but not defined. It is explicitly specialized for `std::deque<T>::iterator` and `join_view` iterators. This is problematic when `__segmented_iterator_traits<_Iterator>` is used as a SFINAE constraint, as it may cause implicit instantiation for an arbitrary `_Iterator` type during substitution, leading to a hard error for SFINAE. Here is a [reproducer](https://godbolt.org/z/xP35GWqhj). This issue first came up in #132896, where `__segmented_iterator_traits` is used with `enable_if` to guide the overload resolution for `std::__for_each_n`. 

This patch fixes the issue by defining a default general template where `__is_segmented_iterator` is `false_type`. This ensures safe instantiation for non-segmented iterator types. The existing specializations, such as `__segmented_iterator_traits<__deque_iterator<...>>` and `__segmented_iterator_traits<_JoinViewIterator>`, provide definitions for segmented iterators. 

>From a5e9953bebd002c7f7a7c3a94f18e7100b853739 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Thu, 3 Apr 2025 16:04:02 -0400
Subject: [PATCH] Fix __segmented_iterator_traits for implicit template
 instantiation

---
 .../include/__iterator/segmented_iterator.h   | 20 +++-----
 libcxx/include/__ranges/join_view.h           |  2 +
 .../iterators/segmented_iterator.pass.cpp     | 51 +++++++++++++++++++
 3 files changed, 60 insertions(+), 13 deletions(-)
 create mode 100644 libcxx/test/libcxx/iterators/segmented_iterator.pass.cpp

diff --git a/libcxx/include/__iterator/segmented_iterator.h b/libcxx/include/__iterator/segmented_iterator.h
index 7a8e1addeacd9..2533502d8883d 100644
--- a/libcxx/include/__iterator/segmented_iterator.h
+++ b/libcxx/include/__iterator/segmented_iterator.h
@@ -51,28 +51,22 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Iterator>
-struct __segmented_iterator_traits;
-/* exposition-only:
-{
-  using __segment_iterator = ...;
-  using __local_iterator   = ...;
+struct __segmented_iterator_traits {
+  using __is_segmented_iterator _LIBCPP_NODEBUG = false_type;
+  using __segment_iterator _LIBCPP_NODEBUG      = void;
+  using __local_iterator _LIBCPP_NODEBUG        = void;
 
+  /* exposition-only:
   static __segment_iterator __segment(_Iterator);
   static __local_iterator __local(_Iterator);
   static __local_iterator __begin(__segment_iterator);
   static __local_iterator __end(__segment_iterator);
   static _Iterator __compose(__segment_iterator, __local_iterator);
+  */
 };
-*/
-
-template <class _Tp, size_t = 0>
-struct __has_specialization : false_type {};
-
-template <class _Tp>
-struct __has_specialization<_Tp, sizeof(_Tp) * 0> : true_type {};
 
 template <class _Iterator>
-using __is_segmented_iterator _LIBCPP_NODEBUG = __has_specialization<__segmented_iterator_traits<_Iterator> >;
+struct __is_segmented_iterator : __segmented_iterator_traits<_Iterator>::__is_segmented_iterator {};
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index 327b349f476a7..266d6c11394ee 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -31,6 +31,7 @@
 #include <__ranges/range_adaptor.h>
 #include <__ranges/view_interface.h>
 #include <__type_traits/common_type.h>
+#include <__type_traits/integral_constant.h>
 #include <__type_traits/maybe_const.h>
 #include <__utility/as_lvalue.h>
 #include <__utility/empty.h>
@@ -378,6 +379,7 @@ template <class _JoinViewIterator>
            __has_random_access_iterator_category<typename _JoinViewIterator::_Outer>::value &&
            __has_random_access_iterator_category<typename _JoinViewIterator::_Inner>::value)
 struct __segmented_iterator_traits<_JoinViewIterator> {
+  using __is_segmented_iterator _LIBCPP_NODEBUG = true_type;
   using __segment_iterator _LIBCPP_NODEBUG =
       __iterator_with_data<typename _JoinViewIterator::_Outer, typename _JoinViewIterator::_Parent*>;
   using __local_iterator _LIBCPP_NODEBUG = typename _JoinViewIterator::_Inner;
diff --git a/libcxx/test/libcxx/iterators/segmented_iterator.pass.cpp b/libcxx/test/libcxx/iterators/segmented_iterator.pass.cpp
new file mode 100644
index 0000000000000..d6e82fbaa8171
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/segmented_iterator.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+
+// <iterator>
+
+// __segmented_iterator_traits<_Iter>
+
+// verifies that __segmented_iterator_traits<_Iter> does not result in implicit
+// template instantaition, which may cause hard errors in SFINAE.
+
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
+#include <array>
+#include <deque>
+#include <list>
+#include <ranges>
+#include <vector>
+#include <__iterator/segmented_iterator.h>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class Iter>
+struct is_segmented_random_access_iterator
+    : std::bool_constant<std::__is_segmented_iterator<Iter>::value &&
+                         std::__has_random_access_iterator_category<
+                             typename std::__segmented_iterator_traits<Iter>::__local_iterator>::value> {};
+
+int main(int, char**) {
+  static_assert(is_segmented_random_access_iterator<std::deque<int>::iterator>::value, "");
+  static_assert(!is_segmented_random_access_iterator<std::vector<int>::iterator>::value, "");
+  static_assert(!is_segmented_random_access_iterator<std::list<int>::iterator>::value, "");
+  static_assert(!is_segmented_random_access_iterator<std::array<int, 0>::iterator>::value, "");
+  static_assert(!is_segmented_random_access_iterator<cpp17_input_iterator<int*>>::value, "");
+  static_assert(!is_segmented_random_access_iterator<forward_iterator<int*>>::value, "");
+  static_assert(!is_segmented_random_access_iterator<random_access_iterator<int*>>::value, "");
+  static_assert(!is_segmented_random_access_iterator<int*>::value, "");
+
+#if TEST_STD_VER >= 20
+  using join_view_iterator = decltype((std::declval<std::vector<std::vector<int > >&>() | std::views::join).begin());
+  static_assert(is_segmented_random_access_iterator<join_view_iterator>::value, "");
+#endif
+
+  return 0;
+}



More information about the libcxx-commits mailing list