mclow.lists updated this revision to Diff 29367.
mclow.lists added a comment.

Wow - this really grew in the telling (as Prof T would say).

I cut this down to just `swap`, and then reworked the swap for all the 
containers. 
Turns out that our swaps were never noexcept for the unordered containers, map 
and set because we wrapped the comparison operators and the hashers, and the 
wrappers were not noexcept-swappable.

Lots of tests to make sure that they're right now.


http://reviews.llvm.org/D10998

Files:
  include/__hash_table
  include/__split_buffer
  include/__tree
  include/deque
  include/forward_list
  include/list
  include/map
  include/memory
  include/string
  include/unordered_map
  include/unordered_set
  include/vector
  test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp
  
test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp
  
test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp
  test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp
  test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp
  
test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp
  test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp
  test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp
  test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp
  test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp
  
test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp
  
test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp
  test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp
  
test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp

Index: test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp
+++ test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(basic_string& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
+//              allocator_traits<Allocator>::is_always_equal::value);
 
 // This tests a conforming extension
 
@@ -32,6 +36,19 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -48,7 +65,21 @@
     {
         typedef std::basic_string<char, std::char_traits<char>, some_alloc<char>> C;
         C c1, c2;
+#if TEST_STD_VER >= 14
+    //  In c++14, if POCS is set, swapping the allocator is required not to throw
+        static_assert( noexcept(swap(c1, c2)), "");
+#else
         static_assert(!noexcept(swap(c1, c2)), "");
+#endif
     }
+#if TEST_STD_VER >= 14
+    {
+        typedef std::basic_string<char, std::char_traits<char>, some_alloc2<char>> C;
+        C c1, c2;
+    //  if the allocators are always equal, then the swap can be noexcept
+        static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp
+++ test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp
@@ -10,8 +10,16 @@
 // <unordered_set>
 
 // void swap(unordered_set& c)
-//     noexcept(!allocator_type::propagate_on_container_swap::value ||
-//              __is_nothrow_swappable<allocator_type>::value);
+//      noexcept(
+//          (!allocator_type::propagate_on_container_swap::value ||
+//           __is_nothrow_swappable<allocator_type>::value) &&
+//           __is_nothrow_swappable<hasher>::value &&
+//           __is_nothrow_swappable<key_equal>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//               noexcept(swap(declval<Hash&>(), declval<Hash&>())) &&
+//               noexcept(swap(declval<Pred&>(), declval<Pred&>())));
 
 // This tests a conforming extension
 
@@ -31,6 +39,22 @@
 };
 
 template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
 struct some_hash
 {
     typedef T value_type;
@@ -38,6 +62,57 @@
     some_hash(const some_hash&);
 };
 
+template <class T>
+struct some_hash2
+{
+    typedef T value_type;
+    some_hash2() {}
+    some_hash2(const some_hash2&);
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_hash2<T>&, some_hash2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -69,5 +144,55 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_set<MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc3<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp
+++ test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp
@@ -10,8 +10,16 @@
 // <unordered_set>
 
 // void swap(unordered_multiset& c)
-//     noexcept(!allocator_type::propagate_on_container_swap::value ||
-//              __is_nothrow_swappable<allocator_type>::value);
+//      noexcept(
+//          (!allocator_type::propagate_on_container_swap::value ||
+//           __is_nothrow_swappable<allocator_type>::value) &&
+//           __is_nothrow_swappable<hasher>::value &&
+//           __is_nothrow_swappable<key_equal>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//               noexcept(swap(declval<Hash&>(), declval<Hash&>())) &&
+//               noexcept(swap(declval<Pred&>(), declval<Pred&>())));
 
 // This tests a conforming extension
 
@@ -31,6 +39,22 @@
 };
 
 template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
 struct some_hash
 {
     typedef T value_type;
@@ -38,6 +62,57 @@
     some_hash(const some_hash&);
 };
 
+template <class T>
+struct some_hash2
+{
+    typedef T value_type;
+    some_hash2() {}
+    some_hash2(const some_hash2&);
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_hash2<T>&, some_hash2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -69,5 +144,55 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_multiset<MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc3<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp
+++ test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp
@@ -10,8 +10,16 @@
 // <unordered_map>
 
 // void swap(unordered_multimap& c)
-//     noexcept(!allocator_type::propagate_on_container_swap::value ||
-//              __is_nothrow_swappable<allocator_type>::value);
+//      noexcept(
+//          (!allocator_type::propagate_on_container_swap::value ||
+//                __is_nothrow_swappable<allocator_type>::value) &&
+//           __is_nothrow_swappable<hasher>::value &&
+//           __is_nothrow_swappable<key_equal>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
+//               __is_nothrow_swappable<hasher>::value &&
+//               __is_nothrow_swappable<key_equal>::value);
 
 // This tests a conforming extension
 
@@ -31,6 +39,22 @@
 };
 
 template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
 struct some_hash
 {
     typedef T value_type;
@@ -38,9 +62,61 @@
     some_hash(const some_hash&);
 };
 
+template <class T>
+struct some_hash2
+{
+    typedef T value_type;
+    some_hash2() {}
+    some_hash2(const some_hash2&);
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_hash2<T>&, some_hash2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
+	typedef std::pair<const MoveOnly, MoveOnly> MapType;
     {
         typedef std::unordered_multimap<MoveOnly, MoveOnly> C;
         C c1, c2;
@@ -48,13 +124,13 @@
     }
     {
         typedef std::unordered_multimap<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                           std::equal_to<MoveOnly>, test_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
+                           std::equal_to<MoveOnly>, test_allocator<MapType>> C;
         C c1, c2;
         static_assert(noexcept(swap(c1, c2)), "");
     }
     {
         typedef std::unordered_multimap<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                          std::equal_to<MoveOnly>, other_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
+                          std::equal_to<MoveOnly>, other_allocator<MapType>> C;
         C c1, c2;
         static_assert(noexcept(swap(c1, c2)), "");
     }
@@ -69,5 +145,54 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_multimap<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc3<MapType>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp
+++ test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp
@@ -10,8 +10,16 @@
 // <unordered_map>
 
 // void swap(unordered_map& c)
-//     noexcept(!allocator_type::propagate_on_container_swap::value ||
-//              __is_nothrow_swappable<allocator_type>::value);
+//      noexcept(
+//          (!allocator_type::propagate_on_container_swap::value ||
+//           __is_nothrow_swappable<allocator_type>::value) &&
+//           __is_nothrow_swappable<hasher>::value &&
+//           __is_nothrow_swappable<key_equal>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//               noexcept(swap(declval<Hash&>(), declval<Hash&>())) &&
+//               noexcept(swap(declval<Pred&>(), declval<Pred&>())));
 
 // This tests a conforming extension
 
@@ -31,6 +39,22 @@
 };
 
 template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
 struct some_hash
 {
     typedef T value_type;
@@ -38,9 +62,62 @@
     some_hash(const some_hash&);
 };
 
+template <class T>
+struct some_hash2
+{
+    typedef T value_type;
+    some_hash2() {}
+    some_hash2(const some_hash2&);
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_hash2<T>&, some_hash2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
+	typedef std::pair<const MoveOnly, MoveOnly> MapType;
     {
         typedef std::unordered_map<MoveOnly, MoveOnly> C;
         C c1, c2;
@@ -48,13 +125,13 @@
     }
     {
         typedef std::unordered_map<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                           std::equal_to<MoveOnly>, test_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
+                           std::equal_to<MoveOnly>, test_allocator<MapType>> C;
         C c1, c2;
         static_assert(noexcept(swap(c1, c2)), "");
     }
     {
         typedef std::unordered_map<MoveOnly, MoveOnly, std::hash<MoveOnly>,
-                          std::equal_to<MoveOnly>, other_allocator<std::pair<const MoveOnly, MoveOnly>>> C;
+                          std::equal_to<MoveOnly>, other_allocator<MapType>> C;
         C c1, c2;
         static_assert(noexcept(swap(c1, c2)), "");
     }
@@ -69,5 +146,54 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, throwable swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for hash, nothrow swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, throwable swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp <MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc <MapType>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc2<MapType>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp
+    typedef std::unordered_map<MoveOnly, MoveOnly, some_hash2<MoveOnly>, some_comp2<MoveOnly>, some_alloc3<MapType>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+#endif
 }
Index: test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp
+++ test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(vector& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
+//              allocator_traits<Allocator>::is_always_equal::value);
 
 // This tests a conforming extension
 
@@ -32,6 +36,19 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -53,7 +70,21 @@
     {
         typedef std::vector<bool, some_alloc<bool>> C;
         C c1, c2;
+#if TEST_STD_VER >= 14
+    //  In c++14, if POCS is set, swapping the allocator is required not to throw
+        static_assert( noexcept(swap(c1, c2)), "");
+#else
         static_assert(!noexcept(swap(c1, c2)), "");
+#endif
     }
+#if TEST_STD_VER >= 14
+    {
+        typedef std::vector<bool, some_alloc2<bool>> C;
+        C c1, c2;
+    //  if the allocators are always equal, then the swap can be noexcept
+        static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp
+++ test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(vector& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
+//              allocator_traits<Allocator>::is_always_equal::value);
 
 // This tests a conforming extension
 
@@ -33,6 +37,19 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -54,7 +71,21 @@
     {
         typedef std::vector<MoveOnly, some_alloc<MoveOnly>> C;
         C c1, c2;
+#if TEST_STD_VER >= 14
+    //  In c++14, if POCS is set, swapping the allocator is required not to throw
+        static_assert( noexcept(swap(c1, c2)), "");
+#else
         static_assert(!noexcept(swap(c1, c2)), "");
+#endif
     }
+#if TEST_STD_VER >= 14
+    {
+        typedef std::vector<MoveOnly, some_alloc2<MoveOnly>> C;
+        C c1, c2;
+    //  if the allocators are always equal, then the swap can be noexcept
+        static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp
+++ test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp
@@ -12,6 +12,9 @@
 // void swap(list& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value);
 
 // This tests a conforming extension
 
@@ -33,6 +36,19 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -54,7 +70,21 @@
     {
         typedef std::list<MoveOnly, some_alloc<MoveOnly>> C;
         C c1, c2;
+#if TEST_STD_VER >= 14
+    //  In c++14, if POCS is set, swapping the allocator is required not to throw
+        static_assert( noexcept(swap(c1, c2)), "");
+#else
         static_assert(!noexcept(swap(c1, c2)), "");
+#endif
     }
+#if TEST_STD_VER >= 14
+    {
+        typedef std::list<MoveOnly, some_alloc2<MoveOnly>> C;
+        C c1, c2;
+    //  if the allocators are always equal, then the swap can be noexcept
+        static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp
+++ test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp
@@ -12,6 +12,9 @@
 // void swap(forward_list& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(is_always_equal<allocator_type>::value);
 
 // This tests a conforming extension
 
@@ -33,6 +36,19 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -54,7 +70,21 @@
     {
         typedef std::forward_list<MoveOnly, some_alloc<MoveOnly>> C;
         C c1, c2;
+#if TEST_STD_VER >= 14
+    //  In c++14, if POCS is set, swapping the allocator is required not to throw
+        static_assert( noexcept(swap(c1, c2)), "");
+#else
         static_assert(!noexcept(swap(c1, c2)), "");
+#endif
     }
+#if TEST_STD_VER >= 14
+    {
+        typedef std::forward_list<MoveOnly, some_alloc2<MoveOnly>> C;
+        C c1, c2;
+    //  if the allocators are always equal, then the swap can be noexcept
+        static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp
+++ test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp
@@ -12,6 +12,9 @@
 // void swap(deque& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value);
 
 // This tests a conforming extension
 
@@ -33,6 +36,19 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -54,7 +70,21 @@
     {
         typedef std::deque<MoveOnly, some_alloc<MoveOnly>> C;
         C c1, c2;
+#if TEST_STD_VER >= 14
+    //  In c++14, if POCS is set, swapping the allocator is required not to throw
+        static_assert( noexcept(swap(c1, c2)), "");
+#else
         static_assert(!noexcept(swap(c1, c2)), "");
+#endif
     }
+#if TEST_STD_VER >= 14
+    {
+        typedef std::deque<MoveOnly, some_alloc2<MoveOnly>> C;
+        C c1, c2;
+    //  if the allocators are always equal, then the swap can be noexcept
+        static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp
+++ test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(set& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//              noexcept(swap(declval<Compare&>(), declval<Compare&>())));                 
 
 // This tests a conforming extension
 
@@ -33,6 +37,60 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -56,5 +114,35 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for comp
+    typedef std::set<MoveOnly, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for comp
+    typedef std::set<MoveOnly, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for comp
+    typedef std::set<MoveOnly, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for comp
+    typedef std::set<MoveOnly, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for comp
+    typedef std::set<MoveOnly, some_comp2<MoveOnly>, some_alloc3<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp
+++ test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(multiset& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//              noexcept(swap(declval<Compare&>(), declval<Compare&>())));                 
 
 // This tests a conforming extension
 
@@ -33,6 +37,60 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -56,5 +114,35 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for comp
+    typedef std::multiset<MoveOnly, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for comp
+    typedef std::multiset<MoveOnly, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for comp
+    typedef std::multiset<MoveOnly, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for comp
+    typedef std::multiset<MoveOnly, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for comp
+    typedef std::multiset<MoveOnly, some_comp2<MoveOnly>, some_alloc3<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp
+++ test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(multimap& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//              noexcept(swap(declval<Compare&>(), declval<Compare&>())));                 
 
 // This tests a conforming extension
 
@@ -33,6 +37,60 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -56,5 +114,35 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for comp
+    typedef std::multimap<MoveOnly, MoveOnly, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for comp
+    typedef std::multimap<MoveOnly, MoveOnly, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for comp
+    typedef std::multimap<MoveOnly, MoveOnly, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for comp
+    typedef std::multimap<MoveOnly, MoveOnly, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for comp
+    typedef std::map<MoveOnly, MoveOnly, some_comp2<MoveOnly>, some_alloc3<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp
===================================================================
--- test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp
+++ test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp
@@ -12,6 +12,10 @@
 // void swap(map& c)
 //     noexcept(!allocator_type::propagate_on_container_swap::value ||
 //              __is_nothrow_swappable<allocator_type>::value);
+//
+//  In C++17, the standard says that swap shall have:
+//     noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+//              noexcept(swap(declval<Compare&>(), declval<Compare&>())));                 
 
 // This tests a conforming extension
 
@@ -33,6 +37,60 @@
     typedef std::true_type propagate_on_container_swap;
 };
 
+template <class T>
+struct some_comp2
+{
+    typedef T value_type;
+    
+    some_comp2() {}
+    some_comp2(const some_comp2&) {}
+    void deallocate(void*, unsigned) {}
+    typedef std::true_type propagate_on_container_swap;
+};
+
+#if TEST_STD_VER >= 14
+template <typename T>
+void swap(some_comp2<T>&, some_comp2<T>&) noexcept {}
+#endif
+
+template <class T>
+struct some_alloc
+{
+    typedef T value_type;
+    
+    some_alloc() {}
+    some_alloc(const some_alloc&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::true_type propagate_on_container_swap;
+};
+
+template <class T>
+struct some_alloc2
+{
+    typedef T value_type;
+    
+    some_alloc2() {}
+    some_alloc2(const some_alloc2&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::true_type is_always_equal;
+};
+
+template <class T>
+struct some_alloc3
+{
+    typedef T value_type;
+    
+    some_alloc3() {}
+    some_alloc3(const some_alloc3&);
+    void deallocate(void*, unsigned) {}
+
+    typedef std::false_type propagate_on_container_swap;
+    typedef std::false_type is_always_equal;
+};
+
 int main()
 {
 #if __has_feature(cxx_noexcept)
@@ -56,5 +114,35 @@
         C c1, c2;
         static_assert(!noexcept(swap(c1, c2)), "");
     }
+
+#if TEST_STD_VER >= 14
+    { // POCS allocator, throwable swap for comp
+    typedef std::map<MoveOnly, MoveOnly, some_comp <MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, throwable swap for comp
+    typedef std::map<MoveOnly, MoveOnly, some_comp <MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert(!noexcept(swap(c1, c2)), "");
+    }
+    { // POCS allocator, nothrow swap for comp
+    typedef std::map<MoveOnly, MoveOnly, some_comp2<MoveOnly>, some_alloc <MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+    { // always equal allocator, nothrow swap for comp
+    typedef std::map<MoveOnly, MoveOnly, some_comp2<MoveOnly>, some_alloc2<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
+
+    { // NOT always equal allocator, nothrow swap for comp
+    typedef std::map<MoveOnly, MoveOnly, some_comp2<MoveOnly>, some_alloc3<MoveOnly>> C;
+    C c1, c2;
+    static_assert( noexcept(swap(c1, c2)), "");
+    }
 #endif
+
+#endif
 }
Index: include/vector
===================================================================
--- include/vector
+++ include/vector
@@ -119,8 +119,8 @@
     void resize(size_type sz, const value_type& c);
 
     void swap(vector&)
-        noexcept(!allocator_type::propagate_on_container_swap::value ||
-                 __is_nothrow_swappable<allocator_type>::value);
+        noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
+                 allocator_traits<allocator_type>::is_always_equal::value);  // C++17
 
     bool __invariants() const;
 };
@@ -237,8 +237,8 @@
     void resize(size_type sz, value_type x);
 
     void swap(vector&)
-        noexcept(!allocator_type::propagate_on_container_swap::value ||
-                 __is_nothrow_swappable<allocator_type>::value);
+        noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
+                 allocator_traits<allocator_type>::is_always_equal::value);  // C++17
     void flip() noexcept;
 
     bool __invariants() const;
@@ -385,14 +385,6 @@
             is_nothrow_move_assignable<allocator_type>::value)
         {__move_assign_alloc(__c, integral_constant<bool,
                       __alloc_traits::propagate_on_container_move_assignment::value>());}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type& __x, allocator_type& __y)
-        _NOEXCEPT_(
-            !__alloc_traits::propagate_on_container_swap::value ||
-            __is_nothrow_swappable<allocator_type>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __alloc_traits::propagate_on_container_swap::value>());}
 private:
     _LIBCPP_INLINE_VISIBILITY
     void __copy_assign_alloc(const __vector_base& __c, true_type)
@@ -421,18 +413,6 @@
     void __move_assign_alloc(__vector_base&, false_type)
         _NOEXCEPT
         {}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type)
-        _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type&, allocator_type&, false_type)
-        _NOEXCEPT
-        {}
 };
 
 template <class _Tp, class _Allocator>
@@ -760,8 +740,12 @@
     void resize(size_type __sz, const_reference __x);
 
     void swap(vector&)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value);
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value);
+#endif
 
     bool __invariants() const;
 
@@ -2016,8 +2000,12 @@
 template <class _Tp, class _Allocator>
 void
 vector<_Tp, _Allocator>::swap(vector& __x)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value)
+#if _LIBCPP_STD_VER >= 14
+    _NOEXCEPT
+#else
+    _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                __is_nothrow_swappable<allocator_type>::value)
+#endif
 {
     _LIBCPP_ASSERT(__alloc_traits::propagate_on_container_swap::value ||
                    this->__alloc() == __x.__alloc(),
@@ -2026,7 +2014,8 @@
     _VSTD::swap(this->__begin_, __x.__begin_);
     _VSTD::swap(this->__end_, __x.__end_);
     _VSTD::swap(this->__end_cap(), __x.__end_cap());
-    __base::__swap_alloc(this->__alloc(), __x.__alloc());
+    __swap_allocator(this->__alloc(), __x.__alloc(), 
+        integral_constant<bool,__alloc_traits::propagate_on_container_swap::value>());
 #if _LIBCPP_DEBUG_LEVEL >= 2
     __get_db()->swap(this, &__x);
 #endif  // _LIBCPP_DEBUG_LEVEL >= 2
@@ -2354,8 +2343,12 @@
     void clear() _NOEXCEPT {__size_ = 0;}
 
     void swap(vector&)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value);
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value);
+#endif
 
     void resize(size_type __sz, value_type __x = false);
     void flip() _NOEXCEPT;
