[libc++] Add a lightweight overridable assertion handler

This patch adds a lightweight assertion handler mechanism that can be
overriden at link-time in a fashion similar to `operator new`.

This is a third take on https://llvm.org/D121123 (which allowed customizing
the assertion handler at compile-time), and https://llvm.org/D119969
(which allowed customizing the assertion handler at runtime only).

This approach is, I think, the best of all three explored approaches.
Indeed, replacing the assertion handler in user code is ergonomic,
yet we retain the ability to provide a custom assertion handler when
deploying to older platforms that don't have a default handler in
the dylib.

As-is, this patch provides a pretty good amount of backwards compatibility
with the previous debug mode:

- Code that used to set _LIBCPP_DEBUG=0 in order to get basic assertions
  in their code will still get basic assertions out of the box, but
  those assertions will be using the new assertion handler support.
- Code that was previously compiled with references to __libcpp_debug_function
  and friends will work out-of-the-box, no changes required. This is
  because we provide the same symbols in the dylib as we used to.
- Code that used to set a custom __libcpp_debug_function will stop
  compiling, because we don't provide that declaration anymore. Users
  will have to migrate to the new way of setting a custom assertion
  handler, which is extremely easy. I suspect that pool of users is
  very limited, so breaking them at compile-time is probably acceptable.

The main downside of this approach is that code being compiled with
assertions enabled but deploying to an older platform where the assertion
handler didn't exist yet will fail to compile. However users can easily
fix the problem by providing a custom assertion handler and defining
the _LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED macro to
let the library know about the custom handler. In a way, this is
actually a feature because it avoids a load-time error that one would
otherwise get when trying to run the code on the older target.

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

NOKEYCHECK=True
GitOrigin-RevId: b0fd9497af6d2efd305e9eecfa0c1e265f1b2192
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 75669bb..2948fdc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,7 +82,10 @@
 include(HandleCompilerRT)
 
 # Basic options ---------------------------------------------------------------
-option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." OFF)
+option(LIBCXX_ENABLE_ASSERTIONS
+  "Enable assertions inside the compiled library, and at the same time make it the
+   default when compiling user code. Note that assertions can be enabled or disabled
+   by users in their own code regardless of this option." OFF)
 option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
 option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
 option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
@@ -694,7 +697,6 @@
 endif()
 
 # Assertion flags =============================================================
-define_if(LIBCXX_ENABLE_ASSERTIONS -D_LIBCPP_DEBUG=0)
 define_if(LIBCXX_DEBUG_BUILD -D_DEBUG)
 if (LIBCXX_ENABLE_ASSERTIONS AND NOT LIBCXX_DEBUG_BUILD)
   # MSVC doesn't like _DEBUG on release builds. See PR 4379.
@@ -896,6 +898,11 @@
 config_define_if_not(LIBCXX_ENABLE_UNICODE _LIBCPP_HAS_NO_UNICODE)
 config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTERS)
 config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
