Remove exception throwing debug mode handler support.

Summary:
The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically,
I thought that if a debug violation aborted, we could only test one violation per file. This made
it impossible to test debug mode. Which throwing behavior we could test more!

However, the throwing approach didn't work either, since there are debug violations underneath noexcept
functions. This lead to the introduction of `_NOEXCEPT_DEBUG`, which was only noexcept when debug
mode was off.

Having thought more and having grown wiser, `_NOEXCEPT_DEBUG` was a horrible decision. It was
viral, it didn't cover all the cases it needed to, and it was observable to the user -- at worst
changing the behavior of their program.

  This patch removes the throwing debug handler, and rewrites the debug tests using 'fork-ing' style
  death tests.

Reviewers: mclow.lists, ldionne, thomasanderson

Reviewed By: ldionne

Subscribers: christof, arphaman, libcxx-commits, #libc

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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@356417 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__config b/include/__config
index 587f388..c1770c1 100644
--- a/include/__config
+++ b/include/__config
@@ -850,22 +850,6 @@
 #  define _NOEXCEPT_(x)
 #endif
 
-#if defined(_LIBCPP_DEBUG_USE_EXCEPTIONS)
-#  if !defined(_LIBCPP_DEBUG)
-#    error cannot use _LIBCPP_DEBUG_USE_EXCEPTIONS unless _LIBCPP_DEBUG is defined
-#  endif
-#  ifdef _LIBCPP_HAS_NO_NOEXCEPT
-#    define _NOEXCEPT_DEBUG
-#    define _NOEXCEPT_DEBUG_(x)
-#  else
-#    define _NOEXCEPT_DEBUG noexcept(false)
-#    define _NOEXCEPT_DEBUG_(x) noexcept(false)
-#  endif
-#else
-#  define _NOEXCEPT_DEBUG _NOEXCEPT
-#  define _NOEXCEPT_DEBUG_(x) _NOEXCEPT_(x)
-#endif
-
 #ifdef _LIBCPP_HAS_NO_UNICODE_CHARS
 typedef unsigned short char16_t;
 typedef unsigned int   char32_t;
diff --git a/include/__debug b/include/__debug
index 281cf66..524c5ff 100644
--- a/include/__debug
+++ b/include/__debug
@@ -11,6 +11,7 @@
 #define _LIBCPP_DEBUG_H
 
 #include <__config>
+#include <iosfwd>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -24,7 +25,6 @@
 #   include <cstdlib>
 #   include <cstdio>
 #   include <cstddef>
-#   include <exception>
 #endif
 
 #if _LIBCPP_DEBUG_LEVEL >= 1 && !defined(_LIBCPP_ASSERT)
@@ -49,10 +49,6 @@
 #define _LIBCPP_DEBUG_MODE(...) ((void)0)
 #endif
 
-#if _LIBCPP_DEBUG_LEVEL < 1
-class _LIBCPP_EXCEPTION_ABI __libcpp_debug_exception;
-#endif
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 struct _LIBCPP_TEMPLATE_VIS __libcpp_debug_info {
@@ -62,6 +58,9 @@
   _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 std::string what() const;
+
   const char* __file_;
   int __line_;
   const char* __pred_;
@@ -79,38 +78,11 @@
 _LIBCPP_NORETURN _LIBCPP_FUNC_VIS
 void __libcpp_abort_debug_function(__libcpp_debug_info const&);
 
-/// __libcpp_throw_debug_function - A debug handler that throws
-///   an instance of __libcpp_debug_exception when called.
- _LIBCPP_NORETURN _LIBCPP_FUNC_VIS
-void __libcpp_throw_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);
 
-// Setup the throwing debug handler during dynamic initialization.
-#if _LIBCPP_DEBUG_LEVEL >= 1 && defined(_LIBCPP_DEBUG_USE_EXCEPTIONS)
-# if defined(_LIBCPP_NO_EXCEPTIONS)
-#   error _LIBCPP_DEBUG_USE_EXCEPTIONS cannot be used when exceptions are disabled.
-# endif
-static bool __init_dummy = __libcpp_set_debug_function(__libcpp_throw_debug_function);
-#endif
-
-#if _LIBCPP_DEBUG_LEVEL >= 1 || defined(_LIBCPP_BUILDING_LIBRARY)
-class _LIBCPP_EXCEPTION_ABI __libcpp_debug_exception : public exception {
-public:
-  __libcpp_debug_exception() _NOEXCEPT;
-  explicit __libcpp_debug_exception(__libcpp_debug_info const& __i);
-  __libcpp_debug_exception(__libcpp_debug_exception const&);
-  ~__libcpp_debug_exception() _NOEXCEPT;
-  const char* what() const _NOEXCEPT;
-private:
-  struct __libcpp_debug_exception_imp;
-  __libcpp_debug_exception_imp *__imp_;
-};
-#endif
-
 #if _LIBCPP_DEBUG_LEVEL >= 2 || defined(_LIBCPP_BUILDING_LIBRARY)
 
 struct _LIBCPP_TYPE_VIS __c_node;
diff --git a/include/__hash_table b/include/__hash_table
index 4409d6d..c5a9db1 100644
--- a/include/__hash_table
+++ b/include/__hash_table
@@ -1260,7 +1260,7 @@
 
     void swap(__hash_table& __u)
 #if _LIBCPP_STD_VER <= 11
-        _NOEXCEPT_DEBUG_(
+        _NOEXCEPT_(
             __is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value
             && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value
                   || __is_nothrow_swappable<__pointer_allocator>::value)
@@ -1268,7 +1268,7 @@
                   || __is_nothrow_swappable<__node_allocator>::value)
             );
 #else
-     _NOEXCEPT_DEBUG_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value);
+     _NOEXCEPT_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value);
 #endif
 
     _LIBCPP_INLINE_VISIBILITY
@@ -2807,7 +2807,7 @@
 void
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
 #if _LIBCPP_STD_VER <= 11
-    _NOEXCEPT_DEBUG_(
+    _NOEXCEPT_(
         __is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value
         && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value
               || __is_nothrow_swappable<__pointer_allocator>::value)
@@ -2815,7 +2815,7 @@
               || __is_nothrow_swappable<__node_allocator>::value)
             )
 #else
-  _NOEXCEPT_DEBUG_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value)
+  _NOEXCEPT_(__is_nothrow_swappable<hasher>::value && __is_nothrow_swappable<key_equal>::value)
 #endif
 {
     _LIBCPP_ASSERT(__node_traits::propagate_on_container_swap::value ||
diff --git a/include/iterator b/include/iterator
index 02cbc50..16c1bcb 100644
--- a/include/iterator
+++ b/include/iterator
@@ -1241,50 +1241,50 @@
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 auto
-operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 -> decltype(__x.base() - __y.base());
 #else
 template <class _Iter1, class _Iter2>
 _LIBCPP_INLINE_VISIBILITY
 typename __wrap_iter<_Iter1>::difference_type
-operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 #endif
 
 template <class _Iter>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 __wrap_iter<_Iter>
-operator+(typename __wrap_iter<_Iter>::difference_type, __wrap_iter<_Iter>) _NOEXCEPT_DEBUG;
+operator+(typename __wrap_iter<_Iter>::difference_type, __wrap_iter<_Iter>) _NOEXCEPT;
 
 template <class _Ip, class _Op> _Op _LIBCPP_INLINE_VISIBILITY copy(_Ip, _Ip, _Op);
 template <class _B1, class _B2> _B2 _LIBCPP_INLINE_VISIBILITY copy_backward(_B1, _B1, _B2);
@@ -1328,7 +1328,7 @@
 private:
     iterator_type __i;
 public:
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter() _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter() _NOEXCEPT
 #if _LIBCPP_STD_VER > 11
                 : __i{}
 #endif
@@ -1339,7 +1339,7 @@
     }
     template <class _Up> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
         __wrap_iter(const __wrap_iter<_Up>& __u,
-            typename enable_if<is_convertible<_Up, iterator_type>::value>::type* = 0) _NOEXCEPT_DEBUG
+            typename enable_if<is_convertible<_Up, iterator_type>::value>::type* = 0) _NOEXCEPT
             : __i(__u.base())
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1369,7 +1369,7 @@
         __get_db()->__erase_i(this);
     }
 #endif
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator*() const _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference operator*() const _NOEXCEPT
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
         _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
@@ -1377,7 +1377,7 @@
 #endif
         return *__i;
     }
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG pointer  operator->() const _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG pointer  operator->() const _NOEXCEPT
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
         _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
@@ -1385,7 +1385,7 @@
 #endif
         return (pointer)_VSTD::addressof(*__i);
     }
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
         _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
@@ -1394,10 +1394,10 @@
         ++__i;
         return *this;
     }
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator++(int) _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator++(int) _NOEXCEPT
         {__wrap_iter __tmp(*this); ++(*this); return __tmp;}
 
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator--() _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator--() _NOEXCEPT
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
         _LIBCPP_ASSERT(__get_const_db()->__decrementable(this),
@@ -1406,11 +1406,11 @@
         --__i;
         return *this;
     }
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator--(int) _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator--(int) _NOEXCEPT
         {__wrap_iter __tmp(*this); --(*this); return __tmp;}
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator+ (difference_type __n) const _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator+ (difference_type __n) const _NOEXCEPT
         {__wrap_iter __w(*this); __w += __n; return __w;}
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator+=(difference_type __n) _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator+=(difference_type __n) _NOEXCEPT
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
         _LIBCPP_ASSERT(__get_const_db()->__addable(this, __n),
@@ -1419,11 +1419,11 @@
         __i += __n;
         return *this;
     }
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator- (difference_type __n) const _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter  operator- (difference_type __n) const _NOEXCEPT
         {return *this + (-__n);}
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator-=(difference_type __n) _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator-=(difference_type __n) _NOEXCEPT
         {*this += -__n; return *this;}
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference    operator[](difference_type __n) const _NOEXCEPT_DEBUG
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG reference    operator[](difference_type __n) const _NOEXCEPT
     {
 #if _LIBCPP_DEBUG_LEVEL >= 2
         _LIBCPP_ASSERT(__get_const_db()->__subscriptable(this, __n),
@@ -1432,7 +1432,7 @@
         return __i[__n];
     }
 
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG iterator_type base() const _NOEXCEPT_DEBUG {return __i;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG iterator_type base() const _NOEXCEPT {return __i;}
 
 private:
 #if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1441,7 +1441,7 @@
         __get_db()->__insert_ic(this, __p);
     }
 #else
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(iterator_type __x) _NOEXCEPT_DEBUG : __i(__x) {}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter(iterator_type __x) _NOEXCEPT : __i(__x) {}
 #endif
 
     template <class _Up> friend class __wrap_iter;
@@ -1452,50 +1452,50 @@
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     bool
-    operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator==(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     bool
-    operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator<(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     bool
-    operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator!=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     bool
-    operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator>(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     bool
-    operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator>=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     bool
-    operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator<=(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 
 #ifndef _LIBCPP_CXX03_LANG
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     auto
-    operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+    operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
     -> decltype(__x.base() - __y.base());
 #else
     template <class _Iter1, class _Iter2>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     typename __wrap_iter<_Iter1>::difference_type
-    operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT_DEBUG;
+    operator-(const __wrap_iter<_Iter1>&, const __wrap_iter<_Iter2>&) _NOEXCEPT;
 #endif
 
     template <class _Iter1>
     _LIBCPP_CONSTEXPR_IF_NODEBUG friend
     __wrap_iter<_Iter1>
-    operator+(typename __wrap_iter<_Iter1>::difference_type, __wrap_iter<_Iter1>) _NOEXCEPT_DEBUG;
+    operator+(typename __wrap_iter<_Iter1>::difference_type, __wrap_iter<_Iter1>) _NOEXCEPT;
 
     template <class _Ip, class _Op> friend _Op copy(_Ip, _Ip, _Op);
     template <class _B1, class _B2> friend _B2 copy_backward(_B1, _B1, _B2);
@@ -1526,7 +1526,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
     return __x.base() == __y.base();
 }
@@ -1534,7 +1534,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
 #if _LIBCPP_DEBUG_LEVEL >= 2
     _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
@@ -1546,7 +1546,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
     return !(__x == __y);
 }
@@ -1554,7 +1554,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
     return __y < __x;
 }
@@ -1562,7 +1562,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
     return !(__x < __y);
 }
@@ -1570,7 +1570,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
     return !(__y < __x);
 }