@@ -2433,26 +2426,6 @@
         _NOEXCEPT
         {}
 
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__storage_allocator& __x, __storage_allocator& __y)
-        _NOEXCEPT_(
-            !__storage_traits::propagate_on_container_swap::value ||
-            __is_nothrow_swappable<allocator_type>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __storage_traits::propagate_on_container_swap::value>());}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__storage_allocator& __x, __storage_allocator& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<allocator_type>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__storage_allocator&, __storage_allocator&, false_type)
-        _NOEXCEPT
-        {}
-
     size_t __hash_code() const _NOEXCEPT;
 
     friend class __bit_reference<vector>;
@@ -3155,13 +3128,18 @@
 template <class _Allocator>
 void
 vector<bool, _Allocator>::swap(vector& __x)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value)
+#if _LIBCPP_STD_VER >= 14
+    _NOEXCEPT
+#else
+    _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                __is_nothrow_swappable<allocator_type>::value)
+#endif
 {
     _VSTD::swap(this->__begin_, __x.__begin_);
     _VSTD::swap(this->__size_, __x.__size_);
     _VSTD::swap(this->__cap(), __x.__cap());
-    __swap_alloc(this->__alloc(), __x.__alloc());
+    __swap_allocator(this->__alloc(), __x.__alloc(), 
+        integral_constant<bool, __alloc_traits::propagate_on_container_swap::value>());
 }
 
 template <class _Allocator>
