[libcxx-commits] [libcxx] 4122db1 - [libc++][hardening] Categorize most assertions inside the container classes.

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 20 10:14:55 PDT 2023


Author: varconst
Date: 2023-07-20T10:14:43-07:00
New Revision: 4122db1fbdeb7a9c5a7c8f0cd7afedd53754eaad

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

LOG: [libc++][hardening] Categorize most assertions inside the container classes.

This introduces:
- `_LIBCPP_ASSERT_VALID_INPUT_RANGE`;
- `_LIBCPP_ASSERT_VALID_CONTAINER_ACCESS`;
- `_LIBCPP_ASSERT_VALID_ITERATOR_ACCESS`;
- `_LIBCPP_ASSERT_VALID_ALLOCATOR`;
- `_LIBCPP_ASSERT_INTERNAL`.

Differential Revision: https://reviews.llvm.org/D155349

Added: 
    

Modified: 
    libcxx/include/__config
    libcxx/include/__expected/expected.h
    libcxx/include/__functional/function.h
    libcxx/include/__iterator/bounded_iter.h
    libcxx/include/__mdspan/extents.h
    libcxx/include/__tree
    libcxx/include/array
    libcxx/include/deque
    libcxx/include/list
    libcxx/include/map
    libcxx/include/optional
    libcxx/include/span
    libcxx/include/string
    libcxx/include/string_view
    libcxx/include/unordered_map
    libcxx/include/unordered_set
    libcxx/include/vector

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__config b/libcxx/include/__config
index c147b0baa4534b..41addf9a04122f 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -233,9 +233,27 @@
 //
 // #define _LIBCPP_ENABLE_DEBUG_MODE 1
 
-// Available checks:
-
-// TODO(hardening): add documentation for 
diff erent checks here.
+// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These
+// macros are only for internal use -- users should only pick one of the high-level hardening modes described above.
+//
+// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and
+//   a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid:
+//   - the sentinel is reachable from the begin iterator;
+//   - TODO(hardening): where applicable, the input range and the output range do not overlap;
+//   - TODO(hardening): both iterators refer to the same container.
+//
+// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through
+//   the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access
+//   a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like
+//   `optional` and `function` are considered one-element containers for the purposes of this check.
+//
+// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
+//   the containers have compatible allocators.
+//
+// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
+//   user input.
+//
+// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.
 
 #  ifndef _LIBCPP_ENABLE_HARDENED_MODE
 #    define _LIBCPP_ENABLE_HARDENED_MODE _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT
@@ -256,26 +274,43 @@
 #  endif
 
 // Hardened mode checks.
+
+// clang-format off
 #  if _LIBCPP_ENABLE_HARDENED_MODE
 
-// TODO(hardening): Once we categorize assertions, only enable the ones that we really want here.
-#    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
-// TODO(hardening): more checks to be added here...
+// Enabled checks.
+#    define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message)      _LIBCPP_ASSERT(expression, message)
+#    define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message)   _LIBCPP_ASSERT(expression, message)
+// TODO(hardening): Don't enable uncategorized assertions in the hardened mode.
+#    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message)          _LIBCPP_ASSERT(expression, message)
+// Disabled checks.
+#    define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message)   _LIBCPP_ASSUME(expression)
+#    define _LIBCPP_ASSERT_INTERNAL(expression, message)               _LIBCPP_ASSUME(expression)
 
 // Debug mode checks.
+
 #  elif _LIBCPP_ENABLE_DEBUG_MODE
 
-// TODO(hardening): Once we categorize assertions, only enable the ones that we really want here.
-#    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
-// TODO(hardening): more checks to be added here...
+// All checks enabled.
+#    define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message)       _LIBCPP_ASSERT(expression, message)
+#    define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message)    _LIBCPP_ASSERT(expression, message)
+#    define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message)    _LIBCPP_ASSERT(expression, message)
+#    define _LIBCPP_ASSERT_INTERNAL(expression, message)                _LIBCPP_ASSERT(expression, message)
+#    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message)           _LIBCPP_ASSERT(expression, message)
+
+// Disable all checks if hardening is not enabled.
 
-// Disable all checks if neither the hardened mode nor the debug mode is enabled.
 #  else
 
-#    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
-// TODO: more checks to be added here...
+// All checks disabled.
+#    define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message)       _LIBCPP_ASSUME(expression)
+#    define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message)    _LIBCPP_ASSUME(expression)
+#    define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message)    _LIBCPP_ASSUME(expression)
+#    define _LIBCPP_ASSERT_INTERNAL(expression, message)                _LIBCPP_ASSUME(expression)
+#    define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message)           _LIBCPP_ASSUME(expression)
 
 #  endif // _LIBCPP_ENABLE_HARDENED_MODE
+// clang-format on
 
 // } HARDENING
 