@@ -1578,7 +1578,7 @@
 template <class _Iter1>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
+operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
 {
     return !(__x == __y);
 }
@@ -1586,7 +1586,7 @@
 template <class _Iter1>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
+operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
 {
     return __y < __x;
 }
@@ -1594,7 +1594,7 @@
 template <class _Iter1>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
+operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
 {
     return !(__x < __y);
 }
@@ -1602,7 +1602,7 @@
 template <class _Iter1>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 bool
-operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT_DEBUG
+operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT
 {
     return !(__y < __x);
 }
@@ -1611,7 +1611,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 auto
-operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 -> decltype(__x.base() - __y.base())
 {
 #if _LIBCPP_DEBUG_LEVEL >= 2
@@ -1624,7 +1624,7 @@
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 typename __wrap_iter<_Iter1>::difference_type
-operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT_DEBUG
+operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
 {
 #if _LIBCPP_DEBUG_LEVEL >= 2
     _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y),
@@ -1638,7 +1638,7 @@
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
 __wrap_iter<_Iter>
 operator+(typename __wrap_iter<_Iter>::difference_type __n,
-          __wrap_iter<_Iter> __x) _NOEXCEPT_DEBUG
+          __wrap_iter<_Iter> __x) _NOEXCEPT
 {
     __x += __n;
     return __x;
diff --git a/include/list b/include/list
index 7b59a0e..6e878f4 100644
--- a/include/list
+++ b/include/list
@@ -647,9 +647,9 @@
 
     void swap(__list_imp& __c)
 #if _LIBCPP_STD_VER >= 14
-        _NOEXCEPT_DEBUG;
+        _NOEXCEPT;
 #else
-        _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                     __is_nothrow_swappable<allocator_type>::value);
 #endif
 
@@ -769,9 +769,9 @@
 void
 __list_imp<_Tp, _Alloc>::swap(__list_imp& __c)
 #if _LIBCPP_STD_VER >= 14
-        _NOEXCEPT_DEBUG
+        _NOEXCEPT
 #else
-        _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                     __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
@@ -1038,9 +1038,9 @@
     _LIBCPP_INLINE_VISIBILITY
     void swap(list& __c)
 #if _LIBCPP_STD_VER >= 14
-        _NOEXCEPT_DEBUG
+        _NOEXCEPT
 #else
-        _NOEXCEPT_DEBUG_(!__node_alloc_traits::propagate_on_container_swap::value ||
+        _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value ||
                    __is_nothrow_swappable<__node_allocator>::value)
 #endif
         {base::swap(__c);}
diff --git a/include/string b/include/string
index 611e345..ab6052d 100644
--- a/include/string
+++ b/include/string
@@ -1236,9 +1236,9 @@
     _LIBCPP_INLINE_VISIBILITY
     void swap(basic_string& __str)
 #if _LIBCPP_STD_VER >= 14
-        _NOEXCEPT_DEBUG;
+        _NOEXCEPT;
 #else
-        _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                     __is_nothrow_swappable<allocator_type>::value);
 #endif
 
@@ -3295,9 +3295,9 @@
 void
 basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str)
 #if _LIBCPP_STD_VER >= 14
-        _NOEXCEPT_DEBUG
+        _NOEXCEPT
 #else
-        _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                     __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
diff --git a/include/vector b/include/vector
index 8413d89..e560b08 100644
--- a/include/vector
+++ b/include/vector
@@ -779,9 +779,9 @@
 
     void swap(vector&)
 #if _LIBCPP_STD_VER >= 14
-        _NOEXCEPT_DEBUG;
+        _NOEXCEPT;
 #else
-        _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
+        _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                     __is_nothrow_swappable<allocator_type>::value);
 #endif
 
@@ -2064,9 +2064,9 @@
 void
 vector<_Tp, _Allocator>::swap(vector& __x)
 #if _LIBCPP_STD_VER >= 14
-    _NOEXCEPT_DEBUG
+    _NOEXCEPT
 #else