Index: include/unordered_set
===================================================================
--- include/unordered_set
+++ include/unordered_set
@@ -120,11 +120,9 @@
     void clear() noexcept;
 
     void swap(unordered_set&)
-        noexcept(
-            (!allocator_type::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<allocator_type>::value) &&
-            __is_nothrow_swappable<hasher>::value &&
-            __is_nothrow_swappable<key_equal>::value);
+       noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+                 noexcept(swap(declval<hasher&>(), declval<hasher&>())) &&
+                 noexcept(swap(declval<key_equal&>(), declval<key_equal&>()))); // C++17
 
     hasher hash_function() const;
     key_equal key_eq() const;
@@ -270,11 +268,9 @@
     void clear() noexcept;
 
     void swap(unordered_multiset&)
-        noexcept(
-            (!allocator_type::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<allocator_type>::value) &&
-            __is_nothrow_swappable<hasher>::value &&
-            __is_nothrow_swappable<key_equal>::value);
+       noexcept(allocator_traits<Allocator>::is_always_equal::value &&
+                 noexcept(swap(declval<hasher&>(), declval<hasher&>())) &&
+                 noexcept(swap(declval<key_equal&>(), declval<key_equal&>()))); // C++17
 
     hasher hash_function() const;
     key_equal key_eq() const;