diff  --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index edcffc8b4579f9..7d57aa4db5f952 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -526,32 +526,32 @@ class expected {
 
   // [expected.object.obs], observers
   _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator-> requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator-> requires the expected to contain a value");
     return std::addressof(__union_.__val_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator-> requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator-> requires the expected to contain a value");
     return std::addressof(__union_.__val_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator* requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
     return __union_.__val_;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator* requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
     return __union_.__val_;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator* requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
     return std::move(__union_.__val_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator* requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
     return std::move(__union_.__val_);
   }
 
@@ -594,22 +594,22 @@ class expected {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return __union_.__unex_;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return __union_.__unex_;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return std::move(__union_.__unex_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return std::move(__union_.__unex_);
   }
 
@@ -1217,7 +1217,7 @@ class expected<_Tp, _Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__has_val_, "expected::operator* requires the expected to contain a value");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
@@ -1233,22 +1233,22 @@ class expected<_Tp, _Err> {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return __union_.__unex_;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return __union_.__unex_;
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return std::move(__union_.__unex_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!__has_val_, "expected::error requires the expected to contain an error");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
     return std::move(__union_.__unex_);
   }
 

diff  --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index 124be82fe4ebfa..3c6e3f450d8b1c 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -923,7 +923,7 @@ class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>
     { }
 
     virtual __base<_Rp(_ArgTypes...)>* __clone() const {
-        _LIBCPP_ASSERT_UNCATEGORIZED(false,
+        _LIBCPP_ASSERT_INTERNAL(false,
             "Block pointers are just pointers, so they should always fit into "
             "std::function's small buffer optimization. This function should "
             "never be invoked.");
@@ -943,7 +943,7 @@ class __func<_Rp1(^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)>
     }
 
     virtual void destroy_deallocate() _NOEXCEPT {
-        _LIBCPP_ASSERT_UNCATEGORIZED(false,
+        _LIBCPP_ASSERT_INTERNAL(false,
             "Block pointers are just pointers, so they should always fit into "
             "std::function's small buffer optimization. This function should "
             "never be invoked.");

diff  --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h
index 6212ebb0bf900b..2a667648871c4c 100644
--- a/libcxx/include/__iterator/bounded_iter.h
+++ b/libcxx/include/__iterator/bounded_iter.h
@@ -81,8 +81,7 @@ struct __bounded_iter {
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __bounded_iter(
       _Iterator __current, _Iterator __begin, _Iterator __end)
       : __current_(__current), __begin_(__begin), __end_(__end) {
-    _LIBCPP_ASSERT_UNCATEGORIZED(
-        __begin <= __end, "__bounded_iter(current, begin, end): [begin, end) is not a valid range");
+    _LIBCPP_ASSERT_INTERNAL(__begin <= __end, "__bounded_iter(current, begin, end): [begin, end) is not a valid range");
   }
 
   template <class _It>
@@ -93,19 +92,19 @@ struct __bounded_iter {
   //
   // These operations check that the iterator is dereferenceable, that is within [begin, end).
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         __in_bounds(__current_), "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
     return *__current_;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         __in_bounds(__current_), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
     return std::__to_address(__current_);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator[](
diff erence_type __n) const _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         __in_bounds(__current_ + __n), "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
     return __current_[__n];
   }

diff  --git a/libcxx/include/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h
index 8c9f12147b5726..42355678d60ccc 100644
--- a/libcxx/include/__mdspan/extents.h
+++ b/libcxx/include/__mdspan/extents.h
@@ -197,17 +197,17 @@ struct __maybe_static_array {
 
   // access functions
   _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__i < __size_, "extents access: index must be less than rank");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
     return _StaticValues::__get(__i);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__i < __size_, "extents access: index must be less than rank");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
     _TStatic __static_val = _StaticValues::__get(__i);
     return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val);
   }
   _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__i < __size_, "extents access: index must be less than rank");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank");
     return __value(__i);
   }
 

diff  --git a/libcxx/include/__tree b/libcxx/include/__tree
index e7761d2ad21657..92b5e65e115827 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -376,9 +376,7 @@ __tree_remove(_NodePtr __root, _NodePtr __z) _NOEXCEPT
 {
     _LIBCPP_ASSERT_UNCATEGORIZED(__root != nullptr, "Root node should not be null");
     _LIBCPP_ASSERT_UNCATEGORIZED(__z != nullptr, "The node to remove should not be null");
-#if _LIBCPP_ENABLE_DEBUG_MODE
-    _LIBCPP_ASSERT_UNCATEGORIZED(std::__tree_invariant(__root), "The tree invariants should hold");
-#endif
+    _LIBCPP_ASSERT_INTERNAL(std::__tree_invariant(__root), "The tree invariants should hold");
     // __z will be removed from the tree.  Client still needs to destruct/deallocate it
     // __y is either __z, or if __z has two children, __tree_next(__z).
     // __y will have at most one child.

diff  --git a/libcxx/include/array b/libcxx/include/array
index 2983b67edb7f6a..3fc25d4c30623d 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -229,12 +229,12 @@ struct _LIBCPP_TEMPLATE_VIS array
     // element access:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
     reference operator[](size_type __n) _NOEXCEPT {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__n < _Size, "out-of-bounds access in std::array<T, N>");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < _Size, "out-of-bounds access in std::array<T, N>");
         return __elems_[__n];
     }
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
     const_reference operator[](size_type __n) const _NOEXCEPT {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__n < _Size, "out-of-bounds access in std::array<T, N>");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < _Size, "out-of-bounds access in std::array<T, N>");
         return __elems_[__n];
     }
 
