Index: libcxx/docs/Status/Cxx2bPapers.csv
===================================================================
--- libcxx/docs/Status/Cxx2bPapers.csv
+++ libcxx/docs/Status/Cxx2bPapers.csv
@@ -25,7 +25,7 @@
 "","","","","",""
 "`P0288R9 <https://wg21.link/P0288R9>`__","LWG","``any_invocable``","October 2021","",""
 "`P0798R8 <https://wg21.link/P0798R8>`__","LWG","Monadic operations for ``std::optional``","October 2021","|Complete|","14.0"
-"`P0849R8 <https://wg21.link/P0849R8>`__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","",""
+"`P0849R8 <https://wg21.link/P0849R8>`__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","|Complete|","14.0"
 "`P1072R10 <https://wg21.link/P1072R10>`__","LWG","``basic_string::resize_and_overwrite``","October 2021","",""
 "`P1147R1 <https://wg21.link/P1147R1>`__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0"
 "`P1272R4 <https://wg21.link/P1272R4>`__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0"
Index: libcxx/include/CMakeLists.txt
===================================================================
--- libcxx/include/CMakeLists.txt
+++ libcxx/include/CMakeLists.txt
@@ -360,8 +360,8 @@
   __tuple
   __undef_macros
   __utility/as_const.h
+  __utility/auto_cast.h
   __utility/cmp.h
-  __utility/decay_copy.h
   __utility/declval.h
   __utility/exchange.h
   __utility/forward.h
Index: libcxx/include/__ranges/access.h
===================================================================
--- libcxx/include/__ranges/access.h
+++ libcxx/include/__ranges/access.h
@@ -14,8 +14,7 @@
 #include <__iterator/readable_traits.h>
 #include <__ranges/enable_borrowed_range.h>
 #include <__utility/as_const.h>
-#include <__utility/decay_copy.h>
-#include <__utility/forward.h>
+#include <__utility/auto_cast.h>
 #include <concepts>
 #include <type_traits>
 
@@ -44,7 +43,7 @@
   concept __member_begin =
     __can_borrow<_Tp> &&
     requires(_Tp&& __t) {
-      { _VSTD::__decay_copy(__t.begin()) } -> input_or_output_iterator;
+      { _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
     };
 
   void begin(auto&) = delete;
@@ -56,7 +55,7 @@
     __can_borrow<_Tp> &&
     __class_or_enum<remove_cvref_t<_Tp> > &&
     requires(_Tp && __t) {
-      { _VSTD::__decay_copy(begin(__t)) } -> input_or_output_iterator;
+      { _LIBCPP_AUTO_CAST(begin(__t)) } -> input_or_output_iterator;
     };
 
   struct __fn {
@@ -75,17 +74,17 @@
     template <class _Tp>
     requires __member_begin<_Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
-    noexcept(noexcept(_VSTD::__decay_copy(__t.begin())))
+    noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.begin())))
     {
-      return __t.begin();
+      return _LIBCPP_AUTO_CAST(__t.begin());
     }
 
     template <class _Tp>
     requires __unqualified_begin<_Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
-    noexcept(noexcept(_VSTD::__decay_copy(begin(__t))))
+    noexcept(noexcept(_LIBCPP_AUTO_CAST(begin(__t))))
     {
-      return begin(__t);
+      return _LIBCPP_AUTO_CAST(begin(__t));
     }
 
     void operator()(auto&&) const = delete;
@@ -108,7 +107,7 @@
     __can_borrow<_Tp> &&
     requires(_Tp&& __t) {
       typename iterator_t<_Tp>;
-      { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).end()) } -> sentinel_for<iterator_t<_Tp> >;
+      { _LIBCPP_AUTO_CAST(__t.end()) } -> sentinel_for<iterator_t<_Tp> >;
     };
 
   void end(auto&) = delete;
