Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[libc++] Fix __segmented_iterator_traits for implicit template instantiation in SFINAE #134304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

winner245
Copy link
Contributor

@winner245 winner245 commented Apr 3, 2025

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. This issue first came up in #135468, where __segmented_iterator_traits is used within enable_if to guide the overload resolution of various std::__for_each_n.

This patch fixes the issue by defining a default empty template consisting of member types only for __is_segmented_iterator = false_type. This ensures safe instantiation for arbitrary non-segmented iterator types. The existing specializations, such as __segmented_iterator_traits<__deque_iterator<...>> and __segmented_iterator_traits<_JoinViewIterator>, provide concrete definitions for segmented iterators where __is_segmented_iterator = true_type.

@winner245 winner245 force-pushed the fix-segmented-iterator-traits branch from a5e9953 to a1e1585 Compare April 4, 2025 01:16
@winner245 winner245 marked this pull request as ready for review April 5, 2025 13:25
@winner245 winner245 requested a review from a team as a code owner April 5, 2025 13:25
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 5, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 5, 2025

@llvm/pr-subscribers-libcxx

Author: Peng Liu (winner245)

Changes

The general template __segmented_iterator_traits&lt;_Iterator&gt; is only declared but not defined. It is explicitly specialized for std::deque&lt;T&gt;::iterator and join_view iterators. This is problematic when __segmented_iterator_traits&lt;_Iterator&gt; 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. This issue first came up in #132896, where __segmented_iterator_traits is used within enable_if to guide the overload resolution of various std::__for_each_n.

This patch fixes the issue by defining a default empty template consisting of member types only for __is_segmented_iterator = false_type. This ensures safe instantiation for arbitrary non-segmented iterator types. The existing specializations, such as __segmented_iterator_traits&lt;__deque_iterator&lt;...&gt;&gt; and __segmented_iterator_traits&lt;_JoinViewIterator&gt;, provide concrete definitions for segmented iterators where __is_segmented_iterator = true_type.


Full diff: https://github.com/llvm/llvm-project/pull/134304.diff

3 Files Affected:

  • (modified) libcxx/include/__iterator/segmented_iterator.h (+7-13)
  • (modified) libcxx/include/__ranges/join_view.h (+2)
  • (added) libcxx/test/libcxx/iterators/segmented_iterator.pass.cpp (+52)
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..d2e2f35fe6f45
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/segmented_iterator.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <__type_traits/integral_constant.h>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class Iter>
+struct is_segmented_random_access_iterator
+    : std::_BoolConstant<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;
+}

@winner245 winner245 self-assigned this Apr 19, 2025
@ldionne
Copy link
Member

ldionne commented May 5, 2025

Removing this from the performance sprint since this is technically not perf related IIUC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants