Debug mode for string.  This commit also marks the first time libc++ debug-mode has found a bug (found one in regex).  Had to play with extern templates a bit to get this to work since string is heavily used within libc++.dylib.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@189114 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__config b/include/__config
index 54ef541..92e5319 100644
--- a/include/__config
+++ b/include/__config
@@ -525,10 +525,25 @@
 #define _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(x)
 #endif  // _LIBCPP_HAS_NO_STRONG_ENUMS
 
+#ifdef _LIBCPP_DEBUG2
+#   if _LIBCPP_DEBUG2 == 0
+#       define _LIBCPP_DEBUG_LEVEL 1
+#   elif _LIBCPP_DEBUG2 == 1
+#       define _LIBCPP_DEBUG_LEVEL 2
+#   else
+#       error Supported values for _LIBCPP_DEBUG2 are 0 and 1
+#   endif
+#   define _LIBCPP_EXTERN_TEMPLATE(...)
+#endif
+
 #ifndef _LIBCPP_EXTERN_TEMPLATE
 #define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
 #endif
 
+#ifndef _LIBCPP_EXTERN_TEMPLATE2
+#define _LIBCPP_EXTERN_TEMPLATE2(...) extern template __VA_ARGS__;
+#endif
+
 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(_WIN32) || defined(__sun__) || defined(__NetBSD__)
 #define _LIBCPP_LOCALE__L_EXTENSIONS 1
 #endif
@@ -544,16 +559,6 @@
 #define _LIBCPP_WCTYPE_IS_MASK
 #endif
 
-#ifdef _LIBCPP_DEBUG2
-#   if _LIBCPP_DEBUG2 == 0
-#       define _LIBCPP_DEBUG_LEVEL 1
-#   elif _LIBCPP_DEBUG2 == 1
-#       define _LIBCPP_DEBUG_LEVEL 2
-#   else
-#       error Supported values for _LIBCPP_DEBUG2 are 0 and 1
-#   endif
-#endif
-
 #ifndef _LIBCPP_STD_VER
 #  if  __cplusplus <= 201103L
 #    define _LIBCPP_STD_VER 11
diff --git a/include/__debug b/include/__debug
index bac580c..f1805ad 100644
--- a/include/__debug
+++ b/include/__debug
@@ -11,6 +11,10 @@
 #ifndef _LIBCPP_DEBUG_H
 #define _LIBCPP_DEBUG_H
 
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
 #if _LIBCPP_DEBUG_LEVEL >= 1
 
 #   include <cstdlib>
@@ -24,10 +28,6 @@
 
 #if _LIBCPP_DEBUG_LEVEL >= 2
 
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 struct _LIBCPP_TYPE_VIS __c_node;
@@ -38,8 +38,15 @@
     __i_node* __next_;
     __c_node* __c_;
 
+#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
     __i_node(const __i_node&) = delete;
     __i_node& operator=(const __i_node&) = delete;
+#else
+private:
+    __i_node(const __i_node&);
+    __i_node& operator=(const __i_node&);
+public:
+#endif
     _LIBCPP_INLINE_VISIBILITY
     __i_node(void* __i, __i_node* __next, __c_node* __c)
         : __i_(__i), __next_(__next), __c_(__c) {}
@@ -54,8 +61,15 @@
     __i_node** end_;
     __i_node** cap_;
 
+#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
     __c_node(const __c_node&) = delete;
     __c_node& operator=(const __c_node&) = delete;
+#else
+private:
+    __c_node(const __c_node&);
+    __c_node& operator=(const __c_node&);
+public:
+#endif
     _LIBCPP_INLINE_VISIBILITY
     __c_node(void* __c, __c_node* __next)
         : __c_(__c), __next_(__next), beg_(nullptr), end_(nullptr), cap_(nullptr) {}
@@ -134,8 +148,15 @@
 
     __libcpp_db();
 public:
+#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
     __libcpp_db(const __libcpp_db&) = delete;
     __libcpp_db& operator=(const __libcpp_db&) = delete;
+#else
+private:
+    __libcpp_db(const __libcpp_db&);
+    __libcpp_db& operator=(const __libcpp_db&);
+public:
+#endif
     ~__libcpp_db();
 
     class __db_c_iterator;
diff --git a/include/__locale b/include/__locale
index 9c51f9e..2c144d2 100644
--- a/include/__locale
+++ b/include/__locale
@@ -256,8 +256,8 @@
     return static_cast<long>(__h);
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS collate<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS collate<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS collate<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS collate<wchar_t>)
 
 // template <class CharT> class collate_byname;
 
