[libcxx-commits] [libcxx] [libc++] Implement N4258(Cleaning-up noexcept in the Library) (PR #120312)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 17 14:03:03 PST 2024


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/120312

None

>From 1818c0259b596ad1d4b9e96532d9b30c3b93ddb4 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 17 Dec 2024 23:02:40 +0100
Subject: [PATCH] [libc++] Implement N4258(Cleaning-up noexcept in the Library)

---
 libcxx/docs/ReleaseNotes/20.rst               |  1 +
 libcxx/docs/Status/Cxx17Papers.csv            |  2 +-
 libcxx/include/__hash_table                   | 28 +++++--
 libcxx/include/__tree                         | 29 +++++--
 libcxx/include/deque                          | 17 +++--
 libcxx/include/forward_list                   | 16 +++-
 libcxx/include/list                           | 18 +++--
 .../move_assign_noexcept.compile.pass.cpp     | 58 ++++++++++++++
 .../map.cons/move_assign_noexcept.pass.cpp    | 59 --------------
 .../move_assign_noexcept.compile.pass.cpp     | 59 ++++++++++++++
 .../move_assign_noexcept.pass.cpp             | 59 --------------
 .../move_assign_noexcept.compile.pass.cpp     | 58 ++++++++++++++
 .../move_assign_noexcept.pass.cpp             | 58 --------------
 .../move_assign_noexcept.compile.pass.cpp     | 58 ++++++++++++++
 .../set.cons/move_assign_noexcept.pass.cpp    | 56 +++++++-------
 .../move_assign_noexcept.compile.pass.cpp     | 46 +++++++++++
 .../deque.cons/move_assign_noexcept.pass.cpp  | 57 --------------
 .../move_assign_noexcept.compile.pass.cpp     | 47 ++++++++++++
 .../move_assign_noexcept.pass.cpp             | 57 --------------
 .../move_assign_noexcept.compile.pass.cpp     | 46 +++++++++++
 .../list.cons/move_assign_noexcept.pass.cpp   | 57 --------------
 .../move_assign_noexcept.compile.pass.cpp     | 75 ++++++++++++++++++
 .../move_assign_noexcept.pass.cpp             | 76 -------------------
 .../move_assign_noexcept.compile.pass.cpp     | 75 ++++++++++++++++++
 .../move_assign_noexcept.pass.cpp             | 75 ------------------
 .../move_assign_noexcept.compile.pass.cpp     | 71 +++++++++++++++++
 .../move_assign_noexcept.pass.cpp             | 75 ------------------
 .../move_assign_noexcept.compile.pass.cpp     | 69 +++++++++++++++++
 .../move_assign_noexcept.pass.cpp             | 75 ------------------
 29 files changed, 772 insertions(+), 705 deletions(-)
 create mode 100644 libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.compile.pass.cpp
 create mode 100644 libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.compile.pass.cpp
 delete mode 100644 libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.pass.cpp

diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index c8a07fb8b73348..935bfde56fc51c 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -45,6 +45,7 @@ Implemented Papers
 - ``std::jthread`` and ``<stop_token>`` are not guarded behind ``-fexperimental-library`` anymore
 - P2674R1: A trait for implicit lifetime types (`Github <https://github.com/llvm/llvm-project/issues/105259>`__)
 - P0429R9: A Standard ``flat_map`` is partially implemented and ``flat_map`` is provided (`Github <https://github.com/llvm/llvm-project/issues/105190>`__)
+- N4258: Cleaning-up noexcept in the Library (`Github <https://github.com/llvm/llvm-project/issues/99937>`__)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv
index a589207085d36f..0ec385cecf27f0 100644
--- a/libcxx/docs/Status/Cxx17Papers.csv
+++ b/libcxx/docs/Status/Cxx17Papers.csv
@@ -3,7 +3,7 @@
 "`N4089 <https://wg21.link/N4089>`__","Safe conversions in ``unique_ptr<T[]>``\ .","2014-11 (Urbana)","|In Progress|","3.9",""
 "`N4169 <https://wg21.link/N4169>`__","A proposal to add invoke function template","2014-11 (Urbana)","|Complete|","3.7",""
 "`N4190 <https://wg21.link/N4190>`__","Removing auto_ptr, random_shuffle(), And Old <functional> Stuff.","2014-11 (Urbana)","|Complete|","15",""
-"`N4258 <https://wg21.link/N4258>`__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|In Progress|","3.7",""
+"`N4258 <https://wg21.link/N4258>`__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|Complete|","20",""
 "`N4259 <https://wg21.link/N4259>`__","Wording for std::uncaught_exceptions","2014-11 (Urbana)","|Complete|","3.7","``std::uncaught_exception`` is deprecated since LLVM 20"
 "`N4277 <https://wg21.link/N4277>`__","TriviallyCopyable ``reference_wrapper``\ .","2014-11 (Urbana)","|Complete|","3.2",""
 "`N4279 <https://wg21.link/N4279>`__","Improved insertion interface for unique-key maps.","2014-11 (Urbana)","|Complete|","3.7",""
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index fe7465a84c4024..24c9df60620be6 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -772,9 +772,16 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u);
   _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u)
