https://gcc.gnu.org/g:d50171bc07006dfb56cae487d72913e5d2567716

commit r15-8296-gd50171bc07006dfb56cae487d72913e5d2567716
Author: Tomasz Kamiński <tkami...@redhat.com>
Date:   Wed Mar 19 11:42:50 2025 +0100

    libstdc++: Support maps deduction from_range of tuples.
    
    This implements part of LWG4223 that enables deduction for maps types
    (map, unordered_map, flat_map and non-unique equivalent) from
    (from_range, rg, ...) arguments, where rg is range of tuple
    or other pair-like.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/ranges_base.h (__detail::__range_key_type):
            Replace RV::first_type with tuple_element_t<0, RV>.
            (__detail::__range_mapped_type) Replace RV::second_type
            with tuple_element_t<1, RV>.
            * testsuite/23_containers/flat_map/1.cc: New tests.
            * testsuite/23_containers/flat_multimap/1.cc: New tests.
            * testsuite/23_containers/map/cons/from_range.cc: New tests.
            * testsuite/23_containers/multimap/cons/from_range.cc: New tests.
            * testsuite/23_containers/unordered_map/cons/from_range.cc: New 
tests.
            * testsuite/23_containers/unordered_multimap/cons/from_range.cc:
            New tests.
    
    Reviewed-by: Jonathan Wakely <jwak...@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkami...@redhat.com>

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h            | 10 +++-
 libstdc++-v3/testsuite/23_containers/flat_map/1.cc | 61 ++++++++++++++++++++
 .../testsuite/23_containers/flat_multimap/1.cc     | 65 ++++++++++++++++++++++
 .../testsuite/23_containers/map/cons/from_range.cc |  8 ++-
 .../23_containers/multimap/cons/from_range.cc      |  8 ++-
 .../23_containers/unordered_map/cons/from_range.cc |  8 ++-
 .../unordered_multimap/cons/from_range.cc          | 12 +++-
 7 files changed, 158 insertions(+), 14 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index c9687c256e99..13bfbb3795bf 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -41,6 +41,10 @@
 #include <bits/max_size_type.h>
 #include <bits/version.h>
 
+#if __glibcxx_ranges_to_container // C++ >= 23
+# include <bits/utility.h> // for tuple_element_t
+#endif
+
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic" // __int128
 
@@ -1093,13 +1097,15 @@ namespace __detail
       = ranges::input_range<_Rg>
          && convertible_to<ranges::range_reference_t<_Rg>, _Tp>;
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4223. Deduction guides for maps are mishandling tuples and references
   template<ranges::input_range _Range>
     using __range_key_type
-      = remove_const_t<typename ranges::range_value_t<_Range>::first_type>;
+      = remove_const_t<tuple_element_t<0, ranges::range_value_t<_Range>>>;
 
   template<ranges::input_range _Range>
     using __range_mapped_type
-      = typename ranges::range_value_t<_Range>::second_type;
+      = tuple_element_t<1, ranges::range_value_t<_Range>>;
 
   // The allocator's value_type for map-like containers.
   template<ranges::input_range _Range>
diff --git a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
index 00254dc2ee62..d9d88c4df6ec 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_map/1.cc
@@ -11,6 +11,67 @@
 #include <vector>
 #include <testsuite_allocator.h>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <tuple>