@@ -1147,10 +1147,10 @@
 {
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS codecvt_byname<char, char, mbstate_t>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS codecvt_byname<wchar_t, char, mbstate_t>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS codecvt_byname<char16_t, char, mbstate_t>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS codecvt_byname<char32_t, char, mbstate_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS codecvt_byname<char, char, mbstate_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS codecvt_byname<wchar_t, char, mbstate_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS codecvt_byname<char16_t, char, mbstate_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS codecvt_byname<char32_t, char, mbstate_t>)
 
 _LIBCPP_FUNC_VIS void __throw_runtime_error(const char*);
 
diff --git a/include/algorithm b/include/algorithm
index 03b872a..442e100 100644
--- a/include/algorithm
+++ b/include/algorithm
@@ -1692,6 +1692,8 @@
     return __i.base();
 }
 
+#if _LIBCPP_DEBUG_LEVEL < 2
+
 template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 typename enable_if
@@ -1704,6 +1706,8 @@
     return __i.base();
 }
 
+#endif  // _LIBCPP_DEBUG_LEVEL < 2
+
 template <class _InputIterator, class _OutputIterator>
 inline _LIBCPP_INLINE_VISIBILITY
 _OutputIterator
diff --git a/include/iterator b/include/iterator
index 87d6d1d..8e92e6f 100644
--- a/include/iterator
+++ b/include/iterator
@@ -1197,12 +1197,13 @@
     _LIBCPP_INLINE_VISIBILITY iterator_type base() const _NOEXCEPT {return __i;}
 
 private:
-    _LIBCPP_INLINE_VISIBILITY __wrap_iter(iterator_type __x) _NOEXCEPT : __i(__x) {}
 #if _LIBCPP_DEBUG_LEVEL >= 2
     _LIBCPP_INLINE_VISIBILITY __wrap_iter(const void* __p, iterator_type __x) : __i(__x)
     {
         __get_db()->__insert_ic(this, __p);
     }
+#else
+    _LIBCPP_INLINE_VISIBILITY __wrap_iter(iterator_type __x) _NOEXCEPT : __i(__x) {}
 #endif
 
     template <class _Up> friend class __wrap_iter;
diff --git a/include/locale b/include/locale
index 8877192..768bb39 100644
--- a/include/locale
+++ b/include/locale
@@ -687,8 +687,8 @@
     return 0;
 }
 
-_LIBCPP_EXTERN_TEMPLATE(struct _LIBCPP_TYPE_VIS __num_get<char>)
-_LIBCPP_EXTERN_TEMPLATE(struct _LIBCPP_TYPE_VIS __num_get<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(struct _LIBCPP_TYPE_VIS __num_get<char>)
+_LIBCPP_EXTERN_TEMPLATE2(struct _LIBCPP_TYPE_VIS __num_get<wchar_t>)
 
 template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >
 class _LIBCPP_TYPE_VIS_ONLY num_get
@@ -1436,8 +1436,8 @@
     return __b;
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS num_get<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS num_get<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS num_get<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS num_get<wchar_t>)
 
 struct _LIBCPP_TYPE_VIS __num_put_base
 {
@@ -1586,8 +1586,8 @@
         __op = __ob + (__np - __nb);
 }
 
-_LIBCPP_EXTERN_TEMPLATE(struct _LIBCPP_TYPE_VIS __num_put<char>)
-_LIBCPP_EXTERN_TEMPLATE(struct _LIBCPP_TYPE_VIS __num_put<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(struct _LIBCPP_TYPE_VIS __num_put<char>)
+_LIBCPP_EXTERN_TEMPLATE2(struct _LIBCPP_TYPE_VIS __num_put<wchar_t>)
 
 template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >
 class _LIBCPP_TYPE_VIS_ONLY num_put
@@ -1770,7 +1770,12 @@
         return do_put(__s, __iob, __fl, (unsigned long)__v);
     const numpunct<char_type>& __np = use_facet<numpunct<char_type> >(__iob.getloc());
     typedef typename numpunct<char_type>::string_type string_type;
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    string_type __tmp(__v ? __np.truename() : __np.falsename());
+    string_type __nm = _VSTD::move(__tmp);
+#else
     string_type __nm = __v ? __np.truename() : __np.falsename();
+#endif
     for (typename string_type::iterator __i = __nm.begin(); __i != __nm.end(); ++__i, ++__s)
         *__s = *__i;
     return __s;
@@ -2066,8 +2071,8 @@
     return __pad_and_output(__s, __o, __op, __oe, __iob, __fl);
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS num_put<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS num_put<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS num_put<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS num_put<wchar_t>)
 
 template <class _CharT, class _InputIterator>
 _LIBCPP_HIDDEN