-      _NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&&
-                     is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable<hasher>::value&&
-                         is_nothrow_move_assignable<key_equal>::value);
+#ifndef _LIBCPP_CXX03_LANG
+      noexcept(is_nothrow_move_assignable<hasher>::value && is_nothrow_move_assignable<key_equal>::value &&
+               ((__node_traits::propagate_on_container_move_assignment::value &&
+                 is_nothrow_move_assignable<__node_allocator>::value)
+#  if _LIBCPP_STD_VER >= 17
+                || allocator_traits<__node_allocator>::is_always_equal::value
+#  endif
+                ))
+#endif
+          ;
   template <class _InputIterator>
   _LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last);
   template <class _InputIterator>
@@ -1240,10 +1247,17 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
-inline __hash_table<_Tp, _Hash, _Equal, _Alloc>&
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_(
-    __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&&
-        is_nothrow_move_assignable<hasher>::value&& is_nothrow_move_assignable<key_equal>::value) {
+inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u)
+#ifndef _LIBCPP_CXX03_LANG
+    noexcept(is_nothrow_move_assignable<hasher>::value && is_nothrow_move_assignable<key_equal>::value &&
+             ((__node_traits::propagate_on_container_move_assignment::value &&
+               is_nothrow_move_assignable<__node_allocator>::value)
+#  if _LIBCPP_STD_VER >= 17
+              || allocator_traits<__node_allocator>::is_always_equal::value
+#  endif
+              ))
+#endif
+{
   __move_assign(__u, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
   return *this;
 }
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index f6ef21cdaa5b98..1c170b999afc37 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -989,9 +989,18 @@ public:
   _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t) _NOEXCEPT_(
       is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<value_compare>::value);
   _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t, const allocator_type& __a);
-  _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) _NOEXCEPT_(
-      __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<value_compare>::value&&
-          is_nothrow_move_assignable<__node_allocator>::value);
+  _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t)
+#ifndef _LIBCPP_CXX03_LANG
+      noexcept(is_nothrow_move_assignable<value_compare>::value &&
+               ((__node_traits::propagate_on_container_move_assignment::value &&
+                 is_nothrow_move_assignable<__node_allocator>::value)
+#  if _LIBCPP_STD_VER >= 17
+                || allocator_traits<__node_allocator>::is_always_equal::value)
+#  endif
+      )
+#endif
+          ;
+
   _LIBCPP_HIDE_FROM_ABI ~__tree();
 
   _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__begin_node()); }
@@ -1522,10 +1531,16 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) {
 }
 
 template <class _Tp, class _Compare, class _Allocator>