+
+struct Gt {
+  template<typename T, typename U>
+  bool operator()(T const& l, U const & r) const
+  { return l > r; }
+};
+
+void
+test_deduction_guide()
+{
+  __gnu_test::test_input_range<std::pair<long, float>> r(0, 0);
+  std::flat_map it1(r.begin(), r.begin());
+  static_assert(std::is_same_v<decltype(it1), std::flat_map<long, float>>);
+  std::flat_map fr1(std::from_range, r);
+  static_assert(std::is_same_v<decltype(fr1), std::flat_map<long, float>>);
+
+  Gt cmp;
+  std::flat_map it2(r.begin(), r.begin(), cmp);
+  static_assert(std::is_same_v<decltype(it2), std::flat_map<long, float, Gt>>);
+  std::flat_map fr2(std::from_range, r, cmp);
+  static_assert(std::is_same_v<decltype(fr2), std::flat_map<long, float, Gt>>);
+
+  using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
+  Alloc alloc;
+  // No matching deduction guide
+  // std::flat_map it3(r.begin(), r.begin(), alloc);
+  std::flat_map fr3(std::from_range, r, alloc);
+  static_assert(std::is_same_v<
+     decltype(fr3),
+     std::flat_map<long, float, std::less<long>,
+                  std::vector<long, __gnu_test::SimpleAllocator<long>>,
+                  std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
+
+  // No matching deduction guide
+  // std::flat_map it4(r.begin(), r.begin(), cmp, alloc);
+  std::flat_map fr4(std::from_range, r, cmp, alloc);
+  static_assert(std::is_same_v<
+     decltype(fr4),
+     std::flat_map<long, float, Gt,
+                  std::vector<long, __gnu_test::SimpleAllocator<long>>,
+                  std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
+
+  // LWG4223: deduces flat_map<long, float const>, which in turn instantiates
+  // std::vector<cosnt float> that is ill-formed.
+  // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
+  // std::flat_map it5(r2.begin(), r2.begin());
+  // std::flat_map fr5(std::from_range, r2);
+
+  // LWG4223: deduces flat_map<const long&, float&>
+  //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+  // std::flat_map it6(r3.begin(), r3.begin());
+  // std::flat_map fr6(std::from_range, r3);
+
+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
+  std::flat_map it7(r4.begin(), r4.begin());
+  static_assert(std::is_same_v<decltype(it7), std::flat_map<long, float>>);
+  std::flat_map fr7(std::from_range, r4);
+  static_assert(std::is_same_v<decltype(fr7), std::flat_map<long, float>>);
+}
 
 template<template<typename> class KeyContainer, template<typename> class 
MappedContainer>
 void
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
index 38650a81bcff..ff180bf1bdf5 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multimap/1.cc
@@ -5,6 +5,71 @@
 #include <vector>
 #include <testsuite_allocator.h>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <tuple>
+
+struct Gt {
+  template<typename T, typename U>
+  bool operator()(T const& l, U const & r) const
+  { return l > r; }
+};
+
+void
+test_deduction_guide()
+{
+  __gnu_test::test_input_range<std::pair<long, float>> r(0, 0);
+  std::flat_multimap it1(r.begin(), r.begin());
+  static_assert(std::is_same_v<decltype(it1), std::flat_multimap<long, 
float>>);
+  std::flat_multimap fr1(std::from_range, r);
+  static_assert(std::is_same_v<decltype(fr1), std::flat_multimap<long, 
float>>);
+
+  Gt cmp;
+  std::flat_multimap it2(r.begin(), r.begin(), cmp);
+  static_assert(std::is_same_v<
+    decltype(it2),
+    std::flat_multimap<long, float, Gt>>);
+  std::flat_multimap fr2(std::from_range, r, cmp);
+  static_assert(std::is_same_v<
+    decltype(fr2),
+    std::flat_multimap<long, float, Gt>>);
+
+  using Alloc = __gnu_test::SimpleAllocator<std::pair<const long, float>>;
+  Alloc alloc;
+  // No matching deduction guide
+  // std::flat_multimap it3(r.begin(), r.begin(), alloc);
+  std::flat_multimap fr3(std::from_range, r, alloc);
+  static_assert(std::is_same_v<
+     decltype(fr3),
+     std::flat_multimap<long, float, std::less<long>,
+                  std::vector<long, __gnu_test::SimpleAllocator<long>>,
+                  std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
+
+  // No matching deduction guide
+  // std::flat_multimap it4(r.begin(), r.begin(), cmp, alloc);
+  std::flat_multimap fr4(std::from_range, r, cmp, alloc);
+  static_assert(std::is_same_v<
+     decltype(fr4),
+     std::flat_multimap<long, float, Gt,
+                  std::vector<long, __gnu_test::SimpleAllocator<long>>,
+                  std::vector<float, __gnu_test::SimpleAllocator<float>>>>);
+
+  // LWG4223: deduces flat_multimap<long, float const>, which in turn 
instantiates
+  // std::vector<cosnt float> that is ill-formed.
+  // __gnu_test::test_input_range<std::pair<const long, const float>> r2(0, 0);
+  // std::flat_multimap it5(r2.begin(), r2.begin());
+  // std::flat_multimap fr5(std::from_range, r2);
+
+  // LWG4223: deduces flat_multimap<const long&, float&>
+  //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
+  // std::flat_multimap it6(r3.begin(), r3.begin());
+  // std::flat_multimap fr6(std::from_range, r3);
+
+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
+  std::flat_multimap it7(r4.begin(), r4.begin());
+  static_assert(std::is_same_v<decltype(it7), std::flat_multimap<long, 
float>>);
+  std::flat_multimap fr7(std::from_range, r4);
+  static_assert(std::is_same_v<decltype(fr7), std::flat_multimap<long, 
float>>);
+}
 
 template<template<typename> class KeyContainer, template<typename> class 
MappedContainer>
 void
diff --git a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc 
b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
index 01e426fde3df..c740471f2da1 100644
--- a/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/map/cons/from_range.cc
@@ -44,9 +44,11 @@ test_deduction_guide()
   //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
   // std::map m6(std::from_range, r3);
 
-  // LWG4223: no deduction guide
-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
-  // std::map m7(std::from_range, r4);
+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
+  std::map m7(std::from_range, r4);
+  static_assert(std::is_same_v<decltype(m7), std::map<long, float>>);
+  std::map it7(r4.begin(), r4.begin());
+  static_assert(std::is_same_v<decltype(it7), std::map<long, float>>);
 }
 
 template<typename T, typename U>
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc 
b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
index e0052e499ca7..3e456f566ccc 100644
--- a/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/multimap/cons/from_range.cc
@@ -44,9 +44,11 @@ test_deduction_guide()
   //__gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
   // std::multimap m6(std::from_range, r3);
 
-  // LWG4223: no deduction guide
-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
-  // std::multimap m7(std::from_range, r4);
+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
+  std::multimap m7(std::from_range, r4);
+  static_assert(std::is_same_v<decltype(m7), std::multimap<long, float>>);
+  std::multimap it7(r4.begin(), r4.begin());
+  static_assert(std::is_same_v<decltype(it7), std::multimap<long, float>>);
 }
 
 template<typename T, typename U>
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 51f8538669ae..6d1da5bf5d18 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
@@ -81,9 +81,11 @@ test_deduction_guide()
   // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
   // std::unordered_map m10(std::from_range, r3);
 
-  // LWG4223: no deduction guide
-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
-  // std::unordered_map m11(std::from_range, r4);
+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
+  std::unordered_map m11(std::from_range, r4);
+  static_assert(std::is_same_v<decltype(m11), std::unordered_map<long, 
float>>);
+  std::unordered_map it11(r4.begin(), r4.begin());
+  static_assert(std::is_same_v<decltype(it11), std::unordered_map<long, 
float>>);
 }
 
 template<typename T, typename U>
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 1baf7305c84e..2ca93d344e9b 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
@@ -87,9 +87,15 @@ test_deduction_guide()
   // __gnu_test::test_input_range<std::pair<const long&, float&>> r3(0, 0);
   // std::unordered_multimap m10(std::from_range, r3);
 
-  // LWG4223: no deduction guide
-  // __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
-  // std::unordered_multimap m11(std::from_range, r4);
+  __gnu_test::test_input_range<std::tuple<long, float>> r4(0, 0);
+  std::unordered_multimap m11(std::from_range, r4);
+  static_assert(std::is_same_v<
+    decltype(m11),
+    std::unordered_multimap<long, float>>);
+  std::unordered_multimap it11(r4.begin(), r4.begin());
+  static_assert(std::is_same_v<
+    decltype(it11),
+    std::unordered_multimap<long, float>>);
 }
 
 template<typename T, typename U>

Reply via email to