@@ -342,13 +342,13 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
     // element access:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
     reference operator[](size_type) _NOEXCEPT {
-      _LIBCPP_ASSERT_UNCATEGORIZED(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
       __libcpp_unreachable();
     }
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
     const_reference operator[](size_type) const _NOEXCEPT {
-      _LIBCPP_ASSERT_UNCATEGORIZED(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
       __libcpp_unreachable();
     }
 
@@ -366,25 +366,25 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
     reference front() _NOEXCEPT {
-      _LIBCPP_ASSERT_UNCATEGORIZED(false, "cannot call array<T, 0>::front() on a zero-sized array");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::front() on a zero-sized array");
       __libcpp_unreachable();
     }
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
     const_reference front() const _NOEXCEPT {
-      _LIBCPP_ASSERT_UNCATEGORIZED(false, "cannot call array<T, 0>::front() on a zero-sized array");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::front() on a zero-sized array");
       __libcpp_unreachable();
     }
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
     reference back() _NOEXCEPT {
-      _LIBCPP_ASSERT_UNCATEGORIZED(false, "cannot call array<T, 0>::back() on a zero-sized array");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::back() on a zero-sized array");
       __libcpp_unreachable();
     }
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
     const_reference back() const _NOEXCEPT {
-      _LIBCPP_ASSERT_UNCATEGORIZED(false, "cannot call array<T, 0>::back() on a zero-sized array");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::back() on a zero-sized array");
       __libcpp_unreachable();
     }
 };

diff  --git a/libcxx/include/deque b/libcxx/include/deque
index b063680500cce4..777f9354259873 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -2597,7 +2597,7 @@ template <class _Tp, class _Allocator>
 void
 deque<_Tp, _Allocator>::pop_back()
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "deque::pop_back called on an empty deque");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "deque::pop_back called on an empty deque");
     size_type __old_sz    = size();
     size_type __old_start = __start_;
     allocator_type& __a = __alloc();

diff  --git a/libcxx/include/list b/libcxx/include/list
index 2512259461500b..37bed3cd89fc96 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -695,10 +695,10 @@ __list_imp<_Tp, _Alloc>::swap(__list_imp& __c)
                     __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__alloc_traits::propagate_on_container_swap::value ||
-                                 this->__node_alloc() == __c.__node_alloc(),
-                                 "list::swap: Either propagate_on_container_swap must be true"
-                                 " or the allocators must compare equal");
+    _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__alloc_traits::propagate_on_container_swap::value ||
+                                        this->__node_alloc() == __c.__node_alloc(),
+                                        "list::swap: Either propagate_on_container_swap must be true"
+                                        " or the allocators must compare equal");
     using _VSTD::swap;
     _VSTD::__swap_allocator(__node_alloc(), __c.__node_alloc());
     swap(__sz(), __c.__sz());
@@ -879,25 +879,25 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     reference front()
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "list::front called on empty list");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::front called on empty list");
         return base::__end_.__next_->__as_node()->__value_;
     }
     _LIBCPP_INLINE_VISIBILITY
     const_reference front() const
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "list::front called on empty list");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::front called on empty list");
         return base::__end_.__next_->__as_node()->__value_;
     }
     _LIBCPP_INLINE_VISIBILITY
     reference back()
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "list::back called on empty list");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::back called on empty list");
         return base::__end_.__prev_->__as_node()->__value_;
     }
     _LIBCPP_INLINE_VISIBILITY
     const_reference back() const
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "list::back called on empty list");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::back called on empty list");
         return base::__end_.__prev_->__as_node()->__value_;
     }
 
@@ -1587,7 +1587,7 @@ template <class _Tp, class _Alloc>
 void
 list<_Tp, _Alloc>::pop_front()
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "list::pop_front() called with empty list");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::pop_front() called with empty list");
     __node_allocator& __na = base::__node_alloc();
     __link_pointer __n = base::__end_.__next_;
     base::__unlink_nodes(__n, __n);
@@ -1601,7 +1601,7 @@ template <class _Tp, class _Alloc>
 void
 list<_Tp, _Alloc>::pop_back()
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "list::pop_back() called on an empty list");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::pop_back() called on an empty list");
     __node_allocator& __na = base::__node_alloc();
     __link_pointer __n = base::__end_.__prev_;
     base::__unlink_nodes(__n, __n);
