diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h
index 7b0a684a2d297e8b591784cebb5177de365fdeec..aca431ae216ff8e62fed4259b2c8e40109ae8946 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -1212,6 +1212,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __nh;
       }
 
+      /// Merge from another container of the same type.
+      void
+      _M_merge_unique(_Hashtable& __src)
+      {
+	__glibcxx_assert(get_allocator() == __src.get_allocator());
+
+	auto __size = size();
+	auto __n_elt = __src.size();
+	size_type __first = 1;
+	// For a container of identical type we can use its private members.
+	auto __p = static_cast<__node_ptr>(&__src._M_before_begin);
+	while (__n_elt--)
+	  {
+	    const auto __prev = __p;
+	    __p = __p->_M_next();
+	    const auto& __node = *__p;
+	    const key_type& __k = _ExtractKey{}(__node._M_v());
+	    if (__size <= __small_size_threshold())
+	      {
+		auto __n = _M_begin();
+		for (; __n; __n = __n->_M_next())
+		  if (this->_M_key_equals(__k, *__n))
+		    break;
+		if (__n)
+		  continue;
+	      }
+
+	    __hash_code __code
+	      = _M_src_hash_code(__src.hash_function(), __k, __node);
+	    size_type __bkt = _M_bucket_index(__code);
+	    if (__size > __small_size_threshold())
+	      if (_M_find_node(__bkt, __k, __code) != nullptr)
+		continue;
+
+	    __hash_code __src_code = __src.hash_function()(__k);
+	    size_type __src_bkt = __src._M_bucket_index(__src_code);
+	    auto __nh = __src._M_extract_node(__src_bkt, __prev);
+	    _M_insert_unique_node(__bkt, __code, __nh._M_ptr,
+				  __first * __n_elt + 1);
+	    __nh.release();
+	    __first = 0;
+	    ++__size;
+	    __p = __prev;
+	  }
+      }
+
       /// Merge from a compatible container into one with unique keys.
       template<typename _Compatible_Hashtable>
 	void
@@ -1221,46 +1267,68 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      node_type>, "Node types are compatible");
 	  __glibcxx_assert(get_allocator() == __src.get_allocator());
 
+	  auto __size = size();
 	  auto __n_elt = __src.size();
+	  size_type __first = 1;
+	  // For a compatible container we can only use the public API,
+	  // so cbegin(), cend(), hash_function(), and extract(iterator).
 	  for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
 	    {
+	      --__n_elt;
 	      auto __pos = __i++;
-	      const size_type __size = size();
 	      const key_type& __k = _ExtractKey{}(*__pos);
 	      if (__size <= __small_size_threshold())
 		{
-		  bool __found = false;
-		  for (auto __n = _M_begin(); __n; __n = __n->_M_next())
+		  auto __n = _M_begin();
+		  for (; __n; __n = __n->_M_next())
 		    if (this->_M_key_equals(__k, *__n))
-		      {
-			__found = true;
-			break;
-		      }
-
-		  if (__found)
-		    {
-		      if (__n_elt != 1)
-			--__n_elt;
-		      continue;
-		    }
+		      break;
+		  if (__n)
+		    continue;
 		}
 
 	      __hash_code __code
 		= _M_src_hash_code(__src.hash_function(), __k, *__pos._M_cur);
 	      size_type __bkt = _M_bucket_index(__code);
-	      if (__size <= __small_size_threshold()
-		  || _M_find_node(__bkt, __k, __code) == nullptr)
-		{
-		  auto __nh = __src.extract(__pos);
-		  _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt);
-		  __nh.release();
-		  __n_elt = 1;
-		}
-	      else if (__n_elt != 1)
-		--__n_elt;
+	      if (__size > __small_size_threshold())
+		if (_M_find_node(__bkt, __k, __code) != nullptr)
+		  continue;
+
+	      auto __nh = __src.extract(__pos);
+	      _M_insert_unique_node(__bkt, __code, __nh._M_ptr,
+				    __first * __n_elt + 1);
+	      __nh.release();
+	      __first = 0;
+	      ++__size;
 	    }
 	}
 
