diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
--- a/libcxx/include/filesystem
+++ b/libcxx/include/filesystem
@@ -792,7 +792,7 @@
   template <class _Iter>
   static typename enable_if<__is_cpp17_forward_iterator<_Iter>::value>::type
   __append_range(__path_string& __dest, _Iter __b, _Iter __e) {
-    __dest.__append_forward_unsafe(__b, __e);
+    __dest.append(__b, __e);
   }
 
   template <class _Iter>
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -1587,23 +1587,6 @@
     return __x;
 }
 
-template <class _Iter>
-struct __libcpp_is_trivial_iterator
-    : public _LIBCPP_BOOL_CONSTANT(is_pointer<_Iter>::value) {};
-
-template <class _Iter>
-struct __libcpp_is_trivial_iterator<move_iterator<_Iter> >
-    : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {};
-
-template <class _Iter>
-struct __libcpp_is_trivial_iterator<reverse_iterator<_Iter> >
-    : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {};
-
-template <class _Iter>
-struct __libcpp_is_trivial_iterator<__wrap_iter<_Iter> >
-    : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {};
-
-
 template <class _Tp, size_t _Np>
 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
 _Tp*
diff --git a/libcxx/include/string b/libcxx/include/string
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -632,29 +632,16 @@
 
 _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __basic_string_common<true>)
 
-#ifdef _LIBCPP_NO_EXCEPTIONS
 template <class _Iter>
-struct __libcpp_string_gets_noexcept_iterator_impl : public true_type {};
-#elif defined(_LIBCPP_HAS_NO_NOEXCEPT)
-template <class _Iter>
-struct __libcpp_string_gets_noexcept_iterator_impl : public false_type {};
-#else
-template <class _Iter, bool = __is_cpp17_forward_iterator<_Iter>::value>
-struct __libcpp_string_gets_noexcept_iterator_impl : public _LIBCPP_BOOL_CONSTANT((
-    noexcept(++(declval<_Iter&>())) &&
-    is_nothrow_assignable<_Iter&, _Iter>::value &&
-    noexcept(declval<_Iter>() == declval<_Iter>()) &&
-    noexcept(*declval<_Iter>())
-)) {};
-
-template <class _Iter>
-struct __libcpp_string_gets_noexcept_iterator_impl<_Iter, false> : public false_type {};
-#endif
+struct __string_is_trivial_iterator : public false_type {};
 
+template <class _Tp>
+struct __string_is_trivial_iterator<_Tp*>
+    : public is_arithmetic<_Tp> {};
 
 template <class _Iter>
-struct __libcpp_string_gets_noexcept_iterator
-    : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value || __libcpp_string_gets_noexcept_iterator_impl<_Iter>::value) {};
+struct __string_is_trivial_iterator<__wrap_iter<_Iter> >
+    : public __string_is_trivial_iterator<_Iter> {};
 
 template <class _CharT, class _Traits, class _Tp>
 struct __can_be_converted_to_string_view : public _BoolConstant<
@@ -1048,20 +1035,16 @@
     _LIBCPP_INLINE_VISIBILITY
     void __append_default_init(size_type __n);
 
-    template <class _ForwardIterator>
-    _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
-    basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator);
     template<class _InputIterator>
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     _EnableIf
         <
-            __is_exactly_cpp17_input_iterator<_InputIterator>::value
-                || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
+            __is_exactly_cpp17_input_iterator<_InputIterator>::value,
             basic_string&
         >
     _LIBCPP_INLINE_VISIBILITY
     append(_InputIterator __first, _InputIterator __last) {
-      const basic_string __temp (__first, __last, __alloc());
+      const basic_string __temp(__first, __last, __alloc());
       append(__temp.data(), __temp.size());
       return *this;
     }
@@ -1069,14 +1052,11 @@
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     _EnableIf
         <
-            __is_cpp17_forward_iterator<_ForwardIterator>::value
-                && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
+            __is_cpp17_forward_iterator<_ForwardIterator>::value,
             basic_string&
         >
     _LIBCPP_INLINE_VISIBILITY
-    append(_ForwardIterator __first, _ForwardIterator __last) {
-      return __append_forward_unsafe(__first, __last);
-    }
+    append(_ForwardIterator __first, _ForwardIterator __last);
 
 #ifndef _LIBCPP_CXX03_LANG
     _LIBCPP_INLINE_VISIBILITY