@@ -121,7 +120,7 @@
     __class_or_enum<remove_cvref_t<_Tp> > &&
     requires(_Tp && __t) {
       typename iterator_t<_Tp>;
-      { _VSTD::__decay_copy(end(_VSTD::forward<_Tp>(__t))) } -> sentinel_for<iterator_t<_Tp> >;
+      { _LIBCPP_AUTO_CAST(end(__t)) } -> sentinel_for<iterator_t<_Tp> >;
     };
 
   class __fn {
@@ -140,17 +139,17 @@
     template <class _Tp>
     requires __member_end<_Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
-    noexcept(noexcept(_VSTD::__decay_copy(__t.end())))
+    noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.end())))
     {
-      return _VSTD::forward<_Tp>(__t).end();
+      return _LIBCPP_AUTO_CAST(__t.end());
     }
 
     template <class _Tp>
     requires __unqualified_end<_Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
-    noexcept(noexcept(_VSTD::__decay_copy(end(__t))))
+    noexcept(noexcept(_LIBCPP_AUTO_CAST(end(__t))))
     {
-      return end(__t);
+      return _LIBCPP_AUTO_CAST(end(__t));
     }
 
     void operator()(auto&&) const = delete;
Index: libcxx/include/__ranges/all.h
===================================================================
--- libcxx/include/__ranges/all.h
+++ libcxx/include/__ranges/all.h
@@ -17,7 +17,7 @@
 #include <__ranges/range_adaptor.h>
 #include <__ranges/ref_view.h>
 #include <__ranges/subrange.h>
-#include <__utility/decay_copy.h>
+#include <__utility/auto_cast.h>
 #include <__utility/declval.h>
 #include <__utility/forward.h>
 #include <type_traits>
@@ -38,9 +38,9 @@
       requires ranges::view<decay_t<_Tp>>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
     constexpr auto operator()(_Tp&& __t) const
-      noexcept(noexcept(_VSTD::__decay_copy(_VSTD::forward<_Tp>(__t))))
+      noexcept(noexcept(_LIBCPP_AUTO_CAST(_VSTD::forward<_Tp>(__t))))
     {
-      return _VSTD::forward<_Tp>(__t);
+      return _LIBCPP_AUTO_CAST(_VSTD::forward<_Tp>(__t));
     }
 
     template<class _Tp>
Index: libcxx/include/__ranges/size.h
===================================================================
--- libcxx/include/__ranges/size.h
+++ libcxx/include/__ranges/size.h
@@ -13,8 +13,7 @@
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
 #include <__ranges/access.h>
-#include <__utility/decay_copy.h>
-#include <__utility/forward.h>
+#include <__utility/auto_cast.h>
 #include <concepts>
 #include <type_traits>
 
@@ -26,7 +25,6 @@
 
 #if !defined(_LIBCPP_HAS_NO_RANGES)
 
-// clang-format off
 namespace ranges {
 template<class>
 inline constexpr bool disable_sized_range = false;
@@ -41,7 +39,7 @@
 
   template <class _Tp>
   concept __member_size = __size_enabled<_Tp> && requires(_Tp&& __t) {
-    { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).size()) } -> __integer_like;
+    { _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like;
   };
 
   template <class _Tp>
@@ -50,7 +48,7 @@
     !__member_size<_Tp> &&
     __class_or_enum<remove_cvref_t<_Tp>> &&
     requires(_Tp&& __t) {
-      { _VSTD::__decay_copy(size(_VSTD::forward<_Tp>(__t))) } -> __integer_like;
+      { _LIBCPP_AUTO_CAST(size(__t)) } -> __integer_like;
     };
 
   template <class _Tp>
@@ -76,14 +74,14 @@
 
     template <__member_size _Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
-        noexcept(noexcept(_VSTD::forward<_Tp>(__t).size())) {
-      return _VSTD::forward<_Tp>(__t).size();
+        noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.size()))) {
+      return _LIBCPP_AUTO_CAST(__t.size());
     }
 
     template <__unqualified_size _Tp>
     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
-        noexcept(noexcept(size(_VSTD::forward<_Tp>(__t)))) {
-      return size(_VSTD::forward<_Tp>(__t));
+        noexcept(noexcept(_LIBCPP_AUTO_CAST(size(__t)))) {
+      return _LIBCPP_AUTO_CAST(size(__t));
     }
 
     template<__difference _Tp>
@@ -118,8 +116,6 @@
 } // namespace __cpo
 } // namespace ranges
 