+if (LIBCXX_ENABLE_ASSERTIONS)
+  config_define(1 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT)
+else()
+  config_define(0 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT)
+endif()
 # Incomplete features get their own specific disabling flags. This makes it
 # easier to grep for target specific flags once the feature is complete.
 config_define_if_not(LIBCXX_ENABLE_INCOMPLETE_FEATURES _LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
diff --git a/cmake/caches/Generic-assertions.cmake b/cmake/caches/Generic-assertions.cmake
index e8ef72a..18eb866 100644
--- a/cmake/caches/Generic-assertions.cmake
+++ b/cmake/caches/Generic-assertions.cmake
@@ -1 +1,3 @@
 set(LIBCXX_ENABLE_ASSERTIONS ON CACHE BOOL "")
+set(LIBCXX_TEST_PARAMS "enable_assertions=True" CACHE STRING "")
+set(LIBCXXABI_TEST_PARAMS "enable_assertions=True" CACHE STRING "")
diff --git a/docs/BuildingLibcxx.rst b/docs/BuildingLibcxx.rst
index 0dd278e..17e90f9 100644
--- a/docs/BuildingLibcxx.rst
+++ b/docs/BuildingLibcxx.rst
@@ -216,7 +216,10 @@
 
   **Default**: ``OFF``
 
-  Build libc++ with assertions enabled.
+  Build libc++ with assertions enabled in the compiled library, and enable assertions
+  by default when building user code as well. Assertions can be turned off by users
+  by defining ``_LIBCPP_ENABLE_ASSERTIONS=0``. For details, see
+  :ref:`the documentation <assertions-mode>`.
 
 .. option:: LIBCXX_ENABLE_SHARED:BOOL
 
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 9e2e4a7..ea42b56 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -46,6 +46,12 @@
   "heapsort with bounce" to reduce the number of comparisons, and rearranges
   elements using move-assignment instead of `swap`.
 
+ - Libc++ now supports a variety of assertions that can be turned on to help catch
+   undefined behavior in user code. This new support is now separate from the old
+   (and incomplete) Debug Mode. Vendors can select whether the library they ship
+   should include assertions or not by default. For details, see
+   :ref:`the documentation <assertions-mode>` about this new feature.
+
 API Changes
 -----------
 
@@ -74,6 +80,10 @@
 - The C++14 function ``std::quoted(const char*)`` is no longer supported in
   C++03 or C++11 modes.
 
+- Setting a custom debug handler with ``std::__libcpp_debug_function`` is not
+  supported anymore. Please migrate to using the new support for
+  :ref:`assertions <assertions-mode>` instead.
+
 ABI Changes
 -----------
 
diff --git a/docs/UsingLibcxx.rst b/docs/UsingLibcxx.rst
index bd999f0..3eab44a 100644
--- a/docs/UsingLibcxx.rst
+++ b/docs/UsingLibcxx.rst
@@ -121,6 +121,92 @@
         <args>
 
 
+.. _assertions-mode:
+
+Enabling the "safe libc++" mode
+===============================
+
+Libc++ contains a number of assertions whose goal is to catch undefined behavior in the
+library, usually caused by precondition violations. Those assertions do not aim to be
+exhaustive -- instead they aim to provide a good balance between safety and performance.
+In particular, these assertions do not change the complexity of algorithms. However, they
+might, in some cases, interfere with compiler optimizations.
+
+By default, these assertions are turned off. Vendors can decide to turn them on while building
+the compiled library by defining ``LIBCXX_ENABLE_ASSERTIONS=ON`` at CMake configuration time.
+When ``LIBCXX_ENABLE_ASSERTIONS`` is used, the compiled library will be built with assertions
+enabled, **and** user code will be built with assertions enabled by default. If
+``LIBCXX_ENABLE_ASSERTIONS=OFF`` at CMake configure time, the compiled library will not contain
+assertions and the default when building user code will be to have assertions disabled.
+As a user, you can consult your vendor to know whether assertions are enabled by default.
+
+Furthermore, independently of any vendor-selected default, users can always control whether
+assertions are enabled in their code by defining ``_LIBCPP_ENABLE_ASSERTIONS=0|1`` before
+including any libc++ header (we recommend passing ``-D_LIBCPP_ENABLE_ASSERTIONS=X`` to the
+compiler). Note that if the compiled library was built by the vendor without assertions,
+functions compiled inside the static or shared library won't have assertions enabled even
+if the user defines ``_LIBCPP_ENABLE_ASSERTIONS=1`` (the same is true for the inverse case
+where the static or shared library was compiled **with** assertions but the user tries to
+disable them). However, most of the code in libc++ is in the headers, so the user-selected
+value for ``_LIBCPP_ENABLE_ASSERTIONS`` (if any) will usually be respected.
+
+When an assertion fails, an assertion handler function is called. The library provides a default
+assertion handler that prints an error message and calls ``std::abort()``. Note that this assertion
+handler is provided by the static or shared library, so it is only available when deploying to a
+platform where the compiled library is sufficiently recent. However, users can also override that
+assertion handler with their own, which can be useful to provide custom behavior, or when deploying
+to older platforms where the default assertion handler isn't available.
+
+Replacing the default assertion handler is done by defining the following function:
+
+.. code-block:: cpp
+
+  void __libcpp_assertion_handler(char const* file, int line, char const* expression, char const* message)
+
+This mechanism is similar to how one can replace the default definition of ``operator new``
+and ``operator delete``. For example:
+
+.. code-block:: cpp
+
+  // In HelloWorldHandler.cpp
+  #include <__assert> // must include <__assert> before defining the handler
+
+  void std::__libcpp_assertion_handler(char const* file, int line, char const* expression, char const* message) {
+    std::printf("Assertion %s failed at %s:%d, more info: %s", expression, file, line, message);
+    std::abort();
+  }
+
+  // In HelloWorld.cpp
+  #include <vector>
+
+  int main() {
+    std::vector<int> v;
+    int& x = v[0]; // Your assertion handler will be called here if _LIBCPP_ENABLE_ASSERTIONS=1
+  }
+
+Also note that the assertion handler should usually not return. Since the assertions in libc++
+catch undefined behavior, your code will proceed with undefined behavior if your assertion
+handler is called and does return.
+
+Furthermore, throwing an exception from the assertion handler is not recommended. Indeed, many
+functions in the library are ``noexcept``, and any exception thrown from the assertion handler
+will result in ``std::terminate`` being called.
+
+Back-deploying with a custom assertion handler
+----------------------------------------------
+When deploying to an older platform that does not provide a default assertion handler, the
+compiler will diagnose the usage of ``std::__libcpp_assertion_handler`` with an error. This
+is done to avoid the load-time error that would otherwise happen if the code was being deployed
+on the older system.
+
+If you are providing a custom assertion handler, this error is effectively a false positive.
+To let the library know that you are providing a custom assertion handler in back-deployment
+scenarios, you must define the ``_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED`` macro,
+and the library will assume that you are providing your own definition. If no definition is
+provided and the code is back-deployed to the older platform, it will fail to load when the
+dynamic linker fails to find a definition for ``std::__libcpp_assertion_handler``, so you
+should only remove the guard rails if you really mean it!
+
 Libc++ Configuration Macros
 ===========================
 
diff --git a/include/__assert b/include/__assert
index 75763d0..93669c6 100644
--- a/include/__assert
+++ b/include/__assert
@@ -10,52 +10,39 @@
 #ifndef _LIBCPP___ASSERT
 #define _LIBCPP___ASSERT
 
+#include <__availability>
 #include <__config>
-#include <iosfwd> // for std::string
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
+// This is for backwards compatibility with code that might have been enabling
+// assertions through the Debug mode previously.
 #if _LIBCPP_DEBUG_LEVEL >= 1
-#   define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : ::std::__libcpp_debug_function(::std::__libcpp_debug_info(__FILE__, __LINE__, #x, m)))
+# ifndef _LIBCPP_ENABLE_ASSERTIONS
+#   define _LIBCPP_ENABLE_ASSERTIONS 1
+# endif
+#endif
+
+#ifndef _LIBCPP_ENABLE_ASSERTIONS
+# define _LIBCPP_ENABLE_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS_DEFAULT
+#endif
+
+#if _LIBCPP_ENABLE_ASSERTIONS != 0 && _LIBCPP_ENABLE_ASSERTIONS != 1
+# error "_LIBCPP_ENABLE_ASSERTIONS must be set to 0 or 1"
+#endif
+
+#if _LIBCPP_ENABLE_ASSERTIONS
+# define _LIBCPP_ASSERT(expression, message) ((expression) ? (void)0 : ::std::__libcpp_assertion_handler(__FILE__, __LINE__, #expression, message))
 #else
-#   define _LIBCPP_ASSERT(x, m) ((void)0)
+# define _LIBCPP_ASSERT(x, m) ((void)0)
 #endif
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info {
-  _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-  __libcpp_debug_info()
-      : __file_(nullptr), __line_(-1), __pred_(nullptr), __msg_(nullptr) {}
-  _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-  __libcpp_debug_info(const char* __f, int __l, const char* __p, const char* __m)
-    : __file_(__f), __line_(__l), __pred_(__p), __msg_(__m) {}
-
-  _LIBCPP_FUNC_VIS string what() const;
-
-  const char* __file_;
-  int __line_;
-  const char* __pred_;
-  const char* __msg_;
-};
-
-/// __libcpp_debug_function_type - The type of the assertion failure handler.
-typedef void(*__libcpp_debug_function_type)(__libcpp_debug_info const&);
-
-/// __libcpp_debug_function - The handler function called when a _LIBCPP_ASSERT
-///    fails.
-extern _LIBCPP_EXPORTED_FROM_ABI __libcpp_debug_function_type __libcpp_debug_function;
-
-/// __libcpp_abort_debug_function - A debug handler that aborts when called.
-_LIBCPP_NORETURN _LIBCPP_FUNC_VIS
-void __libcpp_abort_debug_function(__libcpp_debug_info const&);
-
-/// __libcpp_set_debug_function - Set the debug handler to the specified
-///    function.
-_LIBCPP_FUNC_VIS
-bool __libcpp_set_debug_function(__libcpp_debug_function_type __func);
+_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ASSERTION_HANDLER
+void __libcpp_assertion_handler(char const* __file, int __line, char const* __expression, char const* __message);
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/include/__availability b/include/__availability
index d19c8b1..789e266 100644
--- a/include/__availability
+++ b/include/__availability
@@ -159,6 +159,23 @@
 #   define _LIBCPP_AVAILABILITY_FORMAT
 // #   define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format
 
+    // This controls whether the std::__libcpp_assertion_handler default
+    // assertion handler is provided by the library.
+    //
+    // Note that when users provide their own custom assertion handler,
+    // it doesn't matter whether the dylib provides a default handler,
+    // and the availability markup can actually give a false positive
+    // diagnostic (it will think that no handler is provided, when in
+    // reality the user has provided their own).
+    //
+    // Users can pass -D_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED
+    // to the compiler to tell the library to ignore the fact that the
+    // default handler isn't available on their deployment target. Note that
+    // defining this macro but failing to define a custom assertion handler
+    // will lead to a load-time error on back-deployment targets, so it
+    // should be avoided.
+#   define _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER
+
 #elif defined(__APPLE__)
 
 #   define _LIBCPP_AVAILABILITY_SHARED_MUTEX                                    \
@@ -260,6 +277,9 @@
 #   define _LIBCPP_AVAILABILITY_FORMAT                                          \
         __attribute__((unavailable))
 #   define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format
+
+#   define _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER                       \
+        __attribute__((unavailable))
 #else
 
 // ...New vendors can add availability markup here...
@@ -283,4 +303,14 @@
 #   define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS  _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
 #endif
 
+// Define the special assertion handler availability attribute, which can be silenced by
+// users if they provide their own custom assertion handler. The rest of the code should
+// not use the *_DEFAULT_* macro directly, since that would make it ignore the fact that
+// the user provided a custom handler.
+#if defined(_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED)
+#   define _LIBCPP_AVAILABILITY_ASSERTION_HANDLER /* nothing */
+#else
+#   define _LIBCPP_AVAILABILITY_ASSERTION_HANDLER _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER
+#endif
+
 #endif // _LIBCPP___AVAILABILITY
diff --git a/include/__config_site.in b/include/__config_site.in
index b85262b..38f654a 100644
--- a/include/__config_site.in
+++ b/include/__config_site.in
@@ -32,6 +32,7 @@
 #cmakedefine _LIBCPP_HAS_NO_WIDE_CHARACTERS
 #cmakedefine _LIBCPP_HAS_NO_INCOMPLETE_FORMAT
 #cmakedefine _LIBCPP_HAS_NO_INCOMPLETE_RANGES
+#cmakedefine01 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT
 
 // __USE_MINGW_ANSI_STDIO gets redefined on MinGW
 #ifdef __clang__
diff --git a/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
index 6f5f50e..3457fed 100644
--- a/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
+++ b/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
@@ -1561,6 +1561,7 @@
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_debug_functionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist b/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
index 5aeddaf..f1cb3c7 100644
--- a/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
+++ b/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
@@ -1534,6 +1534,7 @@
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
index 5ad475d..4338fa8 100644
--- a/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
+++ b/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
@@ -1561,6 +1561,7 @@
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_debug_functionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist b/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
index 288d819..5abc715 100644
--- a/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
+++ b/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
@@ -1534,6 +1534,7 @@
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
index e658d33..1341b01 100644
--- a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
+++ b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
@@ -1252,6 +1252,7 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_debug_functionE', 'size': 8, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist
index 77dfde5..0045596 100644
--- a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist
+++ b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist
@@ -1249,6 +1249,7 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_debug_functionE', 'size': 8, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist
index d4d76e9..505aa72 100644
--- a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist
+++ b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist
@@ -1228,6 +1228,7 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist
index c05c231..4edf1d1 100644
--- a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist
+++ b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist
@@ -1224,6 +1224,7 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_debug_functionE', 'size': 8, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__libcpp_assertion_handlerEPKciS1_S1_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIddEEPdEEbT0_S5_T_', 'type': 'FUNC'}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3395003..f091dbf 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@
 set(LIBCXX_SOURCES
   algorithm.cpp
   any.cpp
+  assert.cpp
   atomic.cpp
   barrier.cpp
   bind.cpp
@@ -65,8 +66,8 @@
 
 if (LIBCXX_ENABLE_DEBUG_MODE_SUPPORT)
   list(APPEND LIBCXX_SOURCES
-    assert.cpp
     debug.cpp
+    legacy_debug_handler.cpp
     )
 endif()
 
diff --git a/src/assert.cpp b/src/assert.cpp
index 40c51f8..5445980 100644
--- a/src/assert.cpp
+++ b/src/assert.cpp
@@ -10,29 +10,13 @@
 #include <__config>
 #include <cstdio>
 #include <cstdlib>
-#include <string>
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-std::string __libcpp_debug_info::what() const {
-  string msg = __file_;
-  msg += ":" + std::to_string(__line_) + ": _LIBCPP_ASSERT '";
-  msg += __pred_;
-  msg += "' failed. ";
-  msg += __msg_;
-  return msg;
-}
-
-_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
-    std::fprintf(stderr, "%s\n", info.what().c_str());
-    std::abort();
-}
-
-constinit __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function;
-
-bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
-  __libcpp_debug_function = __func;
-  return true;
+_LIBCPP_WEAK
+void __libcpp_assertion_handler(char const* __file, int __line, char const* __expression, char const* __message) {
+  std::fprintf(stderr, "%s:%d: libc++ assertion '%s' failed. %s\n", __file, __line, __expression, __message);
+  std::abort();
 }
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/src/legacy_debug_handler.cpp b/src/legacy_debug_handler.cpp
new file mode 100644
index 0000000..cb2025b
--- /dev/null
+++ b/src/legacy_debug_handler.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <__config>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+
+// This file defines the legacy default debug handler and related mechanisms
+// to set it. This is for backwards ABI compatibility with code that has been
+// using this debug handler previously.
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info {
+  _LIBCPP_EXPORTED_FROM_ABI string what() const;
+
+  const char* __file_;
+  int __line_;
+  const char* __pred_;
+  const char* __msg_;
+};
+
+std::string __libcpp_debug_info::what() const {
+  string msg = __file_;
+  msg += ":" + std::to_string(__line_) + ": _LIBCPP_ASSERT '";
+  msg += __pred_;
+  msg += "' failed. ";
+  msg += __msg_;
+  return msg;
+}
+
+_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
+  std::fprintf(stderr, "%s\n", info.what().c_str());
+  std::abort();
+}
+
+typedef void (*__libcpp_debug_function_type)(__libcpp_debug_info const&);
+
+_LIBCPP_EXPORTED_FROM_ABI
+constinit __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function;
+
+_LIBCPP_EXPORTED_FROM_ABI
+bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) {
+  __libcpp_debug_function = __func;
+  return true;
+}
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/test/libcxx/assertions/assertions_disabled.pass.cpp b/test/libcxx/assertions/assertions_disabled.pass.cpp
new file mode 100644
index 0000000..52dd785
--- /dev/null
+++ b/test/libcxx/assertions/assertions_disabled.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that _LIBCPP_ASSERT doesn't do anything when assertions are disabled.
+// We need to use -Wno-macro-redefined because the test suite defines
+// _LIBCPP_ENABLE_ASSERTIONS=1 under some configurations.
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-macro-redefined -D_LIBCPP_ENABLE_ASSERTIONS=0
+
+#include <__assert>
+#include <cassert>
+
+bool executed_condition = false;
+bool f() { executed_condition = true; return false; }
+
+int main(int, char**) {
+  _LIBCPP_ASSERT(f(), "message"); // should not execute anything
+  assert(!executed_condition); // really make sure we did not execute anything at all
+  return 0;
+}
diff --git a/test/libcxx/assertions/customize_handler.backdeployment.pass.cpp b/test/libcxx/assertions/customize_handler.backdeployment.pass.cpp
new file mode 100644
index 0000000..59b56d3
--- /dev/null
+++ b/test/libcxx/assertions/customize_handler.backdeployment.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that we can enable assertions when we back-deploy to older platforms
+// if we define _LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED.
+//
+// Note that this test isn't really different from customize_handler.pass.cpp when
+// run outside of back-deployment scenarios, but we still run it all the time.
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 -D_LIBCPP_AVAILABILITY_CUSTOM_ASSERTION_HANDLER_PROVIDED
+
+#include <__assert>
+#include <cassert>
+
+bool handler_called = false;
+void std::__libcpp_assertion_handler(char const*, int, char const*, char const*) {
+  handler_called = true;
+}
+
+int main(int, char**) {
+  _LIBCPP_ASSERT(false, "message");
+  assert(handler_called);
+  return 0;
+}
diff --git a/test/libcxx/assertions/customize_handler.pass.cpp b/test/libcxx/assertions/customize_handler.pass.cpp
new file mode 100644
index 0000000..2a0f26a
--- /dev/null
+++ b/test/libcxx/assertions/customize_handler.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that we can set a custom assertion handler.
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// We flag uses of the assertion handler in older dylibs at compile-time to avoid runtime
+// failures when back-deploying.
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+
+#include <__assert>
+#include <cassert>
+
+bool handler_called = false;
+void std::__libcpp_assertion_handler(char const*, int, char const*, char const*) {
+  handler_called = true;
+}
+
+int main(int, char**) {
+  _LIBCPP_ASSERT(false, "message");
+  assert(handler_called);
+  return 0;
+}
diff --git a/test/libcxx/assertions/debug_mode_compatibility.pass.cpp b/test/libcxx/assertions/debug_mode_compatibility.pass.cpp
new file mode 100644
index 0000000..61ebb7b
--- /dev/null
+++ b/test/libcxx/assertions/debug_mode_compatibility.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// This test ensures that assertions are still enabled when _LIBCPP_DEBUG=0 is
+// defined, for backwards compatibility with code that might have been using
+// it to enable assertions previously.
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+
+// We flag uses of the assertion handler in older dylibs at compile-time to avoid runtime
+// failures when back-deploying.
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+
+#include <__assert>
+#include <cassert>
+
+bool handler_called = false;
+void std::__libcpp_assertion_handler(char const*, int, char const*, char const*) {
+  handler_called = true;
+}
+
+int main(int, char**) {
+  _LIBCPP_ASSERT(false, "message");
+  assert(handler_called);
+  return 0;
+}
diff --git a/test/libcxx/assertions/default_handler.abort.pass.cpp b/test/libcxx/assertions/default_handler.abort.pass.cpp
new file mode 100644
index 0000000..5be0997
--- /dev/null
+++ b/test/libcxx/assertions/default_handler.abort.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that the default assertion handler aborts the program.
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// We flag uses of the assertion handler in older dylibs at compile-time to avoid runtime
+// failures when back-deploying.
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+
+#include <__assert>
+#include <csignal>
+#include <cstdlib>
+
+void signal_handler(int signal) {
+  if (signal == SIGABRT)
+    std::_Exit(EXIT_SUCCESS);
+  std::_Exit(EXIT_FAILURE);
+}
+
+int main(int, char**) {
+  if (std::signal(SIGABRT, signal_handler) != SIG_ERR)
+    _LIBCPP_ASSERT(false, "foo");
+  return EXIT_FAILURE;
+}
diff --git a/test/libcxx/assertions/default_handler.availability.verify.cpp b/test/libcxx/assertions/default_handler.availability.verify.cpp
new file mode 100644
index 0000000..93d6d02
--- /dev/null
+++ b/test/libcxx/assertions/default_handler.availability.verify.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that we diagnose any usage of the default assertion handler on a platform
+// that doesn't support it at compile-time.
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
+
+// REQUIRES: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+
+#include <__assert>
+
+void f() {
+  _LIBCPP_ASSERT(true, "message"); // expected-error {{'__libcpp_assertion_handler' is unavailable}}
+}
diff --git a/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp b/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
index 7150ba0..f9b6a08 100644
--- a/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
+++ b/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // test that array<T, 0>::back() triggers an assertion
 