@@ -1124,8 +1104,7 @@
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     _EnableIf
         <
-           __is_exactly_cpp17_input_iterator<_InputIterator>::value
-                || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
+            __is_exactly_cpp17_input_iterator<_InputIterator>::value,
             basic_string&
         >
         assign(_InputIterator __first, _InputIterator __last);
@@ -1133,8 +1112,7 @@
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     _EnableIf
         <
-            __is_cpp17_forward_iterator<_ForwardIterator>::value
-                 && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
+            __is_cpp17_forward_iterator<_ForwardIterator>::value,
             basic_string&
         >
         assign(_ForwardIterator __first, _ForwardIterator __last);
@@ -1175,8 +1153,7 @@
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     _EnableIf
         <
-           __is_exactly_cpp17_input_iterator<_InputIterator>::value
-                || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
+            __is_exactly_cpp17_input_iterator<_InputIterator>::value,
             iterator
         >
         insert(const_iterator __pos, _InputIterator __first, _InputIterator __last);
@@ -1184,8 +1161,7 @@
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     _EnableIf
         <
-            __is_cpp17_forward_iterator<_ForwardIterator>::value
-                 && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
+            __is_cpp17_forward_iterator<_ForwardIterator>::value,
             iterator
         >
         insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last);
@@ -1721,6 +1697,13 @@
     _LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators();
     _LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(size_type);
 
+    template<class _Tp>
+    _LIBCPP_INLINE_VISIBILITY
+    bool __addr_in_range(_Tp&& __t) const {
+        const volatile void *__p = _VSTD::addressof(__t);
+        return data() <= __p && __p <= data() + size();
+    }
+
     friend basic_string operator+<>(const basic_string&, const basic_string&);
     friend basic_string operator+<>(const value_type*, const basic_string&);
     friend basic_string operator+<>(value_type, const basic_string&);
@@ -2175,9 +2158,23 @@
         __set_long_cap(__cap+1);
         __set_long_size(__sz);
     }
+
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    try
+    {
+#endif  // _LIBCPP_NO_EXCEPTIONS
     for (; __first != __last; ++__first, (void) ++__p)
         traits_type::assign(*__p, *__first);
     traits_type::assign(*__p, value_type());
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    }
+    catch (...)
+    {
+        if (__is_long())
+            __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
+        throw;
+    }
+#endif  // _LIBCPP_NO_EXCEPTIONS
 }
 
 template <class _CharT, class _Traits, class _Allocator>
@@ -2470,8 +2467,7 @@
 template<class _InputIterator>
 _EnableIf
 <
-     __is_exactly_cpp17_input_iterator <_InputIterator>::value
-          || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
+     __is_exactly_cpp17_input_iterator<_InputIterator>::value,
     basic_string<_CharT, _Traits, _Allocator>&
 >
 basic_string<_CharT, _Traits, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
@@ -2485,26 +2481,36 @@
 template<class _ForwardIterator>
 _EnableIf
 <
-    __is_cpp17_forward_iterator<_ForwardIterator>::value
-         && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
+    __is_cpp17_forward_iterator<_ForwardIterator>::value,
     basic_string<_CharT, _Traits, _Allocator>&
 >
 basic_string<_CharT, _Traits, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
 {
-    size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
     size_type __cap = capacity();
-    if (__cap < __n)
+    size_type __n = __string_is_trivial_iterator<_ForwardIterator>::value ?
+        static_cast<size_type>(_VSTD::distance(__first, __last)) : 0;
+
+    if (__string_is_trivial_iterator<_ForwardIterator>::value &&
+        (__cap >= __n || !__addr_in_range(*__first)))
     {
-        size_type __sz = size();
-        __grow_by(__cap, __n - __cap, __sz, 0, __sz);
+        if (__cap < __n)
+        {
+            size_type __sz = size();
+            __grow_by(__cap, __n - __cap, __sz, 0, __sz);
+        }
+        else
+            __invalidate_iterators_past(__n);
+        pointer __p = __get_pointer();
+        for (; __first != __last; ++__first, ++__p)
+            traits_type::assign(*__p, *__first);
+        traits_type::assign(*__p, value_type());
+        __set_size(__n);
     }
     else
-        __invalidate_iterators_past(__n);
-    pointer __p = __get_pointer();
-    for (; __first != __last; ++__first, ++__p)
-        traits_type::assign(*__p, *__first);
-    traits_type::assign(*__p, value_type());
-    __set_size(__n);
+    {
+        const basic_string __temp(__first, __last, __alloc());
+        assign(__temp.data(), __temp.size());
+    }
     return *this;
 }
 