@@ -1615,7 +1615,7 @@ template <class _Tp, class _Alloc>
 typename list<_Tp, _Alloc>::iterator
 list<_Tp, _Alloc>::erase(const_iterator __p)
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__p != end(),
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p != end(),
         "list::erase(iterator) called with a non-dereferenceable iterator");
     __node_allocator& __na = base::__node_alloc();
     __link_pointer __n = __p.__ptr_;
@@ -1752,8 +1752,8 @@ template <class _Tp, class _Alloc>
 void
 list<_Tp, _Alloc>::splice(const_iterator __p, list& __c)
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(this != _VSTD::addressof(__c),
-                                 "list::splice(iterator, list) called with this == &list");
+    _LIBCPP_ASSERT_VALID_INPUT_RANGE(this != _VSTD::addressof(__c),
+                                     "list::splice(iterator, list) called with this == &list");
     if (!__c.empty())
     {
         __link_pointer __f = __c.__end_.__next_;

diff  --git a/libcxx/include/map b/libcxx/include/map
index d21f6b9bc11054..4152d58a2f8844 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -1463,7 +1463,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     insert_return_type insert(node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to map::insert()");
         return __tree_.template __node_handle_insert_unique<
             node_type, insert_return_type>(_VSTD::move(__nh));
@@ -1471,7 +1471,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const_iterator __hint, node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to map::insert()");
         return __tree_.template __node_handle_insert_unique<node_type>(
             __hint.__i_, _VSTD::move(__nh));
@@ -1490,32 +1490,32 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     void merge(map<key_type, mapped_type, _Compare2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __tree_.__node_handle_merge_unique(__source.__tree_);
     }
     template <class _Compare2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(map<key_type, mapped_type, _Compare2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __tree_.__node_handle_merge_unique(__source.__tree_);
     }
     template <class _Compare2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __tree_.__node_handle_merge_unique(__source.__tree_);
     }
     template <class _Compare2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __tree_.__node_handle_merge_unique(__source.__tree_);
     }
 #endif
@@ -2195,7 +2195,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to multimap::insert()");
         return __tree_.template __node_handle_insert_multi<node_type>(
             _VSTD::move(__nh));
@@ -2203,7 +2203,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const_iterator __hint, node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to multimap::insert()");
         return __tree_.template __node_handle_insert_multi<node_type>(
             __hint.__i_, _VSTD::move(__nh));
@@ -2223,32 +2223,32 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __tree_.__node_handle_merge_multi(__source.__tree_);
     }
     template <class _Compare2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __tree_.__node_handle_merge_multi(__source.__tree_);
     }
     template <class _Compare2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(map<key_type, mapped_type, _Compare2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __tree_.__node_handle_merge_multi(__source.__tree_);
     }
     template <class _Compare2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(map<key_type, mapped_type, _Compare2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __tree_.__node_handle_merge_multi(__source.__tree_);
     }
 #endif

diff  --git a/libcxx/include/optional b/libcxx/include/optional
index 6ead4b1e881af0..3a81734208b301 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -412,7 +412,7 @@ struct __optional_storage_base : __optional_destruct_base<_Tp>
     _LIBCPP_INLINE_VISIBILITY
     _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_Args&&... __args)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!has_value(), "__construct called for engaged __optional_storage");
+        _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage");
 #if _LIBCPP_STD_VER >= 20
         _VSTD::construct_at(_VSTD::addressof(this->__val_), _VSTD::forward<_Args>(__args)...);
 #else
@@ -507,7 +507,7 @@ struct __optional_storage_base<_Tp, true>
     _LIBCPP_INLINE_VISIBILITY
     _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!has_value(), "__construct called for engaged __optional_storage");
+        _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage");
         static_assert(__can_bind_reference<_UArg>(),
             "Attempted to construct a reference element in tuple from a "
             "possible temporary");
@@ -996,7 +996,7 @@ public:
     add_pointer_t<value_type const>
     operator->() const
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(this->has_value(), "optional operator-> called on a disengaged value");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
         return _VSTD::addressof(this->__get());
     }
 
@@ -1005,7 +1005,7 @@ public:
     add_pointer_t<value_type>
     operator->()
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(this->has_value(), "optional operator-> called on a disengaged value");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
         return _VSTD::addressof(this->__get());
     }
 
@@ -1014,7 +1014,7 @@ public:
     const value_type&
     operator*() const& noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(this->has_value(), "optional operator* called on a disengaged value");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
         return this->__get();
     }
 
@@ -1023,7 +1023,7 @@ public:
     value_type&
     operator*() & noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(this->has_value(), "optional operator* called on a disengaged value");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
         return this->__get();
     }
 
@@ -1032,7 +1032,7 @@ public:
     value_type&&
     operator*() && noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(this->has_value(), "optional operator* called on a disengaged value");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
         return _VSTD::move(this->__get());
     }
 
@@ -1041,7 +1041,7 @@ public:
     const value_type&&
     operator*() const&& noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(this->has_value(), "optional operator* called on a disengaged value");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
         return _VSTD::move(this->__get());
     }
 