@@ -2733,8 +2738,8 @@
     return __b;
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_get<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_get<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_get<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_get<wchar_t>)
 
 class _LIBCPP_TYPE_VIS __time_get
 {
@@ -2816,8 +2821,8 @@
     virtual const string_type& __X() const      {return this->__X_;}
 };
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_get_byname<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_get_byname<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_get_byname<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_get_byname<wchar_t>)
 
 class _LIBCPP_TYPE_VIS __time_put
 {
@@ -2929,8 +2934,8 @@
     return _VSTD::copy(__nb, __ne, __s);
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_put<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_put<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_put<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_put<wchar_t>)
 
 template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >
 class _LIBCPP_TYPE_VIS_ONLY time_put_byname
@@ -2950,8 +2955,8 @@
     ~time_put_byname() {}
 };
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_put_byname<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS time_put_byname<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_put_byname<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS time_put_byname<wchar_t>)
 
 // money_base
 
@@ -3017,10 +3022,10 @@
 const bool
 moneypunct<_CharT, _International>::intl;
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct<char, false>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct<char, true>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct<wchar_t, false>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct<wchar_t, true>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct<char, false>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct<char, true>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct<wchar_t, false>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct<wchar_t, true>)
 
 // moneypunct_byname
 
@@ -3074,10 +3079,10 @@
 template<> void moneypunct_byname<wchar_t, false>::init(const char*);
 template<> void moneypunct_byname<wchar_t, true>::init(const char*);
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct_byname<char, false>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct_byname<char, true>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct_byname<wchar_t, false>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS moneypunct_byname<wchar_t, true>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct_byname<char, false>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct_byname<char, true>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct_byname<wchar_t, false>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS moneypunct_byname<wchar_t, true>)
 
 // money_get
 
@@ -3133,8 +3138,8 @@
     }
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS __money_get<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS __money_get<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS __money_get<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS __money_get<wchar_t>)
 
 template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >
 class _LIBCPP_TYPE_VIS_ONLY money_get
@@ -3514,8 +3519,8 @@
     return __b;
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS money_get<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS money_get<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS money_get<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS money_get<wchar_t>)
 
 // money_put
 
@@ -3689,8 +3694,8 @@
         __mi = __mb;
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS __money_put<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS __money_put<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS __money_put<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS __money_put<wchar_t>)
 
 template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >
 class _LIBCPP_TYPE_VIS_ONLY money_put
@@ -3846,8 +3851,8 @@
     return __pad_and_output(__s, __mb, __mi, __me, __iob, __fl);
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS money_put<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS money_put<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS money_put<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS money_put<wchar_t>)
 
 // messages
 
@@ -3956,8 +3961,8 @@
 #endif // !_WIN32
 }
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS messages<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS messages<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS messages<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS messages<wchar_t>)
 
 template <class _CharT>
 class _LIBCPP_TYPE_VIS_ONLY messages_byname
@@ -3980,8 +3985,8 @@
     ~messages_byname() {}
 };
 
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS messages_byname<char>)
-_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS messages_byname<wchar_t>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS messages_byname<char>)
+_LIBCPP_EXTERN_TEMPLATE2(class _LIBCPP_TYPE_VIS messages_byname<wchar_t>)
 
 template<class _Codecvt, class _Elem = wchar_t,
          class _Wide_alloc = allocator<_Elem>,
diff --git a/include/regex b/include/regex
index 776bc65..cc06e0b 100644
--- a/include/regex
+++ b/include/regex
@@ -3785,7 +3785,7 @@
                 }
                 __ml->__add_range(_VSTD::move(__start_range), _VSTD::move(__end_range));
             }
-            else
+            else if (!__start_range.empty())
             {
                 if (__start_range.size() == 1)
                     __ml->__add_char(__start_range[0]);
@@ -3793,7 +3793,7 @@
                     __ml->__add_digraph(__start_range[0], __start_range[1]);
             }
         }
-        else
+        else if (!__start_range.empty())
         {
             if (__start_range.size() == 1)
                 __ml->__add_char(__start_range[0]);
diff --git a/include/string b/include/string
index 7439b56..761ff52 100644
--- a/include/string
+++ b/include/string
@@ -447,7 +447,7 @@
 #ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
 #include <cstdint>
 #endif
-#if defined(_LIBCPP_NO_EXCEPTIONS) || defined(_LIBCPP_DEBUG)
+#if defined(_LIBCPP_NO_EXCEPTIONS)
 #include <cassert>
 #endif
 
@@ -605,6 +605,7 @@
 _CharT*
 char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size_t __n)
 {
+    _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
     char_type* __r = __s1;
     for (; __n; --__n, ++__s1, ++__s2)
         assign(*__s1, *__s2);
@@ -656,7 +657,10 @@
         {return (char_type*)memmove(__s1, __s2, __n);}
     _LIBCPP_INLINE_VISIBILITY
     static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n)
-        {return (char_type*)memcpy(__s1, __s2, __n);}
+        {
+            _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
+            return (char_type*)memcpy(__s1, __s2, __n);
+        }
     _LIBCPP_INLINE_VISIBILITY
     static char_type* assign(char_type* __s, size_t __n, char_type __a)
         {return (char_type*)memset(__s, to_int_type(__a), __n);}