@@ -2651,39 +2657,23 @@
     traits_type::assign(*++__p, value_type());
 }
 
-template <class _Tp>
-bool __ptr_in_range (const _Tp* __p, const _Tp* __first, const _Tp* __last)
-{
-    return __first <= __p && __p < __last;
-}
-
-template <class _Tp1, class _Tp2>
-bool __ptr_in_range (const _Tp1*, const _Tp2*, const _Tp2*)
-{
-    return false;
-}
-
 template <class _CharT, class _Traits, class _Allocator>
 template<class _ForwardIterator>
-basic_string<_CharT, _Traits, _Allocator>&
-basic_string<_CharT, _Traits, _Allocator>::__append_forward_unsafe(
+_EnableIf
+<
+    __is_cpp17_forward_iterator<_ForwardIterator>::value,
+    basic_string<_CharT, _Traits, _Allocator>&
+>
+basic_string<_CharT, _Traits, _Allocator>::append(
     _ForwardIterator __first, _ForwardIterator __last)
 {
-    static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
-                  "function requires a ForwardIterator");
     size_type __sz = size();
     size_type __cap = capacity();
     size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
     if (__n)
     {
-        typedef typename iterator_traits<_ForwardIterator>::reference _CharRef;
-        _CharRef __tmp_ref = *__first;
-        if (__ptr_in_range(_VSTD::addressof(__tmp_ref), data(), data() + size()))
-        {
-            const basic_string __temp (__first, __last, __alloc());
-            append(__temp.data(), __temp.size());
-        }
-        else
+        if (__string_is_trivial_iterator<_ForwardIterator>::value &&
+            !__addr_in_range(*__first))
         {
             if (__cap - __sz < __n)
                 __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0);
@@ -2693,6 +2683,11 @@
             traits_type::assign(*__p, value_type());
             __set_size(__sz + __n);
         }
+        else
+        {
+            const basic_string __temp(__first, __last, __alloc());
+            append(__temp.data(), __temp.size());
+        }
     }
     return *this;
 }
@@ -2808,8 +2803,7 @@
 template<class _InputIterator>
 _EnableIf
 <
-   __is_exactly_cpp17_input_iterator<_InputIterator>::value
-        || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
+   __is_exactly_cpp17_input_iterator<_InputIterator>::value,
    typename basic_string<_CharT, _Traits, _Allocator>::iterator
 >
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _InputIterator __first, _InputIterator __last)
@@ -2827,8 +2821,7 @@
 template<class _ForwardIterator>
 _EnableIf
 <
-    __is_cpp17_forward_iterator<_ForwardIterator>::value
-        && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
+    __is_cpp17_forward_iterator<_ForwardIterator>::value,
     typename basic_string<_CharT, _Traits, _Allocator>::iterator
 >
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last)
@@ -2842,34 +2835,35 @@
     size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
     if (__n)
     {
-        typedef typename iterator_traits<_ForwardIterator>::reference _CharRef;
-        _CharRef __tmp_char = *__first;
-        if (__ptr_in_range(_VSTD::addressof(__tmp_char), data(), data() + size()))
+        if (__string_is_trivial_iterator<_ForwardIterator>::value &&
+            !__addr_in_range(*__first))
         {
-            const basic_string __temp(__first, __last, __alloc());
-            return insert(__pos, __temp.data(), __temp.data() + __temp.size());
-        }
-
-        size_type __sz = size();
-        size_type __cap = capacity();
-        value_type* __p;
-        if (__cap - __sz >= __n)
-        {
-            __p = _VSTD::__to_address(__get_pointer());
-            size_type __n_move = __sz - __ip;
-            if (__n_move != 0)
-                traits_type::move(__p + __ip + __n, __p + __ip, __n_move);
+            size_type __sz = size();
+            size_type __cap = capacity();
+            value_type* __p;
+            if (__cap - __sz >= __n)
+            {
+                __p = _VSTD::__to_address(__get_pointer());
+                size_type __n_move = __sz - __ip;
+                if (__n_move != 0)
+                    traits_type::move(__p + __ip + __n, __p + __ip, __n_move);
+            }
+            else
+            {
+                __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n);
+                __p = _VSTD::__to_address(__get_long_pointer());
+            }
+            __sz += __n;
+            __set_size(__sz);
+            traits_type::assign(__p[__sz], value_type());
+            for (__p += __ip; __first != __last; ++__p, ++__first)
+                traits_type::assign(*__p, *__first);
         }
         else
         {
-            __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n);
-            __p = _VSTD::__to_address(__get_long_pointer());
+            const basic_string __temp(__first, __last, __alloc());
+            return insert(__pos, __temp.data(), __temp.data() + __temp.size());
         }