-    _NOEXCEPT_DEBUG_(!__alloc_traits::propagate_on_container_swap::value ||
+    _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                 __is_nothrow_swappable<allocator_type>::value)
 #endif
 {
diff --git a/lib/abi/CHANGELOG.TXT b/lib/abi/CHANGELOG.TXT
index 8055aba..2e0e8a6 100644
--- a/lib/abi/CHANGELOG.TXT
+++ b/lib/abi/CHANGELOG.TXT
@@ -16,6 +16,47 @@
 Version 9.0
 -----------
 
+* rTBD - Remove exception throwing debug mode handler support.
+
+  The reason libc++ implemented a throwing debug mode handler was for ease of testing. Specifically,
+  I thought that if a debug violation aborted, we could only test one violation per file. This made
+  it impossible to test debug mode. Which throwing behavior we could test more!
+
+  However, the throwing approach didn't work either, since there are debug violations underneath noexcept
+  functions. This lead to the introduction of `_NOEXCEPT_DEBUG`, which was only noexcept when debug
+  mode was off.
+
+  Having thought more and having grown wiser, `_NOEXCEPT_DEBUG` was a horrible decision. It was
+  viral, it didn't cover all the cases it needed to, and it was observable to the user -- at worst
+  changing the behavior of their program.
+
+  This patch removes the throwing debug handler, and rewrites the debug tests using 'fork-ing' style
+  death tests.
+
+  All Platforms (ignoring versioning namespaces)
+  ----------------------------------------------
+  Symbol added: _ZNKSt3__119__libcpp_debug_info4whatEv
+  Symbol removed: _ZNKSt3__124__libcpp_debug_exception4whatEv
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1ERKS0_
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC1Ev
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2ERKS0_
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionC2Ev
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD0Ev
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD1Ev
+  Symbol removed: _ZNSt3__124__libcpp_debug_exceptionD2Ev
+  Symbol removed: _ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE
+  Symbol removed: _ZTINSt3__124__libcpp_debug_exceptionE
+  Symbol removed: _ZTSNSt3__124__libcpp_debug_exceptionE
+  Symbol removed: _ZTVNSt3__124__libcpp_debug_exceptionE
+
+
+    x86_64-apple-apple-darwin
+    -------------------------
+    Symbol added: __ZNSt3__111__libcpp_db10__insert_cEPvPFPNS_8__c_nodeES1_S1_S3_E
+    Symbol removed: __ZNSt3__111__libcpp_db10__insert_cEPv
+
 * r355367 - Fix -fsanitize=vptr badness in <__debug>
 
   This patch fixes a lifetime bug when inserting a new container into the debug database. It is
diff --git a/lib/abi/x86_64-apple-darwin.v1.abilist b/lib/abi/x86_64-apple-darwin.v1.abilist
index e861fca..67c8eb5 100644
--- a/lib/abi/x86_64-apple-darwin.v1.abilist
+++ b/lib/abi/x86_64-apple-darwin.v1.abilist
@@ -219,6 +219,7 @@
 {'is_defined': True, 'name': '__ZNKSt3__117moneypunct_bynameIwLb1EE16do_thousands_sepEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__118__time_get_storageIcE15__do_date_orderEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__118__time_get_storageIwE15__do_date_orderEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNKSt3__119__libcpp_debug_info4whatEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__119__shared_weak_count13__get_deleterERKSt9type_info', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__120__codecvt_utf8_utf16IDiE10do_unshiftER11__mbstate_tPcS4_RS4_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__120__codecvt_utf8_utf16IDiE11do_encodingEv', 'type': 'FUNC'}
@@ -261,7 +262,6 @@
 {'is_defined': True, 'name': '__ZNKSt3__121__basic_string_commonILb1EE20__throw_out_of_rangeEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__123__match_any_but_newlineIcE6__execERNS_7__stateIcEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__123__match_any_but_newlineIwE6__execERNS_7__stateIwEE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNKSt3__124__libcpp_debug_exception4whatEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__15ctypeIcE10do_tolowerEPcPKc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__15ctypeIcE10do_tolowerEc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__15ctypeIcE10do_toupperEPcPKc', 'type': 'FUNC'}
@@ -1201,15 +1201,6 @@
 {'is_defined': True, 'name': '__ZNSt3__121recursive_timed_mutexD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__121undeclare_no_pointersEPcm', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_debug_functionE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC1ERKS0_', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC1Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC2ERKS0_', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionC2Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionD1Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__124__libcpp_debug_exceptionD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', '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'}
@@ -1228,7 +1219,6 @@
 {'is_defined': True, 'name': '__ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIyyEEPyEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__127__libcpp_set_debug_functionEPFvRKNS_19__libcpp_debug_infoEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__129__libcpp_abort_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__14cerrE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__14clogE', 'size': 0, 'type': 'OBJECT'}
@@ -1654,7 +1644,6 @@
 {'is_defined': True, 'name': '__ZTINSt3__120__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__120__time_get_c_storageIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__120__time_get_c_storageIwEE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZTINSt3__124__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__15ctypeIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__15ctypeIwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__16locale5facetE', 'size': 0, 'type': 'OBJECT'}
@@ -2182,7 +2171,6 @@
 {'is_defined': True, 'name': '__ZTVNSt3__120__codecvt_utf8_utf16IDiEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__120__codecvt_utf8_utf16IDsEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__120__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZTVNSt3__124__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__15ctypeIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__15ctypeIwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__16locale5facetE', 'size': 0, 'type': 'OBJECT'}
diff --git a/lib/abi/x86_64-apple-darwin.v2.abilist b/lib/abi/x86_64-apple-darwin.v2.abilist
index 90ea1eb..6de64ef 100644
--- a/lib/abi/x86_64-apple-darwin.v2.abilist
+++ b/lib/abi/x86_64-apple-darwin.v2.abilist
@@ -218,6 +218,7 @@
 {'is_defined': True, 'name': '__ZNKSt3__217moneypunct_bynameIwLb1EE16do_thousands_sepEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__218__time_get_storageIcE15__do_date_orderEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__218__time_get_storageIwE15__do_date_orderEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNKSt3__219__libcpp_debug_info4whatEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__219__shared_weak_count13__get_deleterERKSt9type_info', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__220__codecvt_utf8_utf16IDiE10do_unshiftER11__mbstate_tPcS4_RS4_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__220__codecvt_utf8_utf16IDiE11do_encodingEv', 'type': 'FUNC'}
@@ -260,7 +261,6 @@
 {'is_defined': True, 'name': '__ZNKSt3__221__basic_string_commonILb1EE20__throw_out_of_rangeEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__223__match_any_but_newlineIcE6__execERNS_7__stateIcEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__223__match_any_but_newlineIwE6__execERNS_7__stateIwEE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNKSt3__224__libcpp_debug_exception4whatEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__25ctypeIcE10do_tolowerEPcPKc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__25ctypeIcE10do_tolowerEc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNKSt3__25ctypeIcE10do_toupperEPcPKc', 'type': 'FUNC'}
@@ -1123,15 +1123,6 @@
 {'is_defined': True, 'name': '__ZNSt3__221recursive_timed_mutexD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__221undeclare_no_pointersEPcm', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__223__libcpp_debug_functionE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC1ERKS0_', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC1Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC2ERKS0_', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionC2Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionD1Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__224__libcpp_debug_exceptionD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__225notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__227__insertion_sort_incompleteIRNS_6__lessIaaEEPaEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__227__insertion_sort_incompleteIRNS_6__lessIccEEPcEEbT0_S5_T_', 'type': 'FUNC'}
@@ -1150,7 +1141,6 @@
 {'is_defined': True, 'name': '__ZNSt3__227__insertion_sort_incompleteIRNS_6__lessIyyEEPyEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__227__libcpp_set_debug_functionEPFvRKNS_19__libcpp_debug_infoEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__229__libcpp_abort_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '__ZNSt3__229__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__23cinE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__24cerrE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZNSt3__24clogE', 'size': 0, 'type': 'OBJECT'}
@@ -1577,7 +1567,6 @@
 {'is_defined': True, 'name': '__ZTINSt3__220__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__220__time_get_c_storageIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__220__time_get_c_storageIwEE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZTINSt3__224__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__25ctypeIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__25ctypeIwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__26locale5facetE', 'size': 0, 'type': 'OBJECT'}
@@ -1867,7 +1856,6 @@
 {'is_defined': True, 'name': '__ZTSNSt3__220__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__220__time_get_c_storageIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__220__time_get_c_storageIwEE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZTSNSt3__224__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__25ctypeIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__25ctypeIwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__26locale5facetE', 'size': 0, 'type': 'OBJECT'}
@@ -2143,7 +2131,6 @@
 {'is_defined': True, 'name': '__ZTVNSt3__220__codecvt_utf8_utf16IDiEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__220__codecvt_utf8_utf16IDsEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__220__codecvt_utf8_utf16IwEE', 'size': 0, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '__ZTVNSt3__224__libcpp_debug_exceptionE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__25ctypeIcEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__25ctypeIwEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__26locale5facetE', 'size': 0, 'type': 'OBJECT'}
diff --git a/lib/abi/x86_64-unknown-linux-gnu.v1.abilist b/lib/abi/x86_64-unknown-linux-gnu.v1.abilist
index 3051d4c..7db6de0 100644
--- a/lib/abi/x86_64-unknown-linux-gnu.v1.abilist
+++ b/lib/abi/x86_64-unknown-linux-gnu.v1.abilist
@@ -211,6 +211,7 @@
 {'is_defined': True, 'name': '_ZNKSt3__117moneypunct_bynameIwLb1EE16do_thousands_sepEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__118__time_get_storageIcE15__do_date_orderEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__118__time_get_storageIwE15__do_date_orderEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt3__119__libcpp_debug_info4whatEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__119__shared_weak_count13__get_deleterERKSt9type_info', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__120__codecvt_utf8_utf16IDiE10do_unshiftER11__mbstate_tPcS4_RS4_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__120__codecvt_utf8_utf16IDiE11do_encodingEv', 'type': 'FUNC'}
@@ -253,7 +254,6 @@
 {'is_defined': True, 'name': '_ZNKSt3__121__basic_string_commonILb1EE20__throw_out_of_rangeEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__123__match_any_but_newlineIcE6__execERNS_7__stateIcEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__123__match_any_but_newlineIwE6__execERNS_7__stateIwEE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNKSt3__124__libcpp_debug_exception4whatEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__15ctypeIcE10do_tolowerEPcPKc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__15ctypeIcE10do_tolowerEc', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNKSt3__15ctypeIcE10do_toupperEPcPKc', 'type': 'FUNC'}
@@ -1114,15 +1114,6 @@
 {'is_defined': True, 'name': '_ZNSt3__121recursive_timed_mutexD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__121undeclare_no_pointersEPcm', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_debug_functionE', 'size': 8, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC1ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC1ERKS0_', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC1Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC2ERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC2ERKS0_', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionC2Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionD1Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__124__libcpp_debug_exceptionD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', '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'}
@@ -1141,7 +1132,6 @@
 {'is_defined': True, 'name': '_ZNSt3__127__insertion_sort_incompleteIRNS_6__lessIyyEEPyEEbT0_S5_T_', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__127__libcpp_set_debug_functionEPFvRKNS_19__libcpp_debug_infoEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__129__libcpp_abort_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZNSt3__129__libcpp_throw_debug_functionERKNS_19__libcpp_debug_infoE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__14cerrE', 'size': 160, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZNSt3__14clogE', 'size': 160, 'type': 'OBJECT'}
@@ -1524,7 +1514,6 @@
 {'is_defined': True, 'name': '_ZTINSt3__120__codecvt_utf8_utf16IwEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__120__time_get_c_storageIcEE', 'size': 16, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__120__time_get_c_storageIwEE', 'size': 16, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZTINSt3__124__libcpp_debug_exceptionE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__15ctypeIcEE', 'size': 56, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__15ctypeIwEE', 'size': 56, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__16locale5facetE', 'size': 24, 'type': 'OBJECT'}
@@ -1650,7 +1639,6 @@
 {'is_defined': True, 'name': '_ZTSNSt3__120__codecvt_utf8_utf16IwEE', 'size': 34, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__120__time_get_c_storageIcEE', 'size': 34, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__120__time_get_c_storageIwEE', 'size': 34, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZTSNSt3__124__libcpp_debug_exceptionE', 'size': 35, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__15ctypeIcEE', 'size': 18, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__15ctypeIwEE', 'size': 18, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__16locale5facetE', 'size': 22, 'type': 'OBJECT'}
@@ -1762,7 +1750,6 @@
 {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDiEE', 'size': 96, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IDsEE', 'size': 96, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__120__codecvt_utf8_utf16IwEE', 'size': 96, 'type': 'OBJECT'}
-{'is_defined': True, 'name': '_ZTVNSt3__124__libcpp_debug_exceptionE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIcEE', 'size': 104, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__15ctypeIwEE', 'size': 136, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__16locale5facetE', 'size': 40, 'type': 'OBJECT'}
diff --git a/src/debug.cpp b/src/debug.cpp
index 28a1f70..0f75d8c 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -17,14 +17,18 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-static std::string make_what_str(__libcpp_debug_info const& info) {
-  string msg = info.__file_;
-  msg += ":" + to_string(info.__line_) + ": _LIBCPP_ASSERT '";
-  msg += info.__pred_;
+std::string __libcpp_debug_info::what() const {
+  string msg = __file_;
+  msg += ":" + to_string(__line_) + ": _LIBCPP_ASSERT '";
+  msg += __pred_;
   msg += "' failed. ";
-  msg += info.__msg_;
+  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();
+}
 
 _LIBCPP_SAFE_STATIC __libcpp_debug_function_type
     __libcpp_debug_function = __libcpp_abort_debug_function;
@@ -34,51 +38,6 @@
   return true;
 }
 
-_LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) {
-  std::fprintf(stderr, "%s\n", make_what_str(info).c_str());
-  std::abort();
-}
-
-_LIBCPP_NORETURN void __libcpp_throw_debug_function(__libcpp_debug_info const& info) {
-#ifndef _LIBCPP_NO_EXCEPTIONS
-  throw __libcpp_debug_exception(info);
-#else
-  __libcpp_abort_debug_function(info);
-#endif
-}
-
-struct __libcpp_debug_exception::__libcpp_debug_exception_imp {
-  __libcpp_debug_info __info_;
-  std::string __what_str_;
-};
-
-__libcpp_debug_exception::__libcpp_debug_exception() _NOEXCEPT
-    : __imp_(nullptr) {
-}
-
-__libcpp_debug_exception::__libcpp_debug_exception(
-    __libcpp_debug_info const& info) : __imp_(new __libcpp_debug_exception_imp)
-{
-  __imp_->__info_ = info;
-  __imp_->__what_str_ = make_what_str(info);
-}
-__libcpp_debug_exception::__libcpp_debug_exception(
-    __libcpp_debug_exception const& other) : __imp_(nullptr) {
-  if (other.__imp_)
-    __imp_ = new __libcpp_debug_exception_imp(*other.__imp_);
-}
-
-__libcpp_debug_exception::~__libcpp_debug_exception() _NOEXCEPT {
-  if (__imp_)
-    delete __imp_;
-}
-
-const char* __libcpp_debug_exception::what() const _NOEXCEPT {
-  if (__imp_)
-    return __imp_->__what_str_.c_str();
-  return "__libcpp_debug_exception";
-}
-
 _LIBCPP_FUNC_VIS
 __libcpp_db*
 __get_db()
diff --git a/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp b/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp
index 3c31911..b81b257 100644
--- a/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp
+++ b/test/libcxx/containers/sequences/array/array.zero/db_back.pass.cpp
@@ -5,29 +5,18 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++98, c++03
 
-// UNSUPPORTED: libcpp-no-exceptions
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
 
-// test array<T, 0>::front() throws a debug exception.
+// test array<T, 0>::front() raises a debug error.
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include <array>
-
-template <class Array>
-inline bool CheckDebugThrows(Array& Arr) {
-  try {
-    Arr.back();
-  } catch (std::__libcpp_debug_exception const&) {
-    return true;
-  }
-  return false;
-}
+#include "debug_mode_helper.h"
 
 int main(int, char**)
 {
@@ -35,15 +24,15 @@
     typedef std::array<int, 0> C;
     C c = {};
     C const& cc = c;
-    assert(CheckDebugThrows(c));
-    assert(CheckDebugThrows(cc));
+    EXPECT_DEATH( c.back() );
+    EXPECT_DEATH( cc.back() );
   }
   {
     typedef std::array<const int, 0> C;
     C c = {{}};
     C const& cc = c;
-    assert(CheckDebugThrows(c));
-    assert(CheckDebugThrows(cc));
+    EXPECT_DEATH( c.back() );
+    EXPECT_DEATH( cc.back() );
   }
 
   return 0;
diff --git a/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp b/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp
index 9f6f09f..ec7ebbf 100644
--- a/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp
+++ b/test/libcxx/containers/sequences/array/array.zero/db_front.pass.cpp
@@ -5,29 +5,18 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++98, c++03
 
-// UNSUPPORTED: libcpp-no-exceptions
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
 
-// test array<T, 0>::front() throws a debug exception.
+// test array<T, 0>::front() raises a debug error.
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include <array>
-
-template <class Array>
-inline bool CheckDebugThrows(Array& Arr) {
-  try {
-    Arr.front();
-  } catch (std::__libcpp_debug_exception const&) {
-    return true;
-  }
-  return false;
-}
+#include "debug_mode_helper.h"
 
 int main(int, char**)
 {
@@ -35,15 +24,15 @@
     typedef std::array<int, 0> C;
     C c = {};
     C const& cc = c;
-    assert(CheckDebugThrows(c));
-    assert(CheckDebugThrows(cc));
+    EXPECT_DEATH(c.front());
+    EXPECT_DEATH(cc.front());
   }
   {
     typedef std::array<const int, 0> C;
     C c = {{}};
     C const& cc = c;
-    assert(CheckDebugThrows(c));
-    assert(CheckDebugThrows(cc));
+    EXPECT_DEATH(c.front());
+    EXPECT_DEATH(cc.front());
   }
 
   return 0;
diff --git a/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp b/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp
index 56fc326..722dad2 100644
--- a/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp
+++ b/test/libcxx/containers/sequences/array/array.zero/db_indexing.pass.cpp
@@ -5,29 +5,18 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-// XFAIL:*
-// UNSUPPORTED: libcpp-no-exceptions
+// UNSUPPORTED: c++98, c++03
+
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
 
-// test array<T, 0>::operator[] throws a debug exception.
+// test array<T, 0>::operator[] raises a debug error.
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include <array>
-
-template <class Array>
-inline bool CheckDebugThrows(Array& Arr, size_t Index) {
-  try {
-    Arr[Index];
-  } catch (std::__libcpp_debug_exception const&) {
-    return true;
-  }
-  return false;
-}
+#include "debug_mode_helper.h"
 
 int main(int, char**)
 {
@@ -35,19 +24,19 @@
     typedef std::array<int, 0> C;
     C c = {};
     C const& cc = c;
-    assert(CheckDebugThrows(c, 0));
-    assert(CheckDebugThrows(c, 1));
-    assert(CheckDebugThrows(cc, 0));
-    assert(CheckDebugThrows(cc, 1));
+    EXPECT_DEATH( c[0] );
+    EXPECT_DEATH( c[1] );
+    EXPECT_DEATH( cc[0] );
+    EXPECT_DEATH( cc[1] );
   }
   {
     typedef std::array<const int, 0> C;
     C c = {{}};
     C const& cc = c;
-    assert(CheckDebugThrows(c, 0));
-    assert(CheckDebugThrows(c, 1));
-    assert(CheckDebugThrows(cc, 0));
-    assert(CheckDebugThrows(cc, 1));
+    EXPECT_DEATH( c[0] );
+    EXPECT_DEATH( c[1] );
+    EXPECT_DEATH( cc[0] );
+    EXPECT_DEATH( cc[1] );
   }
 
   return 0;
diff --git a/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp b/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp
index d6c2315..056d79c 100644
--- a/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp
+++ b/test/libcxx/debug/containers/db_associative_container_tests.pass.cpp
@@ -7,9 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++98, c++03, c++11, c++14
-// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr
+// UNSUPPORTED: libcpp-no-if-constexpr
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
@@ -17,12 +16,12 @@
 // test container debugging
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 #include <map>
 #include <set>
 #include <utility>
 #include <cassert>
+#include "container_debug_tests.hpp"
 #include "debug_mode_helper.h"
 
 using namespace IteratorDebugChecks;
@@ -40,11 +39,6 @@
 public:
   static void run() {
     Base::run();
-    try {
-     // FIXME Add tests
-    } catch (...) {
-      assert(false && "uncaught debug exception");
-    }
   }
 
 private:
diff --git a/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp b/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp
index d34c864..c2d1cd4 100644
--- a/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp
+++ b/test/libcxx/debug/containers/db_sequence_container_iterators.pass.cpp
@@ -6,11 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// XFAIL: *
 // UNSUPPORTED: c++98, c++03, c++11, c++14
-// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr
+// UNSUPPORTED: libcpp-no-if-constexpr
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
@@ -18,11 +16,12 @@
 // test container debugging
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
+
 #include <forward_list>
 #include <list>
 #include <vector>
 #include <deque>
+#include "container_debug_tests.hpp"
 #include "debug_mode_helper.h"
 
 using namespace IteratorDebugChecks;
@@ -40,11 +39,10 @@
 public:
   static void run() {
     Base::run();
-    try {
-      SanityTest();
-      FrontOnEmptyContainer();
+    SanityTest();
+    FrontOnEmptyContainer();
 
-      if constexpr (CT != CT_ForwardList) {
+    if constexpr(CT != CT_ForwardList) {
         AssignInvalidates();
         BackOnEmptyContainer();
         InsertIterValue();
@@ -52,24 +50,22 @@
         InsertIterIterIter();
         EmplaceIterValue();
         EraseIterIter();
-      } else {
-        SpliceFirstElemAfter();
       }
-      if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
-        PopBack();
-      }
-      if constexpr (CT == CT_List || CT == CT_Deque) {
-        PopFront(); // FIXME: Run with forward list as well
-      }
-      if constexpr (CT == CT_List || CT == CT_ForwardList) {
-        RemoveFirstElem();
-      }
-      if constexpr (CT == CT_List) {
-        SpliceFirstElem();
-        SpliceSameContainer();
-      }
-    } catch (...) {
-      assert(false && "uncaught debug exception");
+    else {
+      SpliceFirstElemAfter();
+    }
+    if constexpr (CT == CT_Vector || CT == CT_Deque || CT == CT_List) {
+      PopBack();
+    }
+    if constexpr (CT == CT_List || CT == CT_Deque) {
+      PopFront(); // FIXME: Run with forward list as well
+    }
+    if constexpr (CT == CT_List || CT == CT_ForwardList) {
+      RemoveFirstElem();
+    }
+    if constexpr (CT == CT_List) {
+      SpliceFirstElem();
+      SpliceSameContainer();
     }
   }
 
@@ -144,9 +140,9 @@
       it3 = C.end();
     };
     auto check = [&]() {
-      CHECK_DEBUG_THROWS( C.erase(it1) );
-      CHECK_DEBUG_THROWS( C.erase(it2) );
-      CHECK_DEBUG_THROWS( C.erase(it3, C.end()) );
+      EXPECT_DEATH( C.erase(it1) );
+      EXPECT_DEATH( C.erase(it2) );
+      EXPECT_DEATH( C.erase(it3, C.end()) );
     };
     reset();
     C.assign(2, makeValueType(4));
@@ -173,8 +169,8 @@
     (void)C.back();
     (void)CC.back();
     C.clear();
-    CHECK_DEBUG_THROWS( C.back() );
-    CHECK_DEBUG_THROWS( CC.back() );
+    EXPECT_DEATH( C.back() );
+    EXPECT_DEATH( CC.back() );
   }
 
   static void FrontOnEmptyContainer() {
@@ -184,8 +180,8 @@
     (void)C.front();
     (void)CC.front();
     C.clear();
-    CHECK_DEBUG_THROWS( C.front() );
-    CHECK_DEBUG_THROWS( CC.front() );
+    EXPECT_DEATH( C.front() );
+    EXPECT_DEATH( CC.front() );
   }
 
   static void EraseIterIter() {
@@ -198,15 +194,15 @@
     iterator it1_back = --C1.end();
     assert(it1_next != it1_back);
     if (CT == CT_Vector) {
-      CHECK_DEBUG_THROWS( C1.erase(it1_next, it1) ); // bad range
+      EXPECT_DEATH( C1.erase(it1_next, it1) ); // bad range
     }
     C1.erase(it1, it1_after_next);
-    CHECK_DEBUG_THROWS( C1.erase(it1) );
-    CHECK_DEBUG_THROWS( C1.erase(it1_next) );
+    EXPECT_DEATH( C1.erase(it1) );
+    EXPECT_DEATH( C1.erase(it1_next) );
     if (CT == CT_List) {
       C1.erase(it1_back);
     } else {
-      CHECK_DEBUG_THROWS( C1.erase(it1_back) );
+      EXPECT_DEATH( C1.erase(it1_back) );
     }
   }
 
@@ -216,10 +212,10 @@
     iterator it1 = C1.end();
     --it1;
     C1.pop_back();
-    CHECK_DEBUG_THROWS( C1.erase(it1) );
+    EXPECT_DEATH( C1.erase(it1) );
     C1.erase(C1.begin());
     assert(C1.size() == 0);
-    CHECK_DEBUG_THROWS( C1.pop_back() );
+    EXPECT_DEATH( C1.pop_back() );
   }
 
   static void PopFront() {
@@ -227,10 +223,10 @@
     Container C1 = makeContainer(2);
     iterator it1 = C1.begin();
     C1.pop_front();
-    CHECK_DEBUG_THROWS( C1.erase(it1) );
+    EXPECT_DEATH( C1.erase(it1) );
     C1.erase(C1.begin());
     assert(C1.size() == 0);
-    CHECK_DEBUG_THROWS( C1.pop_front() );
+    EXPECT_DEATH( C1.pop_front() );
   }
 
   static void InsertIterValue() {
@@ -242,8 +238,8 @@
     Container C2 = C1;
     const value_type value = makeValueType(3);
     value_type rvalue = makeValueType(3);
-    CHECK_DEBUG_THROWS( C2.insert(it1, value) ); // wrong container
-    CHECK_DEBUG_THROWS( C2.insert(it1, std::move(rvalue)) ); // wrong container
+    EXPECT_DEATH( C2.insert(it1, value) ); // wrong container
+    EXPECT_DEATH( C2.insert(it1, std::move(rvalue)) ); // wrong container
     C1.insert(it1_next, value);
     if  (CT == CT_List) {
       C1.insert(it1_next, value);
@@ -251,10 +247,10 @@
       C1.insert(it1_next, std::move(rvalue));
       C1.insert(it1, std::move(rvalue));
     } else {
-      CHECK_DEBUG_THROWS( C1.insert(it1_next, value) ); // invalidated iterator
-      CHECK_DEBUG_THROWS( C1.insert(it1, value) ); // invalidated iterator
-      CHECK_DEBUG_THROWS( C1.insert(it1_next, std::move(rvalue)) ); // invalidated iterator
-      CHECK_DEBUG_THROWS( C1.insert(it1, std::move(rvalue)) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1_next, value) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1, value) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1_next, std::move(rvalue)) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1, std::move(rvalue)) ); // invalidated iterator
     }
   }
 
@@ -266,15 +262,15 @@
     ++it1_next;
     Container C2 = C1;
     const value_type value = makeValueType(3);
-    CHECK_DEBUG_THROWS( C2.emplace(it1, value) ); // wrong container
-    CHECK_DEBUG_THROWS( C2.emplace(it1, makeValueType(4)) ); // wrong container
+    EXPECT_DEATH( C2.emplace(it1, value) ); // wrong container
+    EXPECT_DEATH( C2.emplace(it1, makeValueType(4)) ); // wrong container
     C1.emplace(it1_next, value);
     if  (CT == CT_List) {
       C1.emplace(it1_next, value);
       C1.emplace(it1, value);
     } else {
-      CHECK_DEBUG_THROWS( C1.emplace(it1_next, value) ); // invalidated iterator
-      CHECK_DEBUG_THROWS( C1.emplace(it1, value) ); // invalidated iterator
+      EXPECT_DEATH( C1.emplace(it1_next, value) ); // invalidated iterator
+      EXPECT_DEATH( C1.emplace(it1, value) ); // invalidated iterator
     }
   }
 
@@ -286,14 +282,14 @@
     ++it1_next;
     Container C2 = C1;
     const value_type value = makeValueType(3);
-    CHECK_DEBUG_THROWS( C2.insert(it1, 1, value) ); // wrong container
+    EXPECT_DEATH( C2.insert(it1, 1, value) ); // wrong container
     C1.insert(it1_next, 2, value);
     if  (CT == CT_List) {
       C1.insert(it1_next, 3, value);
       C1.insert(it1, 1, value);
     } else {
-      CHECK_DEBUG_THROWS( C1.insert(it1_next, 1, value) ); // invalidated iterator
-      CHECK_DEBUG_THROWS( C1.insert(it1, 1, value) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1_next, 1, value) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1, 1, value) ); // invalidated iterator
     }
   }
 
