-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[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
base: main
Are you sure you want to change the base?
Conversation
a5e9953
to
a1e1585
Compare
@llvm/pr-subscribers-libcxx Author: Peng Liu (winner245) ChangesThe general template This patch fixes the issue by defining a default empty template consisting of member types only for Full diff: https://github.com/llvm/llvm-project/pull/134304.diff 3 Files Affected:
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;
+}
|
Removing this from the performance sprint since this is technically not perf related IIUC. |
The general template
__segmented_iterator_traits<_Iterator>
is only declared but not defined. It is explicitly specialized forstd::deque<T>::iterator
andjoin_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 withinenable_if
to guide the overload resolution of variousstd::__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
.