-// clang-format off
-
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)
 
 _LIBCPP_END_NAMESPACE_STD
Index: libcxx/include/__utility/auto_cast.h
===================================================================
--- libcxx/include/__utility/auto_cast.h
+++ libcxx/include/__utility/auto_cast.h
@@ -7,29 +7,16 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___UTILITY_DECAY_COPY_H
-#define _LIBCPP___UTILITY_DECAY_COPY_H
+#ifndef _LIBCPP___UTILITY_AUTO_CAST_H
+#define _LIBCPP___UTILITY_AUTO_CAST_H
 
 #include <__config>
-#include <__utility/forward.h>
 #include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
-_LIBCPP_BEGIN_NAMESPACE_STD
+#define _LIBCPP_AUTO_CAST(expr) static_cast<typename decay<decltype((expr))>::type>(expr)
 
-template <class _Tp>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
-typename decay<_Tp>::type __decay_copy(_Tp&& __t)
-#if _LIBCPP_STD_VER > 17
-    noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>)
-#endif
-{
-  return _VSTD::forward<_Tp>(__t);
-}
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP___UTILITY_DECAY_COPY_H
+#endif // _LIBCPP___UTILITY_AUTO_CAST_H
Index: libcxx/include/future
===================================================================
--- libcxx/include/future
+++ libcxx/include/future
@@ -366,7 +366,7 @@
 #include <__debug>
 #include <__memory/allocator_arg_t.h>
 #include <__memory/uses_allocator.h>
-#include <__utility/decay_copy.h>
+#include <__utility/auto_cast.h>
 #include <__utility/forward.h>
 #include <chrono>
 #include <exception>
@@ -2207,16 +2207,16 @@
     {
 #endif
         if (__does_policy_contain(__policy, launch::async))
-        return _VSTD::__make_async_assoc_state<_Rp>(_BF(_VSTD::__decay_copy(_VSTD::forward<_Fp>(__f)),
-                                                     _VSTD::__decay_copy(_VSTD::forward<_Args>(__args))...));
+        return _VSTD::__make_async_assoc_state<_Rp>(_BF(_LIBCPP_AUTO_CAST(_VSTD::forward<_Fp>(__f)),
+                                                        _LIBCPP_AUTO_CAST(_VSTD::forward<_Args>(__args))...));
 #ifndef _LIBCPP_NO_EXCEPTIONS
     }
     catch ( ... ) { if (__policy == launch::async) throw ; }
 #endif
 
     if (__does_policy_contain(__policy, launch::deferred))
-        return _VSTD::__make_deferred_assoc_state<_Rp>(_BF(_VSTD::__decay_copy(_VSTD::forward<_Fp>(__f)),
-                                                        _VSTD::__decay_copy(_VSTD::forward<_Args>(__args))...));
+        return _VSTD::__make_deferred_assoc_state<_Rp>(_BF(_LIBCPP_AUTO_CAST(_VSTD::forward<_Fp>(__f)),
+                                                           _LIBCPP_AUTO_CAST(_VSTD::forward<_Args>(__args))...));
     return future<_Rp>{};
 }
 