diff --git a/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp b/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
index 3395b9e..d359413 100644
--- a/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
+++ b/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // test that array<T, 0>::back() triggers an assertion
 
diff --git a/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp b/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
index 7168b42..e0ae2e6 100644
--- a/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
+++ b/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // test that array<T, 0>::operator[] triggers an assertion
 
diff --git a/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp b/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
index 982f481..fa71fbf 100644
--- a/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // pop_back() more than the number of elements in a deque
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <deque>
 
diff --git a/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp b/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
index 60fce7a..319a386 100644
--- a/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
+++ b/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call erase(const_iterator position) with end()
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <list>
 
diff --git a/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp b/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
index 3e615ee..a17905c 100644
--- a/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // void pop_back();
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <list>
 #include <cassert>
diff --git a/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp b/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
index 87f8e1d..8b13c57 100644
--- a/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call back() on empty container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 #include <cassert>
diff --git a/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp b/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
index 30fff5f..1269540 100644
--- a/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call back() on empty const container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 
diff --git a/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp b/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
index 4c86a09..07c9aee 100644
--- a/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call front() on empty const container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 
diff --git a/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp b/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
index 88efa5d..b8ab564 100644
--- a/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
@@ -10,8 +10,9 @@
 
 // Index const vector out of bounds.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 #include <cassert>
