From: Tomasz Kamiński Date: Wed, 26 Mar 2025 06:34:37 +0000 (+0100) Subject: libstdc++: Check presence of iterator_category for flat_sets insert_range [PR119415] X-Git-Tag: basepoints/gcc-16~628 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=272d26d519f5abcca71f5b1d5acc07319e480ba3;p=thirdparty%2Fgcc.git libstdc++: Check presence of iterator_category for flat_sets insert_range [PR119415] As pointed out by Hewill Kang (reporter) in the issue, checking if iterator of the incoming range satisfies __cpp17_input_iterator, may still lead to hard errors inside of insert_range for iterators that satisfies that concept, but specialize iterator_traits without iterator_category typedef (std::common_iterator specialize iterator_traits without iterator_category in some cases). To address that we instead check if the iterator_traits::iterator_category is present and denote at least input_iterator_tag, using existing __has_input_iter_cat. PR libstdc++/119415 libstdc++-v3/ChangeLog: * include/std/flat_set (_Flat_set_impl:insert_range): Replace __detail::__cpp17_input_iterator with __has_input_iter_cat. * testsuite/23_containers/flat_multiset/1.cc: New tests * testsuite/23_containers/flat_set/1.cc: New tests Reviewed-by: Jonathan Wakely Signed-off-by: Tomasz Kamiński --- diff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set index bab56742ddd..a7b0b8aef15 100644 --- a/libstdc++-v3/include/std/flat_set +++ b/libstdc++-v3/include/std/flat_set @@ -481,7 +481,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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> - && __detail::__cpp17_input_iterator>) + && __has_input_iter_cat>) __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 cc31164315a..dc3cecd9720 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc @@ -152,19 +152,64 @@ struct NoInsertRange : std::vector void insert_range(typename std::vector::const_iterator, R&&) = delete; }; +struct NoCatIterator { + using difference_type = int; + using value_type = int; + + NoCatIterator() : v(0) {} + NoCatIterator(int x) : v(x) {} + + int operator*() const + { return v; } + + NoCatIterator& operator++() + { + ++v; + return *this; + } + + NoCatIterator operator++(int) + { + ++v; + return NoCatIterator(v-1); + } + + bool operator==(const NoCatIterator& rhs) const + { return v == rhs.v; } + +private: + int v; +}; + +template<> +struct std::iterator_traits { + using difference_type = int; + using value_type = int; + using iterator_concept = std::input_iterator_tag; + // no iterator_category, happens also for common_iterator +}; + void test07() { + std::flat_multiset s; + std::flat_multiset, NoInsertRange> s2; + + auto r = std::ranges::subrange(1, 6); + s.insert_range(r); + VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) ); + s2.insert_range(r); + VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) ); + #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); + auto r2 = std::views::iota(__int128(1), __int128(6)); + s.clear(); + s.insert_range(r2); VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) ); - std::flat_multiset, NoInsertRange> s2; - s2.insert_range(r); + s2.clear(); + s2.insert_range(r2); VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) ); #endif } diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc index 16881d788fc..90f5855859f 100644 --- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc +++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc @@ -167,19 +167,64 @@ struct NoInsertRange : std::vector void insert_range(typename std::vector::const_iterator, R&&) = delete; }; +struct NoCatIterator { + using difference_type = int; + using value_type = int; + + NoCatIterator() : v(0) {} + NoCatIterator(int x) : v(x) {} + + int operator*() const + { return v; } + + NoCatIterator& operator++() + { + ++v; + return *this; + } + + NoCatIterator operator++(int) + { + ++v; + return NoCatIterator(v-1); + } + + bool operator==(const NoCatIterator& rhs) const + { return v == rhs.v; } + +private: + int v; +}; + +template<> +struct std::iterator_traits { + using difference_type = int; + using value_type = int; + using iterator_concept = std::input_iterator_tag; + // no iterator_category, happens also for common_iterator +}; + void test07() { + std::flat_set s; + std::flat_set, NoInsertRange> s2; + + auto r = std::ranges::subrange(1, 6); + s.insert_range(r); + VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) ); + s2.insert_range(r); + VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) ); + #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); + auto r2 = std::views::iota(__int128(1), __int128(6)); + s.clear(); + s.insert_range(r2); VERIFY( std::ranges::equal(s, (int[]){1, 2, 3, 4, 5}) ); - std::flat_set, NoInsertRange> s2; - s2.insert_range(r); + s2.clear(); + s2.insert_range(r2); VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) ); #endif }