+      /// Merge from another container of the same type.
+      void
+      _M_merge_multi(_Hashtable& __src)
+      {
+	__glibcxx_assert(get_allocator() == __src.get_allocator());
+
+	if (__src.size() == 0) [[__unlikely__]]
+	  return;
+
+	__node_ptr __hint = nullptr;
+	this->reserve(size() + __src.size());
+	// For a container of identical type we can use its private members.
+	auto __prev = static_cast<__node_ptr>(&__src._M_before_begin);
+	do
+	  {
+	    const auto& __node = *__prev->_M_next();
+	    const key_type& __k = _ExtractKey{}(__node._M_v());
+	    __hash_code __code = this->_M_hash_code(__k);
+	    size_type __src_bkt = __src._M_bucket_index(__node);
+	    auto __nh = __src._M_extract_node(__src_bkt, __prev);
+	    __hint = _M_insert_multi_node(__hint, __code, __nh._M_ptr)._M_cur;
+	    __nh.release();
+	  }
+	while (__prev->_M_nxt != nullptr);
+      }
+
       /// Merge from a compatible container into one with equivalent keys.
       template<typename _Compatible_Hashtable>
 	void
@@ -1272,6 +1340,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 	  __node_ptr __hint = nullptr;
 	  this->reserve(size() + __src.size());
+	  // For a compatible container we can only use the public API,
+	  // so cbegin(), cend(), hash_function(), and extract(iterator).
 	  for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
 	    {
 	      auto __pos = __i++;
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index 3b472534c66054182004aac150219b639df8e1ad..9bc1cca7e1b493d26492bee0e19c9b1de8773693 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -821,6 +821,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	void
 	merge(unordered_map<_Key, _Tp, _H2, _P2, _Alloc>& __source)
 	{
+	  if constexpr (is_same_v<_H2, _Hash> && is_same_v<_P2, _Pred>)
+	    if (std::__addressof(__source) == this) [[__unlikely__]]
+	      return;
+
 	  using _Merge_helper = _Hash_merge_helper<unordered_map, _H2, _P2>;
 	  _M_h._M_merge_unique(_Merge_helper::_S_get_table(__source));
 	}
@@ -828,7 +832,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _H2, typename _P2>
 	void
 	merge(unordered_map<_Key, _Tp, _H2, _P2, _Alloc>&& __source)
-	{ merge(__source); }
+	{
+	  using _Merge_helper = _Hash_merge_helper<unordered_map, _H2, _P2>;
+	  _M_h._M_merge_unique(_Merge_helper::_S_get_table(__source));
+	}
 
       template<typename _H2, typename _P2>
 	void
@@ -1764,6 +1771,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	void
 	merge(unordered_multimap<_Key, _Tp, _H2, _P2, _Alloc>& __source)
 	{
+	  if constexpr (is_same_v<_H2, _Hash> && is_same_v<_P2, _Pred>)
+	    if (std::__addressof(__source) == this) [[__unlikely__]]
+	      return;
+
 	  using _Merge_helper
 	    = _Hash_merge_helper<unordered_multimap, _H2, _P2>;
 	  _M_h._M_merge_multi(_Merge_helper::_S_get_table(__source));
@@ -1772,7 +1783,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _H2, typename _P2>
 	void
 	merge(unordered_multimap<_Key, _Tp, _H2, _P2, _Alloc>&& __source)
-	{ merge(__source); }
+	{
+	  using _Merge_helper
+	    = _Hash_merge_helper<unordered_multimap, _H2, _P2>;
+	  _M_h._M_merge_multi(_Merge_helper::_S_get_table(__source));
+	}
 
       template<typename _H2, typename _P2>
 	void
diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h
index 08dcfa2a9b9abfb2b21bcb41cc4d153e10abad06..a76769df9b934e0197bcee37fd11801dd4c14f1c 100644
--- a/libstdc++-v3/include/bits/unordered_set.h
+++ b/libstdc++-v3/include/bits/unordered_set.h
@@ -602,6 +602,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	void
 	merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source)
 	{
+	  if constexpr (is_same_v<_H2, _Hash> && is_same_v<_P2, _Pred>)
+	    if (std::__addressof(__source) == this) [[__unlikely__]]
+	      return;
+
 	  using _Merge_helper = _Hash_merge_helper<unordered_set, _H2, _P2>;
 	  _M_h._M_merge_unique(_Merge_helper::_S_get_table(__source));
 	}
@@ -609,7 +613,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _H2, typename _P2>
 	void
 	merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source)