diff --git a/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp b/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
index 96944f9..702401e 100644
--- a/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call front() on empty container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 #include <cassert>
diff --git a/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp b/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
index 61f6778..1f26052 100644
--- a/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
@@ -10,8 +10,9 @@
 
 // Index vector out of bounds.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 #include <cassert>
diff --git a/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp b/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
index 880b978..0f95ab8 100644
--- a/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
@@ -10,8 +10,9 @@
 
 // pop_back() more than the number of elements in a vector
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <vector>
 
diff --git a/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp b/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp
index 4512625..706a815 100644
--- a/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp
+++ b/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03
-// UNSUPPORTED: debug_level=0, debug_level=1
+// UNSUPPORTED: debug_level=0, debug_level=1, libcpp-has-assertions
 
 // <vector>
 
diff --git a/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp b/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
index faaffea..b99a5b7 100644
--- a/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
+++ b/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
@@ -10,8 +10,9 @@
 
 // size_type bucket(const key_type& __k) const;
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_map>
 #include <string>
diff --git a/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp b/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
index fba3e59..068114a 100644
--- a/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
+++ b/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket_size(size_type n) const
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_map>
 #include <string>
diff --git a/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp b/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
index 9ece4f9..19427ba 100644
--- a/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
+++ b/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
@@ -15,8 +15,9 @@
 // float max_load_factor() const;
 // void max_load_factor(float mlf);
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_map>
 #include <string>