@@ -713,7 +717,10 @@
         {return (char_type*)wmemmove(__s1, __s2, __n);}
     _LIBCPP_INLINE_VISIBILITY
     static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n)
-        {return (char_type*)wmemcpy(__s1, __s2, __n);}
+        {
+            _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
+            return (char_type*)wmemcpy(__s1, __s2, __n);
+        }
     _LIBCPP_INLINE_VISIBILITY
     static char_type* assign(char_type* __s, size_t __n, char_type __a)
         {return (char_type*)wmemset(__s, __a, __n);}
@@ -841,6 +848,7 @@
 char16_t*
 char_traits<char16_t>::copy(char_type* __s1, const char_type* __s2, size_t __n)
 {
+    _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
     char_type* __r = __s1;
     for (; __n; --__n, ++__s1, ++__s2)
         assign(*__s1, *__s2);
@@ -961,6 +969,7 @@
 char32_t*
 char_traits<char32_t>::copy(char_type* __s1, const char_type* __s2, size_t __n)
 {
+    _LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
     char_type* __r = __s1;
     for (; __n; --__n, ++__s1, ++__s2)
         assign(*__s1, *__s2);
@@ -1072,13 +1081,13 @@
     typedef const value_type&                            const_reference;
     typedef typename __alloc_traits::pointer             pointer;
     typedef typename __alloc_traits::const_pointer       const_pointer;
-#ifdef _LIBCPP_DEBUG
-    typedef __debug_iter<basic_string, pointer>          iterator;
-    typedef __debug_iter<basic_string, const_pointer>    const_iterator;
 
-    friend class __debug_iter<basic_string, pointer>;
-    friend class __debug_iter<basic_string, const_pointer>;
-#elif defined(_LIBCPP_RAW_ITERATORS)
+    static_assert(is_pod<value_type>::value, "Character type of basic_string must be a POD");
+    static_assert((is_same<_CharT, value_type>::value),
+                  "traits_type::char_type must be the same type as CharT");
+    static_assert((is_same<typename allocator_type::value_type, value_type>::value),
+                  "Allocator::value_type must be same type as value_type");
+#if defined(_LIBCPP_RAW_ITERATORS)
     typedef pointer                                      iterator;
     typedef const_pointer                                const_iterator;
 #else  // defined(_LIBCPP_RAW_ITERATORS)
@@ -1152,9 +1161,9 @@
 
 #endif  // _LIBCPP_ALTERNATE_STRING_LAYOUT
 
-    union __lx{__long __lx; __short __lxx;};
+    union __ulx{__long __lx; __short __lxx;};
 
-    enum {__n_words = sizeof(__lx) / sizeof(size_type)};
+    enum {__n_words = sizeof(__ulx) / sizeof(size_type)};
 
     struct __raw
     {
@@ -1173,15 +1182,6 @@
 
     __compressed_pair<__rep, allocator_type> __r_;
 
-#ifdef _LIBCPP_DEBUG
-
-    pair<iterator*, const_iterator*> __iterator_list_;
-
-    _LIBCPP_INLINE_VISIBILITY iterator*&       __get_iterator_list(iterator*)       {return __iterator_list_.first;}
-    _LIBCPP_INLINE_VISIBILITY const_iterator*& __get_iterator_list(const_iterator*) {return __iterator_list_.second;}
-
-#endif  // _LIBCPP_DEBUG
-
 public:
     static const size_type npos = -1;
 
@@ -1239,7 +1239,20 @@
     basic_string& operator=(initializer_list<value_type> __il) {return assign(__il.begin(), __il.size());}
 #endif  // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
 
-#ifndef _LIBCPP_DEBUG
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    _LIBCPP_INLINE_VISIBILITY
+    iterator begin() _NOEXCEPT
+        {return iterator(this, __get_pointer());}
+    _LIBCPP_INLINE_VISIBILITY
+    const_iterator begin() const _NOEXCEPT
+        {return const_iterator(this, __get_pointer());}
+    _LIBCPP_INLINE_VISIBILITY
+    iterator end() _NOEXCEPT
+        {return iterator(this, __get_pointer() + size());}
+    _LIBCPP_INLINE_VISIBILITY
+    const_iterator end() const _NOEXCEPT
+        {return const_iterator(this, __get_pointer() + size());}
+#else
     _LIBCPP_INLINE_VISIBILITY
     iterator begin() _NOEXCEPT
         {return iterator(__get_pointer());}
@@ -1252,12 +1265,7 @@
     _LIBCPP_INLINE_VISIBILITY
     const_iterator end() const _NOEXCEPT
         {return const_iterator(__get_pointer() + size());}
-#else  // _LIBCPP_DEBUG
-    _LIBCPP_INLINE_VISIBILITY iterator       begin()       {return iterator(this, __get_pointer());}
-    _LIBCPP_INLINE_VISIBILITY const_iterator begin() const {return const_iterator(this, data());}
-    _LIBCPP_INLINE_VISIBILITY iterator       end()         {return iterator(this, __get_pointer() + size());}
-    _LIBCPP_INLINE_VISIBILITY const_iterator end() const   {return const_iterator(this, data() + size());}
-#endif  // _LIBCPP_DEBUG
+#endif  // _LIBCPP_DEBUG_LEVEL >= 2
     _LIBCPP_INLINE_VISIBILITY
     reverse_iterator rbegin() _NOEXCEPT
         {return reverse_iterator(end());}
@@ -1520,6 +1528,15 @@
     bool __is_long() const _NOEXCEPT
         {return bool(__r_.first().__s.__size_ & __short_mask);}
 
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+    bool __dereferenceable(const const_iterator* __i) const;
+    bool __decrementable(const const_iterator* __i) const;
+    bool __addable(const const_iterator* __i, ptrdiff_t __n) const;
+    bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const;
+
+#endif  // _LIBCPP_DEBUG_LEVEL >= 2
+
 private:
     _LIBCPP_INLINE_VISIBILITY
     allocator_type& __alloc() _NOEXCEPT
@@ -1732,60 +1749,43 @@
 };
 
 template <class _CharT, class _Traits, class _Allocator>
-#ifndef _LIBCPP_DEBUG
 _LIBCPP_INLINE_VISIBILITY inline
-#endif
 void
 basic_string<_CharT, _Traits, _Allocator>::__invalidate_all_iterators()
 {
-#ifdef _LIBCPP_DEBUG
-    iterator::__remove_all(this);
-    const_iterator::__remove_all(this);
-#endif  // _LIBCPP_DEBUG
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__invalidate_all(this);
+#endif  // _LIBCPP_DEBUG_LEVEL >= 2
 }
 
 template <class _CharT, class _Traits, class _Allocator>
-#ifndef _LIBCPP_DEBUG
 _LIBCPP_INLINE_VISIBILITY inline
-#endif
 void
 basic_string<_CharT, _Traits, _Allocator>::__invalidate_iterators_past(size_type
-#ifdef _LIBCPP_DEBUG
+#if _LIBCPP_DEBUG_LEVEL >= 2
                                                                         __pos
 #endif
                                                                       )
 {
-#ifdef _LIBCPP_DEBUG
-    const_iterator __beg = begin();
-    if (__iterator_list_.first)
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __c_node* __c = __get_db()->__find_c_and_lock(this);
+    if (__c)
     {
-        for (iterator* __p = __iterator_list_.first; __p;)
+        const_pointer __new_last = __get_pointer() + __pos;
+        for (__i_node** __p = __c->end_; __p != __c->beg_; )
         {
-            if (*__p - __beg > static_cast<difference_type>(__pos))
+            --__p;
+            const_iterator* __i = static_cast<const_iterator*>((*__p)->__i_);
+            if (__i->base() > __new_last)
             {
-                iterator* __n = __p;
-                __p = __p->__next;
-                __n->__remove_owner();
+                (*__p)->__c_ = nullptr;
+                if (--__c->end_ != __p)
+                    memmove(__p, __p+1, (__c->end_ - __p)*sizeof(__i_node*));
             }
-            else
-                __p = __p->__next;
         }
+        __get_db()->unlock();
     }
-    if (__iterator_list_.second)
-    {
-        for (const_iterator* __p = __iterator_list_.second; __p;)
-        {
-            if (*__p - __beg > static_cast<difference_type>(__pos))
-            {
-                const_iterator* __n = __p;
-                __p = __p->__next;
-                __n->__remove_owner();
-            }
-            else
-                __p = __p->__next;
-        }
-    }
-#endif  // _LIBCPP_DEBUG
+#endif  // _LIBCPP_DEBUG_LEVEL >= 2
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1793,6 +1793,9 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string()
     _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
     __zero();
 }
 
@@ -1801,6 +1804,9 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const allocator_type& __a)
     : __r_(__a)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
     __zero();
 }
 