-	{ merge(__source); }
+	{
+	  using _Merge_helper = _Hash_merge_helper<unordered_set, _H2, _P2>;
+	  _M_h._M_merge_unique(_Merge_helper::_S_get_table(__source));
+	}
 
       template<typename _H2, typename _P2>
 	void
@@ -1452,6 +1459,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	void
 	merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source)
 	{
+	  if constexpr (is_same_v<_H2, _Hash> && is_same_v<_P2, _Pred>)
+	    if (std::__addressof(__source) == this) [[__unlikely__]]
+	      return;
+
 	  using _Merge_helper
 	    = _Hash_merge_helper<unordered_multiset, _H2, _P2>;
 	  _M_h._M_merge_multi(_Merge_helper::_S_get_table(__source));
@@ -1460,7 +1471,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       template<typename _H2, typename _P2>
 	void
 	merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source)
-	{ merge(__source); }
+	{
+	  using _Merge_helper
+	    = _Hash_merge_helper<unordered_multiset, _H2, _P2>;
+	  _M_h._M_merge_multi(_Merge_helper::_S_get_table(__source));
+	}
 
       template<typename _H2, typename _P2>
 	void
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc
index df9d79ebeaa7c60b358642d54fda426dac67dc2d..c84ef8cb6f7577d43e9dc5fd58f3ee54f5c95e92 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/merge.cc
@@ -290,6 +290,133 @@ test06()
   VERIFY( c2.empty() );
 }
 
+void
+test07()
+{
+  test_type c1{ {1, 1}, {3, 3}, {5, 5} };
+  test_type c2{ {2, 2}, {4, 4}, {6, 6} };
+  const test_type c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+  const test_type c4 = c1;
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  test_type c5 = c3;
+  c2.merge(c5);
+  VERIFY( c2 == c3 );
+  VERIFY( c5 == c3 );
+
+  c5.emplace(9, 9);
+  c2.merge(c5);
+  VERIFY( c2.size() == c3.size() + 1 );
+  VERIFY( c5 == c3 );
+}
+
+void
+test08()
+{
+  test_type c1{ {1, 1}, {3, 3}, {5, 5} };
+  std::unordered_map<int, int, xhash<int>, equal> c2{ {2, 2}, {4, 4}, {6, 6} };
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+  const test_type c4 = c1;
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( equal_elements(c1, c3) );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  auto c5 = c3;
+  c2.merge(c5);
+  VERIFY( c2 == c3 );
+  VERIFY( c5 == c3 );
+
+  c5.emplace(9, 9);
+  c2.merge(c5);
+  VERIFY( c2.size() == c3.size() + 1 );
+  VERIFY( c5 == c3 );
+}
+
+void
+test09()
+{
+  struct stateful_hash
+  {
+    size_t seed = 0;
+
+    auto operator()(const int& i) const noexcept
+    { return std::hash<int>()(i) + seed; }
+  };
+
+  using map_type = std::unordered_map<int, int, stateful_hash>;
+  map_type c1({ {1, 1}, {3, 3}, {5, 5} }, 0, stateful_hash{1});
+  map_type c2({ {2, 2}, {4, 4}, {6, 6} }, 0, stateful_hash{2});
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  test_type c5{ {-1, 1}, {-3, 3}, {-5, 5} };
+  c2.merge(c5);
+  VERIFY( c2.size() == 6 );
+  VERIFY( c5.empty() );
+  auto c6 = c3;
+  c6.merge(c2);
+  VERIFY( c6.size() == 6 );
+  VERIFY( c2.size() == 3 );
+}
+
 int
 main()
 {
@@ -299,4 +426,7 @@ main()
   test04();
   test05();
   test06();
+  test07();
+  test08();
+  test09();
 }
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/merge.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/merge.cc
index 3e2b26380f9ad96f71ab22a2b9c5ab0228c34249..bf03c4cc34e42705d041d8dd2fdc99b47f050dda 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/merge.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/modifiers/merge.cc
@@ -105,6 +105,122 @@ test04()
   VERIFY( c2.empty() );
 }
 
