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
---
Tested on x86_64-linux. OK for trunk?
 libstdc++-v3/include/std/flat_set             |  2 +-
 .../23_containers/flat_multiset/1.cc          | 57 +++++++++++++++++--
 .../testsuite/23_containers/flat_set/1.cc     | 57 +++++++++++++++++--
 3 files changed, 103 insertions(+), 13 deletions(-)

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<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
            {
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<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
 }
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<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
 }
-- 
2.48.1

Reply via email to