Index: include/unordered_map
===================================================================
--- include/unordered_map
+++ include/unordered_map
@@ -401,6 +401,12 @@
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(const _Key& __x) const
         {return static_cast<const _Hash&>(*this)(__x);}
+    void swap(__unordered_map_hasher&__y)
+        _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value)
+    {
+        using _VSTD::swap;
+        swap(static_cast<const _Hash&>(*this), static_cast<const _Hash&>(__y));
+    }
 };
 
 template <class _Key, class _Cp, class _Hash>
@@ -425,8 +431,24 @@
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(const _Key& __x) const
         {return __hash_(__x);}
+    void swap(__unordered_map_hasher&__y)
+        _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value)
+    {
+        using _VSTD::swap;
+        swap(__hash_, __y.__hash_);
+    }
 };
 
+template <class _Key, class _Cp, class _Hash, bool __b>
+inline _LIBCPP_INLINE_VISIBILITY
+void
+swap(__unordered_map_hasher<_Key, _Cp, _Hash, __b>& __x,
+     __unordered_map_hasher<_Key, _Cp, _Hash, __b>& __y)
+    _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
+{
+    __x.swap(__y);
+}
+
 template <class _Key, class _Cp, class _Pred,
           bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value
          >
@@ -453,6 +475,12 @@
     _LIBCPP_INLINE_VISIBILITY
     bool operator()(const _Key& __x, const _Cp& __y) const
         {return static_cast<const _Pred&>(*this)(__x, __y.__cc.first);}