diff  --git a/libcxx/include/span b/libcxx/include/span
index 582bdbf5c14069..b050dfe6e340e5 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -233,7 +233,7 @@ public:
     constexpr explicit span(_It __first, size_type __count)
         : __data_{_VSTD::to_address(__first)} {
       (void)__count;
-      _LIBCPP_ASSERT_UNCATEGORIZED(_Extent == __count, "size mismatch in span's constructor (iterator, len)");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Extent == __count, "size mismatch in span's constructor (iterator, len)");
     }
 
     template <__span_compatible_iterator<element_type> _It, __span_compatible_sentinel_for<_It> _End>
@@ -242,8 +242,8 @@ public:
       // [span.cons]/10
       // Throws: When and what last - first throws.
       [[maybe_unused]] auto __dist = __last - __first;
-      _LIBCPP_ASSERT_UNCATEGORIZED(__dist >= 0, "invalid range in span's constructor (iterator, sentinel)");
-      _LIBCPP_ASSERT_UNCATEGORIZED(
+      _LIBCPP_ASSERT_VALID_INPUT_RANGE(__dist >= 0, "invalid range in span's constructor (iterator, sentinel)");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
           __dist == _Extent, "invalid range in span's constructor (iterator, sentinel): last - first != extent");
     }
 
@@ -261,7 +261,8 @@ public:
     template <__span_compatible_range<element_type> _Range>
     _LIBCPP_INLINE_VISIBILITY
     constexpr explicit span(_Range&& __r) : __data_{ranges::data(__r)} {
-      _LIBCPP_ASSERT_UNCATEGORIZED(ranges::size(__r) == _Extent, "size mismatch in span's constructor (range)");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          ranges::size(__r) == _Extent, "size mismatch in span's constructor (range)");
     }
 
     template <__span_array_convertible<element_type> _OtherElementType>
@@ -273,7 +274,8 @@ public:
     _LIBCPP_INLINE_VISIBILITY
         constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other) noexcept
         : __data_{__other.data()} {
-          _LIBCPP_ASSERT_UNCATEGORIZED(_Extent == __other.size(), "size mismatch in span's constructor (other span)");
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+          _Extent == __other.size(), "size mismatch in span's constructor (other span)");
         }
 
     template <size_t _Count>
@@ -295,14 +297,14 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__count <= size(), "span<T, N>::first(count): count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T, N>::first(count): count out of range");
         return {data(), __count};
     }
 
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__count <= size(), "span<T, N>::last(count): count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T, N>::last(count): count out of range");
         return {data() + size() - __count, __count};
     }
 
@@ -323,11 +325,12 @@ public:
     constexpr span<element_type, dynamic_extent>
        subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__offset <= size(), "span<T, N>::subspan(offset, count): offset out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+            __offset <= size(), "span<T, N>::subspan(offset, count): offset out of range");
         if (__count == dynamic_extent)
             return {data() + __offset, size() - __offset};
-        _LIBCPP_ASSERT_UNCATEGORIZED(__count <= size() - __offset,
-                                     "span<T, N>::subspan(offset, count): offset + count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+            __count <= size() - __offset, "span<T, N>::subspan(offset, count): offset + count out of range");
         return {data() + __offset, __count};
     }
 
@@ -337,19 +340,19 @@ public:
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__idx < size(), "span<T, N>::operator[](index): index out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span<T, N>::operator[](index): index out of range");
         return __data_[__idx];
     }
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "span<T, N>::front() on empty span");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::front() on empty span");
         return __data_[0];
     }
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "span<T, N>::back() on empty span");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::back() on empty span");
         return __data_[size()-1];
     }
 
@@ -419,7 +422,8 @@ public:
     template <__span_compatible_iterator<element_type> _It, __span_compatible_sentinel_for<_It> _End>
     _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, _End __last)
         : __data_(_VSTD::to_address(__first)), __size_(__last - __first) {
-      _LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= 0, "invalid range in span's constructor (iterator, sentinel)");
+        _LIBCPP_ASSERT_VALID_INPUT_RANGE(
+            __last - __first >= 0, "invalid range in span's constructor (iterator, sentinel)");
     }
 
     template <size_t _Sz>
@@ -448,7 +452,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, _Count> first() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(_Count <= size(), "span<T>::first<Count>(): Count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span<T>::first<Count>(): Count out of range");
         return span<element_type, _Count>{data(), _Count};
     }
 
@@ -456,21 +460,21 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, _Count> last() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(_Count <= size(), "span<T>::last<Count>(): Count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span<T>::last<Count>(): Count out of range");
         return span<element_type, _Count>{data() + size() - _Count, _Count};
     }
 
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__count <= size(), "span<T>::first(count): count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T>::first(count): count out of range");
         return {data(), __count};
     }
 
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, dynamic_extent> last (size_type __count) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__count <= size(), "span<T>::last(count): count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T>::last(count): count out of range");
         return {data() + size() - __count, __count};
     }
 
