diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 384e5fdcdc996ee15d1f131e87a2b0c4d4903410..751b7ad119b0273c2950e33351ee9e8f936bec8f 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -308,51 +308,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __a;
     }
 
-  // Fallback implementation of the function in bits/stl_iterator.h used to
-  // remove the __normal_iterator wrapper. See copy, fill, ...
-  template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR
-    inline _Iterator
-    __niter_base(_Iterator __it)
-    _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
-    { return __it; }
-
-#if __cplusplus < 201103L
-  template<typename _Ite, typename _Seq>
-    _Ite
-    __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
-		 std::random_access_iterator_tag>&);
-
- template<typename _Ite, typename _Cont, typename _Seq>
-    _Ite
-    __niter_base(const ::__gnu_debug::_Safe_iterator<
-		 ::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq,
-		 std::random_access_iterator_tag>&);
-#else
-  template<typename _Ite, typename _Seq>
-    _GLIBCXX20_CONSTEXPR
-    decltype(std::__niter_base(std::declval<_Ite>()))
-    __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
-		 std::random_access_iterator_tag>&)
-    noexcept(std::is_nothrow_copy_constructible<_Ite>::value);
-#endif
-
-  // Reverse the __niter_base transformation to get a
-  // __normal_iterator back again (this assumes that __normal_iterator
-  // is only used to wrap random access iterators, like pointers).
-  template<typename _From, typename _To>
-    _GLIBCXX20_CONSTEXPR
-    inline _From
-    __niter_wrap(_From __from, _To __res)
-    { return __from + (std::__niter_base(__res) - std::__niter_base(__from)); }
-
-  // No need to wrap, iterator already has the right type.
-  template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR
-    inline _Iterator
-    __niter_wrap(const _Iterator&, _Iterator __res)
-    { return __res; }
-
   // All of these auxiliary structs serve two purposes.  (1) Replace
   // calls to copy with memmove whenever possible.  (Memmove, not memcpy,
   // because the input and output ranges are permitted to overlap.)
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index 28a600c81cb25190efbe26b11ae08001a5c94b06..be3fa6f7a349e7c8ffcd44b2412dc2525600f2d2 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -654,24 +654,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #  endif // C++20
 # endif // __glibcxx_make_reverse_iterator
 
-  template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR
-    auto
-    __niter_base(reverse_iterator<_Iterator> __it)
-    -> decltype(__make_reverse_iterator(__niter_base(__it.base())))
-    { return __make_reverse_iterator(__niter_base(__it.base())); }
-
   template<typename _Iterator>
     struct __is_move_iterator<reverse_iterator<_Iterator> >
       : __is_move_iterator<_Iterator>
     { };
-
-  template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR
-    auto
-    __miter_base(reverse_iterator<_Iterator> __it)
-    -> decltype(__make_reverse_iterator(__miter_base(__it.base())))
-    { return __make_reverse_iterator(__miter_base(__it.base())); }
 #endif // C++11
 
   // 24.4.2.2.1 back_insert_iterator
@@ -1336,19 +1322,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); }
 
 _GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
+} // namespace __gnu_cxx
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX20_CONSTEXPR
-    _Iterator
-    __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it)
-    _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
-    { return __it.base(); }
-
 #if __cplusplus >= 201103L && __cplusplus <= 201703L
   // Need to overload __to_address because the pointer_traits primary template
   // will deduce element_type of __normal_iterator<T*, C> as T* rather than T.
@@ -1820,13 +1799,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __make_move_if_noexcept_iterator(_Tp* __i)
     { return _ReturnType(__i); }
 
-  template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR
-    auto
-    __niter_base(move_iterator<_Iterator> __it)
-    -> decltype(make_move_iterator(__niter_base(__it.base())))
-    { return make_move_iterator(__niter_base(__it.base())); }
-
   template<typename _Iterator>
     struct __is_move_iterator<move_iterator<_Iterator> >
     {
@@ -1834,12 +1806,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef __true_type __type;
     };
 
-  template<typename _Iterator>
-    _GLIBCXX20_CONSTEXPR
-    auto
-    __miter_base(move_iterator<_Iterator> __it)
-    -> decltype(__miter_base(__it.base()))
-    { return __miter_base(__it.base()); }
 
 #define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter) std::make_move_iterator(_Iter)
 #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) \