@@ -1856,10 +1862,11 @@
 _LIBCPP_INLINE_VISIBILITY inline
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*) detected nullptr");
     __init(__s, traits_type::length(__s));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1867,20 +1874,22 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, const allocator_type& __a)
     : __r_(__a)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*, allocator) detected nullptr");
     __init(__s, traits_type::length(__s));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_INLINE_VISIBILITY inline
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr");
     __init(__s, __n);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1888,10 +1897,11 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s, size_type __n, const allocator_type& __a)
     : __r_(__a)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr");
     __init(__s, __n);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1902,6 +1912,9 @@
         __r_.first().__r = __str.__r_.first().__r;
     else
         __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1912,6 +1925,9 @@
         __r_.first().__r = __str.__r_.first().__r;
     else
         __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -1923,8 +1939,10 @@
     : __r_(_VSTD::move(__str.__r_))
 {
     __str.__zero();
-#ifdef _LIBCPP_DEBUG
-    __str.__invalidate_all_iterators();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+    if (__is_long())
+        __get_db()->swap(this, &__str);
 #endif
 }
 
@@ -1938,8 +1956,10 @@
     else
         __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size());
     __str.__zero();
-#ifdef _LIBCPP_DEBUG
-    __str.__invalidate_all_iterators();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+    if (__is_long())
+        __get_db()->swap(this, &__str);
 #endif
 }
 