diff --git a/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp b/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
index b0b9fb0..7c9841f 100644
--- a/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
+++ b/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket(const key_type& __k) const;
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_map>
 #include <string>
diff --git a/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp b/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
index 1f95e17..751d81a 100644
--- a/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
+++ b/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket_size(size_type n) const
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_map>
 #include <string>
diff --git a/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp b/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
index 559ac62..9ca92ad 100644
--- a/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
+++ b/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
@@ -15,8 +15,9 @@
 // float max_load_factor() const;
 // void max_load_factor(float mlf);
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_map>
 #include <string>
diff --git a/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp b/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
index 0350cd3..ce2b333 100644
--- a/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
+++ b/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket(const key_type& __k) const;
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_set>
 
diff --git a/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp b/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
index a6c9c31..47c3f5d 100644
--- a/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
+++ b/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket_size(size_type n) const
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_set>
 
diff --git a/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp b/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
index e1d07c8..ee179d1 100644
--- a/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
+++ b/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
@@ -15,8 +15,9 @@
 // float max_load_factor() const;
 // void max_load_factor(float mlf);
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_set>
 
diff --git a/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp b/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
index adcd5de..8330939 100644
--- a/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
+++ b/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket(const key_type& __k) const;
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_set>
 
diff --git a/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp b/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
index 1374152..38051a1 100644
--- a/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
+++ b/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
@@ -14,8 +14,9 @@
 
 // size_type bucket_size(size_type n) const
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_set>
 