Index: libcxx/include/module.modulemap
===================================================================
--- libcxx/include/module.modulemap
+++ libcxx/include/module.modulemap
@@ -921,8 +921,8 @@
 
     module __utility {
       module as_const            { private header "__utility/as_const.h" }
+      module auto_cast           { private header "__utility/auto_cast.h" }
       module cmp                 { private header "__utility/cmp.h" }
-      module decay_copy          { private header "__utility/decay_copy.h" }
       module declval             { private header "__utility/declval.h" }
       module exchange            { private header "__utility/exchange.h" }
       module forward             { private header "__utility/forward.h" }
Index: libcxx/include/thread
===================================================================
--- libcxx/include/thread
+++ libcxx/include/thread
@@ -88,7 +88,6 @@
 #include <__mutex_base>
 #include <__thread/poll_with_backoff.h>
 #include <__threading_support>
-#include <__utility/decay_copy.h>
 #include <__utility/forward.h>
 #include <chrono>
 #include <cstddef>
@@ -303,8 +302,8 @@
     typedef tuple<_TSPtr, typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp;
     unique_ptr<_Gp> __p(
             new _Gp(_VSTD::move(__tsp),
-                    _VSTD::__decay_copy(_VSTD::forward<_Fp>(__f)),
-                    _VSTD::__decay_copy(_VSTD::forward<_Args>(__args))...));
+                    _VSTD::forward<_Fp>(__f),
+                    _VSTD::forward<_Args>(__args)...));
     int __ec = _VSTD::__libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
     if (__ec == 0)
         __p.release();
Index: libcxx/include/utility
===================================================================
--- libcxx/include/utility
+++ libcxx/include/utility
@@ -218,6 +218,7 @@
 #include <__debug>
 #include <__tuple>
 #include <__utility/as_const.h>
+#include <__utility/auto_cast.h>
 #include <__utility/cmp.h>
 #include <__utility/declval.h>
 #include <__utility/exchange.h>
Index: libcxx/test/libcxx/diagnostics/detail.headers/utility/auto_cast.module.verify.cpp
===================================================================
--- libcxx/test/libcxx/diagnostics/detail.headers/utility/auto_cast.module.verify.cpp
+++ libcxx/test/libcxx/diagnostics/detail.headers/utility/auto_cast.module.verify.cpp
@@ -11,5 +11,5 @@
 // WARNING: This test was generated by 'generate_private_header_tests.py'
 // and should not be edited manually.
 
-// expected-error@*:* {{use of private header from outside its module: '__utility/decay_copy.h'}}
-#include <__utility/decay_copy.h>
+// expected-error@*:* {{use of private header from outside its module: '__utility/auto_cast.h'}}
+#include <__utility/auto_cast.h>
Index: libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp
===================================================================
--- libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp
+++ libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp
@@ -245,28 +245,27 @@
 ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
 ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<int (&)[10]>()));
 
-template<class T>
 struct NoThrowMemberBegin {
-  T begin() const noexcept;
-};
-ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberBegin<int*>&>()));
-ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<NoThrowMemberBegin<int*>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberBegin<ThrowingIterator<int>>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::cbegin(std::declval<NoThrowMemberBegin<ThrowingIterator<int>>&>()));
+  ThrowingIterator<int> begin() const noexcept; // auto(t.begin()) doesn't throw
+} ntmb;
+static_assert(noexcept(std::ranges::begin(ntmb)));
+static_assert(noexcept(std::ranges::cbegin(ntmb)));
 
-template<class T>
 struct NoThrowADLBegin {
-  friend T begin(NoThrowADLBegin&) noexcept { return T{}; }
-  friend T begin(NoThrowADLBegin const&) noexcept { return T{}; }
-};
-ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLBegin<int*>&>()));
-ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<NoThrowADLBegin<int*>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLBegin<ThrowingIterator<int>>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::cbegin(std::declval<NoThrowADLBegin<ThrowingIterator<int>>&>()));
+  friend ThrowingIterator<int> begin(NoThrowADLBegin&) noexcept;  // auto(begin(t)) doesn't throw
+  friend ThrowingIterator<int> begin(const NoThrowADLBegin&) noexcept;
+} ntab;
+static_assert(noexcept(std::ranges::begin(ntab)));
+static_assert(noexcept(std::ranges::cbegin(ntab)));
+
+struct NoThrowMemberBeginReturnsRef {
+  ThrowingIterator<int>& begin() const noexcept; // auto(t.begin()) may throw
+} ntmbrr;
+static_assert(!noexcept(std::ranges::begin(ntmbrr)));
+static_assert(!noexcept(std::ranges::cbegin(ntmbrr)));
 
 struct BeginReturnsArrayRef {
     auto begin() const noexcept -> int(&)[10];
-    auto end() const noexcept -> int(&)[10];
 } brar;
 static_assert(noexcept(std::ranges::begin(brar)));
 static_assert(noexcept(std::ranges::cbegin(brar)));