+    void swap(__unordered_map_equal&__y)
+        _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value)
+    {
+        using _VSTD::swap;
+        swap(static_cast<const _Pred&>(*this), static_cast<const _Pred&>(__y));
+    }
 };
 
 template <class _Key, class _Cp, class _Pred>
@@ -480,8 +508,24 @@
     _LIBCPP_INLINE_VISIBILITY
     bool operator()(const _Key& __x, const _Cp& __y) const
         {return __pred_(__x, __y.__cc.first);}
+    void swap(__unordered_map_equal&__y)
+        _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value)
+    {
+        using _VSTD::swap;
+        swap(__pred_, __y.__pred_);
+    }
 };
 
+template <class _Key, class _Cp, class _Pred, bool __b>
+inline _LIBCPP_INLINE_VISIBILITY
+void
+swap(__unordered_map_equal<_Key, _Cp, _Pred, __b>& __x,
+     __unordered_map_equal<_Key, _Cp, _Pred, __b>& __y)
+    _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
+{
+    __x.swap(__y);
+}
+
 template <class _Alloc>
 class __hash_map_node_destructor
 {
Index: include/string
===================================================================
--- include/string
+++ include/string
@@ -220,8 +220,8 @@
     basic_string substr(size_type pos = 0, size_type n = npos) const;
 
     void swap(basic_string& str)
-        noexcept(!allocator_type::propagate_on_container_swap::value ||
-                 __is_nothrow_swappable<allocator_type>::value)
+        noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
+                 allocator_traits<allocator_type>::is_always_equal::value);  // C++17
 
     const value_type* c_str() const noexcept;
     const value_type* data() const noexcept;
@@ -1604,8 +1604,12 @@
 
     _LIBCPP_INLINE_VISIBILITY
     void swap(basic_string& __str)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value);
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value);
+#endif
 
     _LIBCPP_INLINE_VISIBILITY
     const value_type* c_str() const _NOEXCEPT {return data();}
@@ -1868,24 +1872,6 @@
         _NOEXCEPT
         {}
 
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type& __x, allocator_type& __y)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __alloc_traits::propagate_on_container_swap::value>());}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<allocator_type>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type&, allocator_type&, false_type) _NOEXCEPT
-        {}
-
     _LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators();
     _LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(size_type);
 
@@ -3366,8 +3352,12 @@
 inline _LIBCPP_INLINE_VISIBILITY
 void
 basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value)
+#endif
 {
 #if _LIBCPP_DEBUG_LEVEL >= 2
     if (!__is_long())
@@ -3377,7 +3367,7 @@
     __get_db()->swap(this, &__str);
 #endif
     _VSTD::swap(__r_.first(), __str.__r_.first());
-    __swap_alloc(__alloc(), __str.__alloc());
+    __swap_allocator(__alloc(), __str.__alloc());
 }
 
 // find
Index: include/memory
===================================================================
--- include/memory
+++ include/memory
@@ -5543,6 +5543,38 @@
 
 _LIBCPP_FUNC_VIS void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space);
 
+// --- Helper for container swap --
+template <typename _Alloc>
+_LIBCPP_INLINE_VISIBILITY
+void __swap_allocator(_Alloc & __a1, _Alloc & __a2)
+#if _LIBCPP_STD_VER >= 14
+    _NOEXCEPT
+#else
+    _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value)
+#endif
+{
+    __swap_allocator(__a1, __a2, 
+      integral_constant<bool, _VSTD::allocator_traits<_Alloc>::propagate_on_container_swap::value>());
+}
+
+template <typename _Alloc>
+_LIBCPP_INLINE_VISIBILITY
+void __swap_allocator(_Alloc & __a1, _Alloc & __a2, true_type)
+#if _LIBCPP_STD_VER >= 14
+    _NOEXCEPT
+#else
+    _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value)
+#endif
+{
+    using _VSTD::swap;
+    swap(__a1, __a2);
+}
+
+template <typename _Alloc>
+_LIBCPP_INLINE_VISIBILITY
+void __swap_allocator(_Alloc &, _Alloc &, false_type) _NOEXCEPT {}
+
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_MEMORY
Index: include/map
===================================================================
--- include/map
+++ include/map
@@ -159,10 +159,8 @@
     void clear() noexcept;
 
     void swap(map& m)
-        noexcept(
-            __is_nothrow_swappable<key_compare>::value &&
-            (!allocator_type::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<allocator_type>::value));
+        noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
+            __is_nothrow_swappable<key_compare>::value); // C++17
 
     // observers:
     allocator_type get_allocator() const noexcept;
@@ -354,10 +352,8 @@
     void clear() noexcept;
 
     void swap(multimap& m)
-        noexcept(
-            __is_nothrow_swappable<key_compare>::value &&
-            (!allocator_type::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<allocator_type>::value));
+        noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
+            __is_nothrow_swappable<key_compare>::value); // C++17
 
     // observers:
     allocator_type get_allocator() const noexcept;