diff --git a/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp b/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
index e0c98ed..8a57e44 100644
--- a/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
+++ b/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
@@ -15,8 +15,9 @@
 // float max_load_factor() const;
 // void max_load_factor(float mlf);
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <unordered_set>
 
diff --git a/test/libcxx/debug/containers/string.pass.cpp b/test/libcxx/debug/containers/string.pass.cpp
index 7206273..56aa96f 100644
--- a/test/libcxx/debug/containers/string.pass.cpp
+++ b/test/libcxx/debug/containers/string.pass.cpp
@@ -82,7 +82,7 @@
     EXPECT_DEATH( C1.erase(it1) );
     C1.erase(C1.begin(), C1.end());
     assert(C1.size() == 0);
-    EXPECT_DEATH_MATCHES(DebugInfoMatcher("string::pop_back(): string is already empty"), C1.pop_back() );
+    TEST_LIBCPP_ASSERT_FAILURE(C1.pop_back(), "string::pop_back(): string is already empty");
   }
 };
 
diff --git a/test/libcxx/debug/debug_abort.pass.cpp b/test/libcxx/debug/debug_abort.pass.cpp
deleted file mode 100644
index f822343..0000000
--- a/test/libcxx/debug/debug_abort.pass.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=1
-
-// Test that the default debug handler aborts the program.
-
-#include <__assert>
-#include <csignal>
-#include <cstdlib>
-
-#include "test_macros.h"
-
-void signal_handler(int signal)
-{
-    if (signal == SIGABRT)
-      std::_Exit(EXIT_SUCCESS);
-    std::_Exit(EXIT_FAILURE);
-}
-
-int main(int, char**)
-{
-  if (std::signal(SIGABRT, signal_handler) != SIG_ERR)
-    _LIBCPP_ASSERT(false, "foo");
-  return EXIT_FAILURE;
-}
diff --git a/test/libcxx/debug/register_debug_handler.pass.cpp b/test/libcxx/debug/register_debug_handler.pass.cpp
deleted file mode 100644
index 9ed97ef..0000000
--- a/test/libcxx/debug/register_debug_handler.pass.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=1
-// UNSUPPORTED: libcxx-no-debug-mode
-
-#include <cstdlib>
-#include <string>
-#include <type_traits>
-#include <__debug>
-#include <cassert>
-
-#include "test_macros.h"
-
-void my_debug_function(std::__libcpp_debug_info const& info) {
-  assert(info.__msg_ == std::string("foo"));
-  std::exit(0);
-}
-
-int main(int, char**)
-{
-  std::__libcpp_set_debug_function(&my_debug_function);
-  _LIBCPP_ASSERT(false, "foo");
-  return 1;
-}
diff --git a/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp
index e73ddfc..ef1cd19 100644
--- a/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp
+++ b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp
@@ -12,8 +12,9 @@
 
 // T* polymorphic_allocator<T>::deallocate(T*, size_t size)
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <experimental/memory_resource>
 #include <type_traits>
diff --git a/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp b/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp
index 8867f34..15bfc5c 100644
--- a/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp
+++ b/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp
@@ -12,8 +12,9 @@
 
 // T* polymorphic_allocator<T>::deallocate(T*, size_t size)
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <experimental/memory_resource>
 #include <type_traits>
diff --git a/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp b/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
index 0612c6b..36b4836 100644
--- a/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
+++ b/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // <filesystem>
 
diff --git a/test/libcxx/iterators/assert.advance.pass.cpp b/test/libcxx/iterators/assert.advance.pass.cpp
index f85dae8..35f7c62 100644
--- a/test/libcxx/iterators/assert.advance.pass.cpp
+++ b/test/libcxx/iterators/assert.advance.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // <list>
 