-__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) _NOEXCEPT_(
-    __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<value_compare>::value&&
-        is_nothrow_move_assignable<__node_allocator>::value)
-
+__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t)
+#ifndef _LIBCPP_CXX03_LANG
+    noexcept(is_nothrow_move_assignable<value_compare>::value &&
+             ((__node_traits::propagate_on_container_move_assignment::value &&
+               is_nothrow_move_assignable<__node_allocator>::value)
+#  if _LIBCPP_STD_VER >= 17
+              || allocator_traits<__node_allocator>::is_always_equal::value)
+#  endif
+    )
+#endif
 {
   __move_assign(__t, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
   return *this;
diff --git a/libcxx/include/deque b/libcxx/include/deque
index 63eb8365531069..21bfad2201c9c1 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -672,9 +672,13 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI deque(deque&& __c) noexcept(is_nothrow_move_constructible<allocator_type>::value);
   _LIBCPP_HIDE_FROM_ABI deque(deque&& __c, const __type_identity_t<allocator_type>& __a);
-  _LIBCPP_HIDE_FROM_ABI deque&
-  operator=(deque&& __c) noexcept(__alloc_traits::propagate_on_container_move_assignment::value &&
-                                  is_nothrow_move_assignable<allocator_type>::value);
+  _LIBCPP_HIDE_FROM_ABI deque& operator=(deque&& __c) noexcept(
+      (__alloc_traits::propagate_on_container_move_assignment::value &&
+       is_nothrow_move_assignable<allocator_type>::value)
+#    if _LIBCPP_STD_VER >= 17
+      || allocator_traits<allocator_type>::is_always_equal::value
+#    endif
+  );
 
   _LIBCPP_HIDE_FROM_ABI void assign(initializer_list<value_type> __il) { assign(__il.begin(), __il.end()); }
 #  endif // _LIBCPP_CXX03_LANG
@@ -1377,8 +1381,11 @@ inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t<alloca
 
 template <class _Tp, class _Allocator>
 inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) noexcept(
-    __alloc_traits::propagate_on_container_move_assignment::value &&
-    is_nothrow_move_assignable<allocator_type>::value) {
+    (__alloc_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable<allocator_type>::value)
+#    if _LIBCPP_STD_VER >= 17
+    || allocator_traits<allocator_type>::is_always_equal::value
+#    endif
+) {
   __move_assign(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
   return *this;
 }
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index 23e8e51632171e..295ba8c5340ef9 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -714,8 +714,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list<value_type> __il, const allocator_type& __a);
 
   _LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept(
-      __node_traits::propagate_on_container_move_assignment::value &&
-      is_nothrow_move_assignable<allocator_type>::value);
+      (__node_traits::propagate_on_container_move_assignment::value &&
+       is_nothrow_move_assignable<allocator_type>::value)
+#    if _LIBCPP_STD_VER >= 17
+      || allocator_traits<allocator_type>::is_always_equal::value
+#    endif
+  );
 
   _LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list<value_type> __il);
 
@@ -1000,8 +1004,12 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) {
 }
 
 template <class _Tp, class _Alloc>
-inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) _NOEXCEPT_(
-    __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<allocator_type>::value) {
+inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept(
+    (__node_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable<allocator_type>::value)
+#    if _LIBCPP_STD_VER >= 17
+    || allocator_traits<allocator_type>::is_always_equal::value
+#    endif
+) {
   __move_assign(__x, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
   return *this;
 }
diff --git a/libcxx/include/list b/libcxx/include/list
index a9d14272742bd4..2b3006aa4067dc 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -727,9 +727,13 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI list(list&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value);
   _LIBCPP_HIDE_FROM_ABI list(list&& __c, const __type_identity_t<allocator_type>& __a);
-  _LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c)
-      _NOEXCEPT_(__node_alloc_traits::propagate_on_container_move_assignment::value&&
-                     is_nothrow_move_assignable<__node_allocator>::value);
+  _LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) noexcept(
+      (__node_alloc_traits::propagate_on_container_move_assignment::value &&
+       is_nothrow_move_assignable<__node_allocator>::value)
+#    if _LIBCPP_STD_VER >= 17
+      || allocator_traits<allocator_type>::is_always_equal::value
+#    endif
+  );
 
   _LIBCPP_HIDE_FROM_ABI list& operator=(initializer_list<value_type> __il) {
     assign(__il.begin(), __il.end());
@@ -1066,8 +1070,12 @@ inline list<_Tp, _Alloc>::list(list&& __c, const __type_identity_t<allocator_typ
 
 template <class _Tp, class _Alloc>
 inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(list&& __c) noexcept(
-    __node_alloc_traits::propagate_on_container_move_assignment::value &&
-    is_nothrow_move_assignable<__node_allocator>::value) {
+    (__node_alloc_traits::propagate_on_container_move_assignment::value &&
+     is_nothrow_move_assignable<__node_allocator>::value)
+#    if _LIBCPP_STD_VER >= 17
+    || allocator_traits<allocator_type>::is_always_equal::value
+#    endif
+) {
   __move_assign(__c, integral_constant<bool, __node_alloc_traits::propagate_on_container_move_assignment::value>());
   return *this;
 }
diff --git a/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..3f00129915a9bf
--- /dev/null
+++ b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+
+// map& operator=(map&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <map>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using multimap_alloc = std::map<MoveOnly, MoveOnly, std::less<MoveOnly>, Alloc<std::pair<const MoveOnly, MoveOnly>>>;
+
+static_assert(std::is_nothrow_move_assignable<multimap_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<multimap_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<multimap_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<multimap_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<multimap_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::map<int, int, some_comp<int>>>::value, "");
diff --git a/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 82a5dbac126102..00000000000000
--- a/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <map>
-
-// map& operator=(map&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <map>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-int main(int, char**)
-{
-    typedef std::pair<const MoveOnly, MoveOnly> V;
-    {
-        typedef std::map<MoveOnly, MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::map<MoveOnly, MoveOnly, std::less<MoveOnly>, test_allocator<V>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::map<MoveOnly, MoveOnly, std::less<MoveOnly>, other_allocator<V>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::map<MoveOnly, MoveOnly, some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..d5db96e4ca57be
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+
+// multimap& operator=(multimap&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <map>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using multimap_alloc =
+    std::multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, Alloc<std::pair<const MoveOnly, MoveOnly>>>;
+
+static_assert(std::is_nothrow_move_assignable<multimap_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<multimap_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<multimap_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<multimap_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<multimap_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::multimap<int, int, some_comp<int>>>::value, "");
diff --git a/libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 4cd8c19fce5f9d..00000000000000
--- a/libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <map>
-
-// multimap& operator=(multimap&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <map>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-int main(int, char**)
-{
-    typedef std::pair<const MoveOnly, MoveOnly> V;
-    {
-        typedef std::multimap<MoveOnly, MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, test_allocator<V>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, other_allocator<V>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::multimap<MoveOnly, MoveOnly, some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..7565c50363a1e9
--- /dev/null
+++ b/libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <set>
+
+// multiset& operator=(multiset&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <set>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_set_alloc = std::set<MoveOnly, std::less<MoveOnly>, Alloc<MoveOnly>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::set<int, some_comp<int>>>::value, "");
diff --git a/libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.pass.cpp
deleted file mode 100644
index a94b5b1abf1e5c..00000000000000
--- a/libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <set>
-
-// multiset& operator=(multiset&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <set>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::multiset<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::multiset<MoveOnly, std::less<MoveOnly>, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::multiset<MoveOnly, std::less<MoveOnly>, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::multiset<MoveOnly, some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..4115c44a2e92cf
--- /dev/null
+++ b/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <set>
+
+// set& operator=(set&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <set>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_map_alloc = std::set<MoveOnly, std::less<MoveOnly>, Alloc<MoveOnly>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_map_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_map_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_map_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_map_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<unordered_map_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::set<int, some_comp<int>>>::value, "");
diff --git a/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.pass.cpp
index 9c177f219dc7b2..2768d3f46d06f4 100644
--- a/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.pass.cpp
@@ -19,40 +19,40 @@
 // UNSUPPORTED: c++03
 
 #include <set>
-#include <cassert>
 
-#include "test_macros.h"
 #include "MoveOnly.h"
 #include "test_allocator.h"
 
 template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
 };
 
-int main(int, char**)
-{
-    {
-        typedef std::set<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::set<MoveOnly, std::less<MoveOnly>, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_set_alloc = std::set<MoveOnly, std::less<MoveOnly>, Alloc<MoveOnly>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<not_always_equal_alloc>>::value, "");
 #if defined(_LIBCPP_VERSION)
-    {
-        typedef std::set<MoveOnly, std::less<MoveOnly>, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<other_allocator>>::value, "");
 #endif // _LIBCPP_VERSION
-    {
-        typedef std::set<MoveOnly, some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
+static_assert(!std::is_nothrow_move_assignable<std::set<int, some_comp<int>>>::value, "");
diff --git a/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..b1d512fdfd6b6e
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <deque>
+
+// deque& operator=(deque&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <deque>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+static_assert(std::is_nothrow_move_assignable<std::deque<MoveOnly>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::deque<MoveOnly, test_allocator<MoveOnly>>>::value, "");
+static_assert(std::is_nothrow_move_assignable<std::deque<MoveOnly, always_equal_alloc<MoveOnly>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::deque<MoveOnly, not_always_equal_alloc<MoveOnly>>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<std::deque<MoveOnly, other_allocator<MoveOnly>>>::value, "");
+#endif // _LIBCPP_VERSION
diff --git a/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.pass.cpp
deleted file mode 100644
index cbefbf6dae9129..00000000000000
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <deque>
-
-// deque& operator=(deque&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <deque>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_alloc
-{
-    typedef T value_type;
-    some_alloc(const some_alloc&);
-    void allocate(std::size_t);
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::deque<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::deque<MoveOnly, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::deque<MoveOnly, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::deque<MoveOnly, some_alloc<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..b173876a7c6a37
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <forward_list>
+
+// forward_list& operator=(forward_list&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <forward_list>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+static_assert(std::is_nothrow_move_assignable<std::forward_list<MoveOnly>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::forward_list<MoveOnly, test_allocator<MoveOnly>>>::value, "");
+static_assert(std::is_nothrow_move_assignable<std::forward_list<MoveOnly, always_equal_alloc<MoveOnly>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::forward_list<MoveOnly, not_always_equal_alloc<MoveOnly>>>::value,
+              "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<std::forward_list<MoveOnly, other_allocator<MoveOnly>>>::value, "");
+#endif // _LIBCPP_VERSION
diff --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.pass.cpp
deleted file mode 100644
index f361e373d23ffc..00000000000000
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <forward_list>
-
-// forward_list& operator=(forward_list&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <forward_list>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_alloc
-{
-    typedef T value_type;
-    some_alloc(const some_alloc&);
-    void allocate(std::size_t);
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::forward_list<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::forward_list<MoveOnly, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::forward_list<MoveOnly, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::forward_list<MoveOnly, some_alloc<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..b7bdbddc802e62
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <list>
+
+// list& operator=(list&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <list>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+static_assert(std::is_nothrow_move_assignable<std::list<MoveOnly>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::list<MoveOnly, test_allocator<MoveOnly>>>::value, "");
+static_assert(std::is_nothrow_move_assignable<std::list<MoveOnly, always_equal_alloc<MoveOnly>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::list<MoveOnly, not_always_equal_alloc<MoveOnly>>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<std::list<MoveOnly, other_allocator<MoveOnly>>>::value, "");
+#endif // _LIBCPP_VERSION
diff --git a/libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 9df8413bb19c4c..00000000000000
--- a/libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <list>
-
-// list& operator=(list&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <list>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_alloc
-{
-    typedef T value_type;
-    some_alloc(const some_alloc&);
-    void allocate(std::size_t);
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::list<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::list<MoveOnly, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::list<MoveOnly, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::list<MoveOnly, some_alloc<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..aca0c094b60921
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// unordered_map& operator=(unordered_map&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <unordered_map>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_hash {
+  using value_type = T;
+  some_hash();
+  some_hash(const some_hash&);
+  some_hash& operator=(const some_hash&);
+
+  std::size_t operator()(T const&) const;
+};
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_set_alloc =
+    std::unordered_map<MoveOnly,
+                       MoveOnly,
+                       std::hash<MoveOnly>,
+                       std::equal_to<MoveOnly>,
+                       Alloc<std::pair<const MoveOnly, MoveOnly>>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::unordered_map<int, int, some_hash<int>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::unordered_map<int, int, std::hash<int>, some_comp<int>>>::value,
+              "");
diff --git a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 9d50537216716a..00000000000000
--- a/libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <unordered_map>
-
-// unordered_map& operator=(unordered_map&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <unordered_map>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-template <class T>
-struct some_hash
-{
-    typedef T value_type;
-    some_hash();
-    some_hash(const some_hash&);
-    some_hash& operator=(const some_hash&);
-
-    std::size_t operator()(T const&) const;
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::unordered_map<MoveOnly, MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_map<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                           std::equal_to<MoveOnly>, test_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::unordered_map<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                          std::equal_to<MoveOnly>, other_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::unordered_map<MoveOnly, MoveOnly, some_hash<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_map<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                                                         some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..41f0831a1281ee
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// unordered_multimap& operator=(unordered_multimap&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <unordered_map>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_hash {
+  using value_type = T;
+  some_hash();
+  some_hash(const some_hash&);
+  some_hash& operator=(const some_hash&);
+
+  std::size_t operator()(T const&) const;
+};
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_set_alloc =
+    std::unordered_multimap<MoveOnly,
+                            MoveOnly,
+                            std::hash<MoveOnly>,
+                            std::equal_to<MoveOnly>,
+                            Alloc<std::pair<const MoveOnly, MoveOnly>>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::unordered_map<int, int, some_hash<int>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::unordered_map<int, int, std::hash<int>, some_comp<int>>>::value,
+              "");
diff --git a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 2cd99546e5bd2a..00000000000000
--- a/libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <unordered_map>
-
-// unordered_multimap& operator=(unordered_multimap&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <unordered_map>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-template <class T>
-struct some_hash
-{
-    typedef T value_type;
-    some_hash();
-    some_hash(const some_hash&);
-    some_hash& operator=(const some_hash&);
-    std::size_t operator()(T const&) const;
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::unordered_multimap<MoveOnly, MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_multimap<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                           std::equal_to<MoveOnly>, test_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::unordered_multimap<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                          std::equal_to<MoveOnly>, other_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_multimap<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                                                         some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..ca79c3d8978c0d
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// unordered_multiset& operator=(unordered_multiset&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <unordered_set>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_hash {
+  using value_type = T;
+  some_hash();
+  some_hash(const some_hash&);
+  some_hash& operator=(const some_hash&);
+
+  std::size_t operator()(T const&) const;
+};
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_set_alloc =
+    std::unordered_multiset<MoveOnly, std::hash<MoveOnly>, std::equal_to<MoveOnly>, Alloc<MoveOnly>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::unordered_multiset<int, some_hash<int>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::unordered_multiset<int, std::hash<int>, some_comp<int>>>::value,
+              "");
diff --git a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 9dbca6e3e86744..00000000000000
--- a/libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <unordered_set>
-
-// unordered_multiset& operator=(unordered_multiset&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <unordered_set>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-template <class T>
-struct some_hash
-{
-    typedef T value_type;
-    some_hash();
-    some_hash(const some_hash&);
-    some_hash& operator=(const some_hash&);
-    std::size_t operator()(T const&) const;
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::unordered_multiset<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_multiset<MoveOnly, std::hash<MoveOnly>,
-                           std::equal_to<MoveOnly>, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::unordered_multiset<MoveOnly, std::hash<MoveOnly>,
-                          std::equal_to<MoveOnly>, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::unordered_multiset<MoveOnly, some_hash<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_multiset<MoveOnly, std::hash<MoveOnly>,
-                                                         some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}
diff --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.compile.pass.cpp
new file mode 100644
index 00000000000000..6e2ea79d122ac1
--- /dev/null
+++ b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.compile.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_set>
+
+// unordered_set& operator=(unordered_set&& c)
+//     noexcept(
+//          allocator_type::propagate_on_container_move_assignment::value &&
+//          is_nothrow_move_assignable<allocator_type>::value &&
+//          is_nothrow_move_assignable<key_compare>::value);
+
+// This tests a conforming extension
+
+// UNSUPPORTED: c++03
+
+#include <unordered_set>
+
+#include "MoveOnly.h"
+#include "test_allocator.h"
+
+template <class T>
+struct some_hash {
+  using value_type = T;
+  some_hash();
+  some_hash(const some_hash&);
+  some_hash& operator=(const some_hash&);
+
+  std::size_t operator()(T const&) const;
+};
+
+template <class T>
+struct some_comp {
+  using value_type = T;
+  some_comp& operator=(const some_comp&);
+  bool operator()(const T&, const T&) const { return false; }
+};
+
+template <class T>
+struct always_equal_alloc {
+  using value_type = T;
+  always_equal_alloc(const always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <class T>
+struct not_always_equal_alloc {
+  int i;
+  using value_type = T;
+  not_always_equal_alloc(const not_always_equal_alloc&);
+  void allocate(std::size_t);
+};
+
+template <template <class> class Alloc>
+using unordered_set_alloc = std::unordered_set<MoveOnly, std::hash<MoveOnly>, std::equal_to<MoveOnly>, Alloc<MoveOnly>>;
+
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<std::allocator>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<test_allocator>>::value, "");
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<always_equal_alloc>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<unordered_set_alloc<not_always_equal_alloc>>::value, "");
+#if defined(_LIBCPP_VERSION)
+static_assert(std::is_nothrow_move_assignable<unordered_set_alloc<other_allocator>>::value, "");
+#endif // _LIBCPP_VERSION
+static_assert(!std::is_nothrow_move_assignable<std::unordered_set<int, some_hash<int>>>::value, "");
+static_assert(!std::is_nothrow_move_assignable<std::unordered_set<int, std::hash<int>, some_comp<int>>>::value, "");
diff --git a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.pass.cpp b/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.pass.cpp
deleted file mode 100644
index 1ff2a7b471a1d7..00000000000000
--- a/libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.pass.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <unordered_set>
-
-// unordered_set& operator=(unordered_set&& c)
-//     noexcept(
-//          allocator_type::propagate_on_container_move_assignment::value &&
-//          is_nothrow_move_assignable<allocator_type>::value &&
-//          is_nothrow_move_assignable<key_compare>::value);
-
-// This tests a conforming extension
-
-// UNSUPPORTED: c++03
-
-#include <unordered_set>
-#include <cassert>
-
-#include "test_macros.h"
-#include "MoveOnly.h"
-#include "test_allocator.h"
-
-template <class T>
-struct some_comp
-{
-    typedef T value_type;
-    some_comp& operator=(const some_comp&);
-    bool operator()(const T&, const T&) const { return false; }
-};
-
-template <class T>
-struct some_hash
-{
-    typedef T value_type;
-    some_hash();
-    some_hash(const some_hash&);
-    some_hash& operator=(const some_hash&);
-    std::size_t operator()(T const&) const;
-};
-
-int main(int, char**)
-{
-    {
-        typedef std::unordered_set<MoveOnly> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_set<MoveOnly, std::hash<MoveOnly>,
-                           std::equal_to<MoveOnly>, test_allocator<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-#if defined(_LIBCPP_VERSION)
-    {
-        typedef std::unordered_set<MoveOnly, std::hash<MoveOnly>,
-                          std::equal_to<MoveOnly>, other_allocator<MoveOnly>> C;
-        static_assert(std::is_nothrow_move_assignable<C>::value, "");
-    }
-#endif // _LIBCPP_VERSION
-    {
-        typedef std::unordered_set<MoveOnly, some_hash<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-    {
-        typedef std::unordered_set<MoveOnly, std::hash<MoveOnly>,
-                                                         some_comp<MoveOnly>> C;
-        static_assert(!std::is_nothrow_move_assignable<C>::value, "");
-    }
-
-  return 0;
-}



More information about the libcxx-commits mailing list