@@ -478,9 +482,10 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     constexpr span<element_type, _Count> subspan() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(_Offset <= size(), "span<T>::subspan<Offset, Count>(): Offset out of range");
-        _LIBCPP_ASSERT_UNCATEGORIZED(_Count == dynamic_extent || _Count <= size() - _Offset,
-                                     "span<T>::subspan<Offset, Count>(): Offset + Count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+            _Offset <= size(), "span<T>::subspan<Offset, Count>(): Offset out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count == dynamic_extent || _Count <= size() - _Offset,
+                                            "span<T>::subspan<Offset, Count>(): Offset + Count out of range");
         return span<element_type, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count};
     }
 
@@ -488,11 +493,11 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__offset <= size(), "span<T>::subspan(offset, count): offset out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span<T>::subspan(offset, count): offset out of range");
         if (__count == dynamic_extent)
             return {data() + __offset, size() - __offset};
-        _LIBCPP_ASSERT_UNCATEGORIZED(__count <= size() - __offset,
-                                     "span<T>::subspan(offset, count): offset + count out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+            __count <= size() - __offset, "span<T>::subspan(offset, count): offset + count out of range");
         return {data() + __offset, __count};
     }
 
@@ -502,19 +507,19 @@ public:
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__idx < size(), "span<T>::operator[](index): index out of range");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span<T>::operator[](index): index out of range");
         return __data_[__idx];
     }
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "span<T>::front() on empty span");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::front() on empty span");
         return __data_[0];
     }
 
     _LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "span<T>::back() on empty span");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::back() on empty span");
         return __data_[size()-1];
     }
 

diff  --git a/libcxx/include/string b/libcxx/include/string
index eeff013c0e8c45..4b96273698166d 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1206,12 +1206,12 @@ public:
     bool empty() const _NOEXCEPT {return size() == 0;}
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __pos) const _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__pos <= size(), "string index out of bounds");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds");
     return *(data() + __pos);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __pos) _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__pos <= size(), "string index out of bounds");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds");
     return *(__get_pointer() + __pos);
   }
 
@@ -1307,22 +1307,22 @@ public:
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void pop_back();
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string::front(): string is empty");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::front(): string is empty");
     return *__get_pointer();
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string::front(): string is empty");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::front(): string is empty");
     return *data();
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string::back(): string is empty");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::back(): string is empty");
     return *(__get_pointer() + size() - 1);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const _NOEXCEPT {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string::back(): string is empty");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::back(): string is empty");
     return *(data() + size() - 1);
   }
 
@@ -1812,16 +1812,16 @@ private:
 
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
     void __set_short_size(size_type __s) _NOEXCEPT {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__s < __min_cap,
-                                     "__s should never be greater than or equal to the short string capacity");
+        _LIBCPP_ASSERT_INTERNAL(
+            __s < __min_cap, "__s should never be greater than or equal to the short string capacity");
         __r_.first().__s.__size_ = __s;
         __r_.first().__s.__is_long_ = false;
     }
 
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
     size_type __get_short_size() const _NOEXCEPT {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!__r_.first().__s.__is_long_,
-                                     "String has to be short when trying to get the short size");
+        _LIBCPP_ASSERT_INTERNAL(
+            !__r_.first().__s.__is_long_, "String has to be short when trying to get the short size");
         return __r_.first().__s.__size_;
     }
 
@@ -2585,7 +2585,7 @@ template <class _Iterator, class _Sentinel>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
 void
 basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _Sentinel __last, size_type __n) {
-  _LIBCPP_ASSERT_UNCATEGORIZED(
+  _LIBCPP_ASSERT_INTERNAL(
       __string_is_trivial_iterator<_Iterator>::value, "The iterator type given to `__assign_trivial` must be trivial");
 
   size_type __cap = capacity();
@@ -3161,7 +3161,8 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
 typename basic_string<_CharT, _Traits, _Allocator>::iterator
 basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __pos)
 {
-  _LIBCPP_ASSERT_UNCATEGORIZED(__pos != end(), "string::erase(iterator) called with a non-dereferenceable iterator");
+  _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+      __pos != end(), "string::erase(iterator) called with a non-dereferenceable iterator");
   iterator __b = begin();
   size_type __r = static_cast<size_type>(__pos - __b);
   erase(__r, 1);
@@ -3173,7 +3174,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
 typename basic_string<_CharT, _Traits, _Allocator>::iterator
 basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __first, const_iterator __last)
 {
-  _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "string::erase(first, last) called with invalid range");
+  _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "string::erase(first, last) called with invalid range");
   iterator __b = begin();
   size_type __r = static_cast<size_type>(__first - __b);
   erase(__r, static_cast<size_type>(__last - __first));
@@ -3185,7 +3186,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
 void
 basic_string<_CharT, _Traits, _Allocator>::pop_back()
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string::pop_back(): string is already empty");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::pop_back(): string is already empty");
     __erase_to_end(size() - 1);
 }
 
