[libcxx-commits] [libcxx] b0fd949 - [libc++] Add a lightweight overridable assertion handler

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 23 12:36:18 PDT 2022


Author: Louis Dionne
Date: 2022-03-23T15:35:46-04:00
New Revision: b0fd9497af6d2efd305e9eecfa0c1e265f1b2192

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

LOG: [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

Added: 
    libcxx/src/legacy_debug_handler.cpp
    libcxx/test/libcxx/assertions/assertions_disabled.pass.cpp
    libcxx/test/libcxx/assertions/customize_handler.backdeployment.pass.cpp
    libcxx/test/libcxx/assertions/customize_handler.pass.cpp
    libcxx/test/libcxx/assertions/debug_mode_compatibility.pass.cpp
    libcxx/test/libcxx/assertions/default_handler.abort.pass.cpp
    libcxx/test/libcxx/assertions/default_handler.availability.verify.cpp
    libcxx/test/support/test.support/test_check_assertion.pass.cpp

Modified: 
    libcxx/CMakeLists.txt
    libcxx/cmake/caches/Generic-assertions.cmake
    libcxx/docs/BuildingLibcxx.rst
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/UsingLibcxx.rst
    libcxx/include/__assert
    libcxx/include/__availability
    libcxx/include/__config_site.in
    libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
    libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
    libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
    libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
    libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
    libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist
    libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist
    libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist
    libcxx/src/CMakeLists.txt
    libcxx/src/assert.cpp
    libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
    libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
    libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
    libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
    libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
    libcxx/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
    libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
    libcxx/test/libcxx/debug/containers/string.pass.cpp
    libcxx/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp
    libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp
    libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
    libcxx/test/libcxx/iterators/assert.advance.pass.cpp
    libcxx/test/libcxx/iterators/assert.next.pass.cpp
    libcxx/test/libcxx/iterators/assert.prev.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
    libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
    libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
    libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
    libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
    libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
    libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
    libcxx/test/support/check_assertion.h
    libcxx/utils/libcxx/test/params.py

Removed: 
    libcxx/test/libcxx/debug/check_assertion_test.pass.cpp
    libcxx/test/libcxx/debug/debug_abort.pass.cpp
    libcxx/test/libcxx/debug/register_debug_handler.pass.cpp


################################################################################
diff  --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 75669bb90e241..2948fdc308842 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -82,7 +82,10 @@ include(CMakeDependentOption)
 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 @@ if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXX_ENABLE_SHARED)
 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_LOCALIZATION _LIBCPP_HAS_NO_LOCALIZATION)
 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/libcxx/cmake/caches/Generic-assertions.cmake b/libcxx/cmake/caches/Generic-assertions.cmake
index e8ef72ad16ebb..18eb86601cf16 100644
--- a/libcxx/cmake/caches/Generic-assertions.cmake
+++ b/libcxx/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/libcxx/docs/BuildingLibcxx.rst b/libcxx/docs/BuildingLibcxx.rst
index 0dd278e43708b..17e90f9bea2cf 100644
--- a/libcxx/docs/BuildingLibcxx.rst
+++ b/libcxx/docs/BuildingLibcxx.rst
@@ -216,7 +216,10 @@ libc++ specific options
 
   **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/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index 9e2e4a78349bb..ea42b56f29d1a 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -46,6 +46,12 @@ New Features
   "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 @@ API Changes
 - 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/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst
index bd999f05c2430..3eab44abe8e95 100644
--- a/libcxx/docs/UsingLibcxx.rst
+++ b/libcxx/docs/UsingLibcxx.rst
@@ -121,6 +121,92 @@ provide pretty-printers itself. Those can be used as:
         <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/libcxx/include/__assert b/libcxx/include/__assert