+void
+test07()
+{
+  test_type c1{ {1, 1}, {3, 3}, {5, 5} };
+  test_type c2{ {2, 2}, {4, 4}, {6, 6} };
+  const test_type c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+  const test_type c4 = c1;
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  auto c5 = c4;
+  c2.merge(c5);
+  VERIFY( c2.size() == 9 );
+  VERIFY( c5.empty() );
+
+  c5 = c4;
+  c5.emplace(9, 9);
+  c2.merge(c5);
+  VERIFY( c2.size() == 16 );
+  VERIFY( c5.empty() );
+}
+
+void
+test08()
+{
+  test_type c1{ {1, 1}, {3, 3}, {5, 5} };
+  std::unordered_map<int, int, hash, equal> c2{ {2, 2}, {4, 4}, {6, 6} };
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+  const test_type c4 = c1;
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+}
+
+void
+test09()
+{
+  struct stateful_hash
+  {
+    size_t seed = 0;
+
+    auto operator()(const int& i) const noexcept
+    { return std::hash<int>()(i) + seed; }
+  };
+
+  using map_type = std::unordered_multimap<int, int, stateful_hash>;
+  map_type c1({ {1, 1}, {3, 3}, {5, 5} }, 0, stateful_hash{1});
+  map_type c2({ {2, 2}, {4, 4}, {6, 6} }, 0, stateful_hash{2});
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  test_type c4{ {-1, 0}, {-3, 0}, {-5, 0} };
+  c2.merge(c4);
+  VERIFY( c2.size() == 6 );
+  VERIFY( c4.empty() );
+  auto c6 = c3;
+  c6.merge(c2);
+  VERIFY( c6.size() == 9 );
+  VERIFY( c2.size() == 0 );
+}
 int
 main()
 {
@@ -112,4 +228,7 @@ main()
   test02();
   test03();
   test04();
+  test07();
+  test08();
+  test09();
 }
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/merge.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/merge.cc
index 41f98f2824927b7959db02b3e91b3edb63761e85..291b4866281e75aa92fcd00b8a82288af6f67358 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/merge.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/modifiers/merge.cc
@@ -126,6 +126,124 @@ test05()
   VERIFY( c2.empty() );
 }
 