@@ -309,14 +305,14 @@
         makeValueType(2),
         makeValueType(3)
     };
-    CHECK_DEBUG_THROWS( C2.insert(it1, V.begin(), V.end()) ); // wrong container
+    EXPECT_DEATH( C2.insert(it1, V.begin(), V.end()) ); // wrong container
     C1.insert(it1_next, V.begin(), V.end());
     if  (CT == CT_List) {
       C1.insert(it1_next, V.begin(), V.end());
       C1.insert(it1, V.begin(), V.end());
     } else {
-      CHECK_DEBUG_THROWS( C1.insert(it1_next, V.begin(), V.end()) ); // invalidated iterator
-      CHECK_DEBUG_THROWS( C1.insert(it1, V.begin(), V.end()) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1_next, V.begin(), V.end()) ); // invalidated iterator
+      EXPECT_DEATH( C1.insert(it1, V.begin(), V.end()) ); // invalidated iterator
     }
   }
 };
diff --git a/test/libcxx/debug/containers/db_string.pass.cpp b/test/libcxx/debug/containers/db_string.pass.cpp
index b2812fc..0fb8af2 100644
--- a/test/libcxx/debug/containers/db_string.pass.cpp
+++ b/test/libcxx/debug/containers/db_string.pass.cpp
@@ -7,9 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++98, c++03, c++11, c++14
-// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr
+// UNSUPPORTED: libcpp-no-if-constexpr
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
@@ -17,11 +16,11 @@
 // test container debugging
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include <string>
 #include <vector>
 
 #include "test_macros.h"