-        __sz += __n;
-        __set_size(__sz);
-        traits_type::assign(__p[__sz], value_type());
-        for (__p += __ip; __first != __last; ++__p, ++__first)
-            traits_type::assign(*__p, *__first);
     }
     return begin() + __ip;
 }
diff --git a/libcxx/test/libcxx/iterators/trivial_iterators.pass.cpp b/libcxx/test/libcxx/iterators/trivial_iterators.pass.cpp
deleted file mode 100644
--- a/libcxx/test/libcxx/iterators/trivial_iterators.pass.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-
-// <iterator>
-
-// __libcpp_is_trivial_iterator<Tp>
-
-// __libcpp_is_trivial_iterator determines if an iterator is a "trivial" one,
-// that can be used w/o worrying about its operations throwing exceptions.
-// Pointers are trivial iterators. Libc++ has three "iterator wrappers":
-// reverse_iterator, move_iterator, and __wrap_iter. If the underlying iterator
-// is trivial, then those are as well.
-//
-
-#include <iterator>
-#include <cassert>
-#include <string>
-#include <vector>
-#include <initializer_list>
-
-#include "test_macros.h"
-#include "test_iterators.h"
-
-#if TEST_STD_VER >= 11
-#define DELETE_FUNCTION = delete
-#else
-#define DELETE_FUNCTION
-#endif
-
-class T;  // incomplete
-
-class my_input_iterator_tag : public std::input_iterator_tag {};
-
-template <class It>
-class my_input_iterator
-{
-    It it_;
-
-    template <class U> friend class my_input_iterator;
-public:
-    typedef          my_input_iterator_tag                     iterator_category;
-    typedef typename std::iterator_traits<It>::value_type      value_type;
-    typedef typename std::iterator_traits<It>::difference_type difference_type;
-    typedef It                                                 pointer;
-    typedef typename std::iterator_traits<It>::reference       reference;
-
-    It base() const {return it_;}
-
-    my_input_iterator() : it_() {}
-    explicit my_input_iterator(It it) : it_(it) {}
-    template <class U>
-        my_input_iterator(const my_input_iterator<U>& u) :it_(u.it_) {}
-
-    reference operator*() const {return *it_;}
-    pointer operator->() const {return it_;}
-
-    my_input_iterator& operator++() {++it_; return *this;}
-    my_input_iterator operator++(int)
-        {my_input_iterator tmp(*this); ++(*this); return tmp;}
-
-    friend bool operator==(const my_input_iterator& x, const my_input_iterator& y)
-        {return x.it_ == y.it_;}
-    friend bool operator!=(const my_input_iterator& x, const my_input_iterator& y)
-        {return !(x == y);}
-
-    template <class T>
-    void operator,(T const &) DELETE_FUNCTION;
-};
-
-template <class T, class U>
-inline
-bool
-operator==(const my_input_iterator<T>& x, const my_input_iterator<U>& y)
-{
-    return x.base() == y.base();
-}
-
-template <class T, class U>
-inline
-bool
-operator!=(const my_input_iterator<T>& x, const my_input_iterator<U>& y)
-{
-    return !(x == y);
-}
-
-
-int main(int, char**)
-{
-//  basic tests
-    static_assert(( std::__libcpp_is_trivial_iterator<char *>::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<const char *>::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<int *>::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<T *>::value), "");
-
-    static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<char *> >      ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<const char *> >::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<int *> >       ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<T *> >         ::value), "");
-
-    static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<char *> >      ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<const char *> >::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<int *> >       ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<T *> >         ::value), "");
-
-    static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<char *> >      ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<const char *> >::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<int *> >       ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<T *> >         ::value), "");
-
-    static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<std::__wrap_iter<char *> > > ::value), "");
-
-//  iterators in the libc++ test suite
-    static_assert((!std::__libcpp_is_trivial_iterator<output_iterator       <char *> >::value), "");
-    static_assert((!std::__libcpp_is_trivial_iterator<input_iterator        <char *> >::value), "");
-    static_assert((!std::__libcpp_is_trivial_iterator<forward_iterator      <char *> >::value), "");
-    static_assert((!std::__libcpp_is_trivial_iterator<bidirectional_iterator<char *> >::value), "");
-    static_assert((!std::__libcpp_is_trivial_iterator<random_access_iterator<char *> >::value), "");
-    static_assert((!std::__libcpp_is_trivial_iterator<ThrowingIterator      <char *> >::value), "");
-    static_assert((!std::__libcpp_is_trivial_iterator<NonThrowingIterator   <char *> >::value), "");
-
-
-//  Iterator classification
-    static_assert(( std::__is_cpp17_input_iterator        <char *>::value), "" );
-    static_assert(( std::__is_cpp17_forward_iterator      <char *>::value), "" );
-    static_assert(( std::__is_cpp17_bidirectional_iterator<char *>::value), "" );
-    static_assert(( std::__is_cpp17_random_access_iterator<char *>::value), "" );
-    static_assert(( std::__is_cpp17_contiguous_iterator   <char *>::value), "" );
-    static_assert((!std::__is_exactly_cpp17_input_iterator<char *>::value), "" );
-
-    static_assert(( std::__is_cpp17_input_iterator        <input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_forward_iterator      <input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_bidirectional_iterator<input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_random_access_iterator<input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_contiguous_iterator   <input_iterator<char *> >::value), "" );
-    static_assert(( std::__is_exactly_cpp17_input_iterator<input_iterator<char *> >::value), "" );
-
-    static_assert(( std::__is_cpp17_input_iterator        <forward_iterator<char *> >::value), "" );
-    static_assert(( std::__is_cpp17_forward_iterator      <forward_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_bidirectional_iterator<forward_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_random_access_iterator<forward_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_contiguous_iterator   <forward_iterator<char *> >::value), "" );
-    static_assert((!std::__is_exactly_cpp17_input_iterator<forward_iterator<char *> >::value), "" );
-
-    static_assert(( std::__is_cpp17_input_iterator        <bidirectional_iterator<char *> >::value), "" );
-    static_assert(( std::__is_cpp17_forward_iterator      <bidirectional_iterator<char *> >::value), "" );
-    static_assert(( std::__is_cpp17_bidirectional_iterator<bidirectional_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_random_access_iterator<bidirectional_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_contiguous_iterator   <bidirectional_iterator<char *> >::value), "" );
-    static_assert((!std::__is_exactly_cpp17_input_iterator<bidirectional_iterator<char *> >::value), "" );
-
-    static_assert(( std::__is_cpp17_input_iterator        <random_access_iterator<char *> >::value), "" );
-    static_assert(( std::__is_cpp17_forward_iterator      <random_access_iterator<char *> >::value), "" );
-    static_assert(( std::__is_cpp17_bidirectional_iterator<random_access_iterator<char *> >::value), "" );
-    static_assert(( std::__is_cpp17_random_access_iterator<random_access_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_contiguous_iterator   <random_access_iterator<char *> >::value), "" );
-    static_assert((!std::__is_exactly_cpp17_input_iterator<random_access_iterator<char *> >::value), "" );
-
-    static_assert(( std::__is_cpp17_input_iterator        <my_input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_forward_iterator      <my_input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_bidirectional_iterator<my_input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_random_access_iterator<my_input_iterator<char *> >::value), "" );
-    static_assert((!std::__is_cpp17_contiguous_iterator   <my_input_iterator<char *> >::value), "" );
-    static_assert(( std::__is_exactly_cpp17_input_iterator<my_input_iterator<char *> >::value), "" );
-
-//
-//  iterators from libc++'s containers
-//
-
-//  vector
-    static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::const_iterator>        ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::reverse_iterator>      ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::const_reverse_iterator>::value), "");
-
-//  string
-    static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::const_iterator>        ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::reverse_iterator>      ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::const_reverse_iterator>::value), "");
-
-#if TEST_STD_VER >= 11
-//  Initializer list  (which has no reverse iterators)
-    static_assert(( std::__libcpp_is_trivial_iterator<std::initializer_list<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_is_trivial_iterator<std::initializer_list<char>::const_iterator>        ::value), "");
-#endif
-
-
-  return 0;
-}
diff --git a/libcxx/test/libcxx/strings/iterators.exceptions.pass.cpp b/libcxx/test/libcxx/strings/iterators.exceptions.pass.cpp
deleted file mode 100644
--- a/libcxx/test/libcxx/strings/iterators.exceptions.pass.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// <iterator>
-
-// __libcpp_is_trivial_iterator<Tp>
-
-// __libcpp_string_gets_noexcept_iterator determines if an iterator can be used
-// w/o worrying about whether or not certain operations can throw.
-// This gives us a "fast path for string operations"
-//
-
-#include <iterator>
-#include <cassert>
-#include <string>
-#include <vector>
-#include <initializer_list>
-
-#include "test_macros.h"
-#include "test_iterators.h"
-
-#ifndef TEST_HAS_NO_EXCEPTIONS
-static const bool expected = false;
-#else
-// Under -fno-exceptions all noexcept expressions are trivially true, so
-// any check for a noexcept returning false must actually check for it being
-// true.
-static const bool expected = true;
-#endif
-
-int main(int, char**)
-{
-//  basic tests
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<char *>::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<const char *>::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<char *> >      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<const char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<char *> >      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<const char *> >::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<char *> >      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<const char *> >::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<std::__wrap_iter<char *> > > ::value), "");
-
-//  iterators in the libc++ test suite
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<output_iterator       <char *> >::value == expected, "");
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<input_iterator        <char *> >::value == expected, "");
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<forward_iterator      <char *> >::value == expected, "");
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<bidirectional_iterator<char *> >::value == expected, "");
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<random_access_iterator<char *> >::value == expected, "");
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<ThrowingIterator      <char *> >::value == expected, "");
-
-#if TEST_STD_VER >= 11
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<NonThrowingIterator   <char *> >::value), "");
-#else
-    static_assert(std::__libcpp_string_gets_noexcept_iterator<NonThrowingIterator   <char *> >::value == expected, "");
-#endif
-
-//
-//  iterators from libc++'s containers
-//
-
-//  string
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_iterator>        ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::reverse_iterator>      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_reverse_iterator>::value), "");
-
-//  vector
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_iterator>        ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::reverse_iterator>      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_reverse_iterator>::value), "");
-
-#if TEST_STD_VER >= 11
-//  Initializer list  (which has no reverse iterators)
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::const_iterator>        ::value), "");
-#endif
-
-  return 0;
-}
diff --git a/libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp b/libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp
deleted file mode 100644
--- a/libcxx/test/libcxx/strings/iterators.noexcept.pass.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-
-// <iterator>
-
-// __libcpp_is_trivial_iterator<Tp>
-
-// __libcpp_string_gets_noexcept_iterator determines if an iterator can be used
-// w/o worrying about whether or not certain operations can throw.
-// This gives us a "fast path for string operations".
-//
-// When exceptions are disabled, all iterators should get this "fast path"
-//
-
-// ADDITIONAL_COMPILE_FLAGS: -fno-exceptions
-
-#include <iterator>
-#include <cassert>
-#include <string>
-#include <vector>
-#include <initializer_list>
-
-#include "test_macros.h"
-#include "test_iterators.h"
-
-int main(int, char**)
-{
-//  basic tests
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<char *>::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<const char *>::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<char *> >      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<const char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<char *> >      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<const char *> >::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<char *> >      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<const char *> >::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<std::__wrap_iter<char *> > > ::value), "");
-
-//  iterators in the libc++ test suite
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<output_iterator       <char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<input_iterator        <char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<forward_iterator      <char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<bidirectional_iterator<char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<random_access_iterator<char *> >::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<ThrowingIterator      <char *> >::value), "");
-
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<NonThrowingIterator   <char *> >::value), "");
-
-//
-//  iterators from libc++'s containers
-//
-
-//  string
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_iterator>        ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::reverse_iterator>      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_reverse_iterator>::value), "");
-
-//  vector
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_iterator>        ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::reverse_iterator>      ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_reverse_iterator>::value), "");
-
-#if TEST_STD_VER >= 11
-//  Initializer list  (which has no reverse iterators)
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::iterator>              ::value), "");
-    static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::const_iterator>        ::value), "");
-#endif
-
-  return 0;
-}
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <string>
+
+#include <cassert>
+#include <string>
+
+struct Incomplete;
+template<class T> struct Holder { T t; };
+
+template<class T>
+struct Charlike {
+    char ch_;
+    Charlike(char ch) : ch_(ch) {}
+    operator char() const { return ch_; }
+};
+
+int main(int, char**)
+{
+    std::string s;
+    Charlike<Holder<Incomplete> > a[] = {'m', 'a', 'h', 'i'};
+    s.append(a, a+4);
+    s.assign(a, a+4);
+    s.insert(s.begin(), a, a+4);
+    s.replace(s.begin(), s.begin()+4, a, a+4);
+    assert(s == "mahimahi");
+
+    return 0;
+}
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
@@ -28,18 +28,27 @@
 }
 
 #ifndef TEST_HAS_NO_EXCEPTIONS
