On 2/19/26 13:04, Jonathan Wakely wrote:
On Thu, 12 Feb 2026 at 18:12, Nathan Myers <[email protected]> wrote:
Changes in v2:
  - Fix numerous errors revealed by actual testing.
  - Delete excess overloads in unordered_multimap and
   unordered_multiset.

Implement the debug versions of new overloads from P2363.

Also, simplify implementation of other overloads to match.

libstdc++-v3/ChangeLog:
         PR libstdc++/117402
         * include/debug/map.h (try_emplace (2x), insert_or_assign (2x)):
         Define heterogeneous overloads, simplify existing overloads.
         * include/debug/unordered_map: Same.
         * include/debug/set.h (insert (2x)):
         Define heterogeneous overloads.
         * include/debug/unordered_set: Same.
---
  libstdc++-v3/include/debug/map.h         | 83 +++++++++++++++++-------
  libstdc++-v3/include/debug/set.h         | 21 ++++++
  libstdc++-v3/include/debug/unordered_map | 64 +++++++++++++++---
  libstdc++-v3/include/debug/unordered_set | 26 ++++++++
  4 files changed, 161 insertions(+), 33 deletions(-)

diff --git a/libstdc++-v3/include/debug/map.h b/libstdc++-v3/include/debug/map.h
index 0fc7afae385..d6d2600d904 100644
--- a/libstdc++-v3/include/debug/map.h
+++ b/libstdc++-v3/include/debug/map.h
@@ -382,18 +382,26 @@ namespace __debug
           return { { __res.first, this }, __res.second };
         }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_tree_key<map> _Kt, typename... _Args>