@@ -1974,6 +1994,9 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string(size_type __n, value_type __c)
 {
     __init(__n, __c);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1982,6 +2005,9 @@
     : __r_(__a)
 {
     __init(__n, __c);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -1993,6 +2019,9 @@
     if (__pos > __str_sz)
         this->__throw_out_of_range();
     __init(__str.data() + __pos, _VSTD::min(__n, __str_sz - __pos));
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -2060,6 +2089,9 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string(_InputIterator __first, _InputIterator __last)
 {
     __init(__first, __last);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -2070,6 +2102,9 @@
     : __r_(__a)
 {
     __init(__first, __last);
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 #ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
@@ -2079,6 +2114,9 @@
 basic_string<_CharT, _Traits, _Allocator>::basic_string(initializer_list<value_type> __il)
 {
     __init(__il.begin(), __il.end());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -2087,6 +2125,9 @@
     : __r_(__a)
 {
     __init(__il.begin(), __il.end());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__insert_c(this);
+#endif
 }
 
 #endif  // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
@@ -2094,7 +2135,9 @@
 template <class _CharT, class _Traits, class _Allocator>
 basic_string<_CharT, _Traits, _Allocator>::~basic_string()
 {
-    __invalidate_all_iterators();
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    __get_db()->__erase_c(this);
+#endif
     if (__is_long())
         __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
 }
@@ -2166,9 +2209,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign recieved nullptr");
     size_type __cap = capacity();
     if (__cap >= __n)
     {
@@ -2342,9 +2383,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::assign recieved nullptr");
     return assign(__s, traits_type::length(__s));
 }
 
@@ -2354,9 +2393,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::append recieved nullptr");
     size_type __cap = capacity();
     size_type __sz = size();
     if (__cap - __sz >= __n)
@@ -2493,9 +2530,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::append recieved nullptr");
     return append(__s, traits_type::length(__s));
 }
 
@@ -2505,9 +2540,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s, size_type __n)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::insert recieved nullptr");
     size_type __sz = size();
     if (__pos > __sz)
         this->__throw_out_of_range();
@@ -2576,13 +2609,22 @@
 >::type
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _InputIterator __first, _InputIterator __last)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+        "string::insert(iterator, range) called with an iterator not"
+        " referring to this string");
+#endif
     size_type __old_sz = size();
     difference_type __ip = __pos - begin();
     for (; __first != __last; ++__first)
         push_back(*__first);
     pointer __p = __get_pointer();
     _VSTD::rotate(__p + __ip, __p + __old_sz, __p + size());
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    return iterator(this, __p + __ip);
+#else
     return iterator(__p + __ip);
+#endif
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -2594,6 +2636,11 @@
 >::type
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+        "string::insert(iterator, range) called with an iterator not"
+        " referring to this string");
+#endif
     size_type __ip = static_cast<size_type>(__pos - begin());
     size_type __sz = size();
     size_type __cap = capacity();
@@ -2645,9 +2692,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::insert recieved nullptr");
     return insert(__pos, __s, traits_type::length(__s));
 }
 
@@ -2682,6 +2727,11 @@
 typename basic_string<_CharT, _Traits, _Allocator>::iterator
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, size_type __n, value_type __c)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+        "string::insert(iterator, n, value) called with an iterator not"
+        " referring to this string");
+#endif
     difference_type __p = __pos - begin();
     insert(static_cast<size_type>(__p), __n, __c);
     return begin() + __p;
@@ -2693,9 +2743,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::replace recieved nullptr");
     size_type __sz = size();
     if (__pos > __sz)
         this->__throw_out_of_range();
@@ -2827,9 +2875,7 @@
 basic_string<_CharT, _Traits, _Allocator>&
 basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s)
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::replace recieved nullptr");
     return replace(__pos, __n1, __s, traits_type::length(__s));
 }
 
@@ -2895,6 +2941,13 @@
 typename basic_string<_CharT, _Traits, _Allocator>::iterator
 basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __pos)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__pos) == this,