+struct Widget { operator char() const { throw 42; } };
+
 template <class S, class It>
 void
 test_exceptions(S s, It first, It last)
 {
-    S aCopy = s;
+    S original = s;
+    typename S::iterator begin = s.begin();
+    typename S::iterator end = s.end();
+
     try {
         s.append(first, last);
         assert(false);
-        }
-    catch (...) {}
+    } catch (...) {}
+
+    // Part of "no effects" is that iterators and pointers
+    // into the string must not have been invalidated.
     LIBCPP_ASSERT(s.__invariants());
-    assert(s == aCopy);
+    assert(s == original);
+    assert(s.begin() == begin);
+    assert(s.end() == end);
 }
 #endif
 
@@ -176,6 +185,9 @@
     test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter());
     test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter());
+
+    Widget w[100];
+    test_exceptions(S(), w, w+100);
     }
 #endif
 
@@ -204,6 +216,23 @@
     assert(s == "ABCD");
     }
 
+    { // regression-test appending to self in sneaky ways
+    std::string s_short = "hello";
+    std::string s_long = "Lorem ipsum dolor sit amet, consectetur/";
+    std::string s_othertype = "hello";
+    const unsigned char *first = reinterpret_cast<const unsigned char*>(s_othertype.data());
+    std::string s_sneaky = "hello";
+
+    test(s_short, s_short.data() + s_short.size(), s_short.data() + s_short.size() + 1,
+         std::string("hello\0", 6));
+    test(s_long, s_long.data() + s_long.size(), s_long.data() + s_long.size() + 1,
+         std::string("Lorem ipsum dolor sit amet, consectetur/\0", 41));
+    test(s_othertype, first + 2, first + 5, std::string("hellollo"));
+
+    s_sneaky.reserve(12);
+    test(s_sneaky, s_sneaky.data(), s_sneaky.data() + 6, std::string("hellohello\0", 11));
+    }
+
   { // test with a move iterator that returns char&&
     typedef forward_iterator<const char*> It;
     typedef std::move_iterator<It> MoveIt;
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
@@ -28,18 +28,27 @@
 }
 
 #ifndef TEST_HAS_NO_EXCEPTIONS