index 75763d0374156..93669c6a0e357 100644
--- a/libcxx/include/__assert
+++ b/libcxx/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/libcxx/include/__availability b/libcxx/include/__availability
index d19c8b1886ef7..789e26679f31e 100644
--- a/libcxx/include/__availability
+++ b/libcxx/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/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index b85262b14cf62..38f654ac69f79 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/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/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
index 6f5f50e997664..3457fedff6ac9 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
index 5aeddafb2f6f9..f1cb3c7a1a14b 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
index 5ad475d43feb9..4338fa80201a2 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
index 288d8194218f2..5abc715dac499 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.nodebug.noincomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
index e658d3321ce8e..1341b0180251a 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.incomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist
index 77dfde59a0794..0045596fe6edb 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.debug.noincomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist
index d4d76e99e712f..505aa72dd0c66 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.nodebug.incomplete.abilist
+++ b/libcxx/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/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist
index c05c231ded49e..4edf1d18d0334 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.debug.incomplete.abilist
+++ b/libcxx/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/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 3395003c373ba..f091dbf635e66 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LIBCXX_LIB_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTOR
 set(LIBCXX_SOURCES
   algorithm.cpp
   any.cpp
+  assert.cpp
   atomic.cpp
   barrier.cpp
   bind.cpp
@@ -65,8 +66,8 @@ set(LIBCXX_SOURCES
 
 if (LIBCXX_ENABLE_DEBUG_MODE_SUPPORT)
   list(APPEND LIBCXX_SOURCES
-    assert.cpp
     debug.cpp
+    legacy_debug_handler.cpp
     )
 endif()
 

diff  --git a/libcxx/src/assert.cpp b/libcxx/src/assert.cpp
index 40c51f872bcd9..54459800728b1 100644
--- a/libcxx/src/assert.cpp
+++ b/libcxx/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/libcxx/src/legacy_debug_handler.cpp b/libcxx/src/legacy_debug_handler.cpp
new file mode 100644
index 0000000000000..cb2025bfc9b6d
--- /dev/null
+++ b/libcxx/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/libcxx/test/libcxx/assertions/assertions_disabled.pass.cpp b/libcxx/test/libcxx/assertions/assertions_disabled.pass.cpp
new file mode 100644
index 0000000000000..52dd7856e473b
--- /dev/null
+++ b/libcxx/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/libcxx/test/libcxx/assertions/customize_handler.backdeployment.pass.cpp b/libcxx/test/libcxx/assertions/customize_handler.backdeployment.pass.cpp
new file mode 100644
index 0000000000000..59b56d328a716
--- /dev/null
+++ b/libcxx/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 
diff erent 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/libcxx/test/libcxx/assertions/customize_handler.pass.cpp b/libcxx/test/libcxx/assertions/customize_handler.pass.cpp
new file mode 100644
index 0000000000000..2a0f26ab852db
--- /dev/null
+++ b/libcxx/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/libcxx/test/libcxx/assertions/debug_mode_compatibility.pass.cpp b/libcxx/test/libcxx/assertions/debug_mode_compatibility.pass.cpp
new file mode 100644
index 0000000000000..61ebb7b316bba
--- /dev/null
+++ b/libcxx/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/libcxx/test/libcxx/debug/debug_abort.pass.cpp b/libcxx/test/libcxx/assertions/default_handler.abort.pass.cpp
similarity index 52%
rename from libcxx/test/libcxx/debug/debug_abort.pass.cpp
rename to libcxx/test/libcxx/assertions/default_handler.abort.pass.cpp
index f8223436d0256..5be0997d67407 100644
--- a/libcxx/test/libcxx/debug/debug_abort.pass.cpp
+++ b/libcxx/test/libcxx/assertions/default_handler.abort.pass.cpp
@@ -6,26 +6,25 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: libcxx-no-debug-mode
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG=1
+// Test that the default assertion handler aborts the program.
 
-// Test that the default debug 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>
 
-#include "test_macros.h"
-
-void signal_handler(int signal)
-{
-    if (signal == SIGABRT)
-      std::_Exit(EXIT_SUCCESS);
-    std::_Exit(EXIT_FAILURE);
+void signal_handler(int signal) {
+  if (signal == SIGABRT)
+    std::_Exit(EXIT_SUCCESS);
+  std::_Exit(EXIT_FAILURE);
 }
 
-int main(int, char**)
-{
+int main(int, char**) {
   if (std::signal(SIGABRT, signal_handler) != SIG_ERR)
     _LIBCPP_ASSERT(false, "foo");
   return EXIT_FAILURE;

diff  --git a/libcxx/test/libcxx/assertions/default_handler.availability.verify.cpp b/libcxx/test/libcxx/assertions/default_handler.availability.verify.cpp
new file mode 100644
index 0000000000000..93d6d020cb1fd
--- /dev/null
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
index 7150ba0c6b6fd..f9b6a088abfe0 100644
--- a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.back.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
index 3395b9e626b2c..d35941333cb3f 100644
--- a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.front.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp b/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
index 7168b4209104a..e0ae2e6878f9f 100644
--- a/libcxx/test/libcxx/containers/sequences/array/array.zero/assert.subscript.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
index 982f481559317..fa71fbf343a17 100644
--- a/libcxx/test/libcxx/containers/sequences/deque/assert.pop_back.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp b/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
index 60fce7a08ab57..319a3866c3a3f 100644
--- a/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.erase_iter.end.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
index 3e615ee630618..a17905c6b2e75 100644
--- a/libcxx/test/libcxx/containers/sequences/list/list.modifiers/assert.pop_back.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
index 87f8e1da4da84..8b13c57b378ce 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.back.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
index 30fff5f31cb2c..1269540363be5 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.cback.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
index 4c86a093fd1ef..07c9aee64d786 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.cfront.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
index 88efa5d20abc0..b8ab564803ccd 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.cindex.oob.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
index 96944f9f934bb..702401ef11856 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.front.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
index 61f677800e7f6..1f2605202811d 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.index.oob.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
index 880b97859e330..0f95ab82ca43f 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/assert.pop_back.empty.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp
index 451262596e5e3..706a815919d54 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/robust_against_adl.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
index faaffea56be26..b99a5b7542c46 100644
--- a/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
index fba3e595438b0..068114afa5904 100644
--- a/libcxx/test/libcxx/containers/unord/unord.map/assert.bucket_size.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
index 9ece4f90ca2df..19427baced2f5 100644
--- a/libcxx/test/libcxx/containers/unord/unord.map/assert.max_load_factor.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
index b0b9fb004843f..7c9841f005e81 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
index 1f95e17473c54..751d81a96df9c 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.bucket_size.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
index 559ac62927322..9ca92ad399669 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multimap/assert.max_load_factor.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
index 0350cd39866f3..ce2b333d8fa41 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
index a6c9c310470d0..47c3f5d4df078 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.bucket_size.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
index e1d07c8ca4f57..ee179d1d4b667 100644
--- a/libcxx/test/libcxx/containers/unord/unord.multiset/assert.max_load_factor.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
index adcd5de6737d1..8330939301675 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
index 13741525b7b0b..38051a1a1b842 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/assert.bucket_size.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp b/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
index e0c98ed478262..8a57e4482b78d 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/assert.max_load_factor.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/debug/containers/string.pass.cpp b/libcxx/test/libcxx/debug/containers/string.pass.cpp
index 7206273c5f5ab..56aa96f47bae7 100644
--- a/libcxx/test/libcxx/debug/containers/string.pass.cpp
+++ b/libcxx/test/libcxx/debug/containers/string.pass.cpp
@@ -82,7 +82,7 @@ struct StringContainerChecks : BasicContainerChecks<Container, CT> {
     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/libcxx/test/libcxx/debug/register_debug_handler.pass.cpp b/libcxx/test/libcxx/debug/register_debug_handler.pass.cpp
deleted file mode 100644
index 9ed97efcda26d..0000000000000
--- a/libcxx/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/libcxx/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp b/libcxx/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp
index e73ddfcb98652..ef1cd194b637d 100644
--- a/libcxx/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/assert.deallocate.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp b/libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp
index 8867f34703499..15bfc5c54ab62 100644
--- a/libcxx/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/assert.deallocate.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
index 0612c6b604ed6..36b48365e3a6c 100644
--- a/libcxx/test/libcxx/input.output/filesystems/class.path/path.itr/assert.iterator.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/iterators/assert.advance.pass.cpp b/libcxx/test/libcxx/iterators/assert.advance.pass.cpp
index f85dae828f9fa..35f7c624213e6 100644
--- a/libcxx/test/libcxx/iterators/assert.advance.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/iterators/assert.next.pass.cpp b/libcxx/test/libcxx/iterators/assert.next.pass.cpp
index 0771539785614..92a22920a0234 100644
--- a/libcxx/test/libcxx/iterators/assert.next.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/iterators/assert.prev.pass.cpp b/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
index 3b92bce4cbd97..19df605518d60 100644
--- a/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
index d1a8cf55f8f7b..2bbf63ca630b8 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.back.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
index 14e3622ec2c6e..d12854dbd5e53 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cback.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
index 22aacd37bbbe4..8a9f3f10c6d01 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cfront.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
index b238fcd4a02fe..b33fe91caa36e 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.cindex.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
index c0b4efba75fcb..5683d257d9e0d 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.front.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
index 33bca86556861..d6fa61ec9d70a 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.access/assert.index.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
index e91f8d646b7dc..96c3ab7e5a8fb 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.erase_iter.null.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
index 8bec8fb815d77..4426cecc8c7dc 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.modifiers/assert.pop_back.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp b/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
index c3b8e682abc8a..61fa310c51487 100644
--- a/libcxx/test/libcxx/strings/string.view/assert.ctor.pointer.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp b/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
index a3f327bc8539e..13ac23d33e509 100644
--- a/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp b/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
index 911fff3ef50dc..a773867802462 100644
--- a/libcxx/test/libcxx/thread/futures/futures.promise/assert.set_exception_at_thread_exit.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
index c389389c10ba7..fa185c5b0a88d 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.dereference.pass.cpp
+++ b/libcxx/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/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
index fde804e987eb6..7ac5dd426e3e2 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/assert.op_arrow.pass.cpp
+++ b/libcxx/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/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h
index 29e8668bef065..30067b4030bf1 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/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 @@ struct DebugInfoMatcher {
   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 @@ struct DeathTest {
     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 @@ struct DeathTest {
     DupFD(GetStdErrWriteFD(), STDERR_FILENO);
 
     GlobalMatcher() = matcher_;
-    std::__libcpp_set_debug_function(&DeathTestDebugHandler);
     f();
     std::exit(RK_DidNotDie);
   }
@@ -242,7 +226,7 @@ struct DeathTest {
     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 @@ struct DeathTest {
   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 @@ inline bool ExpectDeath(const char* stmt, Func&& func) {
 
 #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/libcxx/test/libcxx/debug/check_assertion_test.pass.cpp b/libcxx/test/support/test.support/test_check_assertion.pass.cpp
similarity index 84%
rename from libcxx/test/libcxx/debug/check_assertion_test.pass.cpp
rename to libcxx/test/support/test.support/test_check_assertion.pass.cpp
index ecce86e4fe437..f98bdcb19f5b7 100644
--- a/libcxx/test/libcxx/debug/check_assertion_test.pass.cpp
+++ b/libcxx/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 my_libcpp_assert() {
 }
 
 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/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index c0e5008258f94..2c18aba41af63 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -183,6 +183,14 @@ def getStdFlag(cfg, std):
               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 "


        


More information about the libcxx-commits mailing list