Changes in v7:
  - Regularize comments on new #ifdefs ("C++26", no "P2363").

Changes in v6:
  - More testing for op[] and at(): move-from key argument when
   and only when permitted.

  - Test op[] and at more: move-from key argument when and only
   when permitted.

Changes in v5:
  - Fix typos in set/modifiers/hetero/insert.cc.
  - Fix chart in commit message.

Changes in v4:
  - Rebase on committed P2077 erasures.
  - Remove conditional compilation on impl helpers in
   bits/stl_tree.h, hashtable.h, hashtable_policy.h.
  - Regularize ChangeLog format.
  - Test propagation of heterogeneous key's value category
   through to conversion to key_type.
  - Test propagation of variadic-arguments' value categories
   from try_emplace through to underlying constructors.
  - Regularize template argument name s/_Mapped/_Obj/.

Changes in v3:
  - Make tests run, and pass.
  - Note added members in Changelog.

Change in v2: fix remaining regression, SEGV in 92878_92947.cc.

Implements P2353R5 "Extending associative containers with the
remaining heterogeneous overloads". Adds overloads templated on
heterogeneous key types for several members of associative
containers, particularly insertions:

                      un-   un-  un-  unordered
 set  map  mset mmap  set   map  mset mmap
  @    .    .    .     @     .    .    .   insert
  .    @    .    .     .     @    .    .   op[], at, try_emplace,
                                            insert_or_assign
  .    .    .    .     @     @    @    @   bucket

(Nothing is added to the multiset or multimap tree containers.)
All the insert*() and try_emplace() members also get a hinted
overload.  The at() members get const and non-const overloads.

The new overloads enforce concept __heterogeneous_tree_key or
__heterogeneous_hash_key, as in P2077, to enforce that the
function objects provided meet requirements, and that the key
supplied is not an iterator or the native key. Insertions
implicitly construct the required key_type object from the
argument, by move where permitted.

Doxygen annotations are improved.

libstdc++-v3/ChangeLog:
        PR libstdc++/117402
        * include/bits/stl_map.h (operator[], at (2x), try_emplace (2x),
        insert_or_assign (2x)): Add overloads.
        * include/bits/unordered_map.h: Same, plus...
        (bucket (2x)): Add overloads.
        * include/bits/stl_set.h (insert (2x)): Add overloads.
        * include/bits/unordered_set.h: Same, plus...
        (bucket (2x)): Add overloads.
        * include/bits/hashtable.h (_M_bucket_tr, _M_insert_tr): Define.
        * include/bits/hashtable_policy.h (_M_index_to_tr, _M_at_tr (2x),
        _M_index_to_tr): Define.
        * include/bits/stl_tree.h (_M_get_insert_unique_pos_tr,
        _M_get_insert_hint_unique_pos_tr): Define.
        * include/bits/version.def (associative_heterogeneous_insertion):
        Define.
        * include/bits/version.h: Regenerate.
        * include/std/map (__glibcxx_want_associative_heterogeneous_insertion):
        Define macro.
        * include/std/set: Same.
        * include/std/unordered_map: Same.
        * include/std/unordered_set: Same.
        * testsuite/23_containers/map/modifiers/hetero/insert.cc: New tests.
        * testsuite/23_containers/set/modifiers/hetero/insert.cc: Same.
        * testsuite/23_containers/unordered_map/modifiers/hetero/insert.cc:
        Same.
        * testsuite/23_containers/unordered_multimap/modifiers/hetero/insert.cc:
        Same.
        * testsuite/23_containers/unordered_multiset/modifiers/hetero/insert.cc:
        Same.
        * testsuite/23_containers/unordered_set/modifiers/hetero/insert.cc:
        Same.
---
 libstdc++-v3/include/bits/hashtable.h         |  27 ++
 libstdc++-v3/include/bits/hashtable_policy.h  |  60 ++-
 libstdc++-v3/include/bits/stl_map.h           | 126 ++++++-
 libstdc++-v3/include/bits/stl_set.h           |  21 ++
 libstdc++-v3/include/bits/stl_tree.h          | 106 +++++-
 libstdc++-v3/include/bits/unordered_map.h     |  96 +++++
 libstdc++-v3/include/bits/unordered_set.h     |  32 ++
 libstdc++-v3/include/bits/version.def         |   8 +
 libstdc++-v3/include/bits/version.h           |  10 +
 libstdc++-v3/include/std/map                  |   1 +
 libstdc++-v3/include/std/set                  |   1 +
 libstdc++-v3/include/std/unordered_map        |   1 +
 libstdc++-v3/include/std/unordered_set        |   1 +
 .../map/modifiers/hetero/insert.cc            | 341 +++++++++++++++++
 .../set/modifiers/hetero/insert.cc            | 120 ++++++
 .../unordered_map/modifiers/hetero/insert.cc  | 353 ++++++++++++++++++
 .../modifiers/hetero/insert.cc                |  57 +++
 .../modifiers/hetero/insert.cc                |  56 +++
 .../unordered_set/modifiers/hetero/insert.cc  | 134 +++++++
 19 files changed, 1544 insertions(+), 7 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/23_containers/map/modifiers/hetero/insert.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/set/modifiers/hetero/insert.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/hetero/insert.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/hetero/insert.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/hetero/insert.cc
 create mode 100644 
libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/hetero/insert.cc

diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index 48695c013f3..f4211eba516 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -700,6 +700,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       bucket(const key_type& __k) const
       { return _M_bucket_index(this->_M_hash_code(__k)); }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <typename _Kt>
+       size_type
+       _M_bucket_tr(const _Kt& __k) const
+       { return _M_bucket_index(this->_M_hash_code_tr(__k)); }
+#endif
+
       local_iterator
       begin(size_type __bkt)
       {
@@ -1097,6 +1104,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        std::pair<iterator, bool>
        try_emplace(const_iterator, _KType&& __k, _Args&&... __args)
        {
+         // Note we ignore the hint argument.
          __hash_code __code;
          size_type __bkt;
          if (auto __loc = _M_locate(__k))
@@ -1117,6 +1125,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          __node._M_node = nullptr;
          return { __it, true };
        }
+
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template<typename _Kt>
+       std::pair<iterator, bool>
+       _M_insert_tr(_Kt&& __k)
+       {
+         auto __loc = _M_locate_tr(__k);
+         if (__loc)
+           return { iterator(__loc), false };
+
+         _Scoped_node __node(
+           this->_M_allocate_node(std::forward<_Kt>(__k)), this);
+         auto __it = _M_insert_unique_node(
+           __loc._M_bucket_index, __loc._M_hash_code, __node._M_node);
+         __node._M_node = nullptr;
+         return { __it, true };
+       }
+#endif
 #endif
 
       void
@@ -2363,6 +2389,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        __node._M_node = nullptr;
        return { __pos, true };
       }
+
 #pragma GCC diagnostic pop
 
   template<typename _Key, typename _Value, typename _Alloc,
diff --git a/libstdc++-v3/include/bits/hashtable_policy.h 
b/libstdc++-v3/include/bits/hashtable_policy.h
index 6d7bde1e785..92fa6e82e5b 100644
--- a/libstdc++-v3/include/bits/hashtable_policy.h
+++ b/libstdc++-v3/include/bits/hashtable_policy.h
@@ -872,6 +872,33 @@ namespace __detail
          __throw_out_of_range(__N("unordered_map::at"));
        return __ite->second;
       }