+struct Widget { operator char() const { throw 42; } };
+
 template <class S, class It>
 void
 test_exceptions(S s, It first, It last)
 {
-    S aCopy = s;
+    S original = s;
+    typename S::iterator begin = s.begin();
+    typename S::iterator end = s.end();
+
     try {
         s.assign(first, last);
         assert(false);
-    }
-    catch (...) {}
+    } catch (...) {}
+
+    // Part of "no effects" is that iterators and pointers
+    // into the string must not have been invalidated.
     LIBCPP_ASSERT(s.__invariants());
-    assert(s == aCopy);
+    assert(s == original);
+    assert(s.begin() == begin);
+    assert(s.end() == end);
 }
 #endif
 
@@ -176,6 +185,9 @@
     test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter());
     test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter());
+
+    Widget w[100];
+    test_exceptions(S(), w, w+100);
     }
 #endif
 
@@ -205,5 +217,12 @@
     assert(s == "ABCD");
     }
 
-  return 0;
+    { // regression-test assigning to self in sneaky ways
+    std::string sneaky = "hello";
+    sneaky.resize(sneaky.capacity(), 'x');
+    std::string expected = sneaky + std::string(1, '\0');
+    test(sneaky, sneaky.data(), sneaky.data() + sneaky.size() + 1, expected);
+    }
+
+    return 0;
 }
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
@@ -30,19 +30,29 @@
 }
 
 #ifndef TEST_HAS_NO_EXCEPTIONS
