aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Kamiński <tkaminsk@redhat.com>2025-03-24 18:04:28 +0100
committerTomasz Kamiński <tkaminsk@redhat.com>2025-03-25 10:24:58 +0100
commit4d1b19695669e6c67b9c3df07673bc22cae3a662 (patch)
treef9c578ba3740a04a83c6751d3f4300c32731e517
parent698e337bec3a36230c72816fcb82f1a239e64eba (diff)
downloadgcc-4d1b19695669e6c67b9c3df07673bc22cae3a662.zip
gcc-4d1b19695669e6c67b9c3df07673bc22cae3a662.tar.gz
gcc-4d1b19695669e6c67b9c3df07673bc22cae3a662.tar.bz2
libstdc++: Fix handling of common cpp20-only ranges for flat sets [PR119415]
These patch add check to verify if common range iterators satisfies Cpp17LegacyIterator requirements (__detail::__cpp17_input_iterator), before invoking overloads of insert that accepts two iterators. As such overloads existed before c++20 iterators were introduced, they commonly assume existence of iterator_traits<..>::iterator_category, and passing a cpp20-only iterators, leads to hard errors. In case if user-defined container wants to support more efficient insertion in such cases, it should provided insert_range method, as in the case of standard containers. PR libstdc++/119415 libstdc++-v3/ChangeLog: * include/std/flat_set (_Flat_set_impl:insert_range): Add __detail::__cpp17_input_iterator check. * testsuite/23_containers/flat_multiset/1.cc: New tests * testsuite/23_containers/flat_set/1.cc: New tests Reviewed-by: Patrick Palka <ppalka@redhat.com>, Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
-rw-r--r--libstdc++-v3/include/std/flat_set3
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc27
-rw-r--r--libstdc++-v3/testsuite/23_containers/flat_set/1.cc27
3 files changed, 56 insertions, 1 deletions
diff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set
index 9240f2b..bab5674 100644
--- a/libstdc++-v3/include/std/flat_set
+++ b/libstdc++-v3/include/std/flat_set
@@ -480,7 +480,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename container_type::iterator __it;
if constexpr (requires { _M_cont.insert_range(_M_cont.end(), __rg); })
__it = _M_cont.insert_range(_M_cont.end(), __rg);
- else if constexpr (ranges::common_range<_Rg>)
+ else if constexpr (ranges::common_range<_Rg>
+ && __detail::__cpp17_input_iterator<ranges::iterator_t<_Rg>>)
__it = _M_cont.insert(_M_cont.end(), ranges::begin(__rg), ranges::end(__rg));
else
{
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
index 910f5dc..cc31164 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
@@ -143,6 +143,32 @@ test06()
VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) );
}
+template<typename T>
+struct NoInsertRange : std::vector<T>
+{
+ using std::vector<T>::vector;
+
+ template<typename It, typename R>
+ void insert_range(typename std::vector<T>::const_iterator, R&&) = delete;
+};
+
+void test07()
+{
+#ifdef __SIZEOF_INT128__
+ // PR libstdc++/119415 - flat_foo::insert_range cannot handle common ranges
+ // on c++20 only iterators
+ auto r = std::views::iota(__int128(1), __int128(6));
+
+ std::flat_multiset<int> s;
+ s.insert_range(r);
+ VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) );
+
+ std::flat_multiset<int, std::less<int>, NoInsertRange<int>> s2;
+ s2.insert_range(r);
+ VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) );
+#endif
+}
+
int
main()
{
@@ -153,4 +179,5 @@ main()
test04();
test05();
test06();
+ test07();
}
diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
index f0eaac9..16881d7 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
@@ -158,6 +158,32 @@ test06()
VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) );
}
+template<typename T>
+struct NoInsertRange : std::vector<T>
+{
+ using std::vector<T>::vector;
+
+ template<typename It, typename R>
+ void insert_range(typename std::vector<T>::const_iterator, R&&) = delete;
+};
+
+void test07()
+{
+#ifdef __SIZEOF_INT128__
+ // PR libstdc++/119415 - flat_foo::insert_range cannot handle common ranges
+ // on c++20 only iterators
+ auto r = std::views::iota(__int128(1), __int128(6));
+
+ std::flat_set<int> s;
+ s.insert_range(r);
+ VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) );
+
+ std::flat_set<int, std::less<int>, NoInsertRange<int>> s2;
+ s2.insert_range(r);
+ VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) );
+#endif
+}
+
int
main()
{
@@ -168,4 +194,5 @@ main()
test04();
test05();
test06();
+ test07();
}