+        "string::erase(iterator) called with an iterator not"
+        " referring to this string");
+#endif
+    _LIBCPP_ASSERT(__pos != end(),
+        "string::erase(iterator) called with a non-dereferenceable iterator");
     iterator __b = begin();
     size_type __r = static_cast<size_type>(__pos - __b);
     erase(__r, 1);
@@ -2906,6 +2959,12 @@
 typename basic_string<_CharT, _Traits, _Allocator>::iterator
 basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __first, const_iterator __last)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    _LIBCPP_ASSERT(__get_const_db()->__find_c_from_i(&__first) == this,
+        "string::erase(iterator,  iterator) called with an iterator not"
+        " referring to this string");
+#endif
+    _LIBCPP_ASSERT(__first <= __last, "string::erase(first, last) called with invalid range");
     iterator __b = begin();
     size_type __r = static_cast<size_type>(__first - __b);
     erase(__r, static_cast<size_type>(__last - __first));
@@ -2917,9 +2976,7 @@
 void
 basic_string<_CharT, _Traits, _Allocator>::pop_back()
 {
-#ifdef _LIBCPP_DEBUG
-    assert(!empty());
-#endif
+    _LIBCPP_ASSERT(!empty(), "string::pop_back(): string is already empty");
     size_type __sz;
     if (__is_long())
     {
@@ -3064,9 +3121,7 @@
 typename basic_string<_CharT, _Traits, _Allocator>::const_reference
 basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos) const
 {
-#ifdef __LIBCPP_DEBUG
-    assert(__pos <= size());
-#endif
+    _LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");
     return *(data() + __pos);
 }
 
@@ -3075,9 +3130,7 @@
 typename basic_string<_CharT, _Traits, _Allocator>::reference
 basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos)
 {
-#ifdef __LIBCPP_DEBUG
-    assert(__pos < size());
-#endif
+    _LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");
     return *(__get_pointer() + __pos);
 }
 
@@ -3104,9 +3157,7 @@
 typename basic_string<_CharT, _Traits, _Allocator>::reference
 basic_string<_CharT, _Traits, _Allocator>::front()
 {
-#ifdef _LIBCPP_DEBUG
-    assert(!empty());
-#endif
+    _LIBCPP_ASSERT(!empty(), "string::front(): string is empty");
     return *__get_pointer();
 }
 
@@ -3115,9 +3166,7 @@
 typename basic_string<_CharT, _Traits, _Allocator>::const_reference
 basic_string<_CharT, _Traits, _Allocator>::front() const
 {
-#ifdef _LIBCPP_DEBUG
-    assert(!empty());
-#endif
+    _LIBCPP_ASSERT(!empty(), "string::front(): string is empty");
     return *data();
 }
 
@@ -3126,9 +3175,7 @@
 typename basic_string<_CharT, _Traits, _Allocator>::reference
 basic_string<_CharT, _Traits, _Allocator>::back()
 {
-#ifdef _LIBCPP_DEBUG
-    assert(!empty());
-#endif
+    _LIBCPP_ASSERT(!empty(), "string::back(): string is empty");
     return *(__get_pointer() + size() - 1);
 }
 
@@ -3137,9 +3184,7 @@
 typename basic_string<_CharT, _Traits, _Allocator>::const_reference
 basic_string<_CharT, _Traits, _Allocator>::back() const
 {
-#ifdef _LIBCPP_DEBUG
-    assert(!empty());
-#endif
+    _LIBCPP_ASSERT(!empty(), "string::back(): string is empty");
     return *(data() + size() - 1);
 }
 
@@ -3170,12 +3215,15 @@
         _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value ||
                    __is_nothrow_swappable<allocator_type>::value)
 {
+#if _LIBCPP_DEBUG_LEVEL >= 2
+    if (!__is_long())
+        __get_db()->__invalidate_all(this);
+    if (!__str.__is_long())
+        __get_db()->__invalidate_all(&__str);
+    __get_db()->swap(this, &__str);
+#endif
     _VSTD::swap(__r_.first(), __str.__r_.first());
     __swap_alloc(__alloc(), __str.__alloc());
-#ifdef _LIBCPP_DEBUG
-    __invalidate_all_iterators();
-    __str.__invalidate_all_iterators();
-#endif  // _LIBCPP_DEBUG
 }
 
 // find
@@ -3195,9 +3243,7 @@
                                                 size_type __pos,
                                                 size_type __n) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find(): recieved nullptr");
     size_type __sz = size();
     if (__pos > __sz || __sz - __pos < __n)
         return npos;
@@ -3226,9 +3272,7 @@
 basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s,
                                                 size_type __pos) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::find(): recieved nullptr");
     return find(__s, __pos, traits_type::length(__s));
 }
 
