[libcxx-commits] [libcxx] cd13170 - [libc++] Implement P3567R2 flat_meow fixes (#162022)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Dec 20 13:18:48 PST 2025


Author: Hui
Date: 2025-12-20T21:18:44Z
New Revision: cd13170aea2db35e04e4842806b14383864d3a97

URL: https://github.com/llvm/llvm-project/commit/cd13170aea2db35e04e4842806b14383864d3a97
DIFF: https://github.com/llvm/llvm-project/commit/cd13170aea2db35e04e4842806b14383864d3a97.diff

LOG: [libc++] Implement P3567R2 flat_meow fixes (#162022)

Fixes #171272

---------

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>

Added: 
    libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/22.rst
    libcxx/docs/Status/Cxx2cPapers.csv
    libcxx/include/__flat_map/flat_map.h
    libcxx/include/__flat_map/flat_multimap.h
    libcxx/include/__flat_set/flat_multiset.h
    libcxx/include/__flat_set/flat_set.h
    libcxx/include/flat_map
    libcxx/include/flat_set
    libcxx/include/version
    libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
    libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 5f1e521bd79c2..4a82461b80534 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -334,7 +334,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_expected``                                     ``202211L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_flat_map``                                     ``202207L``
+    ``__cpp_lib_flat_map``                                     ``202511L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_flat_set``                                     ``202207L``
     ---------------------------------------------------------- -----------------

diff  --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 76d3bb263290f..268de27b97a71 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -51,6 +51,7 @@ Implemented Papers
 - P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
 - P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
 - P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
+- P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
 
 Improvements and New Features
 -----------------------------

diff  --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 4c941294ccb40..a9904e2d38422 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -159,7 +159,7 @@
 "","","","","","",""
 "`P3920R0 <https://wg21.link/P3920R0>`__","Wording for NB comment resolution on trivial relocation","2025-11 (Kona)","","","`#171269 <https://github.com/llvm/llvm-project/issues/171269>`__",""
 "`P3016R6 <https://wg21.link/P3016R6>`__","Resolve inconsistencies in begin/end for ``valarray`` and braced initializer lists","2025-11 (Kona)","","","`#171271 <https://github.com/llvm/llvm-project/issues/171271>`__",""
-"`P3567R2 <https://wg21.link/P3567R2>`__","``flat_meow`` Fixes","2025-11 (Kona)","","","`#171272 <https://github.com/llvm/llvm-project/issues/171272>`__",""
+"`P3567R2 <https://wg21.link/P3567R2>`__","``flat_meow`` Fixes","2025-11 (Kona)","|Complete|","22","`#171272 <https://github.com/llvm/llvm-project/issues/171272>`__",""
 "`P3663R3 <https://wg21.link/P3663R3>`__","Future-proof ``submdspan_mapping``","2025-11 (Kona)","","","`#166089 <https://github.com/llvm/llvm-project/issues/166089>`__",""
 "`P3914R0 <https://wg21.link/P3914R0>`__","Assorted NB comment resolutions for Kona 2025","2025-11 (Kona)","","","`#171274 <https://github.com/llvm/llvm-project/issues/171274>`__",""
 "`P3836R2 <https://wg21.link/P3836R2>`__","Make ``optional<T&>`` trivially copyable","2025-11 (Kona)","","","`#171275 <https://github.com/llvm/llvm-project/issues/171275>`__",""

diff  --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h
index 4cd938b54cbf4..97180ab99e441 100644
--- a/libcxx/include/__flat_map/flat_map.h
+++ b/libcxx/include/__flat_map/flat_map.h
@@ -592,6 +592,15 @@ class flat_map {
     __append_sort_merge_unique</*WasSorted = */ false>(ranges::begin(__range), ranges::end(__range));
   }
 
+  template <_ContainerCompatibleRange<value_type> _Range>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_unique_t, _Range&& __range) {
+    if constexpr (ranges::sized_range<_Range>) {
+      __reserve(ranges::size(__range));
+    }
+
+    __append_sort_merge_unique</*WasSorted = */ true>(ranges::begin(__range), ranges::end(__range));
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
     insert(__il.begin(), __il.end());
   }
@@ -741,14 +750,17 @@ class flat_map {
     return iterator(std::move(__key_it), std::move(__mapped_it));
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __y) noexcept {
-    // warning: The spec has unconditional noexcept, which means that
-    // if any of the following functions throw an exception,
-    // std::terminate will be called.
-    // This is discussed in P2767, which hasn't been voted on yet.
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+  swap(flat_map& __y) noexcept(is_nothrow_swappable_v<key_container_type> &&
+                               is_nothrow_swappable_v<mapped_container_type> && is_nothrow_swappable_v<key_compare>) {
+    auto __on_failure = std::__make_exception_guard([&]() noexcept {
+      clear() /* noexcept */;
+      __y.clear() /* noexcept */;
+    });
     ranges::swap(__compare_, __y.__compare_);
     ranges::swap(__containers_.keys, __y.__containers_.keys);
     ranges::swap(__containers_.values, __y.__containers_.values);
+    __on_failure.__complete();
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept {
@@ -886,7 +898,8 @@ class flat_map {
         __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
   }
 
-  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __x, flat_map& __y) noexcept {
+  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+  swap(flat_map& __x, flat_map& __y) noexcept(noexcept(__x.swap(__y))) {
     __x.swap(__y);
   }
 

diff  --git a/libcxx/include/__flat_map/flat_multimap.h b/libcxx/include/__flat_map/flat_multimap.h
index 3db669066ba97..f0540a7d5e8a3 100644
--- a/libcxx/include/__flat_map/flat_multimap.h
+++ b/libcxx/include/__flat_map/flat_multimap.h
@@ -573,6 +573,15 @@ class flat_multimap {
     __append_sort_merge</*WasSorted = */ false>(ranges::begin(__range), ranges::end(__range));
   }
 
+  template <_ContainerCompatibleRange<value_type> _Range>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_equivalent_t, _Range&& __range) {
+    if constexpr (ranges::sized_range<_Range>) {
+      __reserve(ranges::size(__range));
+    }
+
+    __append_sort_merge</*WasSorted = */ true>(ranges::begin(__range), ranges::end(__range));
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
     insert(__il.begin(), __il.end());
   }
@@ -633,13 +642,17 @@ class flat_multimap {
     return iterator(std::move(__key_it), std::move(__mapped_it));
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __y) noexcept {
-    // warning: The spec has unconditional noexcept, which means that
-    // if any of the following functions throw an exception,
-    // std::terminate will be called
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __y) noexcept(
+      is_nothrow_swappable_v<key_container_type> && is_nothrow_swappable_v<mapped_container_type> &&
+      is_nothrow_swappable_v<key_compare>) {
+    auto __on_failure = std::__make_exception_guard([&]() noexcept {
+      clear() /* noexcept */;
+      __y.clear() /* noexcept */;
+    });
     ranges::swap(__compare_, __y.__compare_);
     ranges::swap(__containers_.keys, __y.__containers_.keys);
     ranges::swap(__containers_.values, __y.__containers_.values);
+    __on_failure.__complete();
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept {
@@ -781,7 +794,7 @@ class flat_multimap {
   }
 
   friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
-  swap(flat_multimap& __x, flat_multimap& __y) noexcept {
+  swap(flat_multimap& __x, flat_multimap& __y) noexcept(noexcept(__x.swap(__y))) {
     __x.swap(__y);
   }
 

diff  --git a/libcxx/include/__flat_set/flat_multiset.h b/libcxx/include/__flat_set/flat_multiset.h
index 6a93ec7210e74..b2de63bc3038c 100644
--- a/libcxx/include/__flat_set/flat_multiset.h
+++ b/libcxx/include/__flat_set/flat_multiset.h
@@ -449,6 +449,15 @@ class flat_multiset {
     __append_sort_merge</*WasSorted = */ false>(std::forward<_Range>(__range));
   }
 
+  template <_ContainerCompatibleRange<value_type> _Range>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_equivalent_t, _Range&& __range) {
+    if constexpr (ranges::sized_range<_Range>) {
+      __reserve(ranges::size(__range));
+    }
+
+    __append_sort_merge</*WasSorted = */ true>(std::forward<_Range>(__range));
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
     insert(__il.begin(), __il.end());
   }
@@ -505,13 +514,15 @@ class flat_multiset {
     return iterator(std::move(__key_it));
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multiset& __y) noexcept {
-    // warning: The spec has unconditional noexcept, which means that
-    // if any of the following functions throw an exception,
-    // std::terminate will be called
-    // This is discussed in P3567, which hasn't been voted on yet.
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+  swap(flat_multiset& __y) noexcept(is_nothrow_swappable_v<container_type> && is_nothrow_swappable_v<key_compare>) {
+    auto __on_failure = std::__make_exception_guard([&]() noexcept {
+      clear() /* noexcept */;
+      __y.clear() /* noexcept */;
+    });
     ranges::swap(__compare_, __y.__compare_);
     ranges::swap(__keys_, __y.__keys_);
+    __on_failure.__complete();
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { __keys_.clear(); }
@@ -646,7 +657,7 @@ class flat_multiset {
   }
 
   friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
-  swap(flat_multiset& __x, flat_multiset& __y) noexcept {
+  swap(flat_multiset& __x, flat_multiset& __y) noexcept(noexcept(__x.swap(__y))) {
     __x.swap(__y);
   }
 
@@ -660,7 +671,7 @@ class flat_multiset {
       ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_);
     } else {
       _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
-          ranges::is_sorted(__keys_ | ranges::views::drop(__old_size)), "Key container is not sorted");
+          ranges::is_sorted(__keys_ | ranges::views::drop(__old_size), __compare_), "Key container is not sorted");
     }
     ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_);
     __on_failure.__complete();

diff  --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h
index 1be38f10ea9f3..dad747e7857cd 100644
--- a/libcxx/include/__flat_set/flat_set.h
+++ b/libcxx/include/__flat_set/flat_set.h
@@ -466,6 +466,15 @@ class flat_set {
     __append_sort_merge_unique</*WasSorted = */ false>(std::forward<_Range>(__range));
   }
 
+  template <_ContainerCompatibleRange<value_type> _Range>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(std::sorted_unique_t, _Range&& __range) {
+    if constexpr (ranges::sized_range<_Range>) {
+      __reserve(ranges::size(__range));
+    }
+
+    __append_sort_merge_unique</*WasSorted = */ true>(std::forward<_Range>(__range));
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) {
     insert(__il.begin(), __il.end());
   }
@@ -524,13 +533,15 @@ class flat_set {
     return iterator(std::move(__key_it));
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_set& __y) noexcept {
-    // warning: The spec has unconditional noexcept, which means that
-    // if any of the following functions throw an exception,
-    // std::terminate will be called.
-    // This is discussed in P2767, which hasn't been voted on yet.
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+  swap(flat_set& __y) noexcept(is_nothrow_swappable_v<container_type> && is_nothrow_swappable_v<key_compare>) {
+    auto __on_failure = std::__make_exception_guard([&]() noexcept {
+      clear() /* noexcept */;
+      __y.clear() /* noexcept */;
+    });
     ranges::swap(__compare_, __y.__compare_);
     ranges::swap(__keys_, __y.__keys_);
+    __on_failure.__complete();
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { __keys_.clear(); }
@@ -661,7 +672,8 @@ class flat_set {
         __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
   }
 
-  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_set& __x, flat_set& __y) noexcept {
+  friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
+  swap(flat_set& __x, flat_set& __y) noexcept(noexcept(__x.swap(__y))) {
     __x.swap(__y);
   }
 

diff  --git a/libcxx/include/flat_map b/libcxx/include/flat_map
index eea9896165f06..f2566c7745c88 100644
--- a/libcxx/include/flat_map
+++ b/libcxx/include/flat_map
@@ -17,18 +17,359 @@
 #include <initializer_list>     // see [initializer.list.syn]
 
 namespace std {
+  struct sorted_unique_t { explicit sorted_unique_t() = default; };
+  inline constexpr sorted_unique_t sorted_unique{};
+
   // [flat.map], class template flat_map
   template<class Key, class T, class Compare = less<Key>,
            class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
-    class flat_map;
+  class flat_map {
+  public:
+    // types
+    using key_type               = Key;
+    using mapped_type            = T;
+    using value_type             = pair<key_type, mapped_type>;
+    using key_compare            = Compare;
+    using reference              = pair<const key_type&, mapped_type&>;
+    using const_reference        = pair<const key_type&, const mapped_type&>;
+    using size_type              = size_t;
+    using 
diff erence_type        = ptr
diff _t;
+    using iterator               = implementation-defined; // see [container.requirements]
+    using const_iterator         = implementation-defined; // see [container.requirements]
+    using reverse_iterator       = std::reverse_iterator<iterator>;
+    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+    using key_container_type     = KeyContainer;
+    using mapped_container_type  = MappedContainer;
 
-  struct sorted_unique_t { explicit sorted_unique_t() = default; };
-  inline constexpr sorted_unique_t sorted_unique{};
+    class value_compare {
+    private:
+      key_compare comp;                                         // exposition only
+      constexpr value_compare(key_compare c) : comp(c) { }      // exposition only
+
+    public:
+      constexpr bool operator()(const_reference x, const_reference y) const {
+        return comp(x.first, y.first);
+      }
+    };
+
+    struct containers {
+      key_container_type keys;
+      mapped_container_type values;
+    };
+
+    // [flat.map.cons], constructors
+    constexpr flat_map() : flat_map(key_compare()) { }
+
+    constexpr flat_map(const flat_map&);
+    constexpr flat_map(flat_map&&);
+    constexpr flat_map& operator=(const flat_map&);
+    constexpr flat_map& operator=(flat_map&&);
+
+    constexpr explicit flat_map(const key_compare& comp)
+      : c(), compare(comp) { }
+
+    constexpr flat_map(key_container_type key_cont, mapped_container_type mapped_cont,
+                       const key_compare& comp = key_compare());
+
+    constexpr flat_map(sorted_unique_t, key_container_type key_cont,
+                       mapped_container_type mapped_cont,
+                       const key_compare& comp = key_compare());
+
+    template<class InputIterator>
+      constexpr flat_map(InputIterator first, InputIterator last,
+                         const key_compare& comp = key_compare())
+        : c(), compare(comp) { insert(first, last); }
+
+    template<class InputIterator>
+      constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
+                         const key_compare& comp = key_compare())
+        : c(), compare(comp) { insert(sorted_unique, first, last); }
+
+    template<container-compatible-range<value_type> R>
+      constexpr flat_map(from_range_t, R&& rg)
+        : flat_map(from_range, std::forward<R>(rg), key_compare()) { }
+    template<container-compatible-range<value_type> R>
+      constexpr flat_map(from_range_t, R&& rg, const key_compare& comp)
+        : flat_map(comp) { insert_range(std::forward<R>(rg)); }
+
+    constexpr flat_map(initializer_list<value_type> il, const key_compare& comp = key_compare())
+        : flat_map(il.begin(), il.end(), comp) { }
+
+    constexpr flat_map(sorted_unique_t, initializer_list<value_type> il,
+                       const key_compare& comp = key_compare())
+        : flat_map(sorted_unique, il.begin(), il.end(), comp) { }
+
+    // [flat.map.cons.alloc], constructors with allocators
+
+    template<class Alloc>
+      constexpr explicit flat_map(const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(const key_container_type& key_cont,
+                         const mapped_container_type& mapped_cont,
+                         const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(const key_container_type& key_cont,
+                         const mapped_container_type& mapped_cont,
+                         const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(sorted_unique_t, const key_container_type& key_cont,
+                         const mapped_container_type& mapped_cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(sorted_unique_t, const key_container_type& key_cont,
+                         const mapped_container_type& mapped_cont, const key_compare& comp,
+                         const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(const flat_map&, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(flat_map&&, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_map(InputIterator first, InputIterator last,
+                         const key_compare& comp, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
+                         const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last,
+                         const key_compare& comp, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_map(from_range_t, R&& rg, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(initializer_list<value_type> il, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(initializer_list<value_type> il, const key_compare& comp,
+                         const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_map(sorted_unique_t, initializer_list<value_type> il,
+                         const key_compare& comp, const Alloc& a);
+
+    constexpr flat_map& operator=(initializer_list<value_type>);
+
+    // iterators
+    constexpr iterator               begin() noexcept;
+    constexpr const_iterator         begin() const noexcept;
+    constexpr iterator               end() noexcept;
+    constexpr const_iterator         end() const noexcept;
+
+    constexpr reverse_iterator       rbegin() noexcept;
+    constexpr const_reverse_iterator rbegin() const noexcept;
+    constexpr reverse_iterator       rend() noexcept;
+    constexpr const_reverse_iterator rend() const noexcept;
+
+    constexpr const_iterator         cbegin() const noexcept;
+    constexpr const_iterator         cend() const noexcept;
+    constexpr const_reverse_iterator crbegin() const noexcept;
+    constexpr const_reverse_iterator crend() const noexcept;
+
+    // [flat.map.capacity], capacity
+    constexpr bool empty() const noexcept;
+    constexpr size_type size() const noexcept;
+    constexpr size_type max_size() const noexcept;
+
+    // [flat.map.access], element access
+    constexpr mapped_type& operator[](const key_type& x);
+    constexpr mapped_type& operator[](key_type&& x);
+    template<class K> constexpr mapped_type& operator[](K&& x);
+    constexpr mapped_type& at(const key_type& x);
+    constexpr const mapped_type& at(const key_type& x) const;
+    template<class K> constexpr mapped_type& at(const K& x);
+    template<class K> constexpr const mapped_type& at(const K& x) const;
+
+    // [flat.map.modifiers], modifiers
+    template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
+    template<class... Args>
+      constexpr iterator emplace_hint(const_iterator position, Args&&... args);
+
+    constexpr pair<iterator, bool> insert(const value_type& x)
+      { return emplace(x); }
+    constexpr pair<iterator, bool> insert(value_type&& x)
+      { return emplace(std::move(x)); }
+    constexpr iterator insert(const_iterator position, const value_type& x)
+      { return emplace_hint(position, x); }
+    constexpr iterator insert(const_iterator position, value_type&& x)
+      { return emplace_hint(position, std::move(x)); }
+
+    template<class P> constexpr pair<iterator, bool> insert(P&& x);
+    template<class P>
+      constexpr iterator insert(const_iterator position, P&&);
+    template<class InputIterator>
+      constexpr void insert(InputIterator first, InputIterator last);
+    template<class InputIterator>
+      constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(R&& rg);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(sorted_unique_t, R&& rg);
+
+    constexpr void insert(initializer_list<value_type> il)
+      { insert(il.begin(), il.end()); }
+    constexpr void insert(sorted_unique_t, initializer_list<value_type> il)
+      { insert(sorted_unique, il.begin(), il.end()); }
+
+    constexpr containers extract() &&;
+    constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont);
+
+    template<class... Args>
+      constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
+    template<class... Args>
+      constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
+    template<class K, class... Args>
+      constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args);
+    template<class... Args>
+      constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
+    template<class... Args>
+      constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
+    template<class K, class... Args>
+      constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
+    template<class M>
+      constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
+    template<class M>
+      constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
+    template<class K, class M>
+      constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
+    template<class M>
+      constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
+    template<class M>
+      constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
+    template<class K, class M>
+      constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
+
+    constexpr iterator erase(iterator position);
+    constexpr iterator erase(const_iterator position);
+    constexpr size_type erase(const key_type& x);
+    template<class K> constexpr size_type erase(K&& x);
+    constexpr iterator erase(const_iterator first, const_iterator last);
+
+    constexpr void swap(flat_map& y) noexcept(see below);
+    constexpr void clear() noexcept;
+
+    // observers
+    constexpr key_compare key_comp() const;
+    constexpr value_compare value_comp() const;
+
+    constexpr const key_container_type& keys() const noexcept      { return c.keys; }
+    constexpr const mapped_container_type& values() const noexcept { return c.values; }
+
+    // map operations
+    constexpr iterator find(const key_type& x);
+    constexpr const_iterator find(const key_type& x) const;
+    template<class K> constexpr iterator find(const K& x);
+    template<class K> constexpr const_iterator find(const K& x) const;
+
+    constexpr size_type count(const key_type& x) const;
+    template<class K> constexpr size_type count(const K& x) const;
+
+    constexpr bool contains(const key_type& x) const;
+    template<class K> constexpr bool contains(const K& x) const;
+
+    constexpr iterator lower_bound(const key_type& x);
+    constexpr const_iterator lower_bound(const key_type& x) const;
+    template<class K> constexpr iterator lower_bound(const K& x);
+    template<class K> constexpr const_iterator lower_bound(const K& x) const;
+
+    constexpr iterator upper_bound(const key_type& x);
+    constexpr const_iterator upper_bound(const key_type& x) const;
+    template<class K> constexpr iterator upper_bound(const K& x);
+    template<class K> constexpr const_iterator upper_bound(const K& x) const;
+
+    constexpr pair<iterator, iterator> equal_range(const key_type& x);
+    constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
+    template<class K> constexpr pair<iterator, iterator> equal_range(const K& x);
+    template<class K>
+      constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
+
+    friend constexpr bool operator==(const flat_map& x, const flat_map& y);
+
+    friend constexpr synth-three-way-result<value_type>
+      operator<=>(const flat_map& x, const flat_map& y);
+
+    friend constexpr void swap(flat_map& x, flat_map& y) noexcept(noexcept(x.swap(y)))
+      { x.swap(y); }
+
+  private:
+    containers c;               // exposition only
+    key_compare compare;        // exposition only
+
+    struct key-equiv {  // exposition only
+      constexpr key-equiv(key_compare c) : comp(c) { }
+      constexpr bool operator()(const_reference x, const_reference y) const {
+        return !comp(x.first, y.first) && !comp(y.first, x.first);
+      }
+      key_compare comp;
+    };
+  };
+
+  template<class KeyContainer, class MappedContainer,
+           class Compare = less<typename KeyContainer::value_type>>
+    flat_map(KeyContainer, MappedContainer, Compare = Compare())
+      -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                  Compare, KeyContainer, MappedContainer>;
+
+  template<class KeyContainer, class MappedContainer, class Allocator>
+    flat_map(KeyContainer, MappedContainer, Allocator)
+      -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                  less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
+  template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
+    flat_map(KeyContainer, MappedContainer, Compare, Allocator)
+      -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                  Compare, KeyContainer, MappedContainer>;
+
+  template<class KeyContainer, class MappedContainer,
+           class Compare = less<typename KeyContainer::value_type>>
+    flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare())
+      -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                  Compare, KeyContainer, MappedContainer>;
+
+  template<class KeyContainer, class MappedContainer, class Allocator>
+    flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator)
+      -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                  less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
+  template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
+    flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator)
+      -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                  Compare, KeyContainer, MappedContainer>;
+
+  template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
+    flat_map(InputIterator, InputIterator, Compare = Compare())
+      -> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
+
+  template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
+    flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare())
+      -> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
+
+  template<ranges::input_range R, class Compare = less<range-key-type<R>>,
+           class Allocator = allocator<byte>>
+    flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
+      -> flat_map<range-key-type<R>, range-mapped-type<R>, Compare,
+                  vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>,
+                  vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>;
+
+  template<ranges::input_range R, class Allocator>
+    flat_map(from_range_t, R&&, Allocator)
+      -> flat_map<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>,
+                  vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>,
+                  vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>;
+
+  template<class Key, class T, class Compare = less<Key>>
+    flat_map(initializer_list<pair<Key, T>>, Compare = Compare())
+      -> flat_map<Key, T, Compare>;
+
+  template<class Key, class T, class Compare = less<Key>>
+    flat_map(sorted_unique_t, initializer_list<pair<Key, T>>, Compare = Compare())
+        -> flat_map<Key, T, Compare>;
 
   template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
-           class Allocator>
-    struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>,
-                          Allocator>;
+            class Allocator>
+    struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>, Allocator>
+      : bool_constant<uses_allocator_v<KeyContainer, Allocator> &&
+                      uses_allocator_v<MappedContainer, Allocator>> { };
 
   // [flat.map.erasure], erasure for flat_map
   template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
@@ -36,18 +377,329 @@ namespace std {
     typename flat_map<Key, T, Compare, KeyContainer, MappedContainer>::size_type
       erase_if(flat_map<Key, T, Compare, KeyContainer, MappedContainer>& c, Predicate pred);
 
+  struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
+  inline constexpr sorted_equivalent_t sorted_equivalent{};
+
   // [flat.multimap], class template flat_multimap
   template<class Key, class T, class Compare = less<Key>,
            class KeyContainer = vector<Key>, class MappedContainer = vector<T>>
-    class flat_multimap;
+  class flat_multimap {
+  public:
+    // types
+    using key_type               = Key;
+    using mapped_type            = T;
+    using value_type             = pair<key_type, mapped_type>;
+    using key_compare            = Compare;
+    using reference              = pair<const key_type&, mapped_type&>;
+    using const_reference        = pair<const key_type&, const mapped_type&>;
+    using size_type              = size_t;
+    using 
diff erence_type        = ptr
diff _t;
+    using iterator               = implementation-defined;     // see [container.requirements]
+    using const_iterator         = implementation-defined;     // see [container.requirements]
+    using reverse_iterator       = std::reverse_iterator<iterator>;
+    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+    using key_container_type     = KeyContainer;
+    using mapped_container_type  = MappedContainer;
 
-  struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
-  inline constexpr sorted_equivalent_t sorted_equivalent{};
+    class value_compare {
+    private:
+      key_compare comp;                                         // exposition only
+      constexpr value_compare(key_compare c) : comp(c) { }      // exposition only
+
+    public:
+      constexpr bool operator()(const_reference x, const_reference y) const {
+        return comp(x.first, y.first);
+      }
+    };
+
+    struct containers {
+      key_container_type keys;
+      mapped_container_type values;
+    };
+
+    // [flat.multimap.cons], constructors
+    constexpr flat_multimap() : flat_multimap(key_compare()) { }
+
+    constexpr flat_multimap(const flat_multimap&);
+    constexpr flat_multimap(flat_multimap&&);
+    constexpr flat_multimap& operator=(const flat_multimap&);
+    constexpr flat_multimap& operator=(flat_multimap&&);
+
+    constexpr explicit flat_multimap(const key_compare& comp)
+      : c(), compare(comp) { }
+
+    constexpr flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont,
+                            const key_compare& comp = key_compare());
+
+    constexpr flat_multimap(sorted_equivalent_t,
+                            key_container_type key_cont, mapped_container_type mapped_cont,
+                  const key_compare& comp = key_compare());
+
+    template<class InputIterator>
+      constexpr flat_multimap(InputIterator first, InputIterator last,
+                              const key_compare& comp = key_compare())
+        : c(), compare(comp)
+        { insert(first, last); }
+
+    template<class InputIterator>
+      constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
+                              const key_compare& comp = key_compare())
+        : c(), compare(comp) { insert(sorted_equivalent, first, last); }
+
+    template<container-compatible-range<value_type> R>
+      constexpr flat_multimap(from_range_t, R&& rg)
+        : flat_multimap(from_range, std::forward<R>(rg), key_compare()) { }
+    template<container-compatible-range<value_type> R>
+      constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp)
+        : flat_multimap(comp) { insert_range(std::forward<R>(rg)); }
+
+    constexpr flat_multimap(initializer_list<value_type> il,
+                            const key_compare& comp = key_compare())
+        : flat_multimap(il.begin(), il.end(), comp) { }
+
+    constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
+                            const key_compare& comp = key_compare())
+        : flat_multimap(sorted_equivalent, il.begin(), il.end(), comp) { }
+
+    // [flat.multimap.cons.alloc], constructors with allocators
+
+    template<class Alloc>
+      constexpr explicit flat_multimap(const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(const key_container_type& key_cont,
+                              const mapped_container_type& mapped_cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(const key_container_type& key_cont,
+                              const mapped_container_type& mapped_cont,
+                              const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont,
+                              const mapped_container_type& mapped_cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont,
+                              const mapped_container_type& mapped_cont,
+                              const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(const flat_multimap&, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(flat_multimap&&, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multimap(InputIterator first, InputIterator last,
+                              const key_compare& comp, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
+                              const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last,
+                              const key_compare& comp, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(initializer_list<value_type> il, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(initializer_list<value_type> il, const key_compare& comp,
+                              const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
+                              const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il,
+                              const key_compare& comp, const Alloc& a);
+
+    flat_multimap& operator=(initializer_list<value_type>);
+
+    // iterators
+    constexpr iterator               begin() noexcept;
+    constexpr const_iterator         begin() const noexcept;
+    constexpr iterator               end() noexcept;
+    constexpr const_iterator         end() const noexcept;
+
+    constexpr reverse_iterator       rbegin() noexcept;
+    constexpr const_reverse_iterator rbegin() const noexcept;
+    constexpr reverse_iterator       rend() noexcept;
+    constexpr const_reverse_iterator rend() const noexcept;
+
+    constexpr const_iterator         cbegin() const noexcept;
+    constexpr const_iterator         cend() const noexcept;
+    constexpr const_reverse_iterator crbegin() const noexcept;
+    constexpr const_reverse_iterator crend() const noexcept;
+
+    // capacity
+    constexpr bool empty() const noexcept;
+    constexpr size_type size() const noexcept;
+    constexpr size_type max_size() const noexcept;
+
+    // modifiers
+    template<class... Args> constexpr iterator emplace(Args&&... args);
+    template<class... Args>
+      constexpr iterator emplace_hint(const_iterator position, Args&&... args);
+
+    constexpr iterator insert(const value_type& x)
+      { return emplace(x); }
+    constexpr iterator insert(value_type&& x)
+      { return emplace(std::move(x)); }
+    constexpr iterator insert(const_iterator position, const value_type& x)
+      { return emplace_hint(position, x); }
+    constexpr iterator insert(const_iterator position, value_type&& x)
+      { return emplace_hint(position, std::move(x)); }
+
+    template<class P> constexpr iterator insert(P&& x);
+    template<class P>
+      constexpr iterator insert(const_iterator position, P&&);
+    template<class InputIterator>
+      constexpr void insert(InputIterator first, InputIterator last);
+    template<class InputIterator>
+      constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(R&& rg);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(sorted_equivalent_t, R&& rg);
+
+    constexpr void insert(initializer_list<value_type> il)
+      { insert(il.begin(), il.end()); }
+    constexpr void insert(sorted_equivalent_t, initializer_list<value_type> il)
+      { insert(sorted_equivalent, il.begin(), il.end()); }
+
+    constexpr containers extract() &&;
+    constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont);
+
+    constexpr iterator erase(iterator position);
+    constexpr iterator erase(const_iterator position);
+    constexpr size_type erase(const key_type& x);
+    template<class K> constexpr size_type erase(K&& x);
+    constexpr iterator erase(const_iterator first, const_iterator last);
+
+    constexpr void swap(flat_multimap&)
+      noexcept(is_nothrow_swappable_v<key_container_type> &&
+               is_nothrow_swappable_v<mapped_container_type> &&
+               is_nothrow_swappable_v<key_compare>);
+    constexpr void clear() noexcept;
+
+    // observers
+    constexpr key_compare key_comp() const;
+    constexpr value_compare value_comp() const;
+
+    constexpr const key_container_type& keys() const noexcept { return c.keys; }
+    constexpr const mapped_container_type& values() const noexcept { return c.values; }
+
+    // map operations
+    constexpr iterator find(const key_type& x);
+    constexpr const_iterator find(const key_type& x) const;
+    template<class K> constexpr iterator find(const K& x);
+    template<class K> constexpr const_iterator find(const K& x) const;
+
+    constexpr size_type count(const key_type& x) const;
+    template<class K> constexpr size_type count(const K& x) const;
+
+    constexpr bool contains(const key_type& x) const;
+    template<class K> constexpr bool contains(const K& x) const;
+
+    constexpr iterator lower_bound(const key_type& x);
+    constexpr const_iterator lower_bound(const key_type& x) const;
+    template<class K> constexpr iterator lower_bound(const K& x);
+    template<class K> constexpr const_iterator lower_bound(const K& x) const;
+
+    constexpr iterator upper_bound(const key_type& x);
+    constexpr const_iterator upper_bound(const key_type& x) const;
+    template<class K> constexpr iterator upper_bound(const K& x);
+    template<class K> constexpr const_iterator upper_bound(const K& x) const;
+
+    constexpr pair<iterator, iterator> equal_range(const key_type& x);
+    constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
+    template<class K>
+      constexpr pair<iterator, iterator> equal_range(const K& x);
+    template<class K>
+      constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
+
+    friend constexpr bool operator==(const flat_multimap& x, const flat_multimap& y);
+
+    friend constexpr synth-three-way-result<value_type>
+      operator<=>(const flat_multimap& x, const flat_multimap& y);
+
+    friend constexpr void swap(flat_multimap& x, flat_multimap& y)
+      noexcept(noexcept(x.swap(y)))
+      { x.swap(y); }
+
+  private:
+    containers c;               // exposition only
+    key_compare compare;        // exposition only
+  };
+
+  template<class KeyContainer, class MappedContainer,
+           class Compare = less<typename KeyContainer::value_type>>
+    flat_multimap(KeyContainer, MappedContainer, Compare = Compare())
+      -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                       Compare, KeyContainer, MappedContainer>;
+
+  template<class KeyContainer, class MappedContainer, class Allocator>
+    flat_multimap(KeyContainer, MappedContainer, Allocator)
+      -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                       less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
+  template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
+    flat_multimap(KeyContainer, MappedContainer, Compare, Allocator)
+      -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                       Compare, KeyContainer, MappedContainer>;
+
+  template<class KeyContainer, class MappedContainer,
+           class Compare = less<typename KeyContainer::value_type>>
+    flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare())
+      -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                       Compare, KeyContainer, MappedContainer>;
+
+  template<class KeyContainer, class MappedContainer, class Allocator>
+    flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator)
+      -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                       less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>;
+  template<class KeyContainer, class MappedContainer, class Compare, class Allocator>
+    flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator)
+      -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type,
+                       Compare, KeyContainer, MappedContainer>;
+
+  template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
+    flat_multimap(InputIterator, InputIterator, Compare = Compare())
+      -> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
+
+  template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>>
+    flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare())
+      -> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>;
+
+  template<ranges::input_range R, class Compare = less<range-key-type<R>>,
+           class Allocator = allocator<byte>>
+    flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
+      -> flat_multimap<range-key-type<R>, range-mapped-type<R>, Compare,
+                       vector<range-key-type<R>,
+                              alloc-rebind<Allocator, range-key-type<R>>>,
+                       vector<range-mapped-type<R>,
+                              alloc-rebind<Allocator, range-mapped-type<R>>>>;
+
+  template<ranges::input_range R, class Allocator>
+    flat_multimap(from_range_t, R&&, Allocator)
+      -> flat_multimap<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>,
+                       vector<range-key-type<R>,
+                              alloc-rebind<Allocator, range-key-type<R>>>,
+                       vector<range-mapped-type<R>,
+                              alloc-rebind<Allocator, range-mapped-type<R>>>>;
+
+  template<class Key, class T, class Compare = less<Key>>
+    flat_multimap(initializer_list<pair<Key, T>>, Compare = Compare())
+      -> flat_multimap<Key, T, Compare>;
+
+  template<class Key, class T, class Compare = less<Key>>
+    flat_multimap(sorted_equivalent_t, initializer_list<pair<Key, T>>, Compare = Compare())
+        -> flat_multimap<Key, T, Compare>;
 
   template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,
-           class Allocator>
+            class Allocator>
     struct uses_allocator<flat_multimap<Key, T, Compare, KeyContainer, MappedContainer>,
-                          Allocator>;
+                          Allocator>
+      : bool_constant<uses_allocator_v<KeyContainer, Allocator> &&
+                      uses_allocator_v<MappedContainer, Allocator>> { };
 
   // [flat.multimap.erasure], erasure for flat_multimap
   template<class Key, class T, class Compare, class KeyContainer, class MappedContainer,

diff  --git a/libcxx/include/flat_set b/libcxx/include/flat_set
index 66041a42b79cf..f41e825dbd77e 100644
--- a/libcxx/include/flat_set
+++ b/libcxx/include/flat_set
@@ -17,30 +17,565 @@
 #include <initializer_list>     // see [initializer.list.syn]
 
 namespace std {
+  struct sorted_unique_t { explicit sorted_unique_t() = default; };
+  inline constexpr sorted_unique_t sorted_unique{};
+
   // [flat.set], class template flat_set
   template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
-    class flat_set;
+  class flat_set {
+  public:
+    // types
+    using key_type                  = Key;
+    using value_type                = Key;
+    using key_compare               = Compare;
+    using value_compare             = Compare;
+    using reference                 = value_type&;
+    using const_reference           = const value_type&;
+    using size_type                 = KeyContainer::size_type;
+    using 
diff erence_type           = KeyContainer::
diff erence_type;
+    using iterator                  = implementation-defined;  // see [container.requirements]
+    using const_iterator            = implementation-defined;  // see [container.requirements]
+    using reverse_iterator          = std::reverse_iterator<iterator>;
+    using const_reverse_iterator    = std::reverse_iterator<const_iterator>;
+    using container_type            = KeyContainer;
 
-  struct sorted_unique_t { explicit sorted_unique_t() = default; };
-  inline constexpr sorted_unique_t sorted_unique{};
+    // [flat.set.cons], constructors
+    constexpr flat_set() : flat_set(key_compare()) { }
+
+    constexpr flat_set(const flat_set&);
+    constexpr flat_set(flat_set&&);
+    constexpr flat_set& operator=(const flat_set&);
+    constexpr flat_set& operator=(flat_set&&);
+
+    constexpr explicit flat_set(const key_compare& comp)
+      : c(), compare(comp) { }
+
+    constexpr explicit flat_set(container_type cont, const key_compare& comp = key_compare());
+
+    constexpr flat_set(sorted_unique_t, container_type cont,
+                       const key_compare& comp = key_compare())
+      : c(std::move(cont)), compare(comp) { }
+
+    template<class InputIterator>
+      constexpr flat_set(InputIterator first, InputIterator last,
+                         const key_compare& comp = key_compare())
+        : c(), compare(comp)
+        { insert(first, last); }
+
+    template<class InputIterator>
+      constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
+               const key_compare& comp = key_compare())
+        : c(first, last), compare(comp) { }
+
+    template<container-compatible-range<value_type> R>
+      constexpr flat_set(from_range_t, R&& rg)
+        : flat_set(from_range, std::forward<R>(rg), key_compare()) { }
+    template<container-compatible-range<value_type> R>
+      constexpr flat_set(from_range_t, R&& rg, const key_compare& comp)
+        : flat_set(comp)
+        { insert_range(std::forward<R>(rg)); }
+
+    constexpr flat_set(initializer_list<value_type> il, const key_compare& comp = key_compare())
+        : flat_set(il.begin(), il.end(), comp) { }
+
+    constexpr flat_set(sorted_unique_t, initializer_list<value_type> il,
+             const key_compare& comp = key_compare())
+        : flat_set(sorted_unique, il.begin(), il.end(), comp) { }
+
+    // [flat.set.cons.alloc], constructors with allocators
+
+    template<class Alloc>
+      constexpr explicit flat_set(const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(const container_type& cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(sorted_unique_t, const container_type& cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(sorted_unique_t, const container_type& cont,
+                         const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(const flat_set&, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(flat_set&&, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_set(InputIterator first, InputIterator last,
+                         const key_compare& comp, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
+                         const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last,
+                         const key_compare& comp, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_set(from_range_t, R&& rg, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(initializer_list<value_type> il, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(initializer_list<value_type> il, const key_compare& comp,
+                         const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_set(sorted_unique_t, initializer_list<value_type> il,
+                         const key_compare& comp, const Alloc& a);
+
+    constexpr flat_set& operator=(initializer_list<value_type>);
+
+    // iterators
+    constexpr iterator               begin() noexcept;
+    constexpr const_iterator         begin() const noexcept;
+    constexpr iterator               end() noexcept;
+    constexpr const_iterator         end() const noexcept;
+
+    constexpr reverse_iterator       rbegin() noexcept;
+    constexpr const_reverse_iterator rbegin() const noexcept;
+    constexpr reverse_iterator       rend() noexcept;
+    constexpr const_reverse_iterator rend() const noexcept;
+
+    constexpr const_iterator         cbegin() const noexcept;
+    constexpr const_iterator         cend() const noexcept;
+    constexpr const_reverse_iterator crbegin() const noexcept;
+    constexpr const_reverse_iterator crend() const noexcept;
+
+    // capacity
+    constexpr bool empty() const noexcept;
+    constexpr size_type size() const noexcept;
+    constexpr size_type max_size() const noexcept;
+
+    // [flat.set.modifiers], modifiers
+    template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args);
+    template<class... Args>
+      constexpr iterator emplace_hint(const_iterator position, Args&&... args);
+
+    constexpr pair<iterator, bool> insert(const value_type& x)
+      { return emplace(x); }
+    constexpr pair<iterator, bool> insert(value_type&& x)
+      { return emplace(std::move(x)); }
+    template<class K> constexpr pair<iterator, bool> insert(K&& x);
+    constexpr iterator insert(const_iterator position, const value_type& x)
+      { return emplace_hint(position, x); }
+    constexpr iterator insert(const_iterator position, value_type&& x)
+      { return emplace_hint(position, std::move(x)); }
+    template<class K> constexpr iterator insert(const_iterator hint, K&& x);
+
+    template<class InputIterator>
+      constexpr void insert(InputIterator first, InputIterator last);
+    template<class InputIterator>
+      constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(R&& rg);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(sorted_unique_t, R&& rg);
+
+    constexpr void insert(initializer_list<value_type> il)
+      { insert(il.begin(), il.end()); }
+    constexpr void insert(sorted_unique_t, initializer_list<value_type> il)
+      { insert(sorted_unique, il.begin(), il.end()); }
+
+    constexpr container_type extract() &&;
+    constexpr void replace(container_type&&);
+
+    constexpr iterator erase(iterator position) requires (!same_as<iterator, const_iterator>);
+    constexpr iterator erase(const_iterator position);
+    constexpr size_type erase(const key_type& x);
+    template<class K> constexpr size_type erase(K&& x);
+    constexpr iterator erase(const_iterator first, const_iterator last);
+
+    constexpr void swap(flat_set& y) noexcept(see below);
+    constexpr void clear() noexcept;
+
+    // observers
+    constexpr key_compare key_comp() const;
+    constexpr value_compare value_comp() const;
+
+    // set operations
+    constexpr iterator find(const key_type& x);
+    constexpr const_iterator find(const key_type& x) const;
+    template<class K> constexpr iterator find(const K& x);
+    template<class K> constexpr const_iterator find(const K& x) const;
+
+    constexpr size_type count(const key_type& x) const;
+    template<class K> constexpr size_type count(const K& x) const;
+
+    constexpr bool contains(const key_type& x) const;
+    template<class K> constexpr bool contains(const K& x) const;
+
+    constexpr iterator lower_bound(const key_type& x);
+    constexpr const_iterator lower_bound(const key_type& x) const;
+    template<class K> constexpr iterator lower_bound(const K& x);
+    template<class K> constexpr const_iterator lower_bound(const K& x) const;
+
+    constexpr iterator upper_bound(const key_type& x);
+    constexpr const_iterator upper_bound(const key_type& x) const;
+    template<class K> constexpr iterator upper_bound(const K& x);
+    template<class K> constexpr const_iterator upper_bound(const K& x) const;
+
+    constexpr pair<iterator, iterator> equal_range(const key_type& x);
+    constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
+    template<class K>
+      constexpr pair<iterator, iterator> equal_range(const K& x);
+    template<class K>
+      constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
+
+    friend constexpr bool operator==(const flat_set& x, const flat_set& y);
+
+    friend constexpr synth-three-way-result<value_type>
+      operator<=>(const flat_set& x, const flat_set& y);
+
+    friend constexpr void swap(flat_set& x, flat_set& y) noexcept(noexcept(x.swap(y)))
+      { x.swap(y); }
+
+  private:
+    container_type c;           // exposition only
+    key_compare compare;        // exposition only
+  };
+
+  template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
+    flat_set(KeyContainer, Compare = Compare())
+      -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
+  template<class KeyContainer, class Allocator>
+    flat_set(KeyContainer, Allocator)
+      -> flat_set<typename KeyContainer::value_type,
+                  less<typename KeyContainer::value_type>, KeyContainer>;
+  template<class KeyContainer, class Compare, class Allocator>
+    flat_set(KeyContainer, Compare, Allocator)
+      -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
+
+  template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
+    flat_set(sorted_unique_t, KeyContainer, Compare = Compare())
+      -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
+  template<class KeyContainer, class Allocator>
+    flat_set(sorted_unique_t, KeyContainer, Allocator)
+      -> flat_set<typename KeyContainer::value_type,
+                  less<typename KeyContainer::value_type>, KeyContainer>;
+  template<class KeyContainer, class Compare, class Allocator>
+    flat_set(sorted_unique_t, KeyContainer, Compare, Allocator)
+      -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
+
+  template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
+    flat_set(InputIterator, InputIterator, Compare = Compare())
+      -> flat_set<iter-value-type<InputIterator>, Compare>;
+
+  template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
+    flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare())
+      -> flat_set<iter-value-type<InputIterator>, Compare>;
+
+  template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>,
+           class Allocator = allocator<ranges::range_value_t<R>>>
+    flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
+      -> flat_set<ranges::range_value_t<R>, Compare,
+                  vector<ranges::range_value_t<R>,
+                         alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
+
+  template<ranges::input_range R, class Allocator>
+    flat_set(from_range_t, R&&, Allocator)
+      -> flat_set<ranges::range_value_t<R>, less<ranges::range_value_t<R>>,
+                  vector<ranges::range_value_t<R>,
+                         alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
+
+  template<class Key, class Compare = less<Key>>
+    flat_set(initializer_list<Key>, Compare = Compare())
+      -> flat_set<Key, Compare>;
+
+  template<class Key, class Compare = less<Key>>
+    flat_set(sorted_unique_t, initializer_list<Key>, Compare = Compare())
+      -> flat_set<Key, Compare>;
 
   template<class Key, class Compare, class KeyContainer, class Allocator>
-    struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator>;
+    struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator>
+      : bool_constant<uses_allocator_v<KeyContainer, Allocator>> { };
 
   // [flat.set.erasure], erasure for flat_set
   template<class Key, class Compare, class KeyContainer, class Predicate>
     typename flat_set<Key, Compare, KeyContainer>::size_type
       erase_if(flat_set<Key, Compare, KeyContainer>& c, Predicate pred);
 
+  struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
+  inline constexpr sorted_equivalent_t sorted_equivalent{};
+
    // [flat.multiset], class template flat_multiset
   template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
-    class flat_multiset;
+  class flat_multiset {
+  public:
+    // types
+    using key_type                  = Key;
+    using value_type                = Key;
+    using key_compare               = Compare;
+    using value_compare             = Compare;
+    using reference                 = value_type&;
+    using const_reference           = const value_type&;
+    using size_type                 = KeyContainer::size_type;
+    using 
diff erence_type           = KeyContainer::
diff erence_type;
+    using iterator                  = implementation-defined;  // see [container.requirements]
+    using const_iterator            = implementation-defined;  // see [container.requirements]
+    using reverse_iterator          = std::reverse_iterator<iterator>;
+    using const_reverse_iterator    = std::reverse_iterator<const_iterator>;
+    using container_type            = KeyContainer;
 
-  struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
-  inline constexpr sorted_equivalent_t sorted_equivalent{};
+    // [flat.multiset.cons], constructors
+    constexpr flat_multiset() : flat_multiset(key_compare()) { }
+
+    constexpr flat_multiset(const flat_multiset&);
+    constexpr flat_multiset(flat_multiset&&);
+    constexpr flat_multiset& operator=(const flat_multiset&);
+    constexpr flat_multiset& operator=(flat_multiset&&);
+
+    constexpr explicit flat_multiset(const key_compare& comp)
+      : c(), compare(comp) { }
+
+    constexpr explicit flat_multiset(container_type cont,
+                                     const key_compare& comp = key_compare());
+
+    constexpr flat_multiset(sorted_equivalent_t, container_type cont,
+                            const key_compare& comp = key_compare())
+      : c(std::move(cont)), compare(comp) { }
+
+    template<class InputIterator>
+      constexpr flat_multiset(InputIterator first, InputIterator last,
+                              const key_compare& comp = key_compare())
+        : c(), compare(comp)
+        { insert(first, last); }
+
+    template<class InputIterator>
+      constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
+                              const key_compare& comp = key_compare())
+        : c(first, last), compare(comp) { }
+
+    template<container-compatible-range<value_type> R>
+      constexpr flat_multiset(from_range_t, R&& rg)
+        : flat_multiset(from_range, std::forward<R>(rg), key_compare()) { }
+    template<container-compatible-range<value_type> R>
+      constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp)
+        : flat_multiset(comp)
+        { insert_range(std::forward<R>(rg)); }
+
+    constexpr flat_multiset(initializer_list<value_type> il,
+                            const key_compare& comp = key_compare())
+      : flat_multiset(il.begin(), il.end(), comp) { }
+
+    constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
+                            const key_compare& comp = key_compare())
+        : flat_multiset(sorted_equivalent, il.begin(), il.end(), comp) { }
+
+    // [flat.multiset.cons.alloc], constructors with allocators
+
+    template<class Alloc>
+      constexpr explicit flat_multiset(const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(const container_type& cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(const container_type& cont, const key_compare& comp,
+                              const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(sorted_equivalent_t, const container_type& cont,
+                              const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(const flat_multiset&, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(flat_multiset&&, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multiset(InputIterator first, InputIterator last,
+                              const key_compare& comp, const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
+                              const Alloc& a);
+    template<class InputIterator, class Alloc>
+      constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last,
+                              const key_compare& comp, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a);
+    template<container-compatible-range<value_type> R, class Alloc>
+      constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp,
+                              const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
+                              const Alloc& a);
+    template<class Alloc>
+      constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il,
+                              const key_compare& comp, const Alloc& a);
+
+    constexpr flat_multiset& operator=(initializer_list<value_type>);
+
+    // iterators
+    constexpr iterator               begin() noexcept;
+    constexpr const_iterator         begin() const noexcept;
+    constexpr iterator               end() noexcept;
+    constexpr const_iterator         end() const noexcept;
+
+    constexpr reverse_iterator       rbegin() noexcept;
+    constexpr const_reverse_iterator rbegin() const noexcept;
+    constexpr reverse_iterator       rend() noexcept;
+    constexpr const_reverse_iterator rend() const noexcept;
+
+    constexpr const_iterator         cbegin() const noexcept;
+    constexpr const_iterator         cend() const noexcept;
+    constexpr const_reverse_iterator crbegin() const noexcept;
+    constexpr const_reverse_iterator crend() const noexcept;
+
+    // capacity
+    constexpr bool empty() const noexcept;
+    constexpr size_type size() const noexcept;
+    constexpr size_type max_size() const noexcept;
+
+    // [flat.multiset.modifiers], modifiers
+    template<class... Args> constexpr iterator emplace(Args&&... args);
+    template<class... Args>
+      constexpr iterator emplace_hint(const_iterator position, Args&&... args);
+
+    constexpr iterator insert(const value_type& x)
+      { return emplace(x); }
+    constexpr iterator insert(value_type&& x)
+      { return emplace(std::move(x)); }
+    constexpr iterator insert(const_iterator position, const value_type& x)
+      { return emplace_hint(position, x); }
+    constexpr iterator insert(const_iterator position, value_type&& x)
+      { return emplace_hint(position, std::move(x)); }
+
+    template<class InputIterator>
+      constexpr void insert(InputIterator first, InputIterator last);
+    template<class InputIterator>
+      constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(R&& rg);
+    template<container-compatible-range<value_type> R>
+      constexpr void insert_range(sorted_equivalent_t, R&& rg);
+
+    constexpr void insert(initializer_list<value_type> il)
+      { insert(il.begin(), il.end()); }
+    constexpr void insert(sorted_equivalent_t, initializer_list<value_type> il)
+      { insert(sorted_equivalent, il.begin(), il.end()); }
+
+    constexpr container_type extract() &&;
+    constexpr void replace(container_type&&);
+
+    constexpr iterator erase(iterator position) requires (!same_as<iterator, const_iterator>);
+    constexpr iterator erase(const_iterator position);
+    constexpr size_type erase(const key_type& x);
+    template<class K> constexpr size_type erase(K&& x);
+    constexpr iterator erase(const_iterator first, const_iterator last);
+
+    constexpr void swap(flat_multiset& y) noexcept(see below);
+    constexpr void clear() noexcept;
+
+    // observers
+    constexpr key_compare key_comp() const;
+    constexpr value_compare value_comp() const;
+
+    // set operations
+    constexpr iterator find(const key_type& x);
+    constexpr const_iterator find(const key_type& x) const;
+    template<class K> constexpr iterator find(const K& x);
+    template<class K> constexpr const_iterator find(const K& x) const;
+
+    constexpr size_type count(const key_type& x) const;
+    template<class K> constexpr size_type count(const K& x) const;
+
+    constexpr bool contains(const key_type& x) const;
+    template<class K> constexpr bool contains(const K& x) const;
+
+    constexpr iterator lower_bound(const key_type& x);
+    constexpr const_iterator lower_bound(const key_type& x) const;
+    template<class K> constexpr iterator lower_bound(const K& x);
+    template<class K> constexpr const_iterator lower_bound(const K& x) const;
+
+    constexpr iterator upper_bound(const key_type& x);
+    constexpr const_iterator upper_bound(const key_type& x) const;
+    template<class K> constexpr iterator upper_bound(const K& x);
+    template<class K> constexpr const_iterator upper_bound(const K& x) const;
+
+    constexpr pair<iterator, iterator> equal_range(const key_type& x);
+    constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const;
+    template<class K>
+      constexpr pair<iterator, iterator> equal_range(const K& x);
+    template<class K>
+      constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const;
+
+    friend constexpr bool operator==(const flat_multiset& x, const flat_multiset& y);
+
+    friend constexpr synth-three-way-result<value_type>
+      operator<=>(const flat_multiset& x, const flat_multiset& y);
+
+    friend constexpr void swap(flat_multiset& x, flat_multiset& y)
+      noexcept(noexcept(x.swap(y)))
+      { x.swap(y); }
+
+  private:
+    container_type c;           // exposition only
+    key_compare compare;        // exposition only
+  };
+
+  template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
+    flat_multiset(KeyContainer, Compare = Compare())
+      -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
+  template<class KeyContainer, class Allocator>
+    flat_multiset(KeyContainer, Allocator)
+      -> flat_multiset<typename KeyContainer::value_type,
+                       less<typename KeyContainer::value_type>, KeyContainer>;
+  template<class KeyContainer, class Compare, class Allocator>
+    flat_multiset(KeyContainer, Compare, Allocator)
+      -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
+
+  template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
+    flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare())
+      -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
+  template<class KeyContainer, class Allocator>
+    flat_multiset(sorted_equivalent_t, KeyContainer, Allocator)
+      -> flat_multiset<typename KeyContainer::value_type,
+                       less<typename KeyContainer::value_type>, KeyContainer>;
+  template<class KeyContainer, class Compare, class Allocator>
+    flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator)
+      -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>;
+
+  template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
+    flat_multiset(InputIterator, InputIterator, Compare = Compare())
+      -> flat_multiset<iter-value-type<InputIterator>, Compare>;
+
+  template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
+    flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare())
+      -> flat_multiset<iter-value-type<InputIterator>, Compare>;
+
+  template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>,
+           class Allocator = allocator<ranges::range_value_t<R>>>
+    flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator())
+      -> flat_multiset<ranges::range_value_t<R>, Compare,
+                       vector<ranges::range_value_t<R>,
+                              alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
+
+  template<ranges::input_range R, class Allocator>
+    flat_multiset(from_range_t, R&&, Allocator)
+      -> flat_multiset<ranges::range_value_t<R>, less<ranges::range_value_t<R>>,
+                       vector<ranges::range_value_t<R>,
+                              alloc-rebind<Allocator, ranges::range_value_t<R>>>>;
+
+  template<class Key, class Compare = less<Key>>
+    flat_multiset(initializer_list<Key>, Compare = Compare())
+      -> flat_multiset<Key, Compare>;
+
+  template<class Key, class Compare = less<Key>>
+  flat_multiset(sorted_equivalent_t, initializer_list<Key>, Compare = Compare())
+      -> flat_multiset<Key, Compare>;
 
   template<class Key, class Compare, class KeyContainer, class Allocator>
-    struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>;
+    struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>
+      : bool_constant<uses_allocator_v<KeyContainer, Allocator>> { };
 
   // [flat.multiset.erasure], erasure for flat_multiset
   template<class Key, class Compare, class KeyContainer, class Predicate>

diff  --git a/libcxx/include/version b/libcxx/include/version
index c4daaffd89acf..f959c0ab227ac 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -111,7 +111,7 @@ __cpp_lib_execution                                     201902L <execution>
                                                         201603L // C++17
 __cpp_lib_expected                                      202211L <expected>
 __cpp_lib_filesystem                                    201703L <filesystem>
-__cpp_lib_flat_map                                      202207L <flat_map>
+__cpp_lib_flat_map                                      202511L <flat_map>
 __cpp_lib_flat_set                                      202207L <flat_set>
 __cpp_lib_format                                        202110L <format>
 __cpp_lib_format_path                                   202403L <filesystem>
@@ -498,7 +498,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_constexpr_typeinfo                   202106L
 # define __cpp_lib_containers_ranges                    202202L
 # define __cpp_lib_expected                             202211L
-# define __cpp_lib_flat_map                             202207L
+# define __cpp_lib_flat_map                             202511L
 # define __cpp_lib_flat_set                             202207L
 # define __cpp_lib_format_ranges                        202207L
 // # define __cpp_lib_formatters                           202302L

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp
new file mode 100644
index 0000000000000..124130aa3e108
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_range_sorted_unique.pass.cpp
@@ -0,0 +1,121 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_map>
+
+// template<container-compatible-range<value_type> R>
+//   void insert_range(sorted_unique, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_map>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward<R>(r)); };
+
+using Map = std::flat_map<int, double>;
+
+static_assert(CanInsertRangeSortedUnique<Map, std::ranges::subrange<std::pair<int, double>*>>);
+static_assert(CanInsertRangeSortedUnique<Map, std::ranges::subrange<std::pair<short, double>*>>);
+static_assert(!CanInsertRangeSortedUnique<Map, std::ranges::subrange<int*>>);
+static_assert(!CanInsertRangeSortedUnique<Map, std::ranges::subrange<double*>>);
+
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+  using Key   = typename KeyContainer::value_type;
+  using Value = typename ValueContainer::value_type;
+
+  {
+    using P                 = std::pair<int, int>;
+    using M                 = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+    using It                = forward_iterator<const P*>;
+    M m                     = {{10, 1}, {8, 2}, {5, 3}, {2, 4}, {1, 5}};
+    P ar[]                  = {{1, 2}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+    std::ranges::subrange r = {It(ar), It(ar + 5)};
+    static_assert(std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_unique, r);
+    assert((m == M{{1, 5}, {2, 4}, {3, 1}, {4, 3}, {5, 3}, {8, 2}, {9, 6}, {10, 1}}));
+  }
+  {
+    using P                 = std::pair<int, int>;
+    using M                 = std::flat_map<Key, Value, std::greater<>, KeyContainer, ValueContainer>;
+    using It                = cpp20_input_iterator<const P*>;
+    M m                     = {{8, 1}, {5, 2}, {3, 3}, {2, 4}};
+    P ar[]                  = {{9, 6}, {5, 5}, {4, 3}, {3, 1}, {1, 2}};
+    std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 5))};
+    static_assert(!std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_unique, r);
+    assert((m == M{{1, 2}, {2, 4}, {3, 3}, {4, 3}, {5, 2}, {8, 1}, {9, 6}}));
+  }
+  {
+    // was empty
+    using P = std::pair<int, int>;
+    using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+    M m;
+    P ar[] = {{1, 2}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+    m.insert_range(std::sorted_unique, ar);
+    assert(std::ranges::equal(m, ar));
+  }
+}
+
+constexpr bool test() {
+  test<std::vector<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+  if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+  {
+    test<std::deque<int>, std::vector<int>>();
+  }
+  test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
+  test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+  {
+    // Items are forwarded correctly from the input range
+    std::pair<MoveOnly, MoveOnly> a[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    std::flat_map<MoveOnly, MoveOnly> m;
+    m.insert_range(std::sorted_unique, a | std::views::as_rvalue);
+    std::pair<MoveOnly, MoveOnly> expected[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    assert(std::ranges::equal(m, expected));
+  }
+  {
+    // The element type of the range doesn't need to be std::pair
+    std::pair<int, int> pa[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    std::vector<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 4);
+    std::flat_map<int, int> m;
+    m.insert_range(std::sorted_unique, a);
+    std::pair<int, int> expected[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    assert(std::ranges::equal(m, expected));
+  }
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_unique, newValues); };
+    test_insert_range_exception_guarantee(insert_func);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
index f9708aac62c7e..16f9f8fdbff9f 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_exception.pass.cpp
@@ -7,9 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
-// UNSUPPORTED: no-localization
 // UNSUPPORTED: no-exceptions
 
 // <flat_map>
@@ -17,7 +14,7 @@
 // void swap(flat_map& y) noexcept;
 // friend void swap(flat_map& x, flat_map& y) noexcept
 
-// Test that std::terminate is called if any exception is thrown during swap
+// Test that the invariants are maintained if any exception is thrown during swap
 
 #include <flat_map>
 #include <cassert>
@@ -27,7 +24,6 @@
 
 #include "test_macros.h"
 #include "../helpers.h"
-#include "check_assertion.h"
 
 template <class F>
 void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
@@ -42,8 +38,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
     m1.emplace(2, 2);
     m2.emplace(3, 3);
     m2.emplace(4, 4);
-    // swap is noexcept
-    EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+    try {
+      swap_function(m1, m2);
+      assert(false);
+    } catch (int) {
+      check_invariant(m1);
+      check_invariant(m2);
+      LIBCPP_ASSERT(m1.size() == 0);
+      LIBCPP_ASSERT(m2.size() == 0);
+    }
   }
 
   {
@@ -58,8 +61,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
     m2.emplace(3, 3);
     m2.emplace(4, 4);
 
-    // swap is noexcept
-    EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+    try {
+      swap_function(m1, m2);
+      assert(false);
+    } catch (int) {
+      check_invariant(m1);
+      check_invariant(m2);
+      LIBCPP_ASSERT(m1.size() == 0);
+      LIBCPP_ASSERT(m2.size() == 0);
+    }
   }
 }
 

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
index 37f2914ebfdb2..c7410960ef5a8 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_free.pass.cpp
@@ -31,11 +31,10 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
   { swap(t1, t2) } noexcept;
 };
 
-static_assert(NoExceptAdlSwap<std::flat_map<int, int>>);
-
+static_assert(NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
 static_assert(
-    NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
+    !NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
 #endif
 
 template <class KeyContainer, class ValueContainer>

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
index 771bcd3de2c09..6a00a155f8e16 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/swap_member.pass.cpp
@@ -10,7 +10,7 @@
 
 // <flat_map>
 
-// void swap(flat_map& y) noexcept;
+// void swap(flat_map& y) noexcept(see below);
 
 #include <flat_map>
 #include <cassert>
@@ -31,10 +31,10 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
   { t1.swap(t2) } noexcept;
 };
 
-static_assert(NoExceptMemberSwap<std::flat_map<int, int>>);
+static_assert(NoExceptMemberSwap<std::flat_map<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
 static_assert(
-    NoExceptMemberSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
+    !NoExceptMemberSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
 #endif
 
 template <class KeyContainer, class ValueContainer>

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp
new file mode 100644
index 0000000000000..95d56478970e9
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/insert_range_sorted_equivalent.pass.cpp
@@ -0,0 +1,123 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_map>
+
+// class flat_multimap
+
+// template<container-compatible-range<value_type> R>
+//   void insert_range(sorted_equivalent_t, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_map>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRangeSortedEquivalent =
+    requires(M m, R&& r) { m.insert_range(std::sorted_equivalent, std::forward<R>(r)); };
+
+using Map = std::flat_multimap<int, double>;
+
+static_assert(CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<std::pair<int, double>*>>);
+static_assert(CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<std::pair<short, double>*>>);
+static_assert(!CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<int*>>);
+static_assert(!CanInsertRangeSortedEquivalent<Map, std::ranges::subrange<double*>>);
+
+template <class KeyContainer, class ValueContainer>
+constexpr void test() {
+  using Key   = typename KeyContainer::value_type;
+  using Value = typename ValueContainer::value_type;
+
+  {
+    using P                 = std::pair<int, int>;
+    using M                 = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+    using It                = forward_iterator<const P*>;
+    M m                     = {{10, 1}, {8, 2}, {5, 3}, {2, 4}, {1, 5}};
+    P ar[]                  = {{1, 2}, {1, 4}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+    std::ranges::subrange r = {It(ar), It(ar + 6)};
+    static_assert(std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_equivalent, r);
+    std::vector<P> expected = {{1, 5}, {1, 2}, {1, 4}, {2, 4}, {3, 1}, {4, 3}, {5, 3}, {5, 5}, {8, 2}, {9, 6}, {10, 1}};
+    assert(std::ranges::equal(m, expected));
+  }
+  {
+    using P                 = std::pair<int, int>;
+    using M                 = std::flat_multimap<Key, Value, std::greater<>, KeyContainer, ValueContainer>;
+    using It                = cpp20_input_iterator<const P*>;
+    M m                     = {{8, 1}, {5, 2}, {3, 3}, {2, 4}};
+    P ar[]                  = {{9, 6}, {5, 5}, {4, 3}, {3, 1}, {1, 2}, {1, 4}};
+    std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 6))};
+    static_assert(!std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_equivalent, r);
+    std::vector<P> expected = {{9, 6}, {8, 1}, {5, 2}, {5, 5}, {4, 3}, {3, 3}, {3, 1}, {2, 4}, {1, 2}, {1, 4}};
+    assert(std::ranges::equal(m, expected));
+  }
+  {
+    // was empty
+    using P = std::pair<int, int>;
+    using M = std::flat_multimap<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
+    M m;
+    P ar[] = {{1, 2}, {1, 4}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
+    m.insert_range(std::sorted_equivalent, ar);
+    assert(std::ranges::equal(m, ar));
+  }
+}
+
+constexpr bool test() {
+  test<std::vector<int>, std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+  if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+    test<std::deque<int>, std::vector<int>>();
+  test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
+  test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
+  {
+    // Items are forwarded correctly from the input range
+    std::pair<MoveOnly, MoveOnly> a[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    std::flat_multimap<MoveOnly, MoveOnly> m;
+    m.insert_range(std::sorted_equivalent, a | std::views::as_rvalue);
+    std::pair<MoveOnly, MoveOnly> expected[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    assert(std::ranges::equal(m, expected));
+  }
+  {
+    // The element type of the range doesn't need to be std::pair
+    std::pair<int, int> pa[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    std::vector<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 5);
+    std::flat_multimap<int, int> m;
+    m.insert_range(a);
+    std::pair<int, int> expected[] = {{1, 1}, {1, 1}, {3, 3}, {4, 4}, {5, 5}};
+    assert(std::ranges::equal(m, expected));
+  }
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_equivalent, newValues); };
+    test_insert_range_exception_guarantee(insert_func);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
index a1252f301309a..79ae419d1df37 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_exception.pass.cpp
@@ -7,9 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
-// UNSUPPORTED: no-localization
 // UNSUPPORTED: no-exceptions
 
 // <flat_map>
@@ -29,7 +26,6 @@
 
 #include "test_macros.h"
 #include "../helpers.h"
-#include "check_assertion.h"
 
 template <class F>
 void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
@@ -44,8 +40,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
     m1.emplace(1, 2);
     m2.emplace(3, 3);
     m2.emplace(3, 4);
-    // swap is noexcept
-    EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+    try {
+      swap_function(m1, m2);
+      assert(false);
+    } catch (int) {
+      check_invariant(m1);
+      check_invariant(m2);
+      LIBCPP_ASSERT(m1.size() == 0);
+      LIBCPP_ASSERT(m2.size() == 0);
+    }
   }
 
   {
@@ -60,8 +63,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
     m2.emplace(3, 3);
     m2.emplace(3, 4);
 
-    // swap is noexcept
-    EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+    try {
+      swap_function(m1, m2);
+      assert(false);
+    } catch (int) {
+      check_invariant(m1);
+      check_invariant(m2);
+      LIBCPP_ASSERT(m1.size() == 0);
+      LIBCPP_ASSERT(m2.size() == 0);
+    }
   }
 }
 

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
index efad2d78d5b76..f714af77ca647 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_free.pass.cpp
@@ -33,10 +33,9 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
   { swap(t1, t2) } noexcept;
 };
 
-static_assert(NoExceptAdlSwap<std::flat_multimap<int, int>>);
-
+static_assert(NoExceptAdlSwap< std::flat_multimap<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptAdlSwap<
+static_assert(!NoExceptAdlSwap<
               std::flat_multimap<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
 #endif
 

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
index 8f31884aa3a5f..0c6211ab3c2cc 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.modifiers/swap_member.pass.cpp
@@ -33,9 +33,9 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
   { t1.swap(t2) } noexcept;
 };
 
-static_assert(NoExceptMemberSwap<std::flat_multimap<int, int>>);
+static_assert(NoExceptMemberSwap< std::flat_multimap<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptMemberSwap<
+static_assert(!NoExceptMemberSwap<
               std::flat_multimap<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
 #endif
 

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp
new file mode 100644
index 0000000000000..840f688795e5b
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/insert_range_sorted_equivalent.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_set>
+
+// template<container-compatible-range<value_type> R>
+//   void insert_range(sorted_equivalent_t, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_set>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward<R>(r)); };
+
+using Set = std::flat_multiset<int, double>;
+
+static_assert(CanInsertRange<Set, std::ranges::subrange<int*>>);
+static_assert(CanInsertRange<Set, std::ranges::subrange<short*>>);
+static_assert(!CanInsertRange<Set, std::ranges::subrange<std::pair<int, int>*>>);
+static_assert(!CanInsertRange<Set, std::ranges::subrange<std::pair<short, short>*>>);
+
+template <class KeyContainer>
+constexpr void test_one() {
+  using Key = typename KeyContainer::value_type;
+
+  {
+    using M                 = std::flat_multiset<Key, std::less<Key>, KeyContainer>;
+    using It                = forward_iterator<const int*>;
+    M m                     = {10, 10, 8, 5, 2, 1, 1};
+    int ar[]                = {1, 1, 3, 4, 5, 9};
+    std::ranges::subrange r = {It(ar), It(ar + 6)};
+    static_assert(std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_equivalent, r);
+    assert((m == M{1, 1, 1, 1, 2, 3, 4, 5, 5, 8, 9, 10, 10}));
+  }
+  {
+    using M                 = std::flat_multiset<Key, std::greater<>, KeyContainer>;
+    using It                = cpp20_input_iterator<const int*>;
+    M m                     = {10, 10, 8, 5, 2, 1, 1};
+    int ar[]                = {9, 5, 4, 3, 1, 1};
+    std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 6))};
+    static_assert(!std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_equivalent, r);
+    assert((m == M{1, 1, 1, 1, 2, 3, 4, 5, 5, 8, 9, 10, 10}));
+  }
+  {
+    // was empty
+    using M = std::flat_multiset<Key, std::less<Key>, KeyContainer>;
+    M m;
+    int ar[] = {1, 1, 3, 4, 5, 9};
+    m.insert_range(std::sorted_equivalent, ar);
+    assert((m == M{1, 1, 3, 4, 5, 9}));
+  }
+}
+
+constexpr bool test() {
+  test_one<std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+  if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+    test_one<std::deque<int>>();
+  test_one<MinSequenceContainer<int>>();
+  test_one<std::vector<int, min_allocator<int>>>();
+  {
+    // Items are forwarded correctly from the input range.
+    MoveOnly a[] = {1, 1, 3, 4, 5};
+    std::flat_multiset<MoveOnly> m;
+    m.insert_range(std::sorted_equivalent, a | std::views::as_rvalue);
+    MoveOnly expected[] = {1, 1, 3, 4, 5};
+    assert(std::ranges::equal(m, expected));
+  }
+
+  return true;
+}
+
+void test_exception() {
+  auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_equivalent, newValues); };
+  test_insert_range_exception_guarantee(insert_func);
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+  test_exception();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
index 705ee88994872..4c6f55dd13fe8 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_exception.pass.cpp
@@ -7,9 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
-// UNSUPPORTED: no-localization
 // UNSUPPORTED: no-exceptions
 
 // <flat_set>
@@ -27,7 +24,6 @@
 
 #include "test_macros.h"
 #include "../helpers.h"
-#include "check_assertion.h"
 
 template <class F>
 void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
@@ -41,8 +37,16 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
     m1.emplace(1);
     m2.emplace(1);
     m2.emplace(4);
-    // swap is noexcept
-    EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+
+    try {
+      swap_function(m1, m2);
+      assert(false);
+    } catch (int) {
+      check_invariant(m1);
+      check_invariant(m2);
+      LIBCPP_ASSERT(m1.size() == 0);
+      LIBCPP_ASSERT(m2.size() == 0);
+    }
   }
 }
 

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
index 241f2cf9e0a73..158520d36869c 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_free.pass.cpp
@@ -31,10 +31,9 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
   { swap(t1, t2) } noexcept;
 };
 
-static_assert(NoExceptAdlSwap<std::flat_multiset<int>>);
-
+static_assert(NoExceptAdlSwap<std::flat_multiset<int, std::less<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptAdlSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptAdlSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
 #endif
 
 template <class KeyContainer>

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
index 7ad96ed340955..d5192fa742e81 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/flat.multiset.modifiers/swap_member.pass.cpp
@@ -31,9 +31,9 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
   { t1.swap(t2) } noexcept;
 };
 
-static_assert(NoExceptMemberSwap<std::flat_multiset<int>>);
+static_assert(NoExceptMemberSwap<std::flat_multiset<int, std::less<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptMemberSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptMemberSwap<std::flat_multiset<int, std::less<int>, ThrowOnMoveContainer<int>>>);
 #endif
 
 template <class KeyContainer>

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp
new file mode 100644
index 0000000000000..8d41914fe7ac9
--- /dev/null
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/insert_range_sorted_unique.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <flat_set>
+
+// template<container-compatible-range<value_type> R>
+//   void insert_range(sorted_unique_t, R&& rg);
+
+#include <algorithm>
+#include <deque>
+#include <flat_set>
+#include <functional>
+#include <ranges>
+#include <vector>
+
+#include "MinSequenceContainer.h"
+#include "../helpers.h"
+#include "MoveOnly.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+
+// test constraint container-compatible-range
+template <class M, class R>
+concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward<R>(r)); };
+
+using Set = std::flat_set<int, double>;
+
+static_assert(CanInsertRangeSortedUnique<Set, std::ranges::subrange<int*>>);
+static_assert(CanInsertRangeSortedUnique<Set, std::ranges::subrange<short*>>);
+static_assert(!CanInsertRangeSortedUnique<Set, std::ranges::subrange<std::pair<int, int>*>>);
+static_assert(!CanInsertRangeSortedUnique<Set, std::ranges::subrange<std::pair<short, short>*>>);
+
+template <class KeyContainer>
+constexpr void test_one() {
+  using Key = typename KeyContainer::value_type;
+
+  {
+    using M                 = std::flat_set<Key, std::less<Key>, KeyContainer>;
+    using It                = forward_iterator<const int*>;
+    M m                     = {10, 8, 5, 2, 1};
+    int ar[]                = {1, 3, 4, 5, 9};
+    std::ranges::subrange r = {It(ar), It(ar + 5)};
+    static_assert(std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_unique, r);
+    assert((m == M{1, 2, 3, 4, 5, 8, 9, 10}));
+  }
+  {
+    using M                 = std::flat_set<Key, std::greater<>, KeyContainer>;
+    using It                = cpp20_input_iterator<const int*>;
+    M m                     = {8, 5, 3, 2};
+    int ar[]                = {9, 5, 4, 3, 1};
+    std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 5))};
+    static_assert(!std::ranges::common_range<decltype(r)>);
+    m.insert_range(std::sorted_unique, r);
+    assert((m == M{1, 2, 3, 4, 5, 8, 9}));
+  }
+  {
+    // was empty
+    using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
+    M m;
+    int ar[] = {1, 3, 4, 5, 9};
+    m.insert_range(std::sorted_unique, ar);
+    assert((m == M{1, 3, 4, 5, 9}));
+  }
+}
+
+constexpr bool test() {
+  test_one<std::vector<int>>();
+#ifndef __cpp_lib_constexpr_deque
+  if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+    test_one<std::deque<int>>();
+  test_one<MinSequenceContainer<int>>();
+  test_one<std::vector<int, min_allocator<int>>>();
+  {
+    // Items are forwarded correctly from the input range.
+    MoveOnly a[] = {1, 3, 4, 5};
+    std::flat_set<MoveOnly> m;
+    m.insert_range(std::sorted_unique, a | std::views::as_rvalue);
+    MoveOnly expected[] = {1, 3, 4, 5};
+    assert(std::ranges::equal(m, expected));
+  }
+
+  return true;
+}
+
+void test_exception() {
+  auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_unique, newValues); };
+  test_insert_range_exception_guarantee(insert_func);
+}
+
+int main(int, char**) {
+  test();
+  test_exception();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif
+
+  return 0;
+}

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
index 23a2dc85989bb..eed92bcf4308f 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_exception.pass.cpp
@@ -7,9 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// `check_assertion.h` requires Unix headers and regex support.
-// REQUIRES: has-unix-headers
-// UNSUPPORTED: no-localization
 // UNSUPPORTED: no-exceptions
 
 // <flat_set>
