]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Check presence of iterator_category for flat_sets insert_range [PR119415]
authorTomasz Kamiński <tkaminsk@redhat.com>
Wed, 26 Mar 2025 06:34:37 +0000 (07:34 +0100)
committerTomasz Kamiński <tkaminsk@redhat.com>
Wed, 26 Mar 2025 10:53:26 +0000 (11:53 +0100)
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<It>::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 <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/include/std/flat_set
libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
libstdc++-v3/testsuite/23_containers/flat_set/1.cc

index bab56742ddd6ebb841698a67668a6f6a7d365ba9..a7b0b8aef151020336b8161b2094495ac630b02d 100644 (file)
@@ -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<ranges::iterator_t<_Rg>>)
+                            && __has_input_iter_cat<ranges::iterator_t<_Rg>>)
            __it = _M_cont.insert(_M_cont.end(), ranges::begin(__rg), ranges::end(__rg));
          else
            {
index cc31164315ae11ee87965ad6c310fc3bcd56acf7..dc3cecd9720c943ebc7ed1220a1bd7cad8481d1c 100644 (file)
@@ -152,19 +152,64 @@ struct NoInsertRange : std::vector<T>
   void insert_range(typename std::vector<T>::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<NoCatIterator> {
+  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<int> s;
+  std::flat_multiset<int, std::less<int>, NoInsertRange<int>> s2;
+
+  auto r = std::ranges::subrange<NoCatIterator>(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<int> 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<int, std::less<int>, NoInsertRange<int>> s2;
-  s2.insert_range(r);
+  s2.clear();
+  s2.insert_range(r2);
   VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) );
 #endif
 }
index 16881d788fcd6ed15dcad1e93cca707e27527946..90f5855859f7accea49a3b37a15ae295128cede9 100644 (file)
@@ -167,19 +167,64 @@ struct NoInsertRange : std::vector<T>
   void insert_range(typename std::vector<T>::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<NoCatIterator> {
+  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<int> s;
+  std::flat_set<int, std::less<int>, NoInsertRange<int>> s2;
+
+  auto r = std::ranges::subrange<NoCatIterator>(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<int> 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<int, std::less<int>, NoInsertRange<int>> s2;
-  s2.insert_range(r);
+  s2.clear();
+  s2.insert_range(r2);
   VERIFY( std::ranges::equal(s2, (int[]){1, 2, 3, 4, 5}) );
 #endif
 }