+#include "container_debug_tests.hpp"
 #include "debug_mode_helper.h"
 
 using namespace IteratorDebugChecks;
@@ -43,14 +42,11 @@
   static void run() {
     Base::run_iterator_tests();
     Base::run_allocator_aware_tests();
-    try {
-      for (int N : {3, 128}) {
-        FrontOnEmptyContainer(N);
-        BackOnEmptyContainer(N);
-        PopBack(N);
-      }
-    } catch (...) {
-      assert(false && "uncaught debug exception");
+
+    for (int N : {3, 128}) {
+      FrontOnEmptyContainer(N);
+      BackOnEmptyContainer(N);
+      PopBack(N);
     }
   }
 
@@ -63,10 +59,10 @@
     (void)C.back();
     (void)CC.back();
     C.pop_back();
-    CHECK_DEBUG_THROWS( C.erase(it) );
+    EXPECT_DEATH( C.erase(it) );
     C.clear();
-    CHECK_DEBUG_THROWS( C.back() );
-    CHECK_DEBUG_THROWS( CC.back() );
+    EXPECT_DEATH( C.back() );
+    EXPECT_DEATH( CC.back() );
   }
 
   static void FrontOnEmptyContainer(int N) {
@@ -76,8 +72,8 @@
     (void)C.front();
     (void)CC.front();
     C.clear();
-    CHECK_DEBUG_THROWS( C.front() );
-    CHECK_DEBUG_THROWS( CC.front() );
+    EXPECT_DEATH( C.front() );
+    EXPECT_DEATH( CC.front() );
   }
 
   static void PopBack(int N) {
@@ -86,10 +82,10 @@
     iterator it1 = C1.end();
     --it1;
     C1.pop_back();
-    CHECK_DEBUG_THROWS( C1.erase(it1) );
+    EXPECT_DEATH( C1.erase(it1) );
     C1.erase(C1.begin(), C1.end());
     assert(C1.size() == 0);
-    CHECK_DEBUG_THROWS( C1.pop_back() );
+    EXPECT_DEATH_MATCHES(DebugInfoMatcher("string::pop_back(): string is already empty"), C1.pop_back() );
   }
 };
 
diff --git a/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp b/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp
index 8a6da08..3b20e4c 100644
--- a/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp
+++ b/test/libcxx/debug/containers/db_unord_container_tests.pass.cpp
@@ -7,9 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++98, c++03, c++11, c++14
-// UNSUPPORTED: libcpp-no-exceptions, libcpp-no-if-constexpr
+// UNSUPPORTED: libcpp-no-if-constexpr
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
@@ -17,11 +16,11 @@
 // test container debugging
 
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
 #include <cassert>
+#include "container_debug_tests.hpp"
 #include "debug_mode_helper.h"
 
 using namespace IteratorDebugChecks;
@@ -39,11 +38,6 @@
 public:
   static void run() {
     Base::run();
-    try {
-     // FIXME
-    } catch (...) {
-      assert(false && "uncaught debug exception");
-    }
   }
 private:
 
diff --git a/test/libcxx/debug/debug_helper_test.pass.cpp b/test/libcxx/debug/debug_helper_test.pass.cpp
new file mode 100644
index 0000000..12268e7
--- /dev/null
+++ b/test/libcxx/debug/debug_helper_test.pass.cpp
@@ -0,0 +1,70 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// Can't test the system lib because this test enables debug mode
+// UNSUPPORTED: with_system_cxx_lib
+
+// MODULES_DEFINES: _LIBCPP_DEBUG=1
+
+#define _LIBCPP_DEBUG 1
+
+#include <__debug>
+#include "debug_mode_helper.h"
+
+
+template <class Func>
+inline bool TestDeathTest(const char* stmt, Func&& func, DeathTest::ResultKind ExpectResult, DebugInfoMatcher Matcher = AnyMatcher) {
+  DeathTest DT(Matcher);
+  DeathTest::ResultKind RK = DT.Run(func);
+  auto OnFailure = [&](std::string msg) {
+    std::cerr << "EXPECT_DEATH( " << stmt << " ) failed! (" << msg << ")\n\n";
+    if (!DT.getChildStdErr().empty()) {
+      std::cerr << "---------- standard err ----------\n";
+      std::cerr << DT.getChildStdErr() << "\n";
+    }
+    if (!DT.getChildStdOut().empty()) {
+      std::cerr << "---------- standard out ----------\n";
+      std::cerr << DT.getChildStdOut() << "\n";
+    }
+    return false;
+  };
+  if (RK != ExpectResult)
+    return OnFailure(std::string("expected result did not occur: expected ") + DeathTest::ResultKindToString(ExpectResult) + " got: " + DeathTest::ResultKindToString(RK));
+  return true;
+}
+#define TEST_DEATH_TEST(RK, ...) assert((TestDeathTest(#__VA_ARGS__, [&]() { __VA_ARGS__; }, RK, AnyMatcher )))
+
+#define TEST_DEATH_TEST_MATCHES(RK, Matcher, ...) assert((TestDeathTest(#__VA_ARGS__, [&]() { __VA_ARGS__; }, RK, Matcher)))
+
+void my_libcpp_assert() {
+  _LIBCPP_ASSERT(false, "other");
+}
+
+void test_no_match_found() {
+  DebugInfoMatcher ExpectMatch("my message");
+  TEST_DEATH_TEST_MATCHES(DeathTest::RK_MatchFailure, ExpectMatch, my_libcpp_assert());
+}
+
+void test_did_not_die() {
+  TEST_DEATH_TEST(DeathTest::RK_DidNotDie, ((void)0));
+}
+
+void test_unknown() {
+  TEST_DEATH_TEST(DeathTest::RK_Unknown, std::exit(13));
+}
+
+int main(int, char**)
+{
+  test_no_match_found();
+  test_did_not_die();
+  test_unknown();
+  return 0;
+}
diff --git a/test/libcxx/debug/debug_throw_register.pass.cpp b/test/libcxx/debug/debug_register.pass.cpp
similarity index 66%
rename from test/libcxx/debug/debug_throw_register.pass.cpp
rename to test/libcxx/debug/debug_register.pass.cpp
index 23b4091..1d147af 100644
--- a/test/libcxx/debug/debug_throw_register.pass.cpp
+++ b/test/libcxx/debug/debug_register.pass.cpp
@@ -7,31 +7,27 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: libcpp-no-exceptions
 // MODULES_DEFINES: _LIBCPP_DEBUG=1
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 // Can't test the system lib because this test enables debug mode
 // UNSUPPORTED: with_system_cxx_lib
 
-// Test that defining _LIBCPP_DEBUG_USE_EXCEPTIONS causes _LIBCPP_ASSERT
-// to throw on failure.
-
 #define _LIBCPP_DEBUG 1
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 
 #include <cstdlib>
-#include <exception>
+#include <string>
 #include <type_traits>
 #include <__debug>
 #include <cassert>
 
+void my_debug_function(std::__libcpp_debug_info const& info) {
+  assert(info.__msg_ == std::string("foo"));
+  std::exit(0);
+}
+
 int main(int, char**)
 {
-  try {
-    _LIBCPP_ASSERT(false, "foo");
-    assert(false);
-  } catch (...) {}
-
-  return 0;
+  std::__libcpp_set_debug_function(&my_debug_function);
+  _LIBCPP_ASSERT(false, "foo");
+  return 1;
 }
diff --git a/test/libcxx/debug/debug_throw.pass.cpp b/test/libcxx/debug/debug_throw.pass.cpp
deleted file mode 100644
index 53e8538..0000000
--- a/test/libcxx/debug/debug_throw.pass.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// 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: libcpp-no-exceptions
-// MODULES_DEFINES: _LIBCPP_DEBUG=0
-
-// Can't test the system lib because this test enables debug mode
-// UNSUPPORTED: with_system_cxx_lib
-
-// Test that the default debug handler can be overridden and test the
-// throwing debug handler.
-
-#define _LIBCPP_DEBUG 0
-
-#include <cstdlib>
-#include <exception>
-#include <type_traits>
-#include <__debug>
-
-int main(int, char**)
-{
-  {
-    std::__libcpp_debug_function = std::__libcpp_throw_debug_function;
-    try {
-      _LIBCPP_ASSERT(false, "foo");
-    } catch (std::__libcpp_debug_exception const&) {}
-  }
-  {
-    // test that the libc++ exception type derives from std::exception
-    static_assert((std::is_base_of<std::exception,
-                                  std::__libcpp_debug_exception
-                  >::value), "must be an exception");
-  }
-
-  return 0;
-}
diff --git a/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp b/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp
index 396e4ff..01f07ee 100644
--- a/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp
+++ b/test/libcxx/input.output/filesystems/class.path/path.itr/iterator_db.pass.cpp
@@ -7,9 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++98, c++03
-// UNSUPPORTED: libcpp-no-exceptions
 
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 // MODULES_DEFINES: _LIBCPP_DEBUG=0
 
 // <filesystem>
@@ -17,7 +15,6 @@
 // class path
 
 #define _LIBCPP_DEBUG 0
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include "filesystem_include.hpp"
 #include <iterator>
 #include <type_traits>
@@ -25,51 +22,32 @@
 
 #include "test_macros.h"
 #include "filesystem_test_helper.hpp"