Index: libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp
===================================================================
--- libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp
+++ libcxx/test/std/ranges/range.access/range.access.end/end.pass.cpp
@@ -277,34 +277,34 @@
 ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));
 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));
 
-template<class T>
 struct NoThrowMemberEnd {
-  T begin() const;
-  T end() const noexcept;
-};
-ASSERT_NOEXCEPT(std::ranges::end(std::declval<NoThrowMemberEnd<int*>&>()));
-ASSERT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowMemberEnd<int*>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::end(std::declval<NoThrowMemberEnd<ThrowingIterator<int>>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowMemberEnd<ThrowingIterator<int>>&>()));
+  ThrowingIterator<int> begin() const;
+  ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw
+} ntme;
+static_assert(noexcept(std::ranges::end(ntme)));
+static_assert(noexcept(std::ranges::cend(ntme)));
 
-template<class T>
 struct NoThrowADLEnd {
-  T begin() const;
-  friend T end(NoThrowADLEnd&) noexcept { return T{}; }
-  friend T end(NoThrowADLEnd const&) noexcept { return T{}; }
-};
-ASSERT_NOEXCEPT(std::ranges::end(std::declval<NoThrowADLEnd<int*>&>()));
-ASSERT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowADLEnd<int*>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::end(std::declval<NoThrowADLEnd<ThrowingIterator<int>>&>()));
-ASSERT_NOT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowADLEnd<ThrowingIterator<int>>&>()));
-
-struct BeginReturnsArrayRef {
+  ThrowingIterator<int> begin() const;
+  friend ThrowingIterator<int> end(NoThrowADLEnd&) noexcept;  // auto(end(t)) doesn't throw
+  friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept;
+} ntae;
+static_assert(noexcept(std::ranges::end(ntae)));
+static_assert(noexcept(std::ranges::cend(ntae)));
+
+struct NoThrowMemberEndReturnsRef {
+  ThrowingIterator<int> begin() const;
+  ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw
+} ntmerr;
+static_assert(!noexcept(std::ranges::end(ntmerr)));
+static_assert(!noexcept(std::ranges::cend(ntmerr)));
+
+struct EndReturnsArrayRef {
     auto begin() const noexcept -> int(&)[10];
     auto end() const noexcept -> int(&)[10];
-} brar;
-static_assert(noexcept(std::ranges::end(brar)));
-static_assert(noexcept(std::ranges::cend(brar)));
-
+} erar;
+static_assert(noexcept(std::ranges::end(erar)));
+static_assert(noexcept(std::ranges::cend(erar)));
 
 int main(int, char**) {
   testArray();
Index: libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp
===================================================================
--- libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp
+++ libcxx/test/std/ranges/range.access/range.prim/size.pass.cpp
@@ -124,7 +124,7 @@
 bool constexpr testHasSizeFunction() {
   assert(std::ranges::size(SizeFunction()) == 42);
   ASSERT_SAME_TYPE(decltype(std::ranges::size(SizeFunction())), size_t);
-  assert(std::ranges::size(MoveOnlySizeFunction()) == 42);
+  static_assert(!std::is_invocable_v<RangeSizeT, MoveOnlySizeFunction>);
   assert(std::ranges::size(EnumSizeFunction()) == 42);
   assert(std::ranges::size(SizeFunctionConst()) == 42);
 
Index: libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
===================================================================
--- libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
+++ libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
@@ -21,7 +21,7 @@
 // (It's fixed in the upcoming Clang 14, by https://reviews.llvm.org/D109651.)
 // Prior to the fix, when statically linked, the unwind info for the two
 // (default and overridden) operator new implementations clash.
-// XFAIL: target={{.+}}-windows-gnu && !windows-dll && clang-13
+// UNSUPPORTED: target={{.+}}-windows-gnu && !windows-dll && clang-13
 
 #include <thread>
 #include <new>