+void
+test07()
+{
+  test_type c1{ 1, 3, 5 };
+  test_type c2{ 2, 4, 6 };
+  const test_type c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+  const test_type c4 = c1;
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  auto c5 = c4;
+  c2.merge(c5);
+  VERIFY( c2.size() == 9 );
+  VERIFY( c5.empty() );
+
+  c5 = c4;
+  c5.emplace(9);
+  c2.merge(c5);
+  VERIFY( c2.size() == 16 );
+  VERIFY( c5.empty() );
+
+}
+
+void
+test08()
+{
+  test_type c1{ 1, 3, 5 };
+  std::unordered_set<int, hash, equal> c2{ 2, 4, 6 };
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+  const test_type c4 = c1;
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+}
+
+void
+test09()
+{
+  struct stateful_hash
+  {
+    size_t seed = 0;
+
+    auto operator()(const int& i) const noexcept
+    { return std::hash<int>()(i) + seed; }
+  };
+
+  using set_type = std::unordered_multiset<int, stateful_hash>;
+  set_type c1({ 1, 3, 5 }, 0, stateful_hash{1});
+  set_type c2({ 2, 4, 6 }, 0, stateful_hash{2});
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  test_type c4{ -1, -3, -5 };
+  c2.merge(c4);
+  VERIFY( c2.size() == 6 );
+  VERIFY( c4.empty() );
+  auto c6 = c3;
+  c6.merge(c2);
+  VERIFY( c6.size() == 9 );
+  VERIFY( c2.size() == 0 );
+}
+
 int
 main()
 {
@@ -134,4 +252,7 @@ main()
   test03();
   test04();
   test05();
+  test07();
+  test08();
+  test09();
 }
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/merge.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/merge.cc
index 45fe3952ebbbae3f8fff22316c999aa8d3efe028..6cf2c98d4b3ef979f06cb72ba160eade4d128e42 100644
--- a/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/merge.cc
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/modifiers/merge.cc
@@ -167,6 +167,131 @@ test04()
   VERIFY( c2.empty() );
 }
 
+void
+test07()
+{
+  test_type c1{ 1, 3, 5 };
+  test_type c2{ 2, 4, 6 };
+  const test_type c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  test_type c4 = c3;
+  c2.merge(c4);
+  VERIFY( c2 == c3 );
+  VERIFY( c4 == c3 );
+
+  c4.emplace(9);
+  c2.merge(c4);
+  VERIFY( c2.size() == c3.size() + 1 );
+  VERIFY( c4 == c3 );
+}
+
+void
+test08()
+{
+  test_type c1{ 1, 3, 5 };
+  std::unordered_set<int, hash, equal> c2{ 2, 4, 6 };
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( equal_elements(c1, c3) );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  auto c4 = c3;
+  c2.merge(c4);
+  VERIFY( c2 == c3 );
+  VERIFY( c4 == c3 );
+
+  c4.emplace(9);
+  c2.merge(c4);
+  VERIFY( c2.size() == c3.size() + 1 );
+  VERIFY( c4 == c3 );
+}
+
+void
+test09()
+{
+  struct stateful_hash
+  {
+    size_t seed = 0;
+
+    auto operator()(const int& i) const noexcept
+    { return std::hash<int>()(i) + seed; }
+  };
+
+  using set_type = std::unordered_set<int, stateful_hash>;
+  set_type c1({ 1, 3, 5 }, 0, stateful_hash{1});
+  set_type c2({ 2, 4, 6 }, 0, stateful_hash{2});
+  const auto c3 = c2;
+
+  c1.merge(c2);
+  VERIFY( c1.size() == 6 );
+  VERIFY( c2.empty() );
+
+  c2 = c3;
+  c1.clear();
+  c1.merge(std::move(c2));
+  VERIFY( c1 == c3 );
+  VERIFY( c2.empty() );
+
+  c2.merge(std::move(c1));
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c1);
+  VERIFY( c1.empty() );
+  VERIFY( c2 == c3 );
+
+  c2.merge(c2);
+  VERIFY( c2 == c3 );
+
+  test_type c4{ -1, -3, -5 };
+  c2.merge(c4);
+  VERIFY( c2.size() == 6 );
+  VERIFY( c4.empty() );
+  auto c6 = c3;
+  c6.merge(c2);
+  VERIFY( c6.size() == 6 );
+  VERIFY( c2.size() == 3 );
+}
+
 int
 main()
 {
@@ -174,4 +299,7 @@ main()
   test02();
   test03();
   test04();
+  test07();
+  test08();
+  test09();
 }