@@ -3368,7 +3369,7 @@ basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str)
                     __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(
+    _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
         __alloc_traits::propagate_on_container_swap::value ||
         __alloc_traits::is_always_equal::value ||
         __alloc() == __str.__alloc(), "swapping non-equal allocators");

diff  --git a/libcxx/include/string_view b/libcxx/include/string_view
index 2d00a4e0123660..3149fe250578fb 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -323,8 +323,8 @@ public:
     constexpr _LIBCPP_HIDE_FROM_ABI basic_string_view(_It __begin, _End __end)
        : __data_(_VSTD::to_address(__begin)), __size_(__end - __begin)
     {
-      _LIBCPP_ASSERT_UNCATEGORIZED((__end - __begin) >= 0,
-                                   "std::string_view::string_view(iterator, sentinel) received invalid range");
+      _LIBCPP_ASSERT_VALID_INPUT_RANGE((__end - __begin) >= 0,
+                                       "std::string_view::string_view(iterator, sentinel) received invalid range");
     }
 #endif // _LIBCPP_STD_VER >= 20
 
@@ -405,7 +405,7 @@ public:
     // [string.view.access], element access
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
     const_reference operator[](size_type __pos) const _NOEXCEPT {
-      return _LIBCPP_ASSERT_UNCATEGORIZED(__pos < size(), "string_view[] index out of bounds"), __data_[__pos];
+      return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos < size(), "string_view[] index out of bounds"), __data_[__pos];
     }
 
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
@@ -419,13 +419,14 @@ public:
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
     const_reference front() const _NOEXCEPT
     {
-        return _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string_view::front(): string is empty"), __data_[0];
+        return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string_view::front(): string is empty"), __data_[0];
     }
 
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
     const_reference back() const _NOEXCEPT
     {
-        return _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "string_view::back(): string is empty"), __data_[__size_-1];
+        return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string_view::back(): string is empty"),
+               __data_[__size_ - 1];
     }
 
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
@@ -435,7 +436,7 @@ public:
     _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
     void remove_prefix(size_type __n) _NOEXCEPT
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__n <= size(), "remove_prefix() can't remove more than size()");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n <= size(), "remove_prefix() can't remove more than size()");
         __data_ += __n;
         __size_ -= __n;
     }
@@ -443,7 +444,7 @@ public:
     _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
     void remove_suffix(size_type __n) _NOEXCEPT
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__n <= size(), "remove_suffix() can't remove more than size()");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n <= size(), "remove_suffix() can't remove more than size()");
         __size_ -= __n;
     }
 

diff  --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 4772667dbbf624..8d83063bbeaeb3 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -1457,7 +1457,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     insert_return_type insert(node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_map::insert()");
         return __table_.template __node_handle_insert_unique<
             node_type, insert_return_type>(_VSTD::move(__nh));
@@ -1465,7 +1465,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const_iterator __hint, node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_map::insert()");
         return __table_.template __node_handle_insert_unique<node_type>(
             __hint.__i_, _VSTD::move(__nh));
@@ -1486,32 +1486,32 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_unique(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_unique(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_unique(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_unique(__source.__table_);
     }
 #endif
@@ -2294,7 +2294,7 @@ private:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_multimap::insert()");
         return __table_.template __node_handle_insert_multi<node_type>(
             _VSTD::move(__nh));
@@ -2302,7 +2302,7 @@ private:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const_iterator __hint, node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_multimap::insert()");
         return __table_.template __node_handle_insert_multi<node_type>(
             __hint.__i_, _VSTD::move(__nh));
@@ -2323,32 +2323,32 @@ private:
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
 #endif

diff  --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 2e2f4caddb9938..5e47f12446ff93 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -812,7 +812,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     insert_return_type insert(node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_set::insert()");
         return __table_.template __node_handle_insert_unique<
             node_type, insert_return_type>(_VSTD::move(__nh));
@@ -820,7 +820,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const_iterator __h, node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_set::insert()");
         return __table_.template __node_handle_insert_unique<node_type>(
             __h, _VSTD::move(__nh));
@@ -840,32 +840,32 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_set<key_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __table_.__node_handle_merge_unique(__source.__table_);
     }
     template<class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_set<key_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+          _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                              "merging container with incompatible allocator");
         __table_.__node_handle_merge_unique(__source.__table_);
     }
     template<class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multiset<key_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __table_.__node_handle_merge_unique(__source.__table_);
     }
     template<class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multiset<key_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         __table_.__node_handle_merge_unique(__source.__table_);
     }
 #endif
@@ -1487,7 +1487,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_multiset::insert()");
         return __table_.template __node_handle_insert_multi<node_type>(
             _VSTD::move(__nh));
@@ -1495,7 +1495,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     iterator insert(const_iterator __hint, node_type&& __nh)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(),
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(),
             "node_type with incompatible allocator passed to unordered_multiset::insert()");
         return __table_.template __node_handle_insert_multi<node_type>(
             __hint, _VSTD::move(__nh));