@@ -27,7 +24,6 @@
 
 #include "test_macros.h"
 #include "../helpers.h"
-#include "check_assertion.h"
 
 template <class F>
 void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
@@ -41,8 +37,16 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
     m1.emplace(2);
     m2.emplace(3);
     m2.emplace(4);
-    // swap is noexcept
-    EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
+
+    try {
+      swap_function(m1, m2);
+      assert(false);
+    } catch (int) {
+      check_invariant(m1);
+      check_invariant(m2);
+      LIBCPP_ASSERT(m1.size() == 0);
+      LIBCPP_ASSERT(m2.size() == 0);
+    }
   }
 }
 

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
index 6b4a65e4701b2..b07af85063093 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_free.pass.cpp
@@ -31,10 +31,9 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
   { swap(t1, t2) } noexcept;
 };
 
-static_assert(NoExceptAdlSwap<std::flat_set<int>>);
-
+static_assert(NoExceptAdlSwap<std::flat_set<int, std::less<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptAdlSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptAdlSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
 #endif
 
 template <class KeyContainer>

diff  --git a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
index a3b605ee94cfb..eaecd5f15a661 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/flat.set.modifiers/swap_member.pass.cpp
@@ -31,9 +31,9 @@ concept NoExceptMemberSwap = requires(T t1, T t2) {
   { t1.swap(t2) } noexcept;
 };
 
-static_assert(NoExceptMemberSwap<std::flat_set<int>>);
+static_assert(NoExceptMemberSwap<std::flat_set<int, std::less<int>, std::vector<int>>>);
 #ifndef TEST_HAS_NO_EXCEPTIONS
-static_assert(NoExceptMemberSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
+static_assert(!NoExceptMemberSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
 #endif
 
 template <class KeyContainer>

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp
index 26c8e1bc7d66f..34820de6a53aa 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/flat_map.version.compile.pass.cpp
@@ -67,8 +67,8 @@
 #  ifndef __cpp_lib_flat_map
 #    error "__cpp_lib_flat_map should be defined in c++23"
 #  endif
-#  if __cpp_lib_flat_map != 202207L
-#    error "__cpp_lib_flat_map should have the value 202207L in c++23"
+#  if __cpp_lib_flat_map != 202511L
+#    error "__cpp_lib_flat_map should have the value 202511L in c++23"
 #  endif
 
 #elif TEST_STD_VER > 23
@@ -83,8 +83,8 @@
 #  ifndef __cpp_lib_flat_map
 #    error "__cpp_lib_flat_map should be defined in c++26"
 #  endif
-#  if __cpp_lib_flat_map != 202207L
-#    error "__cpp_lib_flat_map should have the value 202207L in c++26"
+#  if __cpp_lib_flat_map != 202511L
+#    error "__cpp_lib_flat_map should have the value 202511L in c++26"
 #  endif
 
 #endif // TEST_STD_VER > 23

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 65cdf2ded816d..28fae95c1c1f7 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -5093,8 +5093,8 @@
 #  ifndef __cpp_lib_flat_map
 #    error "__cpp_lib_flat_map should be defined in c++23"
 #  endif
-#  if __cpp_lib_flat_map != 202207L
-#    error "__cpp_lib_flat_map should have the value 202207L in c++23"
+#  if __cpp_lib_flat_map != 202511L
+#    error "__cpp_lib_flat_map should have the value 202511L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_flat_set
@@ -6844,8 +6844,8 @@
 #  ifndef __cpp_lib_flat_map
 #    error "__cpp_lib_flat_map should be defined in c++26"
 #  endif
-#  if __cpp_lib_flat_map != 202207L
-#    error "__cpp_lib_flat_map should have the value 202207L in c++26"
+#  if __cpp_lib_flat_map != 202511L
+#    error "__cpp_lib_flat_map should have the value 202511L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_flat_set

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index c91bdf4ed99ec..ff965aaa4ff89 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -557,7 +557,7 @@ def add_version_header(tc):
         },
         {
             "name": "__cpp_lib_flat_map",
-            "values": {"c++23": 202207},
+            "values": {"c++23": 202511},
             "headers": ["flat_map"],
         },
         {


        


More information about the libcxx-commits mailing list