+
+      // op[] for transparent heterogeneous key
+      template <typename _Kt>
+       mapped_type&
+       _M_index_to_tr(const _Kt& __k);
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // DR 761. unordered_map needs an at() member function.
+      template <typename _Kt>
+       mapped_type&
+       _M_at_tr(const _Kt& __k)
+       {
+         auto __ite = static_cast<__hashtable*>(this)->_M_find_tr(__k);
+         if (!__ite._M_cur)
+           __throw_out_of_range(__N("unordered_map::at"));
+         return __ite->second;
+       }
+
+      template <typename _Kt>
+       const mapped_type&
+       _M_at_tr(const _Kt& __k) const
+       {
+         auto __ite = static_cast<const __hashtable*>(this)->_M_find_tr(__k);
+         if (!__ite._M_cur)
+           __throw_out_of_range(__N("unordered_map::at"));
+         return __ite->second;
+       }
     };
 
   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
@@ -901,6 +928,33 @@ namespace __detail
       return __pos->second;
     }
 
+  // op[] for heterogeneous keys
+  template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
+          typename _Hash, typename _RangeHash, typename _Unused,
+          typename _RehashPolicy, typename _Traits>
+    template <typename _Kt>
+      auto
+      _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal,
+               _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>::
+      _M_index_to_tr(const _Kt& __k)
+      -> mapped_type&
+    {
+      __hashtable* __h = static_cast<__hashtable*>(this);
+      __hash_code __code = __h->_M_hash_code_tr(__k);
+      size_t __bkt = __h->_M_bucket_index(__code);
+      if (auto __node = __h->_M_find_node_tr(__bkt, __k, __code))
+       return __node->_M_v().second;
+
+      typename __hashtable::_Scoped_node __node {
+       __h, std::piecewise_construct,
+       std::tuple<key_type>(__k), std::tuple<>()
+      };
+      auto __pos
+       = __h->_M_insert_unique_node(__bkt, __code, __node._M_node);
+      __node._M_node = nullptr;
+      return __pos->second;
+    }
+
   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
           typename _Hash, typename _RangeHash, typename _Unused,
           typename _RehashPolicy, typename _Traits>