@@ -2985,6 +2951,108 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// @} group iterators
 
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+namespace __gnu_debug
+{
+  template<typename _Iterator, typename _Sequence, typename _Category>
+    class _Safe_iterator;
+}
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  /// @cond undocumented
+
+  // Unwrap a __normal_iterator to get the underlying iterator
+  // (usually a pointer). See uses in std::copy, std::fill, etc.
+  template<typename _Iterator, typename _Container>
+    _GLIBCXX20_CONSTEXPR
+    _Iterator
+    __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it)
+    _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
+    { return __it.base(); }
+
+  // Fallback implementation used for iterators that can't be unwrapped.
+  template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
+    inline _Iterator
+    __niter_base(_Iterator __it)
+    _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
+    { return __it; }
+
+  // Overload for _Safe_iterator needs to be declared before uses of
+  // std::__niter_base because we call it qualified so isn't found by ADL.
+#if __cplusplus < 201103L
+  template<typename _Ite, typename _Seq>
+    _Ite
+    __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+		 std::random_access_iterator_tag>&);
+
+ template<typename _Ite, typename _Cont, typename _Seq>
+    _Ite
+    __niter_base(const ::__gnu_debug::_Safe_iterator<
+		 ::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq,
+		 std::random_access_iterator_tag>&);
+#else
+  template<typename _Ite, typename _Seq>
+    _GLIBCXX20_CONSTEXPR
+    decltype(std::__niter_base(std::declval<_Ite>()))
+    __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+		 std::random_access_iterator_tag>&)
+    noexcept(std::is_nothrow_copy_constructible<_Ite>::value);
+#endif
+
+#if __cplusplus >= 201103L
+  template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
+    auto
+    __niter_base(reverse_iterator<_Iterator> __it)
+    -> decltype(__make_reverse_iterator(__niter_base(__it.base())))
+    { return __make_reverse_iterator(__niter_base(__it.base())); }
+
+  template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
+    auto
+    __niter_base(move_iterator<_Iterator> __it)
+    -> decltype(make_move_iterator(__niter_base(__it.base())))
+    { return make_move_iterator(__niter_base(__it.base())); }
+
+  template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
+    auto
+    __miter_base(reverse_iterator<_Iterator> __it)
+    -> decltype(__make_reverse_iterator(__miter_base(__it.base())))
+    { return __make_reverse_iterator(__miter_base(__it.base())); }
+
+  template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
+    auto
+    __miter_base(move_iterator<_Iterator> __it)
+    -> decltype(__miter_base(__it.base()))
+    { return __miter_base(__it.base()); }
+#endif
+
+  // Reverse the __niter_base transformation to get a __normal_iterator
+  // back again (this assumes that __normal_iterator is only used to wrap
+  // random access iterators, like pointers).
+  // All overloads of std::__niter_base must be declared before this.
+  template<typename _From, typename _To>
+    _GLIBCXX20_CONSTEXPR
+    inline _From
+    __niter_wrap(_From __from, _To __res)
+    { return __from + (std::__niter_base(__res) - std::__niter_base(__from)); }
+
+  // No need to wrap, iterator already has the right type.
+  template<typename _Iterator>
+    _GLIBCXX20_CONSTEXPR
+    inline _Iterator
+    __niter_wrap(const _Iterator&, _Iterator __res)
+    { return __res; }
+
+  /// @endcond
+
 #if __cpp_deduction_guides >= 201606
   // These helper traits are used for deduction guides
   // of associative containers.
diff --git a/libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc b/libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bbfd4264a3610950b140463548454a4bfde9209e
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc
@@ -0,0 +1,29 @@
+#include <iterator>
+#include <algorithm>
+#include <vector>
+#ifndef _GLIBCXX_DEBUG
+#include <debug/vector>
+#endif
+
+struct S { };
+
+int main()
+{
+  S s[1];
+  std::vector<S> v(1);
+  std::copy(s, s, v.rbegin());
+#if __cplusplus >= 201103L
+  std::copy(s, s, std::make_move_iterator(v.begin()));
+  std::copy(s, s, std::make_move_iterator(v.rbegin()));
+#endif
+
+#ifndef _GLIBCXX_DEBUG
+  __gnu_debug::vector<S> dv(1);
+  std::copy(s, s, dv.rbegin());
+#if __cplusplus >= 201103L
+  std::copy(s, s, std::make_move_iterator(dv.begin()));
+  std::copy(s, s, std::make_move_iterator(dv.rbegin()));
+#endif
+#endif
+}
+