@@ -479,6 +475,12 @@
     _LIBCPP_INLINE_VISIBILITY
     bool operator()(const _Key& __x, const _CP& __y) const
         {return static_cast<const _Compare&>(*this)(__x, __y.__cc.first);}
+    void swap(__map_value_compare&__y)
+        _NOEXCEPT_(__is_nothrow_swappable<_Compare>::value)
+    {
+        using _VSTD::swap;
+        swap(static_cast<const _Compare&>(*this), static_cast<const _Compare&>(__y));
+    }
 
 #if _LIBCPP_STD_VER > 11
     template <typename _K2>
@@ -521,7 +523,13 @@
     _LIBCPP_INLINE_VISIBILITY
     bool operator()(const _Key& __x, const _CP& __y) const
         {return comp(__x, __y.__cc.first);}
-
+    void swap(__map_value_compare&__y)
+        _NOEXCEPT_(__is_nothrow_swappable<_Compare>::value)
+    {
+        using _VSTD::swap;
+        swap(comp, __y.comp);
+    }
+    
 #if _LIBCPP_STD_VER > 11
     template <typename _K2>
     _LIBCPP_INLINE_VISIBILITY
@@ -537,6 +545,16 @@
 #endif
 };
 
+template <class _Key, class _CP, class _Compare, bool __b>
+inline _LIBCPP_INLINE_VISIBILITY
+void
+swap(__map_value_compare<_Key, _CP, _Compare, __b>& __x,
+     __map_value_compare<_Key, _CP, _Compare, __b>& __y)
+    _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
+{
+    __x.swap(__y);
+}
+
 template <class _Allocator>
 class __map_node_destructor
 {
Index: include/list
===================================================================
--- include/list
+++ include/list
@@ -118,8 +118,7 @@
     void resize(size_type sz, const value_type& c);
 
     void swap(list&)
-        noexcept(!allocator_type::propagate_on_container_swap::value ||
-                 __is_nothrow_swappable<allocator_type>::value);
+        noexcept(allocator_traits<allocator_type>::is_always_equal::value);  // C++17
     void clear() noexcept;
 
     void splice(const_iterator position, list& x);
@@ -593,8 +592,12 @@
     }
 
     void swap(__list_imp& __c)
-        _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<__node_allocator>::value);
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value);
+#endif
 
     _LIBCPP_INLINE_VISIBILITY
     void __copy_assign_alloc(const __list_imp& __c)
@@ -611,24 +614,6 @@
 
 private:
     _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y)
-        _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<__node_allocator>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __node_alloc_traits::propagate_on_container_swap::value>());}
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<__node_allocator>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, false_type)
-        _NOEXCEPT
-        {}
-
-    _LIBCPP_INLINE_VISIBILITY
     void __copy_assign_alloc(const __list_imp& __c, true_type)
         {
             if (__node_alloc() != __c.__node_alloc())
@@ -728,15 +713,19 @@
 template <class _Tp, class _Alloc>
 void
 __list_imp<_Tp, _Alloc>::swap(__list_imp& __c)
-        _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<__node_allocator>::value)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value)
+#endif
 {
     _LIBCPP_ASSERT(__alloc_traits::propagate_on_container_swap::value ||
                    this->__node_alloc() == __c.__node_alloc(),
                    "list::swap: Either propagate_on_container_swap must be true"
                    " or the allocators must compare equal");
     using _VSTD::swap;
-    __swap_alloc(__node_alloc(), __c.__node_alloc());
+    __swap_allocator(__node_alloc(), __c.__node_alloc());
     swap(__sz(), __c.__sz());
     swap(__end_, __c.__end_);
     if (__sz() == 0)
@@ -972,8 +961,12 @@
 
     _LIBCPP_INLINE_VISIBILITY
     void swap(list& __c)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
         _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value ||
                    __is_nothrow_swappable<__node_allocator>::value)
+#endif
         {base::swap(__c);}
     _LIBCPP_INLINE_VISIBILITY
     void clear() _NOEXCEPT {base::clear();}
Index: include/forward_list
===================================================================
--- include/forward_list
+++ include/forward_list
@@ -107,8 +107,7 @@
     iterator erase_after(const_iterator first, const_iterator last);
 
     void swap(forward_list& x)
-        noexcept(!allocator_type::propagate_on_container_swap::value ||
-                 __is_nothrow_swappable<allocator_type>::value);
+        noexcept(allocator_traits<allocator_type>::is_always_equal::value);  // C++17
 
     void resize(size_type n);
     void resize(size_type n, const value_type& v);
@@ -431,8 +430,12 @@
 
 public:
     void swap(__forward_list_base& __x)
-        _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<__node_allocator>::value);
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
+        _NOEXCEPT_(!__node_traits::propagate_on_container_move_assignment::value || 
+                    __is_nothrow_swappable<__node_allocator>::value);
+#endif
 protected:
     void clear() _NOEXCEPT;
 
@@ -454,26 +457,6 @@
     void __move_assign_alloc(__forward_list_base& __x, true_type)
         _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value)
         {__alloc() = _VSTD::move(__x.__alloc());}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y)
-        _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<__node_allocator>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                         __node_traits::propagate_on_container_swap::value>());}
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y,
-                                                                     false_type)
-        _NOEXCEPT
-        {}
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y,
-                                                                      true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<__node_allocator>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
 };
 
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -512,10 +495,15 @@
 inline _LIBCPP_INLINE_VISIBILITY
 void
 __forward_list_base<_Tp, _Alloc>::swap(__forward_list_base& __x)
-        _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<__node_allocator>::value)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
+        _NOEXCEPT_(!__node_traits::propagate_on_container_move_assignment::value || 
+                    __is_nothrow_swappable<__node_allocator>::value)
+#endif
 {
-    __swap_alloc(__alloc(), __x.__alloc());
+    __swap_allocator(__alloc(), __x.__alloc(), 
+            integral_constant<bool, __node_traits::propagate_on_container_swap::value>());
     using _VSTD::swap;
     swap(__before_begin()->__next_, __x.__before_begin()->__next_);
 }