@@ -3255,9 +3299,7 @@
                                                  size_type __pos,
                                                  size_type __n) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::rfind(): recieved nullptr");
     size_type __sz = size();
     __pos = _VSTD::min(__pos, __sz);
     if (__n < __sz - __pos)
@@ -3287,9 +3329,7 @@
 basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s,
                                                  size_type __pos) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::rfind(): recieved nullptr");
     return rfind(__s, __pos, traits_type::length(__s));
 }
 
@@ -3323,9 +3363,7 @@
                                                          size_type __pos,
                                                          size_type __n) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_of(): recieved nullptr");
     size_type __sz = size();
     if (__pos >= __sz || __n == 0)
         return npos;
@@ -3352,9 +3390,7 @@
 basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s,
                                                          size_type __pos) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::find_first_of(): recieved nullptr");
     return find_first_of(__s, __pos, traits_type::length(__s));
 }
 
@@ -3375,9 +3411,7 @@
                                                         size_type __pos,
                                                         size_type __n) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_of(): recieved nullptr");
     if (__n != 0)
     {
         size_type __sz = size();
@@ -3411,9 +3445,7 @@
 basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s,
                                                         size_type __pos) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::find_last_of(): recieved nullptr");
     return find_last_of(__s, __pos, traits_type::length(__s));
 }
 
@@ -3434,9 +3466,7 @@
                                                              size_type __pos,
                                                              size_type __n) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_first_not_of(): recieved nullptr");
     size_type __sz = size();
     if (__pos < __sz)
     {
@@ -3464,9 +3494,7 @@
 basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s,
                                                              size_type __pos) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::find_first_not_of(): recieved nullptr");
     return find_first_not_of(__s, __pos, traits_type::length(__s));
 }
 
@@ -3496,9 +3524,7 @@
                                                             size_type __pos,
                                                             size_type __n) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::find_last_not_of(): recieved nullptr");
     size_type __sz = size();
     if (__pos < __sz)
         ++__pos;
@@ -3526,9 +3552,7 @@
 basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s,
                                                             size_type __pos) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::find_last_not_of(): recieved nullptr");
     return find_last_not_of(__s, __pos, traits_type::length(__s));
 }
 
@@ -3599,9 +3623,7 @@
 int
 basic_string<_CharT, _Traits, _Allocator>::compare(const value_type* __s) const _NOEXCEPT
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::compare(): recieved nullptr");
     return compare(0, npos, __s, traits_type::length(__s));
 }
 
@@ -3611,9 +3633,7 @@
                                                    size_type __n1,
                                                    const value_type* __s) const
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__s != nullptr, "string::compare(): recieved nullptr");
     return compare(__pos1, __n1, __s, traits_type::length(__s));
 }
 
@@ -3624,9 +3644,7 @@
                                                    const value_type* __s,
                                                    size_type __n2) const
 {
-#ifdef _LIBCPP_DEBUG
-    assert(__s != 0);
-#endif
+    _LIBCPP_ASSERT(__n2 == 0 || __s != nullptr, "string::compare(): recieved nullptr");
     size_type __sz = size();
     if (__pos1 > __sz || __n2 == npos)
         this->__throw_out_of_range();
@@ -4102,6 +4120,42 @@
 
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 
+#if _LIBCPP_DEBUG_LEVEL >= 2
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__dereferenceable(const const_iterator* __i) const
+{
+    return this->data() <= _VSTD::__to_raw_pointer(__i->base()) &&
+           _VSTD::__to_raw_pointer(__i->base()) < this->data() + this->size();
+}
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__decrementable(const const_iterator* __i) const
+{
+    return this->data() < _VSTD::__to_raw_pointer(__i->base()) &&
+           _VSTD::__to_raw_pointer(__i->base()) <= this->data() + this->size();
+}
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__addable(const const_iterator* __i, ptrdiff_t __n) const
+{
+    const value_type* __p = _VSTD::__to_raw_pointer(__i->base()) + __n;
+    return this->data() <= __p && __p <= this->data() + this->size();
+}
+
+template<class _CharT, class _Traits, class _Allocator>
+bool
+basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator* __i, ptrdiff_t __n) const
+{
+    const value_type* __p = _VSTD::__to_raw_pointer(__i->base()) + __n;
+    return this->data() <= __p && __p < this->data() + this->size();
+}
+
+#endif  // _LIBCPP_DEBUG_LEVEL >= 2
+
 #if _LIBCPP_STD_VER > 11 
 // Literal suffixes for basic_string [basic.string.literals]
 // inline // Deviation from N3690.
@@ -4140,10 +4194,7 @@
 
 _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS basic_string<char>)
 _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS basic_string<wchar_t>)
-
-extern template
-    string
-    operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
+_LIBCPP_EXTERN_TEMPLATE(string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&))
 
 _LIBCPP_END_NAMESPACE_STD