@@ -1413,8 +1467,7 @@ namespace __detail
       template<typename _Kt>
        bool
        _M_key_equals_tr(const _Kt& __k,
-                        const _Hash_node_value<_Value,
-                                            __hash_cached::value>& __n) const
+         const _Hash_node_value<_Value, __hash_cached::value>& __n) const
        {
          static_assert(
            __is_invocable<const _Equal&, const _Kt&, const _Key&>{},
@@ -1439,8 +1492,7 @@ namespace __detail
       template<typename _Kt>
        bool
        _M_equals_tr(const _Kt& __k, __hash_code __c,
-                    const _Hash_node_value<_Value,
-                                           __hash_cached::value>& __n) const
+         const _Hash_node_value<_Value, __hash_cached::value>& __n) const
        {
          if constexpr (__hash_cached::value)
            if (__c != __n._M_hash_code)
diff --git a/libstdc++-v3/include/bits/stl_map.h 
b/libstdc++-v3/include/bits/stl_map.h
index 4cb0c982c3d..f4b0982af72 100644
--- a/libstdc++-v3/include/bits/stl_map.h
+++ b/libstdc++-v3/include/bits/stl_map.h
@@ -511,6 +511,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       max_size() const _GLIBCXX_NOEXCEPT
       { return _M_t.max_size(); }
 
+      ///@{
       // [23.3.1.2] element access
       /**
        *  @brief  Subscript ( @c [] ) access to %map data.
@@ -560,6 +561,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }
 #endif
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt>
+       mapped_type&
+       operator[](_Kt&& __k)
+       { return try_emplace(std::forward<_Kt>(__k)).first->second; }
+#endif
+      ///@}
+
+      ///@{
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 464. Suggestion for new member functions in standard containers.
       /**
@@ -578,6 +588,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        return (*__i).second;
       }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt>
+       mapped_type&
+       at(const _Kt& __k)
+       {
+         iterator __i = lower_bound(__k);
+         if (__i == end() || key_comp()(__k, (*__i).first))
+           __throw_out_of_range(__N("map::at"));
+         return (*__i).second;
+       }
+#endif
+
       const mapped_type&
       at(const key_type& __k) const
       {
@@ -587,6 +609,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        return (*__i).second;
       }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt>
+       const mapped_type&
+       at(const _Kt& __k) const
+       {
+         const_iterator __i = lower_bound(__k);
+         if (__i == end() || key_comp()(__k, (*__i).first))
+           __throw_out_of_range(__N("map::at"));
+         return (*__i).second;
+       }
+#endif
+      ///@}
+
       // modifiers
 #if __cplusplus >= 201103L
       /**
@@ -728,6 +763,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif // C++17
 
 #ifdef __glibcxx_map_try_emplace // C++ >= 17 && HOSTED
+      ///@{
       /**
        *  @brief Attempts to build and insert a std::pair into the %map.
        *
@@ -781,6 +817,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          return {__i, false};
        }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt, typename ..._Args>
+       pair<iterator, bool>
+       try_emplace(_Kt&& __k, _Args&&... __args)
+       {
+         iterator __i = lower_bound(__k);
+         if (__i == end() || key_comp()(__k, (*__i).first))
+           {
+             __i = _M_t._M_emplace_hint_unique(__i, std::piecewise_construct,
+               std::forward_as_tuple(std::forward<_Kt>(__k)),
+               std::forward_as_tuple(std::forward<_Args>(__args)...));
+             return {__i, true};
+           }
+         return {__i, false};
+       }
+#endif
+      ///@}
+
+      ///@{
       /**
        *  @brief Attempts to build and insert a std::pair into the %map.
        *
@@ -845,6 +900,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        }
 #endif
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt, typename ..._Args>
+       iterator
+       try_emplace(const_iterator __hint, _Kt&& __k, _Args&&... __args)
+       {
+         iterator __i;
+         auto __true_hint = _M_t._M_get_insert_hint_unique_pos_tr(__hint, __k);
+         if (__true_hint.second)
+           __i = _M_t._M_emplace_hint_unique(iterator(__true_hint.second),
+               std::piecewise_construct,
+               std::forward_as_tuple(std::forward<_Kt>(__k)),
+               std::forward_as_tuple(std::forward<_Args>(__args)...));
+         else
+           __i = iterator(__true_hint.first);
+         return __i;
+       }
+#endif
+      ///@}
+
+      ///@{
       /**
        *  @brief Attempts to insert a std::pair into the %map.
        *  @param __x Pair to be inserted (see std::make_pair for easy
@@ -896,7 +971,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          return _M_t._M_emplace_unique(std::forward<_Pair>(__x));
        }
 #endif
-      /// @}
+      ///@}
 
 #if __cplusplus >= 201103L
       /**
@@ -929,6 +1004,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        }
 #endif
 
+      ///@{
       /**
        *  @brief Attempts to insert a std::pair into the %map.
        *  @param  __position  An iterator that serves as a hint as to where the
@@ -992,6 +1068,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        { _M_t._M_insert_range_unique(__first, __last); }
 
 #if __cplusplus > 201402L
+      ///@{
       /**
        *  @brief Attempts to insert or assign a std::pair into the %map.
        *  @param __k    Key to use for finding a possibly existing pair in
@@ -1046,6 +1123,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          return {__i, false};
        }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt, typename _Obj>
+       pair<iterator, bool>
+       insert_or_assign(_Kt&& __k, _Obj&& __obj)
+       {
+         iterator __i = lower_bound(__k);
+         if (__i == end() || key_comp()(__k, (*__i).first))
+           {
+             __i = _M_t._M_emplace_hint_unique(__i,
+               std::piecewise_construct,
+               std::forward_as_tuple(std::forward<_Kt>(__k)),
+               std::forward_as_tuple(std::forward<_Obj>(__obj)));
+             return {__i, true};
+           }
+         (*__i).second = std::forward<_Obj>(__obj);
+         return {__i, false};
+       }
+#endif
+      ///@}
+#endif
+
+#if __cplusplus > 201402L
+      ///@{
       /**
        *  @brief Attempts to insert or assign a std::pair into the %map.
        *  @param  __hint  An iterator that serves as a hint as to where the
@@ -1105,9 +1205,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          (*__i).second = std::forward<_Obj>(__obj);
          return __i;
        }
+
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<map> _Kt, typename _Obj>
+       iterator
+       insert_or_assign(const_iterator __hint, _Kt&& __k, _Obj&& __obj)
+       {
+         iterator __i;
+         auto __true_hint =
+           _M_t._M_get_insert_hint_unique_pos_tr(__hint, __k);
+         if (__true_hint.second)
+           {
+             return _M_t._M_emplace_hint_unique(
+               iterator(__true_hint.second),
+               std::piecewise_construct,
+               std::forward_as_tuple(std::forward<_Kt>(__k)),
+               std::forward_as_tuple(std::forward<_Obj>(__obj)));
+           }
+         __i = iterator(__true_hint.first);
+         (*__i).second = std::forward<_Obj>(__obj);
+         return __i;
+       }
+#endif
+      ///@}
 #endif
 
 #if __cplusplus >= 201103L
+      ///@{
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 130. Associative erase should return an iterator.
       /**
diff --git a/libstdc++-v3/include/bits/stl_set.h 
b/libstdc++-v3/include/bits/stl_set.h
index d3a4c089110..d3e876039d8 100644
--- a/libstdc++-v3/include/bits/stl_set.h
+++ b/libstdc++-v3/include/bits/stl_set.h
@@ -517,6 +517,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        }
 #endif
 
+      ///@{
       /**
        *  @brief Attempts to insert an element into the %set.
        *  @param  __x  Element to be inserted.
@@ -548,6 +549,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }
 #endif
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<set> _Kt>
+       pair<iterator, bool>
+       insert(_Kt&& __x)
+       {
+         auto __p = _M_t._M_insert_unique(std::forward<_Kt>(__x));
+         return {__p.first, __p.second};
+       }
+#endif
+      ///@}
+
+      ///@{
       /**
        *  @brief Attempts to insert an element into the %set.
        *  @param  __position  An iterator that serves as a hint as to where the
@@ -577,6 +590,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       { return _M_t._M_insert_unique_(__position, std::move(__x)); }
 #endif
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_tree_key<set> _Kt>
+       iterator
+       insert(const_iterator __position, _Kt&& __x)
+       { return _M_t._M_insert_unique_(__position, std::forward<_Kt>(__x)); }
+#endif
+      ///@}
+
       /**
        *  @brief A template function that attempts to insert a range
        *  of elements.
diff --git a/libstdc++-v3/include/bits/stl_tree.h 
b/libstdc++-v3/include/bits/stl_tree.h
index 5d361b55028..ebe4810bcbc 100644
--- a/libstdc++-v3/include/bits/stl_tree.h
+++ b/libstdc++-v3/include/bits/stl_tree.h
@@ -1459,6 +1459,10 @@ namespace __rb_tree
       pair<_Base_ptr, _Base_ptr>
       _M_get_insert_unique_pos(const key_type& __k);
 
+      template <typename _Kt>
+       pair<_Base_ptr, _Base_ptr>
+       _M_get_insert_unique_pos_tr(const _Kt& __k);
+
       pair<_Base_ptr, _Base_ptr>
       _M_get_insert_equal_pos(const key_type& __k);
 
@@ -1466,6 +1470,11 @@ namespace __rb_tree
       _M_get_insert_hint_unique_pos(const_iterator __pos,
                                    const key_type& __k);
 
+      template <typename _Kt>
+       pair<_Base_ptr, _Base_ptr>
+       _M_get_insert_hint_unique_pos_tr(
+         const_iterator __pos, const _Kt& __k);
+
       pair<_Base_ptr, _Base_ptr>
       _M_get_insert_hint_equal_pos(const_iterator __pos,
                                   const key_type& __k);
@@ -2060,7 +2069,7 @@ namespace __rb_tree
       _M_move_assign(_Rb_tree&, false_type);
 #endif
 
-#if __glibcxx_node_extract // >= C++17
+#ifdef __glibcxx_node_extract // >= C++17
       static _Node_ptr
       _S_adapt(typename _Node_alloc_traits::pointer __ptr)
       {
@@ -2810,6 +2819,40 @@ namespace __rb_tree
       return _Res(__j._M_node, _Base_ptr());
     }
 
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+          typename _Compare, typename _Alloc>
+    template <typename _Kt>
+      pair<
+       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+         _Base_ptr,
+       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+         _Base_ptr>
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_get_insert_unique_pos_tr(const _Kt& __k)
+    {
+      typedef pair<_Base_ptr, _Base_ptr> _Res;
+      _Base_ptr __x = _M_begin();
+      _Base_ptr __y = _M_end();
+      bool __comp = true;
+      while (__x)
+       {
+         __y = __x;
+         __comp = _M_key_compare(__k, _S_key(__x));
+         __x = __comp ? _S_left(__x) : _S_right(__x);
+       }
+      iterator __j = iterator(__y);
+      if (__comp)
+       {
+         if (__j == begin())
+           return _Res(__x, __y);
+         else
+           --__j;
+       }
+      if (_M_key_compare(_S_key(__j._M_node), __k))
+       return _Res(__x, __y);
+      return _Res(__j._M_node, _Base_ptr());
+    }
+
   template<typename _Key, typename _Val, typename _KeyOfValue,
           typename _Compare, typename _Alloc>
     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
@@ -2936,6 +2979,65 @@ namespace __rb_tree
        return _Res(__position._M_node, _Base_ptr());
     }
 
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+          typename _Compare, typename _Alloc>
+    template <typename _Kt>
+      pair<
+       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+         _Base_ptr,
+       typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+         _Base_ptr>
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_get_insert_hint_unique_pos_tr(
+         const_iterator __position, const _Kt& __k)
+      {
+       typedef pair<_Base_ptr, _Base_ptr> _Res;
+
+       // end()
+       if (__position._M_node == _M_end())
+         {
+           if (size() > 0 && _M_key_compare(_S_key(_M_rightmost()), __k))
+             return _Res(_Base_ptr(), _M_rightmost());
+           else
+             return _M_get_insert_unique_pos_tr(__k);
+         }
+       else if (_M_key_compare(__k, _S_key(__position._M_node)))
+         {
+           // First, try before...
+           iterator __before(__position._M_node);
+           if (__position._M_node == _M_leftmost()) // begin()
+             return _Res(_M_leftmost(), _M_leftmost());
+           else if (_M_key_compare(_S_key((--__before)._M_node), __k))
+             {
+               if (!_S_right(__before._M_node))
+                 return _Res(_Base_ptr(), __before._M_node);
+               else
+                 return _Res(__position._M_node, __position._M_node);
+             }
+           else
+             return _M_get_insert_unique_pos_tr(__k);
+         }
+       else if (_M_key_compare(_S_key(__position._M_node), __k))
+         {
+           // ... then try after.
+           iterator __after(__position._M_node);
+           if (__position._M_node == _M_rightmost())
+             return _Res(_Base_ptr(), _M_rightmost());
+           else if (_M_key_compare(__k, _S_key((++__after)._M_node)))
+             {
+               if (!_S_right(__position._M_node))
+                 return _Res(_Base_ptr(), __position._M_node);
+               else
+                 return _Res(__after._M_node, __after._M_node);
+             }
+           else
+             return _M_get_insert_unique_pos_tr(__k);
+         }
+       else
+         // Equivalent keys.
+         return _Res(__position._M_node, _Base_ptr());
+      }
+
   template<typename _Key, typename _Val, typename _KeyOfValue,
           typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
@@ -3155,7 +3257,7 @@ namespace __rb_tree
          return __z._M_insert(__res);
        return __z._M_insert_equal_lower();
       }
-#endif
+#endif  // >= C++11
 
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
diff --git a/libstdc++-v3/include/bits/unordered_map.h 
b/libstdc++-v3/include/bits/unordered_map.h
index 9b74cba8675..1bd2906ace4 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -456,6 +456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        emplace(_Args&&... __args)
        { return _M_h.emplace(std::forward<_Args>(__args)...); }
 
+      ///@{
       /**
        *  @brief Attempts to build and insert a std::pair into the
        *  %unordered_map.
@@ -520,6 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif // node_extract
 
 #ifdef __glibcxx_unordered_map_try_emplace // C++ >= 17 && HOSTED
+      ///@{
       /**
        *  @brief Attempts to build and insert a std::pair into the
        *  %unordered_map.
@@ -558,6 +560,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
                                  std::forward<_Args>(__args)...);
        }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename ..._Args>
+       pair<iterator, bool>
+       try_emplace(_Kt&& __k, _Args&&... __args)
+       {
+         return _M_h.try_emplace(cend(),
+           std::forward<_Kt>(__k), std::forward<_Args>(__args)...);
+       }
+#endif
+      ///@}
+
+      ///@{
       /**
        *  @brief Attempts to build and insert a std::pair into the
        *  %unordered_map.
@@ -605,6 +619,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        }
 #endif // __glibcxx_unordered_map_try_emplace
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename ..._Args>
+       iterator
+       try_emplace(const_iterator __hint, _Kt&& __k, _Args&&... __args)
+       {
+         return _M_h.try_emplace(__hint,
+           std::forward<_Kt>(__k), std::forward<_Args>(__args)...).first;
+       }
+#endif
+      ///@}
+
       ///@{
       /**
        *  @brief Attempts to insert a std::pair into the %unordered_map.
@@ -722,6 +747,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif
 
 #ifdef __glibcxx_unordered_map_try_emplace // >= C++17 && HOSTED
+      ///@{
       /**
        *  @brief Attempts to insert a std::pair into the %unordered_map.
        *  @param __k    Key to use for finding a possibly existing pair in
@@ -765,6 +791,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          return __ret;
        }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename _Obj>
+       pair<iterator, bool>
+       insert_or_assign(_Kt&& __k, _Obj&& __obj)
+       {
+         auto __ret = _M_h.try_emplace(
+           cend(), std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
+         if (!__ret.second)
+           __ret.first->second = std::forward<_Obj>(__obj);
+         return __ret;
+       }
+#endif
+      ///@}
+
+      ///@{
       /**
        *  @brief Attempts to insert a std::pair into the %unordered_map.
        *  @param  __hint  An iterator that serves as a hint as to where the
@@ -813,6 +854,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
            __ret.first->second = std::forward<_Obj>(__obj);
          return __ret.first;
        }
+
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt, typename _Obj>
+       iterator
+       insert_or_assign(const_iterator __hint, _Kt&& __k, _Obj&& __obj)
+       {
+         auto __ret = _M_h.try_emplace(__hint,
+           std::forward<_Kt>(__k), std::forward<_Obj>(__obj));
+         if (!__ret.second)
+           __ret.first->second = std::forward<_Obj>(__obj);
+         return __ret.first;
+       }
+#endif
+      ///@}
 #endif // unordered_map_try_emplace
 
       ///@{
@@ -1089,6 +1144,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       mapped_type&
       operator[](key_type&& __k)
       { return _M_h[std::move(__k)]; }
+
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt>
+       mapped_type&
+       operator[](_Kt&& __k)
+      {
+       return try_emplace(std::forward<_Kt>(__k)).first->second;
+      }
+#endif
       ///@}
 
       ///@{
@@ -1103,9 +1167,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       at(const key_type& __k)
       { return _M_h.at(__k); }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt>
+       mapped_type&
+       at(const _Kt& __k)
+       { return _M_h._M_at_tr(__k); }
+#endif
+
       const mapped_type&
       at(const key_type& __k) const
       { return _M_h.at(__k); }
+
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt>
+       const mapped_type&
+       at(const _Kt& __k) const
+       { return _M_h._M_at_tr(__k); }
+#endif
       ///@}
 
       // bucket interface.
@@ -1129,6 +1207,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket_size(size_type __n) const
       { return _M_h.bucket_size(__n); }
 
+      ///@{
       /*
        * @brief  Returns the bucket index of a given element.
        * @param  __key  A key instance.
@@ -1138,6 +1217,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket(const key_type& __key) const
       { return _M_h.bucket(__key); }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_map> _Kt>
+       size_type
+       bucket(const _Kt& __key) const
+       { return _M_h._M_bucket_tr(__key); }
+#endif
+      ///@}
+
       /**
        *  @brief  Returns a read/write iterator pointing to the first bucket
        *         element.
@@ -2176,6 +2263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket_size(size_type __n) const
       { return _M_h.bucket_size(__n); }
 
+      ///@{
       /*
        * @brief  Returns the bucket index of a given element.
        * @param  __key  A key instance.
@@ -2185,6 +2273,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket(const key_type& __key) const
       { return _M_h.bucket(__key); }
 
+#ifdef __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_multimap> _Kt>
+       size_type
+       bucket(const _Kt& __key) const
+       { return _M_h._M_bucket_tr(__key); }
+#endif
+      ///@}
+
       /**
        *  @brief  Returns a read/write iterator pointing to the first bucket
        *         element.
diff --git a/libstdc++-v3/include/bits/unordered_set.h 
b/libstdc++-v3/include/bits/unordered_set.h
index 22b2ad9caf4..c64fe01c447 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -493,6 +493,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       std::pair<iterator, bool>
       insert(value_type&& __x)
       { return _M_h.insert(std::move(__x)); }
+
+#if __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       std::pair<iterator, bool>
+       insert(_Kt&&  __x)
+       { return _M_h._M_insert_tr(std::forward<_Kt>(__x)); }
+#endif
       ///@}
 
       ///@{
@@ -522,6 +529,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       iterator
       insert(const_iterator __hint, value_type&& __x)
       { return _M_h.insert(__hint, std::move(__x)); }
+
+#if __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       iterator
+       insert(const_iterator, _Kt&& __x)
+       { return _M_h._M_insert_tr(std::forward<_Kt>(__x)).first; }
+#endif
       ///@}
 
       /**
@@ -876,6 +890,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket_size(size_type __n) const
       { return _M_h.bucket_size(__n); }
 
+      ///@{
       /*
        * @brief  Returns the bucket index of a given element.
        * @param  __key  A key instance.
@@ -885,6 +900,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket(const key_type& __key) const
       { return _M_h.bucket(__key); }
 
+#if __glibcxx_associative_heterogeneous_insertion  // C++26
+      template <__heterogeneous_hash_key<unordered_set> _Kt>
+       size_type
+       bucket(const _Kt& __key) const
+       { return _M_h._M_bucket_tr(__key); }
+#endif
+      ///@}
+
       ///@{
       /**
        *  @brief  Returns a read-only (constant) iterator pointing to the first
@@ -1884,6 +1907,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket_size(size_type __n) const
       { return _M_h.bucket_size(__n); }
 
+      ///@{
       /*
        * @brief  Returns the bucket index of a given element.
        * @param  __key  A key instance.
@@ -1893,6 +1917,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       bucket(const key_type& __key) const
       { return _M_h.bucket(__key); }
 
+#if __glibcxx_associative_heterogeneous_insertion  //  C++26
+      template <__heterogeneous_hash_key<unordered_multiset> _Kt>
+       size_type
+       bucket(const _Kt& __key) const
+       { return _M_h._M_bucket_tr(__key); }
+#endif
+      ///@}
+
       ///@{
       /**
        *  @brief  Returns a read-only (constant) iterator pointing to the first
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 4b8e9d43ec2..01725999c52 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1641,6 +1641,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = associative_heterogeneous_insertion;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+  };
+};
+
 ftms = {
   name = is_scoped_enum;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 7602225cb6d..b376c428ced 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1811,6 +1811,16 @@
 #endif /* !defined(__cpp_lib_associative_heterogeneous_erasure) */
 #undef __glibcxx_want_associative_heterogeneous_erasure
 
+#if !defined(__cpp_lib_associative_heterogeneous_insertion)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_associative_heterogeneous_insertion 202306L
+#  if defined(__glibcxx_want_all) || 
defined(__glibcxx_want_associative_heterogeneous_insertion)
+#   define __cpp_lib_associative_heterogeneous_insertion 202306L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_associative_heterogeneous_insertion) */
+#undef __glibcxx_want_associative_heterogeneous_insertion
+
 #if !defined(__cpp_lib_is_scoped_enum)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_is_scoped_enum 202011L
diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map
index 91612cf42c4..66edadbc6dc 100644
--- a/libstdc++-v3/include/std/map
+++ b/libstdc++-v3/include/std/map
@@ -80,6 +80,7 @@
 #define __glibcxx_want_nonmember_container_access
 #define __glibcxx_want_tuple_like
 #define __glibcxx_want_associative_heterogeneous_erasure
+#define __glibcxx_want_associative_heterogeneous_insertion
 #include <bits/version.h>
 
 #if __cplusplus >= 201703L
diff --git a/libstdc++-v3/include/std/set b/libstdc++-v3/include/std/set
index 28eef1fc490..dc550f1d0b6 100644
--- a/libstdc++-v3/include/std/set
+++ b/libstdc++-v3/include/std/set
@@ -78,6 +78,7 @@
 #define __glibcxx_want_node_extract
 #define __glibcxx_want_nonmember_container_access
 #define __glibcxx_want_associative_heterogeneous_erasure
+#define __glibcxx_want_associative_heterogeneous_insertion
 #include <bits/version.h>
 
 #if __cplusplus >= 201703L
diff --git a/libstdc++-v3/include/std/unordered_map 
b/libstdc++-v3/include/std/unordered_map
index f63be4104c5..e9cf191e749 100644
--- a/libstdc++-v3/include/std/unordered_map
+++ b/libstdc++-v3/include/std/unordered_map
@@ -57,6 +57,7 @@
 #define __glibcxx_want_unordered_map_try_emplace
 #define __glibcxx_want_tuple_like
 #define __glibcxx_want_associative_heterogeneous_erasure
+#define __glibcxx_want_associative_heterogeneous_insertion
 #include <bits/version.h>
 
 #if __cplusplus >= 201703L
diff --git a/libstdc++-v3/include/std/unordered_set 
b/libstdc++-v3/include/std/unordered_set
index 45e6a915eb9..ee16489290e 100644
--- a/libstdc++-v3/include/std/unordered_set
+++ b/libstdc++-v3/include/std/unordered_set
@@ -55,6 +55,7 @@
 #define __glibcxx_want_node_extract
 #define __glibcxx_want_nonmember_container_access
 #define __glibcxx_want_associative_heterogeneous_erasure
+#define __glibcxx_want_associative_heterogeneous_insertion
 #include <bits/version.h>
 
 #if __cplusplus >= 201703L
diff --git 
a/libstdc++-v3/testsuite/23_containers/map/modifiers/hetero/insert.cc 
b/libstdc++-v3/testsuite/23_containers/map/modifiers/hetero/insert.cc
new file mode 100644
index 00000000000..73db5d28b26
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/hetero/insert.cc
@@ -0,0 +1,341 @@
+// { dg-do run { target c++26 } }
+
+#include <map>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <compare>
+#include <cstring>
+#include <testsuite_hooks.h>
+
+struct Y;
+
+struct X {
+  std::string s;
+  X(std::string_view str) : s(str) {}
+  X(Y&& y);
+  X(const Y& y);
+  friend auto operator<=>(X const& a, X const& b) = default;
+};
+
+struct Y {
+  std::string s;
+  Y() = default;
+  Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+  Y(const Y& y) = default;
+  Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
+  Y& operator=(const Y& y) = default;
+  Y(std::string_view sv) : s(sv) {}
+  Y(int n) : s(std::string('a', n)) {}
+  Y(const Y& a, const Y& b) : s(a.s + "1" + b.s) { }
+  Y(const Y& a, Y&& b)      : s(a.s + "2" + b.s) { b.s.clear(); }
+  Y(Y&& a, const Y& b)      : s(a.s + "3" + b.s) { a.s.clear(); }
+  Y(Y&& a, Y&& b)           : s(a.s + "4" + b.s) { a.s.clear(), b.s.clear(); }
+  friend auto operator<=>(Y const& a, Y const& b) = default;
+  friend auto operator<=>(X const& a, Y const& b) { return a.s <=> b.s; }
+};
+
+X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+X::X(const Y& y) : s(y.s) {}
+
+using cmp = std::less<void>;
+
+void test1()  // op[]
+{
+  std::map<X, Y, cmp> amap{cmp{}};
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+  Y x{"dei"}, y{"deh"}, z{"deg"};
+  amap[z] = 4;
+  VERIFY(amap.size() == 4);
+  VERIFY(z.s.size() == 3);  // not moved from.
+
+  amap[std::move(z)] = 5;
+  VERIFY(amap.size() == 4);
+  VERIFY(z.s.size() == 3);  // not moved from.
+
+  VERIFY(amap[std::move(y)] == Y{});
+  VERIFY(amap.size() == 5);
+  VERIFY(y.s.empty());      // moved from.
+
+  amap[std::move(x)] = 7;
+  VERIFY(amap.size() == 6);
+  VERIFY(x.s.empty());      // moved from
+}
+
+void test2() // at()
+{
+  std::map<X, Y, cmp> amap{cmp{}};
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  Y y{"def"};
+  try
+    {
+      VERIFY(2 == amap.at(y));
+      VERIFY(amap.size() == 3);
+      VERIFY(4 == (amap.at(std::move(y)) = 4));
+      VERIFY(amap.size() == 3);
+      VERIFY(y.s.size() == 3);  // not moved from
+    }
+  catch(...) { VERIFY(false); }
+  try
+  {
+    amap.at(Y{"deg"}) = 4;
+    VERIFY(false);  // Should have thrown.
+  }
+  catch (std::out_of_range&) { VERIFY(amap.size() == 3); }
+  catch (...) { VERIFY(false); } // Wrong exception.
+
+  auto const& amapr{amap};
+  Y z{"deh"};
+  try
+    {
+      amapr.at(std::move(z));
+      VERIFY(false);  // Should have thrown.
+    }
+  catch (std::out_of_range&) {  }
+  catch (...) { VERIFY(false); } // Wrong exception.
+  VERIFY(amapr.size() == 3);
+  VERIFY(z.s.size() == 3);  // not moved from
+}
+
+void test3()  // try_emplace
+{
+  std::map<X, Y, cmp> amap{cmp{}};
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  { // Fail, already there
+    auto a = amap;
+    auto [it, res] = a.try_emplace(Y{"def"}, Y{"xyz"});
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{2});
+  }
+  { // Fail, already there, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto [it, res] = a.try_emplace(std::move(y), std::move(z));
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{2});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Succeed, construct
+    auto a = amap;
+    Y m("m"), n("n"), o("o"), p("p"), dek("dek");
+    {
+      auto [it, res] = a.try_emplace(Y{"deg"}, m, n);
+      VERIFY(res);
+      VERIFY(a.size() == 4);
+      VERIFY(it->first == X{"deg"});
+      VERIFY(it->second == Y{"m1n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.size() == 1);
+    }
+    {
+      auto [it, res] = a.try_emplace(Y{"deh"}, m, std::move(n));
+      VERIFY(res);
+      VERIFY(a.size() == 5);
+      VERIFY(it->first == X{"deh"});
+      VERIFY(it->second == Y{"m2n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.empty());
+    }
+    {
+      auto [it, res] = a.try_emplace(Y{"dei"}, std::move(m), o);
+      VERIFY(res);
+      VERIFY(a.size() == 6);
+      VERIFY(it->first == X{"dei"});
+      VERIFY(it->second == Y{"m3o"});
+      VERIFY(m.s.empty());
+      VERIFY(o.s.size() == 1);
+    }
+    {
+      auto [it, res] = a.try_emplace(Y{"dej"}, std::move(o), std::move(p));
+      VERIFY(res);
+      VERIFY(a.size() == 7);
+      VERIFY(it->first == X{"dej"});
+      VERIFY(it->second == Y{"o4p"});
+      VERIFY(o.s.empty());
+      VERIFY(p.s.empty());
+    }
+    {
+      auto [it, res] = a.try_emplace(std::move(dek), Y("q"), Y("r"));
+      VERIFY(res);
+      VERIFY(a.size() == 8);
+      VERIFY(dek.s.empty());
+      VERIFY(it->first == X{"dek"});
+      VERIFY(it->second == Y{"q4r"});
+    }
+  }
+  { // Succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto [it, res] = a.try_emplace(std::move(y), std::move(z));
+    VERIFY(res);
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty()); // moved from
+    VERIFY(z.s.empty()); // moved from
+  }
+  { // Hinted, fail
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{2});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Hinted, fail, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{2});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Hinted, succeed, construct
+    auto a = amap;
+    Y m("m"), n("n"), o("o"), p("p"), dek("dek");
+    {
+      auto it = a.try_emplace(a.begin(), Y{"deg"}, m, n);
+      VERIFY(a.size() == 4);
+      VERIFY(it->first == X{"deg"});
+      VERIFY(it->second == Y{"m1n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.size() == 1);
+    }
+    {
+      auto it = a.try_emplace(a.begin(), Y{"deh"}, m, std::move(n));
+      VERIFY(a.size() == 5);
+      VERIFY(it->first == X{"deh"});
+      VERIFY(it->second == Y{"m2n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.empty());
+    }
+    {
+      auto it = a.try_emplace(a.begin(), Y{"dei"}, std::move(m), o);
+      VERIFY(a.size() == 6);
+      VERIFY(it->first == X{"dei"});
+      VERIFY(it->second == Y{"m3o"});
+      VERIFY(m.s.empty());
+      VERIFY(o.s.size() == 1);
+    }
+    {
+      auto it = a.try_emplace(a.begin(), Y{"dej"}, std::move(o), std::move(p));
+      VERIFY(a.size() == 7);
+      VERIFY(it->first == X{"dej"});
+      VERIFY(it->second == Y{"o4p"});
+      VERIFY(o.s.empty());
+      VERIFY(p.s.empty());
+    }
+    {
+      auto it = a.try_emplace(a.begin(), std::move(dek), Y("q"), Y("r"));
+      VERIFY(a.size() == 8);
+      VERIFY(dek.s.empty());
+      VERIFY(it->first == X{"dek"});
+      VERIFY(it->second == Y{"q4r"});
+    }
+  }
+  {  // Hinted, succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty()); // moved from
+    VERIFY(z.s.empty());  // moved from
+  }
+}
+
+void test4()  // insert_or_assign
+{
+  std::map<X, Y, cmp> amap{cmp{}};
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  { // Already there, replace
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto [it, res] = a.insert_or_assign(y, z);
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Already there, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto [it, res] = a.insert_or_assign(std::move(y), std::move(z));
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.empty());      // moved from
+  }
+  { // Succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto [it, res] = a.insert_or_assign(std::move(y), std::move(z));
+    VERIFY(res);
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty()); // moved from
+    VERIFY(z.s.empty()); // moved from
+  }
+  { // Hinted, already there, replace
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), y, z);
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Hinted, already there, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), std::move(y), std::move(z));
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.empty());      // moved from
+  }
+  {  // Hinted, succeed
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), y, z);
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  {  // Hinted, succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), std::move(y), std::move(z));
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty());  // moved from
+    VERIFY(z.s.empty());  // moved from
+  }
+}
+
+int main()
+{
+  test1();
+  test2();
+  test3();
+  test4();
+}
diff --git 
a/libstdc++-v3/testsuite/23_containers/set/modifiers/hetero/insert.cc 
b/libstdc++-v3/testsuite/23_containers/set/modifiers/hetero/insert.cc
new file mode 100644
index 00000000000..ac13b514778
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/set/modifiers/hetero/insert.cc
@@ -0,0 +1,120 @@
+// { dg-do run { target c++26 } }
+
+#include <set>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <compare>
+#include <cstring>
+#include <testsuite_hooks.h>
+
+struct Y;
+
+struct X {
+  std::string s;
+  X(std::string_view str) : s(str) {}
+  X(Y&& y);
+  X(const Y& y);
+
+  friend auto operator<=>(X const& a, X const& b) = default;
+};
+
+struct Y {
+  std::string s;
+  Y() = default;
+  Y(std::string_view sv) : s(sv) {}
+  Y(int a, int b = 0) : s(std::string('a', a + b)) {}
+  Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+  Y(const Y& y) = default;
+  Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
+  Y& operator=(const Y& y) = default;
+  friend auto operator<=>(Y const& a, Y const& b) = default;
+  friend auto operator<=>(X const& a, Y const& b) { return a.s <=> b.s; }
+};
+
+X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+X::X(const Y& y) : s(y.s) {}
+
+using cmp = std::less<void>;
+
+void test1()  // insert
+{
+  std::set<X, cmp> aset{cmp{}};
+  aset.insert({X{"abc"}, X{"def"}, X{"ghi"}});
+
+  { // Fail
+    auto a = aset;
+    Y y{"def"};
+    auto [it, res] = a.insert(y);
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Fail, move
+    auto a = aset;
+    Y y{"def"};
+    auto [it, res] = a.insert(std::move(y));
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Succeed
+    auto a = aset;
+    Y y{"deg"};
+    auto [it, res] = a.insert(y);
+    VERIFY(res);
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deg");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Succeed, move
+    auto a = aset;
+    Y y{"deg"};
+    auto [it, res] = a.insert(std::move(y));
+    VERIFY(res);
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deg");
+    VERIFY(y.s.empty());  // moved
+  }
+
+
+  { // Hinted, fail
+    auto a = aset;
+    Y y{"def"};
+    auto it = a.insert(a.begin(), y);
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Hinted, fail, move
+    auto a = aset;
+    Y y{"def"};
+    auto it = a.insert(a.begin(), std::move(y));
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Hinted, succeed
+    auto a = aset;
+    Y y{"deh"};
+    auto it = a.insert(a.begin(), y);
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deh");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Hinted, succeed, move
+    auto a = aset;
+    Y y{"deh"};
+    auto it = a.insert(a.begin(), std::move(y));
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deh");
+    VERIFY(y.s.empty());  // moved
+  }
+}
+
+int main()
+{
+  test1();
+}
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/hetero/insert.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/hetero/insert.cc
new file mode 100644
index 00000000000..8f7f88ce9e1
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/hetero/insert.cc
@@ -0,0 +1,353 @@
+// { dg-do run { target c++26 } }
+
+#include <unordered_map>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <functional>
+#include <compare>
+#include <testsuite_hooks.h>
+
+struct Y;
+
+struct X {
+  std::string s;
+  X(std::string_view str) : s(str) {}
+  X(Y&& y);
+  X(const Y& y);
+  friend bool operator==(X const& a, X const& b) = default;
+};
+
+struct Y {
+  std::string s;
+  Y() = default;
+  Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+  Y(const Y& y) = default;
+  Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
+  Y& operator=(const Y& y) = default;
+  Y(std::string_view sv) : s(sv) {}
+  Y(int n) : s(std::string('a', n)) {}
+  Y(const Y& a, const Y& b) : s(a.s + "1" + b.s) { }
+  Y(const Y& a, Y&& b)      : s(a.s + "2" + b.s) { b.s.clear(); }
+  Y(Y&& a, const Y& b)      : s(a.s + "3" + b.s) { a.s.clear(); }
+  Y(Y&& a, Y&& b)           : s(a.s + "4" + b.s) { a.s.clear(), b.s.clear(); }
+  friend bool operator==(Y const& a, Y const& b) = default;
+  friend bool operator==(X const& a, Y const& b) { return a.s == b.s; }
+};
+
+X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+X::X(const Y& y) : s(y.s) {}
+
+struct Hash {
+  using is_transparent = void;
+  template <typename T>
+    auto operator()(T const& t) const
+    { return std::hash<decltype(T::s)>{}(t.s); }
+};
+
+using Equal = std::equal_to<void>;
+
+void test1()  // op[]
+{
+  std::unordered_map<X, Y, Hash, Equal> amap;
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  Y x{"dei"}, y{"deh"}, z{"deg"};
+  amap[z] = 4;
+  VERIFY(amap.size() == 4);
+  VERIFY(z.s.size() == 3);  // not moved from.
+
+  amap[std::move(z)] = 5;
+  VERIFY(amap.size() == 4);
+  VERIFY(z.s.size() == 3);  // not moved from.
+
+  VERIFY(amap[std::move(y)] == Y{});
+  VERIFY(amap.size() == 5);
+  VERIFY(y.s.empty());      // moved from.
+
+  amap[std::move(x)] = 7;
+  VERIFY(amap.size() == 6);
+  VERIFY(x.s.empty());      // moved from
+}
+
+void test2() // at()
+{
+  std::unordered_map<X, Y, Hash, Equal> amap;
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  Y x{"def"};
+  try
+    {
+      VERIFY(2 == amap.at(x));
+      VERIFY(amap.size() == 3);
+      VERIFY(x.s.size() == 3);   // not moved from
+      VERIFY(4 == (amap.at(x) = 4));
+      VERIFY(amap.size() == 3);
+      VERIFY(x.s.size() == 3);   // not moved from
+    }
+  catch(...) { VERIFY(false); }
+
+  Y z{"deg"};
+  try
+  {
+    amap.at(z) = 4;
+    VERIFY(false);  // Should have thrown.
+  }
+  catch (std::out_of_range&) { VERIFY(amap.size() == 3); }
+  catch (...) { VERIFY(false); } // Wrong exception.
+  VERIFY(z.s.size() == 3);   // not moved from
+
+  Y y{"deh"};
+  auto const& amapr{amap};
+  try
+    {
+      amapr.at(y);
+      VERIFY(false);  // Should have thrown.
+    }
+  catch (std::out_of_range&) {  }
+  catch (...) { VERIFY(false); } // Wrong exception.
+  VERIFY(amapr.size() == 3);
+  VERIFY(y.s.size() == 3);  // not moved from
+}
+
+void test3()  // try_emplace
+{
+  std::unordered_map<X, Y, Hash, Equal> amap;
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  { // Fail, already there
+    auto a = amap;
+    auto [it, res] = a.try_emplace(Y{"def"}, Y{"xyz"});
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{2});
+  }
+  { // Fail, already there, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto [it, res] = a.try_emplace(std::move(y), std::move(z));
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{2});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Succeed, construct
+    auto a = amap;
+    Y m("m"), n("n"), o("o"), p("p"), dek("dek");
+    {
+      auto [it, res] = a.try_emplace(Y{"deg"}, m, n);
+      VERIFY(res);
+      VERIFY(a.size() == 4);
+      VERIFY(it->first == X{"deg"});
+      VERIFY(it->second == Y{"m1n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.size() == 1);
+    }
+    {
+      auto [it, res] = a.try_emplace(Y{"deh"}, m, std::move(n));
+      VERIFY(res);
+      VERIFY(a.size() == 5);
+      VERIFY(it->first == X{"deh"});
+      VERIFY(it->second == Y{"m2n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.empty());
+    }
+    {
+      auto [it, res] = a.try_emplace(Y{"dei"}, std::move(m), o);
+      VERIFY(res);
+      VERIFY(a.size() == 6);
+      VERIFY(it->first == X{"dei"});
+      VERIFY(it->second == Y{"m3o"});
+      VERIFY(m.s.empty());
+      VERIFY(o.s.size() == 1);
+    }
+    {
+      auto [it, res] = a.try_emplace(Y{"dej"}, std::move(o), std::move(p));
+      VERIFY(res);
+      VERIFY(a.size() == 7);
+      VERIFY(it->first == X{"dej"});
+      VERIFY(it->second == Y{"o4p"});
+      VERIFY(o.s.empty());
+      VERIFY(p.s.empty());
+    }
+    {
+      auto [it, res] = a.try_emplace(std::move(dek), Y("q"), Y("r"));
+      VERIFY(res);
+      VERIFY(a.size() == 8);
+      VERIFY(dek.s.empty());
+      VERIFY(it->first == X{"dek"});
+      VERIFY(it->second == Y{"q4r"});
+    }
+  }
+  { // Succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto [it, res] = a.try_emplace(std::move(y), std::move(z));
+    VERIFY(res);
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty()); // moved from
+    VERIFY(z.s.empty()); // moved from
+  }
+  { // Hinted, fail
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{2});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Hinted, fail, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{2});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Hinted, succeed, construct
+    auto a = amap;
+    Y m("m"), n("n"), o("o"), p("p"), dek("dek");
+    {
+      auto it = a.try_emplace(a.begin(), Y{"deg"}, m, n);
+      VERIFY(a.size() == 4);
+      VERIFY(it->first == X{"deg"});
+      VERIFY(it->second == Y{"m1n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.size() == 1);
+    }
+    {
+      auto it = a.try_emplace(a.begin(), Y{"deh"}, m, std::move(n));
+      VERIFY(a.size() == 5);
+      VERIFY(it->first == X{"deh"});
+      VERIFY(it->second == Y{"m2n"});
+      VERIFY(m.s.size() == 1);
+      VERIFY(n.s.empty());
+    }
+    {
+      auto it = a.try_emplace(a.begin(), Y{"dei"}, std::move(m), o);
+      VERIFY(a.size() == 6);
+      VERIFY(it->first == X{"dei"});
+      VERIFY(it->second == Y{"m3o"});
+      VERIFY(m.s.empty());
+      VERIFY(o.s.size() == 1);
+    }
+    {
+      auto it = a.try_emplace(a.begin(), Y{"dej"}, std::move(o), std::move(p));
+      VERIFY(a.size() == 7);
+      VERIFY(it->first == X{"dej"});
+      VERIFY(it->second == Y{"o4p"});
+      VERIFY(o.s.empty());
+      VERIFY(p.s.empty());
+    }
+    {
+      auto it = a.try_emplace(a.begin(), std::move(dek), Y("q"), Y("r"));
+      VERIFY(a.size() == 8);
+      VERIFY(dek.s.empty());
+      VERIFY(it->first == X{"dek"});
+      VERIFY(it->second == Y{"q4r"});
+    }
+  }
+  {  // Hinted, succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto it = a.try_emplace(a.begin(), std::move(y), std::move(z));
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty()); // moved from
+    VERIFY(z.s.empty());  // moved from
+  }
+}
+
+void test4()  // insert_or_assign
+{
+  std::unordered_map<X, Y, Hash, Equal> amap;
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"ghi"}, 3}});
+
+  { // Already there, replace
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto [it, res] = a.insert_or_assign(y, z);
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Already there, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto [it, res] = a.insert_or_assign(std::move(y), std::move(z));
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(a.at(Y{"def"}) == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.empty());      // moved from
+  }
+  { // Succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto [it, res] = a.insert_or_assign(std::move(y), std::move(z));
+    VERIFY(res);
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty()); // moved from
+    VERIFY(z.s.empty()); // moved from
+  }
+  { // Hinted, already there, replace
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), y, z);
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  { // Hinted, already there, move
+    auto a = amap;
+    Y y{"def"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), std::move(y), std::move(z));
+    VERIFY(a.size() == 3);
+    VERIFY(it->first == X{"def"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.empty());      // moved from
+  }
+  {  // Hinted, succeed
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), y, z);
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.size() == 3);  // not moved from
+    VERIFY(z.s.size() == 3);  // not moved from
+  }
+  {  // Hinted, succeed, move
+    auto a = amap;
+    Y y{"tuv"}, z{"xyz"};
+    auto it = a.insert_or_assign(a.begin(), std::move(y), std::move(z));
+    VERIFY(it->first == X{"tuv"});
+    VERIFY(it->second == Y{"xyz"});
+    VERIFY(a.size() == 4);
+    VERIFY(y.s.empty());  // moved from
+    VERIFY(z.s.empty());  // moved from
+  }
+}
+
+int main()
+{
+  test1();
+  test2();
+  test3();
+  test4();
+}
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/hetero/insert.cc
 