@@ -703,8 +691,12 @@
 
     _LIBCPP_INLINE_VISIBILITY
     void swap(forward_list& __x)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
         _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value ||
                    __is_nothrow_swappable<__node_allocator>::value)
+#endif
         {base::swap(__x);}
 
     void resize(size_type __n);
Index: include/deque
===================================================================
--- include/deque
+++ include/deque
@@ -124,8 +124,7 @@
     iterator erase(const_iterator p);
     iterator erase(const_iterator f, const_iterator l);
     void swap(deque& c)
-        noexcept(!allocator_type::propagate_on_container_swap::value ||
-                 __is_nothrow_swappable<allocator_type>::value);
+        noexcept(allocator_traits<allocator_type>::is_always_equal::value);  // C++17
     void clear() noexcept;
 };
 
@@ -954,8 +953,12 @@
 
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
     void swap(__deque_base& __c)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value);
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value);
+#endif
 protected:
     void clear() _NOEXCEPT;
 
@@ -991,26 +994,6 @@
     _LIBCPP_INLINE_VISIBILITY
     void __move_assign_alloc(__deque_base&, false_type) _NOEXCEPT
         {}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type& __x, allocator_type& __y)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __alloc_traits::propagate_on_container_swap::value>());}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<allocator_type>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(allocator_type&, allocator_type&, false_type)
-        _NOEXCEPT
-        {}
 };
 
 template <class _Tp, class _Allocator>
@@ -1134,13 +1117,17 @@
 template <class _Tp, class _Allocator>
 void
 __deque_base<_Tp, _Allocator>::swap(__deque_base& __c)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
-                   __is_nothrow_swappable<allocator_type>::value)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value)
+#endif
 {
     __map_.swap(__c.__map_);
     _VSTD::swap(__start_, __c.__start_);
     _VSTD::swap(size(), __c.size());
-    __swap_alloc(__alloc(), __c.__alloc());
+    __swap_allocator(__alloc(), __c.__alloc());
 }
 
 template <class _Tp, class _Allocator>
@@ -1342,8 +1329,12 @@
     iterator erase(const_iterator __f, const_iterator __l);
 
     void swap(deque& __c)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT;
+#else
         _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                    __is_nothrow_swappable<allocator_type>::value);
+#endif
     void clear() _NOEXCEPT;
 
     _LIBCPP_INLINE_VISIBILITY
@@ -2277,13 +2268,13 @@
             __buf(max<size_type>(2 * __base::__map_.capacity(), 1),
                   0, __base::__map_.__alloc());
 
-		typedef __allocator_destructor<_Allocator> _Dp;
-		unique_ptr<pointer, _Dp> __hold(
-			__alloc_traits::allocate(__a, __base::__block_size),
-				_Dp(__a, __base::__block_size));
-		__buf.push_back(__hold.get());
-		__hold.release();
-	
+        typedef __allocator_destructor<_Allocator> _Dp;
+        unique_ptr<pointer, _Dp> __hold(
+            __alloc_traits::allocate(__a, __base::__block_size),
+                _Dp(__a, __base::__block_size));
+        __buf.push_back(__hold.get());
+        __hold.release();
+    
         for (typename __base::__map_pointer __i = __base::__map_.begin();
                 __i != __base::__map_.end(); ++__i)
             __buf.push_back(*__i);
@@ -2420,12 +2411,12 @@
                   __base::__map_.size(),
                   __base::__map_.__alloc());
 
-		typedef __allocator_destructor<_Allocator> _Dp;
-		unique_ptr<pointer, _Dp> __hold(
-			__alloc_traits::allocate(__a, __base::__block_size),
-				_Dp(__a, __base::__block_size));
-		__buf.push_back(__hold.get());
-		__hold.release();
+        typedef __allocator_destructor<_Allocator> _Dp;
+        unique_ptr<pointer, _Dp> __hold(
+            __alloc_traits::allocate(__a, __base::__block_size),
+                _Dp(__a, __base::__block_size));
+        __buf.push_back(__hold.get());
+        __hold.release();
 
         for (typename __base::__map_pointer __i = __base::__map_.end();
                 __i != __base::__map_.begin();)
@@ -2793,8 +2784,12 @@
 inline _LIBCPP_INLINE_VISIBILITY
 void
 deque<_Tp, _Allocator>::swap(deque& __c)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
-                   __is_nothrow_swappable<allocator_type>::value)
+#if _LIBCPP_STD_VER >= 14
+        _NOEXCEPT
+#else
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || 
+                    __is_nothrow_swappable<allocator_type>::value)
+#endif
 {
     __base::swap(__c);
 }
Index: include/__tree
===================================================================
--- include/__tree
+++ include/__tree
@@ -926,9 +926,12 @@
 
     void swap(__tree& __t)
         _NOEXCEPT_(
-            __is_nothrow_swappable<value_compare>::value &&
-            (!__node_traits::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<__node_allocator>::value));
+            __is_nothrow_swappable<value_compare>::value
+#if _LIBCPP_STD_VER <= 11
+            && (!__node_traits::propagate_on_container_swap::value ||
+                 __is_nothrow_swappable<__node_allocator>::value)
+#endif
+            );
 
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 #ifndef _LIBCPP_HAS_NO_VARIADICS
@@ -1096,25 +1099,6 @@
     _LIBCPP_INLINE_VISIBILITY
     void __move_assign_alloc(__tree& __t, false_type) _NOEXCEPT {}
 
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y)
-        _NOEXCEPT_(
-            !__node_traits::propagate_on_container_swap::value ||
-            __is_nothrow_swappable<__node_allocator>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __node_traits::propagate_on_container_swap::value>());}
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<__node_allocator>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, false_type)
-        _NOEXCEPT
-        {}
-
     __node_pointer __detach();
     static __node_pointer __detach(__node_pointer);
 
@@ -1452,15 +1436,18 @@
 template <class _Tp, class _Compare, class _Allocator>
 void
 __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t)