+       pair<iterator, bool>
+       try_emplace(_Kt&& __k, _Args&&... __args)
+       {
+         auto __res = _Base::try_emplace(
+           std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
+         return { { __res.first, this }, __res.second };
+       }
+#endif
+
        template <typename... _Args>
          iterator
          try_emplace(const_iterator __hint, const key_type& __k,
                      _Args&&... __args)
          {
           __glibcxx_check_insert(__hint);
-         return
-           {
-             _Base::try_emplace(__hint.base(), __k,
-                                std::forward<_Args>(__args)...),
-             this
-           };
+         auto __it = _Base::try_emplace(__hint.base(), __k,
+           std::forward<_Args>(__args)...);
+         return { __it, this };
         }

        template <typename... _Args>
@@ -401,14 +409,23 @@ namespace __debug
          try_emplace(const_iterator __hint, key_type&& __k, _Args&&... __args)
          {
           __glibcxx_check_insert(__hint);
-         return
-           {
-             _Base::try_emplace(__hint.base(), std::move(__k),
-                                std::forward<_Args>(__args)...),
-             this
-           };
+         auto __it = _Base::try_emplace(__hint.base(), std::move(__k),
+           std::forward<_Args>(__args)...);
+         return { __it, this };
         }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_tree_key<map> _Kt, typename... _Args>
+       iterator
+       try_emplace(const_iterator __hint, _Kt&& __k, _Args&&... __args)
+       {
+         __glibcxx_check_insert(__hint);
+         auto __it = _Base::try_emplace(__hint.base(),
+           std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
+         return { __it, this };
+       }
+# endif
+
        template <typename _Obj>
          std::pair<iterator, bool>
          insert_or_assign(const key_type& __k, _Obj&& __obj)
@@ -427,18 +444,26 @@ namespace __debug
           return { { __res.first, this }, __res.second };
         }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_tree_key<map> _Kt, typename _Obj>
+       std::pair<iterator, bool>
+       insert_or_assign(_Kt&& __k, _Obj&& __obj)
+       {
+         auto __res = _Base::insert_or_assign(
+           std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
+         return { { __res.first, this }, __res.second };
+       }
+#endif
+
        template <typename _Obj>
          iterator
          insert_or_assign(const_iterator __hint,
                           const key_type& __k, _Obj&& __obj)
         {
           __glibcxx_check_insert(__hint);
-         return
-           {
-             _Base::insert_or_assign(__hint.base(), __k,
-                                     std::forward<_Obj>(__obj)),
-             this
-           };
+         auto __it = _Base::insert_or_assign(__hint.base(), __k,
+           std::forward<_Obj>(__obj));
+         return { __it, this };
         }

        template <typename _Obj>
@@ -446,13 +471,23 @@ namespace __debug
          insert_or_assign(const_iterator __hint, key_type&& __k, _Obj&& __obj)
          {
           __glibcxx_check_insert(__hint);
-         return
-           {
-             _Base::insert_or_assign(__hint.base(), std::move(__k),
-                                     std::forward<_Obj>(__obj)),
-             this
-           };
+         auto __it = _Base::insert_or_assign(__hint.base(), std::move(__k),
+           std::forward<_Obj>(__obj));
+         return { __it, this };
         }
+
+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_tree_key<map> _Kt, typename _Obj>
+       iterator
+       insert_or_assign(const_iterator __hint, _Kt&& __k, _Obj&& __obj)
+       {
+         __glibcxx_check_insert(__hint);
+         auto __it = _Base::insert_or_assign(__hint.base(),
+           std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
+         return { __it, this };
+       }
+# endif
+
  #endif // C++17

  #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
diff --git a/libstdc++-v3/include/debug/set.h b/libstdc++-v3/include/debug/set.h
index 99701d4a6d7..9180a87285b 100644
--- a/libstdc++-v3/include/debug/set.h
+++ b/libstdc++-v3/include/debug/set.h
@@ -283,6 +283,16 @@ namespace __debug
        }
  #endif

+#ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_tree_key<set> _Kt>
+       std::pair<iterator, bool>
+       insert(_Kt&& __x)
+       {
+         auto __res = _Base::insert(std::forward<_Kt>(__x));
+         return { { __res.first, this }, __res.second };
+       }
+#endif
+
        iterator
        insert(const_iterator __position, const value_type& __x)
        {
@@ -299,6 +309,17 @@ namespace __debug
        }
  #endif

+#ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_tree_key<set> _Kt>
+       iterator
+       insert(const_iterator __position, _Kt&& __x)
+       {
+         __glibcxx_check_insert(__position);
+         auto __it = _Base::insert(__position.base(), std::forward<_Kt>(__x));
+         return { __it, this };
+       }
+#endif
+
        template <typename _InputIterator>
         void
         insert(_InputIterator __first, _InputIterator __last)
diff --git a/libstdc++-v3/include/debug/unordered_map 
b/libstdc++-v3/include/debug/unordered_map
index 4bde18c917b..1dda76dcf32 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -500,6 +500,17 @@ namespace __debug
           return { { __res.first, this }, __res.second };
         }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename... _Args>
+       pair<iterator, bool>
+       try_emplace(_Kt&& __k, _Args&&... __args)
+       {
+         auto __res = _Base::try_emplace(std::forward<_Kt>(__k),
+           std::forward<_Args>(__args)...);
+         return { { __res.first, this }, __res.second };
+       }
+# endif
+
        template <typename... _Args>
         iterator
         try_emplace(const_iterator __hint, const key_type& __k,
@@ -516,10 +527,21 @@ namespace __debug
         try_emplace(const_iterator __hint, key_type&& __k, _Args&&... __args)
         {
           __glibcxx_check_insert(__hint);
-         return { _Base::try_emplace(__hint.base(), std::move(__k),
-                                     std::forward<_Args>(__args)...),
-                  this };
+         auto __it = _Base::try_emplace(__hint.base(), std::move(__k),
+           std::forward<_Args>(__args)...);
+         return { __it, this };

Are all these try_emplace overloads missing calls to _M_check_rehashed?

Yes, indeed.

_M_check_rehashed is also called in erase operations even if currently we never rehash on erasure, even in tr1 implementation by the way.

Maybe it's done this way just in case we start rehash on erasure one day. But it's already inconsistent then as erase of an iterator range is not doing the same.


I think I should have added those in r6-2989-g66c182be120bb3 when
adding try_emplace to the debug maps.
But  that's a pre-existing problem that can be solved separately.

This is OK for trunk (after the main P2363 patch is pushed, of course).






         }
+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename... _Args>
+       iterator
+       try_emplace(const_iterator __hint, _Kt&& __k, _Args&&... __args)
+       {
+         __glibcxx_check_insert(__hint);
+         auto __it = _Base::try_emplace(__hint.base(),
+           std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
+         return { __it, this };
+       }
+# endif

        template <typename _Obj>
         pair<iterator, bool>
@@ -539,15 +561,26 @@ namespace __debug
           return { { __res.first, this }, __res.second };
         }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename _Obj>
+       pair<iterator, bool>
+       insert_or_assign(_Kt&& __k, _Obj&& __obj)
+       {
+         auto __res = _Base::insert_or_assign(
+           std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
+         return { { __res.first, this }, __res.second };
+       }
+# endif
+
        template <typename _Obj>
         iterator
         insert_or_assign(const_iterator __hint, const key_type& __k,
                          _Obj&& __obj)
         {
           __glibcxx_check_insert(__hint);
-         return { _Base::insert_or_assign(__hint.base(), __k,
-                                          std::forward<_Obj>(__obj)),
-                  this };
+         auto __it = _Base::insert_or_assign(__hint.base(), __k,
+           std::forward<_Obj>(__obj));
+         return { __it, this };
         }

        template <typename _Obj>
@@ -555,10 +588,23 @@ namespace __debug
         insert_or_assign(const_iterator __hint, key_type&& __k, _Obj&& __obj)
         {
           __glibcxx_check_insert(__hint);
-         return { _Base::insert_or_assign(__hint.base(), std::move(__k),
-                                          std::forward<_Obj>(__obj)),
-                  this };
+         auto __it = _Base::insert_or_assign(__hint.base(), std::move(__k),
+           std::forward<_Obj>(__obj));
+         return { __it, this };
         }
+
+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename _Obj>
+       iterator
+       insert_or_assign(const_iterator __hint, _Kt&& __k, _Obj&& __obj)
+       {
+         __glibcxx_check_insert(__hint);
+         auto __it = _Base::insert_or_assign(__hint.base(),
+           std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
+         return { __it, this };
+       }
+# endif
+
  #endif // C++17

  #ifdef __glibcxx_node_extract // >= C++17 && HOSTED
diff --git a/libstdc++-v3/include/debug/unordered_set 
b/libstdc++-v3/include/debug/unordered_set
index de999a76890..06430e7cf64 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -413,6 +413,18 @@ namespace __debug
         return { { __res.first, this }, __res.second };
        }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       std::pair<iterator, bool>
+       insert(_Kt&& __obj)
+       {
+         size_type __bucket_count = this->bucket_count();
+         auto __res = _Base::insert(std::forward<_Kt>(__obj));
+         _M_check_rehashed(__bucket_count);
+         return { { __res.first, this }, __res.second };
+       }
+#endif
+
        iterator
        insert(const_iterator __hint, value_type&& __obj)
        {
@@ -423,6 +435,20 @@ namespace __debug
         return { __it, this };
        }

+# ifdef __glibcxx_associative_heterogeneous_insertion
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       iterator
+       insert(const_iterator __hint, _Kt&& __obj)
+       {
+         __glibcxx_check_insert(__hint);
+         size_type __bucket_count = this->bucket_count();
+         auto __it = _Base::insert(
+           __hint.base(), std::forward<_Kt>(__obj));
+         _M_check_rehashed(__bucket_count);
+         return { __it, this };
+       }
+#endif
+
        void
        insert(std::initializer_list<value_type> __l)
        {
--
2.52.0

Reply via email to