https://gcc.gnu.org/g:64f5c854597759fd11648b7d9e3884b8c69f218f

commit r15-8293-g64f5c854597759fd11648b7d9e3884b8c69f218f
Author: Tomasz Kamiński <tkami...@redhat.com>
Date:   Tue Mar 18 16:10:48 2025 +0100

    libstdc++-v3: Implement allocator-aware from_range_t constructors for 
unordered containers.
    
    This patch implements part of LWG2713 covering the from_range
    constructors, which makes std::ranges::to<std::unordered_set>(alloc)
    well-formed. Likewise for rest of unordered containers.
    
    As this consturctors were added to v15, this has no impact
    on code that compiled with previous versions.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/unordered_map.h
            (unordered_map(from_range_t, _Rg&&, const allocator_type&))
            (unordered_multimap(from_range_t, _Rg&&, const allocator_type&)):
            Define.
            * include/bits/unordered_set.h
            (unordered_set(from_range_t, _Rg&&, const allocator_type&))
            (unordered_multiset(from_range_t, _Rg&&, const allocator_type&)):
            Define.
            * testsuite/23_containers/unordered_map/cons/from_range.cc: New 
tests.
            New tests.
            * testsuite/23_containers/unordered_multimap/cons/from_range.cc:
            New tests.
            * testsuite/23_containers/unordered_multiset/cons/from_range.cc:
            New tests.
            * testsuite/23_containers/unordered_set/cons/from_range.cc: New 
tests.
            * testsuite/std/ranges/conv/1.cc: New tests.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/unordered_map.h          | 14 +++++++++++++
 libstdc++-v3/include/bits/unordered_set.h          | 15 ++++++++++++++
 .../23_containers/unordered_map/cons/from_range.cc | 24 ++++++++++------------
 .../unordered_multimap/cons/from_range.cc          | 24 ++++++++++------------
 .../unordered_multiset/cons/from_range.cc          | 22 +++++++++-----------
 .../23_containers/unordered_set/cons/from_range.cc | 22 +++++++++-----------
 libstdc++-v3/testsuite/std/ranges/conv/1.cc        | 22 ++++++++++++++++++++
 7 files changed, 93 insertions(+), 50 deletions(-)

diff --git a/libstdc++-v3/include/bits/unordered_map.h 
b/libstdc++-v3/include/bits/unordered_map.h
index 4a0527c6025e..49e97e2dfca9 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -300,6 +300,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          : _M_h(__n, __hf, __eql, __a)
          { insert_range(std::forward<_Rg>(__rg)); }
 
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 2713. More missing allocator-extended constructors for unordered 
containers
+       template<__detail::__container_compatible_range<value_type> _Rg>
+        unordered_map(from_range_t, _Rg&& __rg, const allocator_type& __a)
+         : _M_h(0, hasher(), key_equal(), __a)
+         { insert_range(std::forward<_Rg>(__rg)); }
+
        template<__detail::__container_compatible_range<value_type> _Rg>
         unordered_map(from_range_t, _Rg&& __rg, size_type __n,
                       const allocator_type& __a)
@@ -1546,6 +1553,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          : _M_h(__n, __hf, __eql, __a)
          { insert_range(std::forward<_Rg>(__rg)); }
 
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 2713. More missing allocator-extended constructors for unordered 
containers
+       template<__detail::__container_compatible_range<value_type> _Rg>
+        unordered_multimap(from_range_t, _Rg&& __rg, const allocator_type& __a)
+         : _M_h(0, hasher(), key_equal(), __a)
+         { insert_range(std::forward<_Rg>(__rg)); }
+
        template<__detail::__container_compatible_range<value_type> _Rg>
         unordered_multimap(from_range_t, _Rg&& __rg, size_type __n,
                            const allocator_type& __a)
diff --git a/libstdc++-v3/include/bits/unordered_set.h 
b/libstdc++-v3/include/bits/unordered_set.h
index cfa8ee297f4e..4bc256c17c1e 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -294,6 +294,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          : _M_h(__n, __hf, __eql, __a)
          { insert_range(std::forward<_Rg>(__rg)); }
 
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 2713. More missing allocator-extended constructors for unordered 
container
+       template<__detail::__container_compatible_range<_Value> _Rg>
+        unordered_set(from_range_t, _Rg&& __rg, const allocator_type& __a)
+         : _M_h(0, hasher(), key_equal(), __a)
+         { insert_range(std::forward<_Rg>(__rg)); }
+
        template<__detail::__container_compatible_range<_Value> _Rg>
         unordered_set(from_range_t, _Rg&& __rg, size_type __n,
                       const allocator_type& __a)
@@ -1265,6 +1272,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          : _M_h(__n, __hf, __eql, __a)
          { insert_range(std::forward<_Rg>(__rg)); }
 