b/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/hetero/insert.cc
new file mode 100644
index 00000000000..6430201c9c6
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/hetero/insert.cc
@@ -0,0 +1,57 @@
+// { dg-do run { target c++26 } }
+
+#include <unordered_map>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct Y;
+
+struct X {
+  std::string s;
+  X(std::string_view str) : s(str) {}
+  X(Y&& y);
+  X(const Y& y);
+  friend bool operator==(X const& a, X const& b) = default;
+};
+
+struct Y {
+  std::string s;
+  Y() = default;
+  Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+  Y(const Y& y) = default;
+  Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
+  Y& operator=(const Y& y) = default;
+  Y(std::string_view sv) : s(sv) {}
+  Y(int a, int b = 0) : s(std::string('a', a + b)) {}
+  friend bool operator==(Y const& a, Y const& b) = default;
+  friend bool operator==(X const& a, Y const& b) { return a.s == b.s; }
+};
+
+X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+X::X(const Y& y) : s(y.s) {}
+
+struct Hash {
+  using is_transparent = void;
+  template <typename T>
+    auto operator()(T const& t) const
+    { return std::hash<decltype(T::s)>{}(t.s); }
+};
+
+using Equal = std::equal_to<void>;
+
+void test1()  // bucket
+{
+  std::unordered_multimap<X, Y, Hash, Equal> amap;
+  amap.insert({{X{"abc"}, 1}, {X{"def"}, 2}, {X{"def"}, 3}, {X{"ghi"}, 3}});
+
+  auto const& amapr{amap};
+  VERIFY(amapr.bucket(X{"def"}) == amapr.bucket(Y{"def"}));
+}
+
+int main()
+{
+  test1();
+}
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/hetero/insert.cc
 