+struct Widget { operator char() const { throw 42; } };
+
 template <class S, class It>
 void
 test_exceptions(S s, typename S::difference_type pos, It first, It last)
 {
     typename S::const_iterator p = s.cbegin() + pos;
-    S aCopy = s;
+
+    S original = s;
+    typename S::iterator begin = s.begin();
+    typename S::iterator end = s.end();
+
     try {
         s.insert(p, first, last);
         assert(false);
-        }
-    catch (...) {}
+    } catch (...) {}
+
+    // Part of "no effects" is that iterators and pointers
+    // into the string must not have been invalidated.
     LIBCPP_ASSERT(s.__invariants());
-    assert(s == aCopy);
+    assert(s == original);
+    assert(s.begin() == begin);
+    assert(s.end() == end);
 }
 #endif
 
@@ -153,6 +163,9 @@
     test_exceptions(S(), 0, TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S(), 0, TIter(s, s+10, 5, TIter::TADereference), TIter());
     test_exceptions(S(), 0, TIter(s, s+10, 6, TIter::TAComparison), TIter());
+
+    Widget w[100];
+    test_exceptions(S(), 0, w, w+100);
     }
 #endif
 
@@ -181,6 +194,19 @@
     assert(s == "ABCD");
     }
 
+    { // regression-test inserting into self in sneaky ways
+    std::string s_short = "hello";
+    std::string s_long = "Lorem ipsum dolor sit amet, consectetur/";
+    std::string s_othertype = "hello";
+    const unsigned char *first = reinterpret_cast<const unsigned char*>(s_othertype.data());
+
+    test(s_short, 0, s_short.data() + s_short.size(), s_short.data() + s_short.size() + 1,
+         std::string("\0hello", 6));
+    test(s_long, 0, s_long.data() + s_long.size(), s_long.data() + s_long.size() + 1,
+         std::string("\0Lorem ipsum dolor sit amet, consectetur/", 41));
+    test(s_othertype, 1, first + 2, first + 5, std::string("hlloello"));
+    }
+
   { // test with a move iterator that returns char&&
     typedef input_iterator<const char*> It;
     typedef std::move_iterator<It> MoveIt;
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
@@ -36,20 +36,30 @@
 }
 
 #ifndef TEST_HAS_NO_EXCEPTIONS
+struct Widget { operator char() const { throw 42; } };
+
 template <class S, class It>
 void
 test_exceptions(S s, typename S::size_type pos1, typename S::size_type n1, It f, It l)
 {
     typename S::const_iterator first = s.begin() + pos1;
     typename S::const_iterator last = s.begin() + pos1 + n1;
-    S aCopy = s;
+
+    S original = s;
+    typename S::iterator begin = s.begin();
+    typename S::iterator end = s.end();
+
     try {
         s.replace(first, last, f, l);
         assert(false);
-        }
-    catch (...) {}
+    } catch (...) {}
+
+    // Part of "no effects" is that iterators and pointers
+    // into the string must not have been invalidated.
     LIBCPP_ASSERT(s.__invariants());
-    assert(s == aCopy);
+    assert(s == original);
+    assert(s.begin() == begin);
+    assert(s.end() == end);
 }
 #endif
 
@@ -1005,6 +1015,9 @@
     test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 4, TIter::TAIncrement), TIter());
     test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 5, TIter::TADereference), TIter());
     test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 6, TIter::TAComparison), TIter());
+
+    Widget w[100];
+    test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, w, w+100);
     }
 #endif