https://gcc.gnu.org/g:4d1b19695669e6c67b9c3df07673bc22cae3a662

commit r15-8879-g4d1b19695669e6c67b9c3df07673bc22cae3a662
Author: Tomasz Kamiński <tkami...@redhat.com>
Date:   Mon Mar 24 18:04:28 2025 +0100

    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 <ppa...@redhat.com>, Jonathan Wakely 
<jwak...@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/std/flat_set                  |  3 ++-
 .../testsuite/23_containers/flat_multiset/1.cc     | 27 ++++++++++++++++++++++
 libstdc++-v3/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 9240f2b9a2eb..bab56742ddd6 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 910f5dca5be4..cc31164315ae 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 f0eaac936bf6..16881d788fcd 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();
 }

Reply via email to