-    _NOEXCEPT_(
-        __is_nothrow_swappable<value_compare>::value &&
-        (!__node_traits::propagate_on_container_swap::value ||
-         __is_nothrow_swappable<__node_allocator>::value))
+        _NOEXCEPT_(
+            __is_nothrow_swappable<value_compare>::value
+#if _LIBCPP_STD_VER <= 11
+            && (!__node_traits::propagate_on_container_swap::value ||
+                 __is_nothrow_swappable<__node_allocator>::value)
+#endif
+            )
 {
     using _VSTD::swap;
     swap(__begin_node_, __t.__begin_node_);
     swap(__pair1_.first(), __t.__pair1_.first());
-    __swap_alloc(__node_alloc(), __t.__node_alloc());
+    __swap_allocator(__node_alloc(), __t.__node_alloc());
     __pair3_.swap(__t.__pair3_);
     if (size() == 0)
         __begin_node() = __end_node();
Index: include/__split_buffer
===================================================================
--- include/__split_buffer
+++ include/__split_buffer
@@ -156,25 +156,6 @@
     _LIBCPP_INLINE_VISIBILITY
     void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT
         {}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y)
-        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value||
-                   __is_nothrow_swappable<__alloc_rr>::value)
-        {__swap_alloc(__x, __y, integral_constant<bool,
-                      __alloc_traits::propagate_on_container_swap::value>());}
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<__alloc_rr>::value)
-        {
-            using _VSTD::swap;
-            swap(__x, __y);
-        }
-
-    _LIBCPP_INLINE_VISIBILITY
-    static void __swap_alloc(__alloc_rr&, __alloc_rr&, false_type) _NOEXCEPT
-        {}
 };
 
 template <class _Tp, class _Allocator>
@@ -431,7 +412,7 @@
     _VSTD::swap(__begin_, __x.__begin_);
     _VSTD::swap(__end_, __x.__end_);
     _VSTD::swap(__end_cap(), __x.__end_cap());
-    __swap_alloc(__alloc(), __x.__alloc());
+    __swap_allocator(__alloc(), __x.__alloc());
 }
 
 template <class _Tp, class _Allocator>
Index: include/__hash_table
===================================================================
--- include/__hash_table
+++ include/__hash_table
@@ -985,12 +985,14 @@
 
     void swap(__hash_table& __u)
         _NOEXCEPT_(
-            (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<__pointer_allocator>::value) &&
-            (!__node_traits::propagate_on_container_swap::value ||
-             __is_nothrow_swappable<__node_allocator>::value) &&
-            __is_nothrow_swappable<hasher>::value &&
-            __is_nothrow_swappable<key_equal>::value);
+            __is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value
+#if _LIBCPP_STD_VER <= 11
+            && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value
+                  || __is_nothrow_swappable<__pointer_allocator>::value)
+            && (!__node_traits::propagate_on_container_swap::value
+                  || __is_nothrow_swappable<__node_allocator>::value)
+#endif
+            );
 
     _LIBCPP_INLINE_VISIBILITY
     size_type max_bucket_count() const _NOEXCEPT
@@ -1118,38 +1120,6 @@
     _LIBCPP_INLINE_VISIBILITY
         void __move_assign_alloc(__hash_table&, false_type) _NOEXCEPT {}
 
-    template <class _Ap>
-    _LIBCPP_INLINE_VISIBILITY
-    static
-    void
-    __swap_alloc(_Ap& __x, _Ap& __y)
-        _NOEXCEPT_(
-            !allocator_traits<_Ap>::propagate_on_container_swap::value ||
-            __is_nothrow_swappable<_Ap>::value)
-    {
-        __swap_alloc(__x, __y,
-                     integral_constant<bool,
-                        allocator_traits<_Ap>::propagate_on_container_swap::value
-                                      >());
-    }
-
-    template <class _Ap>
-    _LIBCPP_INLINE_VISIBILITY
-    static
-    void
-    __swap_alloc(_Ap& __x, _Ap& __y, true_type)
-        _NOEXCEPT_(__is_nothrow_swappable<_Ap>::value)
-    {
-        using _VSTD::swap;
-        swap(__x, __y);
-    }
-
-    template <class _Ap>
-    _LIBCPP_INLINE_VISIBILITY
-    static
-    void
-    __swap_alloc(_Ap&, _Ap&, false_type) _NOEXCEPT {}
-
     void __deallocate(__node_pointer __np) _NOEXCEPT;
     __node_pointer __detach() _NOEXCEPT;
 
@@ -2382,12 +2352,14 @@
 void
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
     _NOEXCEPT_(
-        (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value ||
-         __is_nothrow_swappable<__pointer_allocator>::value) &&
-        (!__node_traits::propagate_on_container_swap::value ||
-         __is_nothrow_swappable<__node_allocator>::value) &&
-        __is_nothrow_swappable<hasher>::value &&
-        __is_nothrow_swappable<key_equal>::value)
+        __is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value
+#if _LIBCPP_STD_VER <= 11
+        && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value
+              || __is_nothrow_swappable<__pointer_allocator>::value)
+        && (!__node_traits::propagate_on_container_swap::value
+              || __is_nothrow_swappable<__node_allocator>::value)
+#endif
+            )
 {
     {
     __node_pointer_pointer __npp = __bucket_list_.release();
@@ -2395,9 +2367,9 @@
     __u.__bucket_list_.reset(__npp);
     }
     _VSTD::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size());
-    __swap_alloc(__bucket_list_.get_deleter().__alloc(),
+    __swap_allocator(__bucket_list_.get_deleter().__alloc(),
              __u.__bucket_list_.get_deleter().__alloc());
-    __swap_alloc(__node_alloc(), __u.__node_alloc());
+    __swap_allocator(__node_alloc(), __u.__node_alloc());
     _VSTD::swap(__p1_.first().__next_, __u.__p1_.first().__next_);
     __p2_.swap(__u.__p2_);
     __p3_.swap(__u.__p3_);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to