diff --git a/test/libcxx/iterators/assert.next.pass.cpp b/test/libcxx/iterators/assert.next.pass.cpp
index 0771539..92a2292 100644
--- a/test/libcxx/iterators/assert.next.pass.cpp
+++ b/test/libcxx/iterators/assert.next.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // <list>
 
diff --git a/test/libcxx/iterators/assert.prev.pass.cpp b/test/libcxx/iterators/assert.prev.pass.cpp
index 3b92bce..19df605 100644
--- a/test/libcxx/iterators/assert.prev.pass.cpp
+++ b/test/libcxx/iterators/assert.prev.pass.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // <list>
 
diff --git a/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp b/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
index d1a8cf5..2bbf63c 100644
--- a/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call back() on empty container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 
diff --git a/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp b/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
index 14e3622..d12854d 100644
--- a/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call back() on empty const container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 
diff --git a/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp b/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
index 22aacd3..8a9f3f1 100644
--- a/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call front() on empty const container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 
diff --git a/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp b/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
index b238fcd..b33fe91 100644
--- a/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
@@ -10,8 +10,9 @@
 
 // Index const string out of bounds.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 #include <cassert>
diff --git a/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp b/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
index c0b4efb..5683d25 100644
--- a/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call front() on empty container.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 #include <cassert>
diff --git a/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp b/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
index 33bca86..d6fa61e 100644
--- a/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
@@ -10,8 +10,9 @@
 
 // Index string out of bounds.
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 #include <cassert>
diff --git a/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp b/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
index e91f8d6..96c3ab7 100644
--- a/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
@@ -10,8 +10,9 @@
 
 // Call erase(const_iterator position) with end()
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 
diff --git a/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp b/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
index 8bec8fb..4426cec 100644
--- a/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
+++ b/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
@@ -10,8 +10,9 @@
 
 // void pop_back();
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <string>
 
diff --git a/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp b/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
index c3b8e68..61fa310 100644
--- a/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
+++ b/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
@@ -8,8 +8,9 @@
 
 // UNSUPPORTED: c++11, c++14
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // Construct a string_view from a null pointer
 // constexpr basic_string_view( const CharT* s );
diff --git a/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp b/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
index a3f327b..13ac23d 100644
--- a/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
+++ b/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
@@ -8,8 +8,9 @@
 
 // UNSUPPORTED: libcpp-has-no-threads
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // <future>
 
diff --git a/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp b/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
index 911fff3..a773867 100644
--- a/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
+++ b/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
@@ -8,8 +8,9 @@
 
 // UNSUPPORTED: libcpp-has-no-threads
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 // <future>
 
diff --git a/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp b/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
index c389389..fa185c5 100644
--- a/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
+++ b/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
@@ -15,8 +15,9 @@
 
 // UNSUPPORTED: c++11, c++14
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <optional>
 
diff --git a/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp b/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
index fde804e..7ac5dd4 100644
--- a/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
+++ b/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
@@ -13,8 +13,9 @@
 
 // UNSUPPORTED: c++11, c++14
 
-// UNSUPPORTED: c++03, windows, libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=0
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
 #include <optional>
 
diff --git a/test/support/check_assertion.h b/test/support/check_assertion.h
index 29e8668..30067b4 100644
--- a/test/support/check_assertion.h
+++ b/test/support/check_assertion.h
@@ -9,16 +9,6 @@
 #ifndef TEST_SUPPORT_CHECK_ASSERTION_H
 #define TEST_SUPPORT_CHECK_ASSERTION_H
 
-#ifndef _LIBCPP_DEBUG
-#error _LIBCPP_DEBUG must be defined before including this header
-#endif
-
-#include <ciso646>
-#ifndef _LIBCPP_VERSION
-#error "This header may only be used for libc++ tests"
-#endif
-
-#include <__debug>
 #include <cassert>
 #include <cstddef>
 #include <cstdio>
@@ -33,28 +23,31 @@
 #include "test_macros.h"
 #include "test_allocator.h"
 
+#ifndef _LIBCPP_VERSION
+# error "This header may only be used for libc++ tests"
+#endif
+
 #if TEST_STD_VER < 11
 # error "C++11 or greater is required to use this header"
 #endif
 
-struct DebugInfoMatcher {
+struct AssertionInfoMatcher {
   static const int any_line = -1;
   static constexpr const char* any_file = "*";
   static constexpr const char* any_msg = "*";
 
-  constexpr DebugInfoMatcher() : is_empty_(true), msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) { }
-  constexpr DebugInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
+  constexpr AssertionInfoMatcher() : is_empty_(true), msg_(any_msg, __builtin_strlen(any_msg)), file_(any_file, __builtin_strlen(any_file)), line_(any_line) { }
+  constexpr AssertionInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
     : is_empty_(false), msg_(msg, __builtin_strlen(msg)), file_(file, __builtin_strlen(file)), line_(line) {}
 
-  bool Matches(std::__libcpp_debug_info const& got) const {
+  bool Matches(char const* file, int line, char const* message) const {
     assert(!empty() && "empty matcher");
 
-    if (CheckLineMatches(got.__line_) && CheckFileMatches(got.__file_) &&
-        CheckMessageMatches(got.__msg_))
+    if (CheckLineMatches(line) && CheckFileMatches(file) && CheckMessageMatches(message))
         return true;
     // Write to stdout because that's the file descriptor captured by the parent
     // process.
-    std::printf("Failed to match debug info!\n%s\nVS\n%s\n", ToString().data(), got.what().data());
+    std::printf("Failed to match assertion info!\n%s\nVS\n%s:%d (%s)\n", ToString().data(), file, line, message);
     return false;
   }
 
@@ -108,10 +101,10 @@
   int line_;
 };
 
-static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg);
+static constexpr AssertionInfoMatcher AnyMatcher(AssertionInfoMatcher::any_msg);
 