+#include "debug_mode_helper.h"
 
 int main(int, char**) {
   using namespace fs;
-  using ExType = std::__libcpp_debug_exception;
   // Test incrementing/decrementing a singular iterator
   {
     path::iterator singular;
-    try {
-      ++singular;
-      assert(false);
-    } catch (ExType const&) {}
-    try {
-      --singular;
-      assert(false);
-    } catch (ExType const&) {}
+    EXPECT_DEATH( ++singular );
+    EXPECT_DEATH( --singular );
   }
   // Test decrementing the begin iterator
   {
     path p("foo/bar");
     auto it = p.begin();
-    try {
-      --it;
-      assert(false);
-    } catch (ExType const&) {}
     ++it;
     ++it;
-    try {
-      ++it;
-      assert(false);
-    } catch (ExType const&) {}
+    EXPECT_DEATH( ++it );
   }
   // Test incrementing the end iterator
   {
     path p("foo/bar");
     auto it = p.end();
-    try {
-      ++it;
-      assert(false);
-    } catch (ExType const&) {}
+    EXPECT_DEATH( ++it );
     --it;
     --it;
-    try {
-      --it;
-      assert(false);
-    } catch (ExType const&) {}
+    EXPECT_DEATH( --it );
   }
 
   return 0;
diff --git a/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp b/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp
index 78a8aaa..a01df4b 100644
--- a/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp
+++ b/test/libcxx/thread/futures/futures.promise/set_exception.pass.cpp
@@ -6,11 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: libcpp-no-exceptions
 // UNSUPPORTED: libcpp-has-no-threads
 // UNSUPPORTED: c++98, c++03
 
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 // MODULES_DEFINES: _LIBCPP_DEBUG=0
 
 // Can't test the system lib because this test enables debug mode
@@ -24,33 +22,28 @@
 // Test that a null exception_ptr is diagnosed.
 
 #define _LIBCPP_DEBUG 0
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
+
 #include <future>
 #include <exception>
 #include <cstdlib>
 #include <cassert>
 
 
+#include "debug_mode_helper.h"
+
 int main(int, char**)
 {
-    typedef std::__libcpp_debug_exception ExType;
     {
         typedef int T;
         std::promise<T> p;
-        try {
-            p.set_exception(std::exception_ptr());
-            assert(false);
-        } catch (ExType const&) {
-        }
+
+        EXPECT_DEATH( p.set_exception(std::exception_ptr()) );
     }
     {
         typedef int& T;
         std::promise<T> p;
-        try {
-            p.set_exception(std::exception_ptr());
-            assert(false);
-        } catch (ExType const&) {
-        }
+
+        EXPECT_DEATH( p.set_exception(std::exception_ptr()) );
     }
 
   return 0;
diff --git a/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp b/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp
index baf5ba9..999c5c7 100644
--- a/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp
+++ b/test/libcxx/thread/futures/futures.promise/set_exception_at_thread_exit.pass.cpp
@@ -10,7 +10,6 @@
 // UNSUPPORTED: libcpp-has-no-threads
 // UNSUPPORTED: c++98, c++03
 
-// MODULES_DEFINES: _LIBCPP_DEBUG_USE_EXCEPTIONS
 // MODULES_DEFINES: _LIBCPP_DEBUG=0
 
 // Can't test the system lib because this test enables debug mode
@@ -24,33 +23,27 @@
 // Test that a null exception_ptr is diagnosed.
 
 #define _LIBCPP_DEBUG 0
-#define _LIBCPP_DEBUG_USE_EXCEPTIONS
 #include <future>
 #include <exception>
 #include <cstdlib>
 #include <cassert>
+#include "debug_mode_helper.h"
 
 
 int main(int, char**)
 {
-    typedef std::__libcpp_debug_exception ExType;
     {
         typedef int T;
         std::promise<T> p;
-        try {
-            p.set_exception_at_thread_exit(std::exception_ptr());
-            assert(false);
-        } catch (ExType const& value) {
-        }
+
+        EXPECT_DEATH( p.set_exception_at_thread_exit(std::exception_ptr()) );
+
     }
     {
         typedef int& T;
         std::promise<T> p;
-        try {
-            p.set_exception_at_thread_exit(std::exception_ptr());
-            assert(false);
-        } catch (ExType const& value) {
-        }
+
+        EXPECT_DEATH( p.set_exception_at_thread_exit(std::exception_ptr()) );
     }
 
   return 0;
diff --git a/test/support/container_debug_tests.hpp b/test/support/container_debug_tests.hpp
new file mode 100644
index 0000000..ff843eb
--- /dev/null
+++ b/test/support/container_debug_tests.hpp
@@ -0,0 +1,371 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_SUPPORT_CONTAINER_DEBUG_TESTS_H
+#define TEST_SUPPORT_CONTAINER_DEBUG_TESTS_H
+
+#include <ciso646>
+#ifndef _LIBCPP_VERSION
+#error This header may only be used for libc++ tests"
+#endif
+
+#ifndef _LIBCPP_DEBUG
+#error _LIBCPP_DEBUG must be defined before including this header
+#endif
+
+#include <__debug>
+#include <utility>
+#include <cstddef>
+#include <cstdlib>
+#include <cassert>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+#include "test_macros.h"
+#include "debug_mode_helper.h"
+#include "assert_checkpoint.h"
+#include "test_allocator.h"
+
+// These test make use of 'if constexpr'.
+#if TEST_STD_VER <= 14
+#error This header may only be used in C++17 and greater
+#endif
+
+#ifndef __cpp_if_constexpr
+#error These tests require if constexpr
+#endif
+
+
+namespace IteratorDebugChecks {
+
+enum ContainerType {
+  CT_None,
+  CT_String,
+  CT_Vector,
+  CT_VectorBool,
+  CT_List,
+  CT_Deque,
+  CT_ForwardList,
+  CT_Map,
+  CT_Set,
+  CT_MultiMap,
+  CT_MultiSet,
+  CT_UnorderedMap,
+  CT_UnorderedSet,
+  CT_UnorderedMultiMap,
+  CT_UnorderedMultiSet
+};
+
+constexpr bool isSequential(ContainerType CT) {
+  return CT_Vector >= CT && CT_ForwardList <= CT;
+}
+
+constexpr bool isAssociative(ContainerType CT) {
+  return CT_Map >= CT && CT_MultiSet <= CT;
+}
+
+constexpr bool isUnordered(ContainerType CT) {
+  return CT_UnorderedMap >= CT && CT_UnorderedMultiSet <= CT;
+}
+
+constexpr bool isSet(ContainerType CT) {
+  return CT == CT_Set
+      || CT == CT_MultiSet
+      || CT == CT_UnorderedSet
+      || CT == CT_UnorderedMultiSet;
+}
+
+constexpr bool isMap(ContainerType CT) {
+  return CT == CT_Map
+      || CT == CT_MultiMap
+      || CT == CT_UnorderedMap
+      || CT == CT_UnorderedMultiMap;
+}
+
+constexpr bool isMulti(ContainerType CT) {
+  return CT == CT_MultiMap
+      || CT == CT_MultiSet
+      || CT == CT_UnorderedMultiMap
+      || CT == CT_UnorderedMultiSet;
+}
+
+template <class Container, class ValueType = typename Container::value_type>
+struct ContainerDebugHelper {
+  static_assert(std::is_constructible<ValueType, int>::value,
+                "must be constructible from int");
+
+  static ValueType makeValueType(int val = 0, int = 0) {
+    return ValueType(val);
+  }
+};
+
+template <class Container>
+struct ContainerDebugHelper<Container, char> {
+  static char makeValueType(int = 0, int = 0) {
+    return 'A';
+  }
+};
+
+template <class Container, class Key, class Value>
+struct ContainerDebugHelper<Container, std::pair<const Key, Value> > {
+  using ValueType = std::pair<const Key, Value>;
+  static_assert(std::is_constructible<Key, int>::value,
+                "must be constructible from int");
+  static_assert(std::is_constructible<Value, int>::value,
+                "must be constructible from int");
+
+  static ValueType makeValueType(int key = 0, int val = 0) {
+    return ValueType(key, val);
+  }
+};
+
+template <class Container, ContainerType CT,
+    class Helper = ContainerDebugHelper<Container> >
+struct BasicContainerChecks {
+  using value_type = typename Container::value_type;
+  using iterator = typename Container::iterator;
+  using const_iterator = typename Container::const_iterator;
+  using allocator_type = typename Container::allocator_type;
+  using traits = std::iterator_traits<iterator>;
+  using category = typename traits::iterator_category;
+
+  static_assert(std::is_same<test_allocator<value_type>, allocator_type>::value,
+                "the container must use a test allocator");
+
+  static constexpr bool IsBiDir =
+      std::is_convertible<category, std::bidirectional_iterator_tag>::value;
+
+ public:
+  static void run() {
+    run_iterator_tests();
+    run_container_tests();
+    run_allocator_aware_tests();
+  }
+
+  static void run_iterator_tests() {
+    try {
+      TestNullIterators<iterator>();
+      TestNullIterators<const_iterator>();
+      if constexpr (IsBiDir) { DecrementBegin(); }
+      IncrementEnd();
+      DerefEndIterator();
+    } catch (...) {
+      assert(false && "uncaught debug exception");
+    }
+  }
+
+  static void run_container_tests() {
+    try {
+      CopyInvalidatesIterators();
+      MoveInvalidatesIterators();
+      if constexpr (CT != CT_ForwardList) {
+        EraseIter();
+        EraseIterIter();
+      }
+    } catch (...) {
+      assert(false && "uncaught debug exception");
+    }
+  }
+
+  static void run_allocator_aware_tests() {
+    try {
+      SwapNonEqualAllocators();
+      if constexpr (CT != CT_ForwardList ) {
+        // FIXME: This should work for both forward_list and string
+        SwapInvalidatesIterators();
+      }
+    } catch (...) {
+      assert(false && "uncaught debug exception");
+    }
+  }
+
+  static Container makeContainer(int size, allocator_type A = allocator_type()) {
+    Container C(A);
+    if constexpr (CT == CT_ForwardList) {
+      for (int i = 0; i < size; ++i)
+        C.insert_after(C.before_begin(), Helper::makeValueType(i));
+    } else {
+      for (int i = 0; i < size; ++i)
+        C.insert(C.end(), Helper::makeValueType(i));
+      assert(C.size() == static_cast<std::size_t>(size));
+    }
+    return C;
+  }
+
+  static value_type makeValueType(int value) {
+    return Helper::makeValueType(value);
+  }
+
+ private:
+  // Iterator tests
+  template <class Iter>
+  static void TestNullIterators() {
+    CHECKPOINT("testing null iterator");
+    Iter it;
+    EXPECT_DEATH( ++it );
+    EXPECT_DEATH( it++ );
+    EXPECT_DEATH( *it );
+    if constexpr (CT != CT_VectorBool) {
+      EXPECT_DEATH( it.operator->() );
+    }
+    if constexpr (IsBiDir) {
+      EXPECT_DEATH( --it );
+      EXPECT_DEATH( it-- );
+    }
+  }
+
+  static void DecrementBegin() {
+    CHECKPOINT("testing decrement on begin");
+    Container C = makeContainer(1);
+    iterator i = C.end();
+    const_iterator ci = C.cend();
+    --i;
+    --ci;
+    assert(i == C.begin());
+    EXPECT_DEATH( --i );
+    EXPECT_DEATH( i-- );
+    EXPECT_DEATH( --ci );
+    EXPECT_DEATH( ci-- );
+  }
+
+  static void IncrementEnd() {
+    CHECKPOINT("testing increment on end");
+    Container C = makeContainer(1);
+    iterator i = C.begin();
+    const_iterator ci = C.begin();
+    ++i;
+    ++ci;
+    assert(i == C.end());
+    EXPECT_DEATH( ++i );
+    EXPECT_DEATH( i++ );
+    EXPECT_DEATH( ++ci );
+    EXPECT_DEATH( ci++ );
+  }
+
+  static void DerefEndIterator() {
+    CHECKPOINT("testing deref end iterator");
+    Container C = makeContainer(1);
+    iterator i = C.begin();
+    const_iterator ci = C.cbegin();
+    (void)*i; (void)*ci;
+    if constexpr (CT != CT_VectorBool) {
+      i.operator->();
+      ci.operator->();
+    }
+    ++i; ++ci;
+    assert(i == C.end());
+    EXPECT_DEATH( *i );
+    EXPECT_DEATH( *ci );
+    if constexpr (CT != CT_VectorBool) {
+      EXPECT_DEATH( i.operator->() );
+      EXPECT_DEATH( ci.operator->() );
+    }
+  }
+
+  // Container tests
+  static void CopyInvalidatesIterators() {
+    CHECKPOINT("copy invalidates iterators");
+    Container C1 = makeContainer(3);
+    iterator i = C1.begin();
+    Container C2 = C1;
+    if constexpr (CT == CT_ForwardList) {
+      iterator i_next = i;
+      ++i_next;
+      (void)*i_next;
+      EXPECT_DEATH( C2.erase_after(i) );
+      C1.erase_after(i);
+      EXPECT_DEATH( *i_next );
+    } else {
+      EXPECT_DEATH( C2.erase(i) );
+      (void)*i;
+      C1.erase(i);
+      EXPECT_DEATH( *i );
+    }
+  }
+
+  static void MoveInvalidatesIterators() {
+    CHECKPOINT("copy move invalidates iterators");
+    Container C1 = makeContainer(3);
+    iterator i = C1.begin();
+    Container C2 = std::move(C1);
+    (void) *i;
+    if constexpr (CT == CT_ForwardList) {
+      EXPECT_DEATH( C1.erase_after(i) );
+      C2.erase_after(i);
+    } else {
+      EXPECT_DEATH( C1.erase(i) );
+      C2.erase(i);
+      EXPECT_DEATH(*i);
+    }
+  }
+
+  static void EraseIter() {
+    CHECKPOINT("testing erase invalidation");
+    Container C1 = makeContainer(2);
+    iterator it1 = C1.begin();
+    iterator it1_next = it1;
+    ++it1_next;
+    Container C2 = C1;
+    EXPECT_DEATH( C2.erase(it1) ); // wrong container
+    EXPECT_DEATH( C2.erase(C2.end()) ); // erase with end
+    C1.erase(it1_next);
+    EXPECT_DEATH( C1.erase(it1_next) ); // invalidated iterator
+    C1.erase(it1);
+    EXPECT_DEATH( C1.erase(it1) ); // invalidated iterator
+  }
+
+  static void EraseIterIter() {
+    CHECKPOINT("testing erase iter iter invalidation");
+    Container C1 = makeContainer(2);
+    iterator it1 = C1.begin();
+    iterator it1_next = it1;
+    ++it1_next;
+    Container C2 = C1;
+    iterator it2 = C2.begin();
+    iterator it2_next = it2;
+    ++it2_next;
+    EXPECT_DEATH( C2.erase(it1, it1_next) ); // begin from wrong container
+    EXPECT_DEATH( C2.erase(it1, it2_next) ); // end   from wrong container
+    EXPECT_DEATH( C2.erase(it2, it1_next) ); // both  from wrong container
+    C2.erase(it2, it2_next);
+  }
+
+  // Allocator aware tests
+  static void SwapInvalidatesIterators() {
+    CHECKPOINT("testing swap invalidates iterators");
+    Container C1 = makeContainer(3);
+    Container C2 = makeContainer(3);
+    iterator it1 = C1.begin();
+    iterator it2 = C2.begin();
+    swap(C1, C2);
+    EXPECT_DEATH( C1.erase(it1) );
+    if (CT == CT_String) {
+      EXPECT_DEATH(C1.erase(it2));
+    } else
+      C1.erase(it2);
+    //C2.erase(it1);
+    EXPECT_DEATH( C1.erase(it1) );
+  }
+
+  static void SwapNonEqualAllocators() {
+    CHECKPOINT("testing swap with non-equal allocators");
+    Container C1 = makeContainer(3, allocator_type(1));
+    Container C2 = makeContainer(1, allocator_type(2));
+    Container C3 = makeContainer(2, allocator_type(2));
+    swap(C2, C3);
+    EXPECT_DEATH( swap(C1, C2) );
+  }
+
+ private:
+  BasicContainerChecks() = delete;
+};
+
+} // namespace IteratorDebugChecks
+
+#endif // TEST_SUPPORT_CONTAINER_DEBUG_TESTS_H
diff --git a/test/support/debug_mode_helper.h b/test/support/debug_mode_helper.h
index 611b4db..6a662d1 100644
--- a/test/support/debug_mode_helper.h
+++ b/test/support/debug_mode_helper.h
@@ -12,9 +12,6 @@
 #ifndef _LIBCPP_DEBUG
 #error _LIBCPP_DEBUG must be defined before including this header
 #endif
-#ifndef _LIBCPP_DEBUG_USE_EXCEPTIONS
-#error _LIBCPP_DEBUG_USE_EXCEPTIONS must be defined before including this header
-#endif
 
 #include <ciso646>
 #ifndef _LIBCPP_VERSION
@@ -26,360 +23,280 @@
 #include <cstddef>
 #include <cstdlib>
 #include <cassert>
+#include <string_view>
+#include <sstream>
+#include <iostream>
 
+#include <unistd.h>
+#include <sys/wait.h>
 #include "test_macros.h"
 #include "assert_checkpoint.h"
 #include "test_allocator.h"
 
-// These test make use of 'if constexpr'.
-#if TEST_STD_VER <= 14
-#error This header may only be used in C++17 and greater
-#endif
-#ifdef TEST_HAS_NO_EXCEPTIONS
-#error These tests require exceptions
+#if TEST_STD_VER < 11
+# error "C++11 or greater is required to use this header"
 #endif
 
-#ifndef __cpp_if_constexpr
-#error These tests require if constexpr
-#endif
+struct DebugInfoMatcher {
+  static const int any_line = -1;
+  static constexpr const char* any_file = "*";
+  static constexpr const char* any_msg = "*";
 
-/// Assert that the specified expression throws a libc++ debug exception.
-#define CHECK_DEBUG_THROWS(...) assert((CheckDebugThrows( [&]() { __VA_ARGS__; } )))
+  constexpr DebugInfoMatcher() : is_empty(true), msg(any_msg), file(any_file), line(any_line) { }
+  constexpr DebugInfoMatcher(const char* msg, const char* file = any_file, int line = any_line)
+    : is_empty(false), msg(msg), file(file), line(line) {}
 
-template <class Func>
-inline bool CheckDebugThrows(Func&& func) {
-  try {
-    func();
-  } catch (std::__libcpp_debug_exception const&) {
+  bool Matches(std::__libcpp_debug_info const& got) const {
+    assert(!empty() && "empty matcher");
+
+    if (CheckLineMatches(got.__line_) && CheckFileMatches(got.__file_) &&
+        CheckMessageMatches(got.__msg_))
+        return true;
+    // Write to stdout because that's the file descriptor captured by the parent
+    // process.
+    std::cout << "Failed to match debug info!\n"
+              << ToString() << "\n"
+              << "VS\n"
+              << got.what() << "\n";
+      return false;
+    }
+
+  std::string ToString() const {
+    std::stringstream ss;
+    ss << "msg = \"" << msg << "\"\n"
+       << "line = " << (line == any_line ? "'*'" : std::to_string(line)) << "\n"
+       << "file = " << (file == any_file ? "'*'" : any_file) << "";
+    return ss.str();
+  }
+
+  bool empty() const { return is_empty; }
+private:
+  bool CheckLineMatches(int got_line) const {
+    if (line == any_line)
+      return true;
+    return got_line == line;
+  }
+
+  bool CheckFileMatches(std::string_view got_file) const {
+    assert(!empty() && "empty matcher");
+    if (file == any_file)
+      return true;
+    std::size_t found_at = got_file.find(file);
+    if (found_at == std::string_view::npos)
+      return false;
+    // require the match start at the beginning of the file or immediately after
+    // a directory separator.
+    if (found_at != 0) {
+      char last_char = got_file[found_at - 1];
+      if (last_char != '/' && last_char != '\\')
+        return false;
+    }
+    // require the match goes until the end of the string.
+    return got_file.substr(found_at) == file;
+  }
+
+  bool CheckMessageMatches(std::string_view got_msg) const {
+    assert(!empty() && "empty matcher");
+    if (msg == any_msg)
+      return true;
+    std::size_t found_at = got_msg.find(msg);
+    if (found_at == std::string_view::npos)
+      return false;
+    // Allow any match
     return true;
   }
-  return false;
-}
-
-namespace IteratorDebugChecks {
-
-enum ContainerType {
-  CT_None,
-  CT_String,
-  CT_Vector,
-  CT_VectorBool,
-  CT_List,
-  CT_Deque,
-  CT_ForwardList,
-  CT_Map,
-  CT_Set,
-  CT_MultiMap,
-  CT_MultiSet,
-  CT_UnorderedMap,
-  CT_UnorderedSet,
-  CT_UnorderedMultiMap,
-  CT_UnorderedMultiSet
-};
-
-constexpr bool isSequential(ContainerType CT) {
-  return CT_Vector >= CT && CT_ForwardList <= CT;
-}
-
-constexpr bool isAssociative(ContainerType CT) {
-  return CT_Map >= CT && CT_MultiSet <= CT;
-}
-
-constexpr bool isUnordered(ContainerType CT) {
-  return CT_UnorderedMap >= CT && CT_UnorderedMultiSet <= CT;
-}
-
-constexpr bool isSet(ContainerType CT) {
-  return CT == CT_Set
-      || CT == CT_MultiSet
-      || CT == CT_UnorderedSet
-      || CT == CT_UnorderedMultiSet;
-}
-
-constexpr bool isMap(ContainerType CT) {
-  return CT == CT_Map
-      || CT == CT_MultiMap
-      || CT == CT_UnorderedMap
-      || CT == CT_UnorderedMultiMap;
-}
-
-constexpr bool isMulti(ContainerType CT) {
-  return CT == CT_MultiMap
-      || CT == CT_MultiSet
-      || CT == CT_UnorderedMultiMap
-      || CT == CT_UnorderedMultiSet;
-}
-
-template <class Container, class ValueType = typename Container::value_type>
-struct ContainerDebugHelper {
-  static_assert(std::is_constructible<ValueType, int>::value,
-                "must be constructible from int");
-
-  static ValueType makeValueType(int val = 0, int = 0) {
-    return ValueType(val);
-  }
-};
-
-template <class Container>
-struct ContainerDebugHelper<Container, char> {
-  static char makeValueType(int = 0, int = 0) {
-    return 'A';
-  }
-};
-
-template <class Container, class Key, class Value>
-struct ContainerDebugHelper<Container, std::pair<const Key, Value> > {
-  using ValueType = std::pair<const Key, Value>;
-  static_assert(std::is_constructible<Key, int>::value,
-                "must be constructible from int");
-  static_assert(std::is_constructible<Value, int>::value,
-                "must be constructible from int");
-
-  static ValueType makeValueType(int key = 0, int val = 0) {
-    return ValueType(key, val);
-  }
-};
-
-template <class Container, ContainerType CT,
-    class Helper = ContainerDebugHelper<Container> >
-struct BasicContainerChecks {
-  using value_type = typename Container::value_type;
-  using iterator = typename Container::iterator;
-  using const_iterator = typename Container::const_iterator;
-  using allocator_type = typename Container::allocator_type;
-  using traits = std::iterator_traits<iterator>;
-  using category = typename traits::iterator_category;
-
-  static_assert(std::is_same<test_allocator<value_type>, allocator_type>::value,
-                "the container must use a test allocator");
-
-  static constexpr bool IsBiDir =
-      std::is_convertible<category, std::bidirectional_iterator_tag>::value;
-
-public:
-  static void run() {
-    run_iterator_tests();
-    run_container_tests();
-    run_allocator_aware_tests();
-  }
-
-  static void run_iterator_tests() {
-    try {
-      TestNullIterators<iterator>();
-      TestNullIterators<const_iterator>();
-      if constexpr (IsBiDir) { DecrementBegin(); }
-      IncrementEnd();
-      DerefEndIterator();
-    } catch (...) {
-      assert(false && "uncaught debug exception");
-    }
-  }
-
-  static void run_container_tests() {
-    try {
-      CopyInvalidatesIterators();
-      MoveInvalidatesIterators();
-      if constexpr (CT != CT_ForwardList) {
-          EraseIter();
-          EraseIterIter();
-      }
-    } catch (...) {
-      assert(false && "uncaught debug exception");
-    }
-  }
-
-  static void run_allocator_aware_tests() {
-    try {
-      SwapNonEqualAllocators();
-      if constexpr (CT != CT_ForwardList ) {
-          // FIXME: This should work for both forward_list and string
-          SwapInvalidatesIterators();
-      }
-    } catch (...) {
-      assert(false && "uncaught debug exception");
-    }
-  }
-
-  static Container makeContainer(int size, allocator_type A = allocator_type()) {
-    Container C(A);
-    if constexpr (CT == CT_ForwardList) {
-      for (int i = 0; i < size; ++i)
-        C.insert_after(C.before_begin(), Helper::makeValueType(i));
-    } else {
-      for (int i = 0; i < size; ++i)
-        C.insert(C.end(), Helper::makeValueType(i));
-      assert(C.size() == static_cast<std::size_t>(size));
-    }
-    return C;
-  }
-
-  static value_type makeValueType(int value) {
-    return Helper::makeValueType(value);
-  }
-
 private:
-  // Iterator tests
-  template <class Iter>
-  static void TestNullIterators() {
-    CHECKPOINT("testing null iterator");
-    Iter it;
-    CHECK_DEBUG_THROWS( ++it );
-    CHECK_DEBUG_THROWS( it++ );
-    CHECK_DEBUG_THROWS( *it );
-    if constexpr (CT != CT_VectorBool) {
-      CHECK_DEBUG_THROWS( it.operator->() );
-    }
-    if constexpr (IsBiDir) {
-      CHECK_DEBUG_THROWS( --it );
-      CHECK_DEBUG_THROWS( it-- );
-    }
-  }
-
-  static void DecrementBegin() {
-    CHECKPOINT("testing decrement on begin");
-    Container C = makeContainer(1);
-    iterator i = C.end();
-    const_iterator ci = C.cend();
-    --i;
-    --ci;
-    assert(i == C.begin());
-    CHECK_DEBUG_THROWS( --i );
-    CHECK_DEBUG_THROWS( i-- );
-    CHECK_DEBUG_THROWS( --ci );
-    CHECK_DEBUG_THROWS( ci-- );
-  }
-
-  static void IncrementEnd() {
-    CHECKPOINT("testing increment on end");
-    Container C = makeContainer(1);
-    iterator i = C.begin();
-    const_iterator ci = C.begin();
-    ++i;
-    ++ci;
-    assert(i == C.end());
-    CHECK_DEBUG_THROWS( ++i );
-    CHECK_DEBUG_THROWS( i++ );
-    CHECK_DEBUG_THROWS( ++ci );
-    CHECK_DEBUG_THROWS( ci++ );
-  }
-
-  static void DerefEndIterator() {
-    CHECKPOINT("testing deref end iterator");
-    Container C = makeContainer(1);
-    iterator i = C.begin();
-    const_iterator ci = C.cbegin();
-    (void)*i; (void)*ci;
-    if constexpr (CT != CT_VectorBool) {
-      i.operator->();
-      ci.operator->();
-    }
-    ++i; ++ci;
-    assert(i == C.end());
-    CHECK_DEBUG_THROWS( *i );
-    CHECK_DEBUG_THROWS( *ci );
-    if constexpr (CT != CT_VectorBool) {
-      CHECK_DEBUG_THROWS( i.operator->() );
-      CHECK_DEBUG_THROWS( ci.operator->() );
-    }
-  }
-
-  // Container tests
-  static void CopyInvalidatesIterators() {
-    CHECKPOINT("copy invalidates iterators");
-    Container C1 = makeContainer(3);
-    iterator i = C1.begin();
-    Container C2 = C1;
-    if constexpr (CT == CT_ForwardList) {
-      iterator i_next = i;
-      ++i_next;
-      (void)*i_next;
-      CHECK_DEBUG_THROWS( C2.erase_after(i) );
-      C1.erase_after(i);
-      CHECK_DEBUG_THROWS( *i_next );
-    } else {
-      CHECK_DEBUG_THROWS( C2.erase(i) );
-      (void)*i;
-      C1.erase(i);
-      CHECK_DEBUG_THROWS( *i );
-    }
-  }
-
-  static void MoveInvalidatesIterators() {
-    CHECKPOINT("copy move invalidates iterators");
-    Container C1 = makeContainer(3);
-    iterator i = C1.begin();
-    Container C2 = std::move(C1);
-    (void) *i;
-    if constexpr (CT == CT_ForwardList) {
-      CHECK_DEBUG_THROWS( C1.erase_after(i) );
-      C2.erase_after(i);
-    } else {
-      CHECK_DEBUG_THROWS( C1.erase(i) );
-      C2.erase(i);
-      CHECK_DEBUG_THROWS(*i);
-    }
-  }
-
-  static void EraseIter() {
-    CHECKPOINT("testing erase invalidation");
-    Container C1 = makeContainer(2);
-    iterator it1 = C1.begin();
-    iterator it1_next = it1;
-    ++it1_next;
-    Container C2 = C1;
-    CHECK_DEBUG_THROWS( C2.erase(it1) ); // wrong container
-    CHECK_DEBUG_THROWS( C2.erase(C2.end()) ); // erase with end
-    C1.erase(it1_next);
-    CHECK_DEBUG_THROWS( C1.erase(it1_next) ); // invalidated iterator
-    C1.erase(it1);
-    CHECK_DEBUG_THROWS( C1.erase(it1) ); // invalidated iterator
-  }
-
-  static void EraseIterIter() {
-    CHECKPOINT("testing erase iter iter invalidation");
-    Container C1 = makeContainer(2);
-    iterator it1 = C1.begin();
-    iterator it1_next = it1;
-    ++it1_next;
-    Container C2 = C1;
-    iterator it2 = C2.begin();
-    iterator it2_next = it2;
-    ++it2_next;
-    CHECK_DEBUG_THROWS( C2.erase(it1, it1_next) ); // begin from wrong container
-    CHECK_DEBUG_THROWS( C2.erase(it1, it2_next) ); // end   from wrong container
-    CHECK_DEBUG_THROWS( C2.erase(it2, it1_next) ); // both  from wrong container
-    C2.erase(it2, it2_next);
-  }
-
-  // Allocator aware tests
-  static void SwapInvalidatesIterators() {
-    CHECKPOINT("testing swap invalidates iterators");
-    Container C1 = makeContainer(3);
-    Container C2 = makeContainer(3);
-    iterator it1 = C1.begin();
-    iterator it2 = C2.begin();
-    swap(C1, C2);
-    CHECK_DEBUG_THROWS( C1.erase(it1) );
-    if (CT == CT_String) {
-      CHECK_DEBUG_THROWS(C1.erase(it2));
-    } else
-      C1.erase(it2);
-    //C2.erase(it1);
-    CHECK_DEBUG_THROWS( C1.erase(it1) );
-  }
-
-  static void SwapNonEqualAllocators() {
-    CHECKPOINT("testing swap with non-equal allocators");
-    Container C1 = makeContainer(3, allocator_type(1));
-    Container C2 = makeContainer(1, allocator_type(2));
-    Container C3 = makeContainer(2, allocator_type(2));
-    swap(C2, C3);
-    CHECK_DEBUG_THROWS( swap(C1, C2) );
-  }
-
-private:
-  BasicContainerChecks() = delete;
+  bool is_empty;
+  std::string_view msg;
+  std::string_view file;
+  int line;
 };
 
-} // namespace IteratorDebugChecks
+static constexpr DebugInfoMatcher AnyMatcher(DebugInfoMatcher::any_msg);
+
+inline DebugInfoMatcher& GlobalMatcher() {
+  static DebugInfoMatcher GMatch;
+  return GMatch;
+}
+
+struct DeathTest {
+  enum ResultKind {
+    RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown
+  };
+
+  static const char* ResultKindToString(ResultKind RK) {
+#define CASE(K) case K: return #K
+    switch (RK) {
+    CASE(RK_MatchFailure);
+    CASE(RK_DidNotDie);
+    CASE(RK_SetupFailure);
+    CASE(RK_MatchFound);
+    CASE(RK_Unknown);
+    }
+    return "not a result kind";
+  }
+
+  static bool IsValidResultKind(int val) {
+    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) {}
+
+  template <class Func>
+  ResultKind Run(Func&& f) {
+    int pipe_res = pipe(stdout_pipe_fd_);
+    assert(pipe_res != -1 && "failed to create pipe");
+    pipe_res = pipe(stderr_pipe_fd_);
+    assert(pipe_res != -1 && "failed to create pipe");
+    pid_t child_pid = fork();
+    assert(child_pid != -1 &&
+        "failed to fork a process to perform a death test");
+    child_pid_ = child_pid;
+    if (child_pid_ == 0) {
+      RunForChild(std::forward<Func>(f));
+      assert(false && "unreachable");
+    }
+    return RunForParent();
+  }
+
+  int getChildExitCode() const { return exit_code_; }
+  std::string const& getChildStdOut() const { return stdout_from_child_; }
+  std::string const& getChildStdErr() const { return stderr_from_child_; }
+private:
+  template <class Func>
+  TEST_NORETURN void RunForChild(Func&& f) {
+    close(GetStdOutReadFD()); // don't need to read from the pipe in the child.
+    close(GetStdErrReadFD());
+    auto DupFD = [](int DestFD, int TargetFD) {
+      int dup_result = dup2(DestFD, TargetFD);
+      if (dup_result == -1)
+        std::exit(RK_SetupFailure);
+    };
+    DupFD(GetStdOutWriteFD(), STDOUT_FILENO);
+    DupFD(GetStdErrWriteFD(), STDERR_FILENO);
+
+    GlobalMatcher() = matcher_;
+    std::__libcpp_set_debug_function(&DeathTestDebugHandler);
+    f();
+    std::exit(RK_DidNotDie);
+  }
+
+  static std::string ReadChildIOUntilEnd(int FD) {
+    std::string error_msg;
+    char buffer[256];
+    int num_read;
+    do {
+      while ((num_read = read(FD, buffer, 255)) > 0) {
+        buffer[num_read] = '\0';
+        error_msg += buffer;
+      }
+    } while (num_read == -1 && errno == EINTR);
+    return error_msg;
+  }
+
+  void CaptureIOFromChild() {
+    close(GetStdOutWriteFD()); // no need to write from the parent process
+    close(GetStdErrWriteFD());
+    stdout_from_child_ = ReadChildIOUntilEnd(GetStdOutReadFD());
+    stderr_from_child_ = ReadChildIOUntilEnd(GetStdErrReadFD());
+    close(GetStdOutReadFD());
+    close(GetStdErrReadFD());
+  }
+
+  ResultKind RunForParent() {
+    CaptureIOFromChild();
+
+    int status_value;
+    pid_t result = waitpid(child_pid_, &status_value, 0);
+    assert(result != -1 && "there is no child process to wait for");
+
+    if (WIFEXITED(status_value)) {
+      exit_code_ = WEXITSTATUS(status_value);
+      if (!IsValidResultKind(exit_code_))
+        return RK_Unknown;
+      return static_cast<ResultKind>(exit_code_);
+    }
+    return RK_Unknown;
+  }
+
+  DeathTest(DeathTest const&) = delete;
+  DeathTest& operator=(DeathTest const&) = delete;
+
+  int GetStdOutReadFD() const {
+    return stdout_pipe_fd_[0];
+  }
+
+  int GetStdOutWriteFD() const {
+    return stdout_pipe_fd_[1];
+  }
+
+  int GetStdErrReadFD() const {
+    return stderr_pipe_fd_[0];
+  }
+
+  int GetStdErrWriteFD() const {
+    return stderr_pipe_fd_[1];
+  }
+private:
+  DebugInfoMatcher matcher_;
+  pid_t child_pid_ = -1;
+  int exit_code_ = -1;
+  int stdout_pipe_fd_[2];
+  int stderr_pipe_fd_[2];
+  std::string stdout_from_child_;
+  std::string stderr_from_child_;
+};
+
+template <class Func>
+inline bool ExpectDeath(const char* stmt, Func&& func, DebugInfoMatcher Matcher) {
+  DeathTest DT(Matcher);
+  DeathTest::ResultKind RK = DT.Run(func);
+  auto OnFailure = [&](const char* msg) {
+    std::cerr << "EXPECT_DEATH( " << stmt << " ) failed! (" << msg << ")\n\n";
+    if (RK != DeathTest::RK_Unknown) {
+      std::cerr << "child exit code: " << DT.getChildExitCode() << "\n";
+    }
+    if (!DT.getChildStdErr().empty()) {
+      std::cerr << "---------- standard err ----------\n";
+      std::cerr << DT.getChildStdErr() << "\n";
+    }
+    if (!DT.getChildStdOut().empty()) {
+      std::cerr << "---------- standard out ----------\n";
+      std::cerr << DT.getChildStdOut() << "\n";
+    }
+    return false;
+  };
+  switch (RK) {
+  case DeathTest::RK_MatchFound:
+    return true;
+  case DeathTest::RK_SetupFailure:
+    return OnFailure("child failed to setup test environment");
+  case DeathTest::RK_Unknown:
+      return OnFailure("reason unknown");
+  case DeathTest::RK_DidNotDie:
+      return OnFailure("child did not die");
+  case DeathTest::RK_MatchFailure:
+      return OnFailure("matcher failed");
+  }
+}
+
+template <class Func>
+inline bool ExpectDeath(const char* stmt, Func&& func) {
+  return ExpectDeath(stmt, func, AnyMatcher);
+}
+
+/// Assert that the specified expression throws a libc++ debug exception.
+#define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } )))
+
+#define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher)))
 
 #endif // TEST_SUPPORT_DEBUG_MODE_HELPER_H