b/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/hetero/insert.cc
new file mode 100644
index 00000000000..59ed43c16d2
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/hetero/insert.cc
@@ -0,0 +1,56 @@
+// { dg-do run { target c++26 } }
+
+#include <unordered_set>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct Y;
+
+struct X {
+  std::string s;
+  X(Y&& y);
+  X(const Y& y);
+  X(std::string_view str) : s(str) {}
+  friend bool operator==(X const& a, X const& b) = default;
+};
+
+struct Y {
+  std::string s;
+  Y() = default;
+  Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+  Y(const Y& y) = default;
+  Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
+  Y& operator=(const Y& y) = default;
+  Y(std::string_view sv) : s(sv) {}
+  friend bool operator==(Y const& a, Y const& b) = default;
+  friend bool operator==(X const& a, Y const& b) { return a.s == b.s; }
+};
+
+X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+X::X(const Y& y) : s(y.s) {}
+
+struct Hash {
+  using is_transparent = void;
+  template <typename T>
+    auto operator()(T const& t) const
+    { return std::hash<decltype(T::s)>{}(t.s); }
+};
+
+using Equal = std::equal_to<void>;
+
+void test1()  // bucket
+{
+  std::unordered_multiset<X, Hash, Equal> aset{};
+  aset.insert({X{"abc"}, X{"def"}, X{"def"}, X{"ghi"}});
+
+  auto const& asetr{aset};
+  VERIFY(asetr.bucket(X{"def"}) == asetr.bucket(Y{"def"}));
+}
+
+int main()
+{
+  test1();
+}
diff --git 
a/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/hetero/insert.cc 
b/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/hetero/insert.cc
new file mode 100644
index 00000000000..320143f2ea4
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/hetero/insert.cc
@@ -0,0 +1,134 @@
+// { dg-do run { target c++26 } }
+
+#include <unordered_set>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct Y;
+
+struct X {
+  std::string s;
+  X(std::string_view str) : s(str) {}
+  X(Y&& y);
+  X(const Y& y);
+  friend bool operator==(X const& a, X const& b) = default;
+};
+
+struct Y {
+  std::string s;
+  Y() = default;
+  Y(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+  Y(const Y& y) = default;
+  Y& operator=(Y&& y) { s = std::move(y.s); y.s.clear(); return *this; }
+  Y& operator=(const Y& y) = default;
+  Y(int a, int b = 0) : s(std::string('a', a + b)) {}
+  Y(std::string_view sv) : s(sv) {}
+  friend bool operator==(Y const& a, Y const& b) = default;
+  friend bool operator==(X const& a, Y const& b) { return a.s == b.s; }
+};
+
+X::X(Y&& y) : s(std::move(y.s)) { y.s.clear(); }
+X::X(const Y& y) : s(y.s) {}
+
+struct Hash {
+  using is_transparent = void;
+  template <typename T>
+    auto operator()(T const& t) const { return 
std::hash<decltype(T::s)>{}(t.s); }
+};
+
+using Equal = std::equal_to<void>;
+
+void test1()  // insert
+{
+  std::unordered_set<X, Hash, Equal> aset;
+  aset.insert({X{"abc"}, X{"def"}, X{"ghi"}});
+
+  { // Fail
+    auto a = aset;
+    Y y{"def"};
+    auto [it, res] = a.insert(y);
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Fail, move
+    auto a = aset;
+    Y y{"def"};
+    auto [it, res] = a.insert(std::move(y));
+    VERIFY(!res);
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Succeed
+    auto a = aset;
+    Y y{"deg"};
+    auto [it, res] = a.insert(y);
+    VERIFY(res);
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deg");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Succeed, move
+    auto a = aset;
+    Y y{"deg"};
+    auto [it, res] = a.insert(std::move(y));
+    VERIFY(res);
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deg");
+    VERIFY(y.s.empty());  // moved
+  }
+
+
+  { // Hinted, fail
+    auto a = aset;
+    Y y{"def"};
+    auto it = a.insert(a.begin(), y);
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Hinted, fail, move
+    auto a = aset;
+    Y y{"def"};
+    auto it = a.insert(a.begin(), std::move(y));
+    VERIFY(a.size() == 3);
+    VERIFY(it->s == "def");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Hinted, succeed
+    auto a = aset;
+    Y y{"deh"};
+    auto it = a.insert(a.begin(), y);
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deh");
+    VERIFY(y.s.size() == 3);  // not moved
+  }
+  { // Hinted, succeed, move
+    auto a = aset;
+    Y y{"deh"};
+    auto it = a.insert(a.begin(), std::move(y));
+    VERIFY(a.size() == 4);
+    VERIFY(it->s == "deh");
+    VERIFY(y.s.empty());  // moved
+  }
+}
+
+void test2()  // bucket
+{
+  std::unordered_set<X, Hash, Equal> aset{};
+  aset.insert({X{"abc"}, X{"def"}, X{"ghi"}});
+
+  auto const& asetr{aset};
+  VERIFY(asetr.bucket(X{"def"}) == asetr.bucket(Y{"def"}));
+}
+
+int main()
+{
+  test1();
+  test2();
+}
-- 
2.52.0

Reply via email to