+
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 2713. More missing allocator-extended constructors for unordered 
container
+       template<__detail::__container_compatible_range<_Value> _Rg>
+        unordered_multiset(from_range_t, _Rg&& __rg, const allocator_type& __a)
+         : _M_h(0, hasher(), key_equal(), __a)
+         { insert_range(std::forward<_Rg>(__rg)); }
+
        template<__detail::__container_compatible_range<_Value> _Rg>
         unordered_multiset(from_range_t, _Rg&& __rg, size_type __n,
                            const allocator_type& __a)
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
index b3cbb2e60625..51f8538669ae 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/cons/from_range.cc
@@ -49,12 +49,11 @@ test_deduction_guide()
 
   using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
   Alloc alloc;
-  // LWG2713: there is no matching constructor
-  // std::unordered_map m5(std::from_range, r, alloc);
-  // static_assert(std::is_same_v<
-  //   decltype(m5),
-  //   std::unordered_map<long, float,
-  //                      std::hash<long>, std::equal_to<long>, Alloc>>);
+  std::unordered_map m5(std::from_range, r, alloc);
+  static_assert(std::is_same_v<
+    decltype(m5),
+    std::unordered_map<long, float,
+                      std::hash<long>, std::equal_to<long>, Alloc>>);
 
   std::unordered_map m6(std::from_range, r, 0, alloc);
   static_assert(std::is_same_v<
@@ -154,13 +153,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
   VERIFY( is_equal(m9.hash_function(), hf) );
   VERIFY( is_equal(m9.key_eq(), eqf) );
 
-  // LWG2713: there is no matching constructor
-  // std::unordered_map<K, V, Hash, Equal, Alloc>
-  //   ma1(std::from_range, Range(a, a+14), alloc);
-  // VERIFY( eq(ma1, {a, 9}) );
-  // VERIFY( is_equal(ma1.hash_function(), Hash()) );
-  // VERIFY( is_equal(ma1.key_eq(), Equal()) );
-  // VERIFY( ma1.get_allocator() == alloc );
+  std::unordered_map<K, V, Hash, Equal, Alloc>
+    ma1(std::from_range, Range(a, a+14), alloc);
+  VERIFY( eq(ma1, {a, 9}) );
+  VERIFY( is_equal(ma1.hash_function(), Hash()) );
+  VERIFY( is_equal(ma1.key_eq(), Equal()) );
+  VERIFY( ma1.get_allocator() == alloc );
 
   std::unordered_map<K, V, Hash, Equal, Alloc>
     ma2(std::from_range, Range(a, a+14), 2, alloc);
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
index 381302bf7fd4..1baf7305c84e 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/cons/from_range.cc
@@ -54,12 +54,11 @@ test_deduction_guide()
 
   using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
   Alloc alloc;
-  // LWG2713: there is no matching constructor
-  // std::unordered_multimap m5(std::from_range, r, alloc);
-  // static_assert(std::is_same_v<
-  //   decltype(m5),
-  //   std::unordered_multimap<long, float,
-  //                           std::hash<long>, std::equal_to<long>, Alloc>>);
+  std::unordered_multimap m5(std::from_range, r, alloc);
+  static_assert(std::is_same_v<
+    decltype(m5),
+    std::unordered_multimap<long, float,
+                           std::hash<long>, std::equal_to<long>, Alloc>>);
 
   std::unordered_multimap m6(std::from_range, r, 0, alloc);
   static_assert(std::is_same_v<
@@ -160,13 +159,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
   VERIFY( is_equal(m9.hash_function(), hf) );
   VERIFY( is_equal(m9.key_eq(), eqf) );
 
-  // LWG2713: there is no matching constructor
-  // std::unordered_multimap<K, V, Hash, Equal, Alloc>
-  //   ma1(std::from_range, Range(a, a+14), alloc);
-  // VERIFY( eq(ma1, {a, 14}) );
-  // VERIFY( is_equal(ma1.hash_function(), Hash()) );
-  // VERIFY( is_equal(ma1.key_eq(), Equal()) );
-  // VERIFY( ma1.get_allocator() == alloc );
+  std::unordered_multimap<K, V, Hash, Equal, Alloc>
+    ma1(std::from_range, Range(a, a+14), alloc);
+  VERIFY( eq(ma1, {a, 14}) );
+  VERIFY( is_equal(ma1.hash_function(), Hash()) );
+  VERIFY( is_equal(ma1.key_eq(), Equal()) );
+  VERIFY( ma1.get_allocator() == alloc );
 
   std::unordered_multimap<K, V, Hash, Equal, Alloc>
     ma2(std::from_range, Range(a, a+14), 2, alloc);
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
index cb522b012aae..45c3848f5ce3 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/cons/from_range.cc
@@ -50,11 +50,10 @@ test_deduction_guide(long* p)
 
   using Alloc = __gnu_test::SimpleAllocator<long>;
   Alloc alloc;
-  // LWG2713: there is no matching constructor
-  // std::unordered_multiset s5(std::from_range, r, alloc);
-  // static_assert(std::is_same_v<
-  //   decltype(s5),
-  //   std::unordered_multiset<long, std::hash<long>, std::equal_to<long>, 
Alloc>>);
+  std::unordered_multiset s5(std::from_range, r, alloc);
+  static_assert(std::is_same_v<
+    decltype(s5),
+    std::unordered_multiset<long, std::hash<long>, std::equal_to<long>, 
Alloc>>);
 
   std::unordered_multiset s6(std::from_range, r, 0, alloc);
   static_assert(std::is_same_v<
@@ -137,13 +136,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
   VERIFY( is_equal(s9.hash_function(), hf) );
   VERIFY( is_equal(s9.key_eq(), eqf) );
 
-  // LWG2713: there is no matching constructor
-  // std::unordered_multiset<V, Hash, Equal, Alloc>
-  //   sa(std::from_range, Range(a, a+14), alloc);
-  // VERIFY( eq(sa1, {a, 14}) );
-  // VERIFY( is_equal(sa1.hash_function(), Hash()) );
-  // VERIFY( is_equal(sa1.key_eq(), Equal()) );
-  // VERIFY( sa1.get_allocator() == alloc );
+  std::unordered_multiset<V, Hash, Equal, Alloc>
+    sa1(std::from_range, Range(a, a+14), alloc);
+  VERIFY( eq(sa1, {a, 14}) );
+  VERIFY( is_equal(sa1.hash_function(), Hash()) );
+  VERIFY( is_equal(sa1.key_eq(), Equal()) );
+  VERIFY( sa1.get_allocator() == alloc );
 
   std::unordered_multiset<V, Hash, Equal, Alloc>
     sa2(std::from_range, Range(a, a+14), 2, alloc);
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
index c1acf1436610..0806045539f2 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/cons/from_range.cc
@@ -49,11 +49,10 @@ test_deduction_guide(long* p)
 
   using Alloc = __gnu_test::SimpleAllocator<long>;
   Alloc alloc;
-  // LWG2713: there is no matching constructor
-  // std::unordered_set s5(std::from_range, r, alloc);
-  // static_assert(std::is_same_v<
-  //   decltype(s5),
-  //   std::unordered_set<long, std::hash<long>, std::equal_to<long>, Alloc>>);
+  std::unordered_set s5(std::from_range, r, alloc);
+  static_assert(std::is_same_v<
+    decltype(s5),
+    std::unordered_set<long, std::hash<long>, std::equal_to<long>, Alloc>>);
 
   std::unordered_set s6(std::from_range, r, 0, alloc);
   static_assert(std::is_same_v<
@@ -136,13 +135,12 @@ do_test(Alloc alloc, Hash hf, Equal eqf)
   VERIFY( is_equal(s9.hash_function(), hf) );
   VERIFY( is_equal(s9.key_eq(), eqf) );
 
-  // LWG2713: there is no matching constructor
-  // std::unordered_set<V, Hash, Equal, Alloc>
-  //   sa(std::from_range, Range(a, a+14), alloc);
-  // VERIFY( eq(sa1, {a, 9}) );
-  // VERIFY( is_equal(sa1.hash_function(), Hash()) );
-  // VERIFY( is_equal(sa1.key_eq(), Equal()) );
-  // VERIFY( sa1.get_allocator() == alloc );
+  std::unordered_set<V, Hash, Equal, Alloc>
+    sa1(std::from_range, Range(a, a+14), alloc);
+  VERIFY( eq(sa1, {a, 9}) );
+  VERIFY( is_equal(sa1.hash_function(), Hash()) );
+  VERIFY( is_equal(sa1.key_eq(), Equal()) );
+  VERIFY( sa1.get_allocator() == alloc );
 
   std::unordered_set<V, Hash, Equal, Alloc>
     sa2(std::from_range, Range(a, a+14), 2, alloc);
diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc 
b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
index 231cb9d9934a..2caa1b83f30f 100644
--- a/libstdc++-v3/testsuite/std/ranges/conv/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
@@ -12,6 +12,7 @@
 #include <testsuite_hooks.h>
 #include <testsuite_allocator.h>
 #include <testsuite_iterators.h>
+#include <unordered_map>
 
 void
 test_p1206r7_examples()
@@ -478,6 +479,26 @@ test_pr119282()
   return true;
 }
 
+void
+test_lwg2713()
+{
+  using Alloc = __gnu_test::uneq_allocator<std::pair<const int, const char*>>;
+  const Alloc alloc(303);
+  const std::map<int, const char*> m{{1, "one"}, {2, "two"}, {3, "three"}};
+  namespace ranges = std::ranges;
+
+  // Call constructors with bucket count
+  auto m1 = m | ranges::to<std::unordered_map>(0, alloc);
+  VERIFY( m1.get_allocator() == alloc );
+  auto m2 = m | ranges::to<std::unordered_multimap>(0, alloc);
+  VERIFY( m2.get_allocator() == alloc );
+  // These call constructors added in lwg2713
+  auto m3 = m | ranges::to<std::unordered_map>(alloc);
+  VERIFY( m3.get_allocator() == alloc );
+  auto m4 = m | ranges::to<std::unordered_multimap>(alloc);
+  VERIFY( m4.get_allocator() == alloc );
+}
+
 int main()
 {
   test_p1206r7_examples();
@@ -487,6 +508,7 @@ int main()
   test_2_1_3();
   test_2_1_4();
   test_2_2();
+  test_lwg2713();
   test_lwg3984();
   test_nodiscard();
   test_constexpr();

Reply via email to