[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