From 4d1b19695669e6c67b9c3df07673bc22cae3a662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kami=C5=84ski?= Date: Mon, 24 Mar 2025 18:04:28 +0100 Subject: [PATCH] libstdc++: Fix handling of common cpp20-only ranges for flat sets [PR119415] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 , Jonathan Wakely Signed-off-by: Tomasz KamiƄski --- libstdc++-v3/include/std/flat_set | 3 ++- .../23_containers/flat_multiset/1.cc | 27 +++++++++++++++++++ .../testsuite/23_containers/flat_set/1.cc | 27 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set index 9240f2b9a2e..bab56742ddd 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>) __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 910f5dca5be..cc31164315a 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 +struct NoInsertRange : std::vector +{ + using std::vector::vector; + + template + void insert_range(typename std::vector::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 s; + s.insert_range(r); + VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) ); + + std::flat_multiset, NoInsertRange> 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 f0eaac936bf..16881d788fc 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 +struct NoInsertRange : std::vector +{ + using std::vector::vector; + + template + void insert_range(typename std::vector::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 s; + s.insert_range(r); + VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) ); + + std::flat_set, NoInsertRange> 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(); }