@@ -1516,32 +1516,32 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multiset<key_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_multiset<key_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_set<key_type, _H2, _P2, allocator_type>& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
     template <class _H2, class _P2>
     _LIBCPP_INLINE_VISIBILITY
     void merge(unordered_set<key_type, _H2, _P2, allocator_type>&& __source)
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(__source.get_allocator() == get_allocator(),
-                                     "merging container with incompatible allocator");
+        _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__source.get_allocator() == get_allocator(),
+                                            "merging container with incompatible allocator");
         return __table_.__node_handle_merge_multi(__source.__table_);
     }
 #endif

diff  --git a/libcxx/include/vector b/libcxx/include/vector
index 0adf9f6a2011ca..19bf49513a667b 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -619,22 +619,22 @@ public:
 
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference       front() _NOEXCEPT
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "front() called on an empty vector");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
         return *this->__begin_;
     }
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "front() called on an empty vector");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
         return *this->__begin_;
     }
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference       back() _NOEXCEPT
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "back() called on an empty vector");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
         return *(this->__end_ - 1);
     }
     _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back()  const _NOEXCEPT
     {
-        _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "back() called on an empty vector");
+        _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector");
         return *(this->__end_ - 1);
     }
 
@@ -1531,7 +1531,7 @@ inline _LIBCPP_HIDE_FROM_ABI
 typename vector<_Tp, _Allocator>::reference
 vector<_Tp, _Allocator>::operator[](size_type __n) _NOEXCEPT
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__n < size(), "vector[] index out of bounds");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
     return this->__begin_[__n];
 }
 
@@ -1541,7 +1541,7 @@ inline _LIBCPP_HIDE_FROM_ABI
 typename vector<_Tp, _Allocator>::const_reference
 vector<_Tp, _Allocator>::operator[](size_type __n) const _NOEXCEPT
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__n < size(), "vector[] index out of bounds");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds");
     return this->__begin_[__n];
 }
 
@@ -1687,7 +1687,7 @@ inline
 void
 vector<_Tp, _Allocator>::pop_back()
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(!empty(), "vector::pop_back called on an empty vector");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector::pop_back called on an empty vector");
     this->__destruct_at_end(this->__end_ - 1);
 }
 
@@ -1697,7 +1697,7 @@ inline _LIBCPP_HIDE_FROM_ABI
 typename vector<_Tp, _Allocator>::iterator
 vector<_Tp, _Allocator>::erase(const_iterator __position)
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__position != end(),
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__position != end(),
         "vector::erase(iterator) called with a non-dereferenceable iterator");
     
diff erence_type __ps = __position - cbegin();
     pointer __p = this->__begin_ + __ps;
@@ -1710,7 +1710,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
 typename vector<_Tp, _Allocator>::iterator
 vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last)
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "vector::erase(first, last) called with invalid range");
+    _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "vector::erase(first, last) called with invalid range");
     pointer __p = this->__begin_ + (__first - begin());
     if (__first != __last) {
         this->__destruct_at_end(std::move(__p + (__last - __first), this->__end_, __p));
@@ -2003,10 +2003,10 @@ vector<_Tp, _Allocator>::swap(vector& __x)
                 __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__alloc_traits::propagate_on_container_swap::value ||
-                                 this->__alloc() == __x.__alloc(),
-                                 "vector::swap: Either propagate_on_container_swap must be true"
-                                 " or the allocators must compare equal");
+    _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__alloc_traits::propagate_on_container_swap::value ||
+                                        this->__alloc() == __x.__alloc(),
+                                        "vector::swap: Either propagate_on_container_swap must be true"
+                                        " or the allocators must compare equal");
     std::swap(this->__begin_, __x.__begin_);
     std::swap(this->__end_, __x.__end_);
     std::swap(this->__end_cap(), __x.__end_cap());
@@ -2956,7 +2956,7 @@ template <class _Allocator>
 template <class _ForwardIterator, class _Sentinel>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
 void vector<bool, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, 
diff erence_type __ns) {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__ns >= 0, "invalid range specified");
+    _LIBCPP_ASSERT_VALID_INPUT_RANGE(__ns >= 0, "invalid range specified");
 
     clear();
 
@@ -3155,7 +3155,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
 typename vector<bool, _Allocator>::iterator
 vector<bool, _Allocator>::__insert_with_size(const_iterator __position, _ForwardIterator __first, _Sentinel __last,
                                              
diff erence_type __n_signed) {
-    _LIBCPP_ASSERT_UNCATEGORIZED(__n_signed >= 0, "invalid range specified");
+    _LIBCPP_ASSERT_VALID_INPUT_RANGE(__n_signed >= 0, "invalid range specified");
     const size_type __n = static_cast<size_type>(__n_signed);
     iterator __r;
     size_type __c = capacity();


        


More information about the libcxx-commits mailing list