-inline DebugInfoMatcher& GlobalMatcher() {
-  static DebugInfoMatcher GMatch;
+inline AssertionInfoMatcher& GlobalMatcher() {
+  static AssertionInfoMatcher GMatch;
   return GMatch;
 }
 
@@ -136,15 +129,7 @@
     return val >= RK_DidNotDie && val <= RK_Unknown;
   }
 
-  TEST_NORETURN static void DeathTestDebugHandler(std::__libcpp_debug_info const& info) {
-    assert(!GlobalMatcher().empty());
-    if (GlobalMatcher().Matches(info)) {
-      std::exit(RK_MatchFound);
-    }
-    std::exit(RK_MatchFailure);
-  }
-
-  DeathTest(DebugInfoMatcher const& Matcher) : matcher_(Matcher) {}
+  DeathTest(AssertionInfoMatcher const& Matcher) : matcher_(Matcher) {}
 
   template <class Func>
   ResultKind Run(Func&& f) {
@@ -180,7 +165,6 @@
     DupFD(GetStdErrWriteFD(), STDERR_FILENO);
 
     GlobalMatcher() = matcher_;
-    std::__libcpp_set_debug_function(&DeathTestDebugHandler);
     f();
     std::exit(RK_DidNotDie);
   }
@@ -242,7 +226,7 @@
     return stderr_pipe_fd_[1];
   }
 private:
-  DebugInfoMatcher matcher_;
+  AssertionInfoMatcher matcher_;
   pid_t child_pid_ = -1;
   int exit_code_ = -1;
   int stdout_pipe_fd_[2];
@@ -251,8 +235,16 @@
   std::string stderr_from_child_;
 };
 
+void std::__libcpp_assertion_handler(char const* file, int line, char const* /*expression*/, char const* message) {
+  assert(!GlobalMatcher().empty());
+  if (GlobalMatcher().Matches(file, line, message)) {
+    std::exit(DeathTest::RK_MatchFound);
+  }
+  std::exit(DeathTest::RK_MatchFailure);
+}
+
 template <class Func>
-inline bool ExpectDeath(const char* stmt, Func&& func, DebugInfoMatcher Matcher) {
+inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) {
   DeathTest DT(Matcher);
   DeathTest::ResultKind RK = DT.Run(func);
   auto OnFailure = [&](const char* msg) {
@@ -293,6 +285,6 @@
 
 #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
 
-#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, DebugInfoMatcher(message))))
+#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message))))
 
 #endif // TEST_SUPPORT_CHECK_ASSERTION_H
diff --git a/test/libcxx/debug/check_assertion_test.pass.cpp b/test/support/test.support/test_check_assertion.pass.cpp
similarity index 83%
rename from test/libcxx/debug/check_assertion_test.pass.cpp
rename to test/support/test.support/test_check_assertion.pass.cpp
index ecce86e..f98bdcb 100644
--- a/test/libcxx/debug/check_assertion_test.pass.cpp
+++ b/test/support/test.support/test_check_assertion.pass.cpp
@@ -6,17 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: libcxx-no-debug-mode, c++03, windows
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=1
+// UNSUPPORTED: c++03, windows
+// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11|12}}
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1
 
-#include <__debug>
+#include <cassert>
 #include <cstdio>
+#include <string>
 
 #include "check_assertion.h"
-#include "test_macros.h"
 
 template <class Func>
-inline bool TestDeathTest(const char* stmt, Func&& func, DeathTest::ResultKind ExpectResult, DebugInfoMatcher Matcher = AnyMatcher) {
+inline bool TestDeathTest(const char* stmt, Func&& func, DeathTest::ResultKind ExpectResult, AssertionInfoMatcher Matcher = AnyMatcher) {
   DeathTest DT(Matcher);
   DeathTest::ResultKind RK = DT.Run(func);
   auto OnFailure = [&](std::string msg) {
@@ -42,7 +43,7 @@
 }
 
 void test_no_match_found() {
-  DebugInfoMatcher ExpectMatch("my message");
+  AssertionInfoMatcher ExpectMatch("my message");
   TEST_DEATH_TEST_MATCHES(DeathTest::RK_MatchFailure, ExpectMatch, my_libcpp_assert());
 }
 
diff --git a/utils/libcxx/test/params.py b/utils/libcxx/test/params.py
index c0e5008..2c18aba 100644
--- a/utils/libcxx/test/params.py
+++ b/utils/libcxx/test/params.py
@@ -183,6 +183,14 @@
               AddFeature('libcxx-no-debug-mode')
             ]),
 
+  Parameter(name='enable_assertions', choices=[True, False], type=bool, default=False,
+            help="Whether to enable assertions when compiling the test suite. This is only meaningful when "
+                 "running the tests against libc++.",
+            actions=lambda assertions: [
+              AddCompileFlag('-D_LIBCPP_ENABLE_ASSERTIONS=1'),
+              AddFeature('libcpp-has-assertions')
+            ] if assertions else []),
+
   Parameter(name='additional_features', type=list, default=[],
             help="A comma-delimited list of additional features that will be enabled when running the tests. "
                  "This should be used sparingly since specifying ad-hoc features manually is error-prone and "