[libcxx-commits] [libcxx] [libc++] Add __simple_tuple and replace a bunch of uses of tuple with it (PR #214566)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 14 06:03:32 PDT 2026


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/214566

>From 6c5028658b5d7fae957da2e57ebe6a05e0b7e838 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 6 Aug 2026 21:55:00 +0200
Subject: [PATCH] [libc++] Add __simple_tuple and replace a bunch of uses of
 tuple with it

---
 libcxx/include/CMakeLists.txt                 |   3 +-
 libcxx/include/__functional/bind_back.h       |  45 +++-----
 libcxx/include/__functional/bind_front.h      |  18 +--
 libcxx/include/__functional/perfect_forward.h |  33 +++---
 libcxx/include/__mutex/once_flag.h            |  15 +--
 libcxx/include/__tuple/simple_tuple.h         | 108 ++++++++++++++++++
 libcxx/include/algorithm                      |   2 +
 libcxx/include/future                         |  12 +-
 libcxx/include/module.modulemap.in            |   3 +-
 libcxx/include/mutex                          |  20 ++--
 libcxx/include/numeric                        |   2 +
 libcxx/include/tuple                          |   4 +-
 libcxx/include/vector                         |   4 +
 .../test/libcxx/transitive_includes/cxx26.csv |   6 -
 .../futures/futures.async/async.verify.cpp    |   6 +-
 .../thread.lock.guard/assign.compile.pass.cpp |   1 +
 .../thread.lock.guard/copy.compile.pass.cpp   |   1 +
 .../copy_assign.compile.pass.cpp              |   1 +
 .../copy_ctor.compile.pass.cpp                |   1 +
 .../member_swap.pass.cpp                      |   1 +
 .../nonmember_swap.pass.cpp                   |   1 +
 .../thread.lock.unique.mod/release.pass.cpp   |   1 +
 .../thread.lock.unique.obs/mutex.pass.cpp     |   1 +
 .../thread.lock.unique.obs/op_bool.pass.cpp   |   1 +
 .../thread.lock.unique.obs/owns_lock.pass.cpp |   1 +
 .../func.bind.partial/bind_back.verify.cpp    |   4 +-
 .../bind_front.nttp.verify.cpp                |   2 +-
 27 files changed, 203 insertions(+), 94 deletions(-)
 create mode 100644 libcxx/include/__tuple/simple_tuple.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d24ae7a73a825..21276786837c3 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -619,7 +619,7 @@ set(files
   __memory/noexcept_move_assign_container.h
   __memory/out_ptr.h
   __memory/pointer_traits.h
-  __memory/pstl.h  
+  __memory/pstl.h
   __memory/ranges_construct_at.h
   __memory/ranges_destroy.h
   __memory/ranges_uninitialized_algorithms.h
@@ -830,6 +830,7 @@ set(files
   __tuple/find_index.h
   __tuple/ignore.h
   __tuple/sfinae_helpers.h
+  __tuple/simple_tuple.h
   __tuple/tuple_element.h
   __tuple/tuple_like.h
   __tuple/tuple_like_no_subrange.h
diff --git a/libcxx/include/__functional/bind_back.h b/libcxx/include/__functional/bind_back.h
index 41177144d81fe..575d7813f7d59 100644
--- a/libcxx/include/__functional/bind_back.h
+++ b/libcxx/include/__functional/bind_back.h
@@ -13,10 +13,10 @@
 #include <__config>
 #include <__functional/invoke.h>
 #include <__functional/perfect_forward.h>
+#include <__tuple/simple_tuple.h>
 #include <__type_traits/decay.h>
 #include <__utility/forward.h>
 #include <__utility/integer_sequence.h>
-#include <tuple>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -26,40 +26,33 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 20
 
-template <size_t _NBound, class = make_index_sequence<_NBound>>
-struct __bind_back_op;
-
-template <size_t _NBound, size_t... _Ip>
-struct __bind_back_op<_NBound, index_sequence<_Ip...>> {
+struct __bind_back_op {
   template <class _Fn, class _BoundArgs, class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __f, _BoundArgs&& __bound_args, _Args&&... __args) const
-      noexcept(noexcept(std::invoke(std::forward<_Fn>(__f),
-                                    std::forward<_Args>(__args)...,
-                                    std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...)))
-          -> decltype(std::invoke(std::forward<_Fn>(__f),
-                                  std::forward<_Args>(__args)...,
-                                  std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...)) {
-    return std::invoke(std::forward<_Fn>(__f),
-                       std::forward<_Args>(__args)...,
-                       std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...);
+      noexcept(noexcept(decay_t<_BoundArgs>::__apply_back(
+          std::forward<_BoundArgs>(__bound_args), std::forward<_Fn>(__f), std::forward<_Args>(__args)...)))
+          -> decltype(decay_t<_BoundArgs>::__apply_back(
+              std::forward<_BoundArgs>(__bound_args), std::forward<_Fn>(__f), std::forward<_Args>(__args)...)) {
+    return decay_t<_BoundArgs>::__apply_back(
+        std::forward<_BoundArgs>(__bound_args), std::forward<_Fn>(__f), std::forward<_Args>(__args)...);
   }
 };
 
 template <class _Fn, class _BoundArgs>
-struct __bind_back_t : __perfect_forward<__bind_back_op<tuple_size_v<_BoundArgs>>, _Fn, _BoundArgs> {
-  using __perfect_forward<__bind_back_op<tuple_size_v<_BoundArgs>>, _Fn, _BoundArgs>::__perfect_forward;
+struct __bind_back_t : __perfect_forward<__bind_back_op, _Fn, _BoundArgs> {
+  using __perfect_forward<__bind_back_op, _Fn, _BoundArgs>::__perfect_forward;
 };
 
 template <class _Fn, class... _Args>
   requires is_constructible_v<decay_t<_Fn>, _Fn> && is_move_constructible_v<decay_t<_Fn>> &&
-               (is_constructible_v<decay_t<_Args>, _Args> && ...) && (is_move_constructible_v<decay_t<_Args>> && ...)
+           (is_constructible_v<decay_t<_Args>, _Args> && ...) && (is_move_constructible_v<decay_t<_Args>> && ...)
 _LIBCPP_HIDE_FROM_ABI constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) noexcept(
-    noexcept(__bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-        std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))))
-    -> decltype(__bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-        std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))) {
-  return __bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-      std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...));
+    noexcept(__bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+        std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...))))
+    -> decltype(__bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+        std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...))) {
+  return __bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+      std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...));
 }
 
 #  if _LIBCPP_STD_VER >= 23
@@ -71,8 +64,8 @@ template <class _Fn, class... _Args>
                 "bind_back requires all decay_t<Args> to be constructible from respective Args");
   static_assert((is_move_constructible_v<decay_t<_Args>> && ...),
                 "bind_back requires all decay_t<Args> to be move constructible");
-  return __bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-      std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...));
+  return __bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+      std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...));
 }
 #  endif // _LIBCPP_STD_VER >= 23
 
diff --git a/libcxx/include/__functional/bind_front.h b/libcxx/include/__functional/bind_front.h
index 97f8f4c458702..de354bbdb0f4a 100644
--- a/libcxx/include/__functional/bind_front.h
+++ b/libcxx/include/__functional/bind_front.h
@@ -31,8 +31,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 struct __bind_front_op {
   template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const noexcept(
-      noexcept(std::invoke(std::forward<_Args>(__args)...))) -> decltype(std::invoke(std::forward<_Args>(__args)...)) {
+  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const
+      noexcept(noexcept(std::invoke(std::forward<_Args>(__args)...)))
+          -> decltype(std::invoke(std::forward<_Args>(__args)...)) {
     return std::invoke(std::forward<_Args>(__args)...);
   }
 };
@@ -58,15 +59,14 @@ struct __nttp_bind_front_t;
 
 template <auto _Fn, size_t... _Indices, class... _BoundArgs>
 struct __nttp_bind_front_t<_Fn, index_sequence<_Indices...>, _BoundArgs...> {
-  tuple<_BoundArgs...> __bound_args_;
+  using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_BoundArgs...>;
+  _TupleT __bound_args_;
 
   template <class _Self, class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(this _Self&& __self, _Args&&... __args) noexcept(noexcept(std::invoke(
-      _Fn, std::get<_Indices>(std::forward<_Self>(__self).__bound_args_)..., std::forward<_Args>(__args)...)))
-      -> decltype(std::invoke(
-          _Fn, std::get<_Indices>(std::forward<_Self>(__self).__bound_args_)..., std::forward<_Args>(__args)...)) {
-    return std::invoke(
-        _Fn, std::get<_Indices>(std::forward<_Self>(__self).__bound_args_)..., std::forward<_Args>(__args)...);
+  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(this _Self&& __self, _Args&&... __args) noexcept(
+      noexcept(_TupleT::__apply(std::forward<_Self>(__self).__bound_args_, _Fn, std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(std::forward<_Self>(__self).__bound_args_, _Fn, std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(std::forward<_Self>(__self).__bound_args_, _Fn, std::forward<_Args>(__args)...);
   }
 };
 
diff --git a/libcxx/include/__functional/perfect_forward.h b/libcxx/include/__functional/perfect_forward.h
index c0408b410e2f9..83ef1c3ba1331 100644
--- a/libcxx/include/__functional/perfect_forward.h
+++ b/libcxx/include/__functional/perfect_forward.h
@@ -12,6 +12,8 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
+#include <__tuple/simple_tuple.h>
+#include <__type_traits/conjunction.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_constructible.h>
@@ -19,7 +21,6 @@
 #include <__utility/forward.h>
 #include <__utility/integer_sequence.h>
 #include <__utility/move.h>
-#include <tuple>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -38,10 +39,12 @@ struct __perfect_forward_impl;
 template <class _Op, size_t... _Idx, class... _BoundArgs>
 struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 private:
-  tuple<_BoundArgs...> __bound_args_;
+  using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_BoundArgs...>;
+
+  _TupleT __bound_args_;
 
 public:
-  template <class... _Args, class = enable_if_t< is_constructible_v<tuple<_BoundArgs...>, _Args&&...> >>
+  template <class... _Args, enable_if_t<_And<is_constructible<_BoundArgs, _Args&&>...>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI explicit constexpr __perfect_forward_impl(_Args&&... __bound_args)
       : __bound_args_(std::forward<_Args>(__bound_args)...) {}
 
@@ -53,9 +56,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs&..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) & noexcept(
-      noexcept(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs&..., _Args...>>>
@@ -63,9 +66,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs const&..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const& noexcept(
-      noexcept(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs const&..., _Args...>>>
@@ -73,9 +76,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) && noexcept(
-      noexcept(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs..., _Args...>>>
@@ -83,9 +86,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs const..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const&& noexcept(
-      noexcept(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs const..., _Args...>>>
diff --git a/libcxx/include/__mutex/once_flag.h b/libcxx/include/__mutex/once_flag.h
index 9999852b8b78a..f5cc8bed2d19a 100644
--- a/libcxx/include/__mutex/once_flag.h
+++ b/libcxx/include/__mutex/once_flag.h
@@ -11,15 +11,10 @@
 
 #include <__config>
 #include <__memory/addressof.h>
-#include <__tuple/tuple_size.h>
+#include <__tuple/simple_tuple.h>
 #include <__type_traits/invoke.h>
 #include <__utility/forward.h>
-#include <__utility/integer_sequence.h>
 #include <__utility/move.h>
-#include <cstdint>
-#ifndef _LIBCPP_CXX03_LANG
-#  include <tuple>
-#endif
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -87,9 +82,9 @@ class __call_once_param {
   _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
 
   _LIBCPP_HIDE_FROM_ABI void operator()() {
-    [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> void {
-      std::__invoke(std::get<_Indices>(std::move(__f_))...);
-    }(__make_index_sequence<tuple_size<_Fp>::value>());
+    _Fp::__apply(std::move(__f_), []<class... _Args>(_Args&&... __args) -> void {
+      std::__invoke(std::forward<_Args>(__args)...);
+    });
   }
 };
 
@@ -131,7 +126,7 @@ inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_acquire_load(_ValueType const*
 template <class _Callable, class... _Args>
 inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) {
   if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
-    typedef tuple<_Callable&&, _Args&&...> _Gp;
+    typedef __simple_tuple<_Callable&&, _Args&&...> _Gp;
     _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);
     __call_once_param<_Gp> __p(__f);
     std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Gp>));
diff --git a/libcxx/include/__tuple/simple_tuple.h b/libcxx/include/__tuple/simple_tuple.h
new file mode 100644
index 0000000000000..71da2f19679a6
--- /dev/null
+++ b/libcxx/include/__tuple/simple_tuple.h
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TUPLE_SIMPLE_TUPLE_H
+#define _LIBCPP___TUPLE_SIMPLE_TUPLE_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/copy_cvref.h>
+#include <__type_traits/disjunction.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_empty.h>
+#include <__type_traits/is_final.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/remove_cvref.h>
+#include <__utility/forward.h>
+#include <__utility/integer_sequence.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#ifndef _LIBCPP_CXX03_LANG
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <size_t, class _Tp, bool = is_empty<_Tp>::value && !__is_final_v<_Tp>>
+struct __simple_tuple_base {
+  _Tp __val_;
+
+  __simple_tuple_base() = default;
+
+  template <class _Arg, __enable_if_t<_IsNotSame<__remove_cvref_t<_Arg>, __simple_tuple_base>::value, int> = 0>
+  constexpr __simple_tuple_base(_Arg&& __arg) : __val_(std::forward<_Arg>(__arg)) {}
+};
+
+template <size_t _Index, class _Tp>
+struct __simple_tuple_base<_Index, _Tp, true> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_;
+
+  __simple_tuple_base() = default;
+
+  template <class _Arg, __enable_if_t<_IsNotSame<__remove_cvref_t<_Arg>, __simple_tuple_base>::value, int> = 0>
+  constexpr __simple_tuple_base(_Arg&& __arg) : __val_(std::forward<_Arg>(__arg)) {}
+};
+
+template <class _IndexSequence, class... _Bases>
+struct __simple_tuple_impl;
+
+template <class _Ap, class _Bp>
+using __tuple_forward _LIBCPP_NODEBUG = _If<is_reference<_Bp>::value, _Bp, __copy_cvref_t<_Ap, _Bp>>;
+
+template <size_t... _Indices, class... _Types>
+struct __simple_tuple_impl<__index_sequence<_Indices...>, _Types...> : __simple_tuple_base<_Indices, _Types>... {
+  __simple_tuple_impl() = default;
+
+  template <class... _Args,
+            __enable_if_t<_Or<integral_constant<bool, (sizeof...(_Args) != 1)>,
+                              _IsNotSame<__remove_cvref_t<_Args>, __simple_tuple_impl>...>::value,
+                          int> = 0>
+  constexpr __simple_tuple_impl(_Args&&... __args)
+      : __simple_tuple_base<_Indices, _Types>(std::forward<_Args>(__args))... {}
+
+  template <class _Self, class _Func, class... _Args>
+  static constexpr auto __apply(_Self&& __self, _Func&& __func, _Args&&... __args) noexcept(
+      __is_nothrow_invocable_v<_Func, __tuple_forward<_Self, _Types>..., _Args...>)
+      -> __invoke_result_t<_Func, __tuple_forward<_Self, _Types>..., _Args...> {
+    return std::__invoke(
+        std::forward<_Func>(__func),
+        static_cast<__tuple_forward<_Self, _Types>&&>(
+            static_cast<__copy_cvref_t<_Self, __simple_tuple_base<_Indices, _Types>>&&>(__self).__val_)...,
+        std::forward<_Args>(__args)...);
+  }
+
+  template <class _Self, class _Func, class... _Args>
+  static constexpr auto __apply_back(_Self&& __self, _Func&& __func, _Args&&... __args) noexcept(
+      __is_nothrow_invocable_v<_Func, _Args..., __tuple_forward<_Self, _Types>...>)
+      -> __invoke_result_t<_Func, _Args..., __tuple_forward<_Self, _Types>...> {
+    return std::__invoke(
+        std::forward<_Func>(__func),
+        std::forward<_Args>(__args)...,
+        static_cast<__tuple_forward<_Self, _Types>&&>(
+            static_cast<__copy_cvref_t<_Self, __simple_tuple_base<_Indices, _Types>>&&>(__self).__val_)...);
+  }
+};
+
+template <class... _Args>
+using __simple_tuple _LIBCPP_NODEBUG = __simple_tuple_impl<__index_sequence_for<_Args...>, _Args...>;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_CXX03_LANG
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___TUPLE_SIMPLE_TUPLE_H
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 1e1587cc56131..63eae0aa37b4a 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -2106,7 +2106,9 @@ template <class BidirectionalIterator, class Compare>
 
 #  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER >= 17 && _LIBCPP_STD_VER <= 23
 #    include <optional>
+#    include <tuple>
 #  endif
+
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 
 #endif // _LIBCPP_ALGORITHM
diff --git a/libcxx/include/future b/libcxx/include/future
index 30091660a4286..fa331887299df 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -390,9 +390,11 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
 #    include <__system_error/error_code.h>
 #    include <__system_error/error_condition.h>
 #    include <__thread/thread.h>
+#    include <__tuple/simple_tuple.h>
 #    include <__type_traits/add_reference.h>
 #    include <__type_traits/aligned_storage.h>
 #    include <__type_traits/conditional.h>
+#    include <__type_traits/conjunction.h>
 #    include <__type_traits/decay.h>
 #    include <__type_traits/enable_if.h>
 #    include <__type_traits/invoke.h>
@@ -408,7 +410,6 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
 #    include <__utility/move.h>
 #    include <__utility/swap.h>
 #    include <stdexcept>
-#    include <tuple>
 #    include <version>
 
 #    if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -1831,7 +1832,8 @@ _LIBCPP_HIDE_FROM_ABI future<_Rp> __make_async_assoc_state(_Fp&& __f) {
 
 template <class _Fp, class... _Args>
 class _LIBCPP_HIDDEN __async_func {
-  tuple<_Fp, _Args...> __f_;
+  using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_Fp, _Args...>;
+  _TupleT __f_;
 
 public:
   using _Rp _LIBCPP_NODEBUG = __invoke_result_t<_Fp, _Args...>;
@@ -1843,9 +1845,9 @@ public:
   _LIBCPP_HIDE_FROM_ABI __async_func(__async_func&& __f) : __f_(std::move(__f.__f_)) {}
 
   _LIBCPP_HIDE_FROM_ABI _Rp operator()() {
-    return [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> _Rp {
-      return std::__invoke(std::move(std::get<_Indices>(__f_))...);
-    }(__index_sequence_for<_Fp, _Args...>{});
+    return _TupleT::__apply(__f_, []<class... _LArgs>(_LArgs&&... __args) -> _Rp {
+      return std::__invoke(std::move(__args)...);
+    });
   }
 };
 
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index a5eac9fc149f0..036ffd4b5f32d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1701,7 +1701,7 @@ module std {
     module noexcept_move_assign_container     { header "__memory/noexcept_move_assign_container.h" }
     module out_ptr                            { header "__memory/out_ptr.h" }
     module pointer_traits                     { header "__memory/pointer_traits.h" }
-    module pstl                               { header "__memory/pstl.h" }    
+    module pstl                               { header "__memory/pstl.h" }
     module ranges_construct_at                { header "__memory/ranges_construct_at.h" }
     module ranges_destroy                     { header "__memory/ranges_destroy.h" }
     module ranges_uninitialized_algorithms {
@@ -2212,6 +2212,7 @@ module std {
     module find_index               { header "__tuple/find_index.h" }
     module ignore                   { header "__tuple/ignore.h" }
     module sfinae_helpers           { header "__tuple/sfinae_helpers.h" }
+    module simple_tuple             { header "__tuple/simple_tuple.h" }
     module tuple_element            { header "__tuple/tuple_element.h" }
     module tuple_like_no_subrange   { header "__tuple/tuple_like_no_subrange.h" }
     module tuple_like               { header "__tuple/tuple_like.h" }
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 24e6cab850c46..dc06b23ce1bda 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -200,11 +200,9 @@ template<class Callable, class ...Args>
 #  include <__mutex/unique_lock.h>
 #  include <__thread/id.h>
 #  include <__thread/support.h>
+#  include <__tuple/simple_tuple.h>
 #  include <__utility/forward.h>
 #  include <limits>
-#  ifndef _LIBCPP_CXX03_LANG
-#    include <tuple>
-#  endif
 #  include <version>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -471,7 +469,7 @@ public:
 template <class... _MArgs>
 class _LIBCPP_SCOPED_LOCKABLE scoped_lock {
   static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
-  typedef tuple<_MArgs&...> _MutexTuple;
+  using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_MArgs&...>;
 
 public:
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) _LIBCPP_ACQUIRE_CAPABILITY(__margs...)
@@ -484,20 +482,14 @@ public:
       : __t_(__margs...) {}
 
   _LIBCPP_RELEASE_CAPABILITY() _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
-    __unlock_unpack(make_index_sequence<sizeof...(_MArgs)>(), __t_);
+    _TupleT::__apply(__t_, [] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS(auto&... __args) { (__args.unlock(), ...); });
   }
 
   scoped_lock(scoped_lock const&)            = delete;
   scoped_lock& operator=(scoped_lock const&) = delete;
 
 private:
-  template <size_t... _Indx>
-  _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(index_sequence<_Indx...>, _MutexTuple& __mt)
-      _LIBCPP_RELEASE_CAPABILITY(std::get<_Indx>(__mt)...) {
-    (std::get<_Indx>(__mt).unlock(), ...);
-  }
-
-  _MutexTuple __t_;
+  _TupleT __t_;
 };
 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);
 
@@ -510,6 +502,10 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
+#  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
+#    include <tuple>
+#  endif
+
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 
 #endif // _LIBCPP_MUTEX
diff --git a/libcxx/include/numeric b/libcxx/include/numeric
index 876d36421f43c..6566fd72ece92 100644
--- a/libcxx/include/numeric
+++ b/libcxx/include/numeric
@@ -192,7 +192,9 @@ constexpr T saturating_cast(U x) noexcept;                    // freestanding, S
 
 #  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER >= 17 && _LIBCPP_STD_VER <= 23
 #    include <optional>
+#    include <tuple>
 #  endif
+
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 
 #endif // _LIBCPP_NUMERIC
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 2f0127bc7388d..e23ac88c9cdd1 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -660,8 +660,8 @@ public:
             // the two conditions below are not in spec. The purpose is to disable the UTypes Ctor when copy/move Ctor
             // can work. Otherwise, is_constructible can trigger hard error in those cases
             // https://godbolt.org/z/M94cGdKcE
-            _Not<is_same<_OtherTuple, const tuple&> >,
-            _Not<is_same<_OtherTuple, tuple&&> >,
+            _IsNotSame<_OtherTuple, const tuple&>,
+            _IsNotSame<_OtherTuple, tuple&&>,
             is_constructible<_Tp, __copy_cvref_t<_OtherTuple, _Up> >...,
             _Or<_BoolConstant<sizeof...(_Tp) != 1>,
                 // _Tp and _Up are 1-element packs - the pack expansions look
diff --git a/libcxx/include/vector b/libcxx/include/vector
index f2ae5ad4aed28..66fc67cc165f7 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -348,6 +348,10 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
 #    pragma GCC system_header
 #  endif
 
+#  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 14
+#    include <tuple>
+#  endif
+
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 
 #endif // _LIBCPP_VECTOR
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 62b58acd1e58e..d09947ff7d297 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -1,6 +1,5 @@
 algorithm cctype
 algorithm climits
-algorithm compare
 algorithm cstdint
 algorithm cstring
 algorithm ctime
@@ -10,7 +9,6 @@ algorithm initializer_list
 algorithm iosfwd
 algorithm limits
 algorithm ratio
-algorithm tuple
 algorithm version
 any cstdint
 any initializer_list
@@ -645,19 +643,16 @@ memory_resource tuple
 memory_resource version
 mutex cerrno
 mutex climits
-mutex compare
 mutex cstdint
 mutex cstring
 mutex ctime
 mutex limits
 mutex ratio
-mutex tuple
 mutex version
 new version
 numbers version
 numeric cctype
 numeric climits
-numeric compare
 numeric cstdint
 numeric cstring
 numeric ctime
@@ -666,7 +661,6 @@ numeric cwctype
 numeric initializer_list
 numeric limits
 numeric ratio
-numeric tuple
 numeric version
 optional compare
 optional cstdint
diff --git a/libcxx/test/std/thread/futures/futures.async/async.verify.cpp b/libcxx/test/std/thread/futures/futures.async/async.verify.cpp
index 2cb15a79ae089..16307a1082003 100644
--- a/libcxx/test/std/thread/futures/futures.async/async.verify.cpp
+++ b/libcxx/test/std/thread/futures/futures.async/async.verify.cpp
@@ -40,8 +40,7 @@ void f() {
       F f;
       static_cast<void>(std::async(f));
       // expected-error@*:* {{static assertion failed}}
-      // expected-error@*:* {{no matching constructor for initialization}}
-      // expected-error@*:* 0-1 {{call to deleted constructor}}
+      // expected-error@*:* 0-2 {{call to deleted constructor}}
     }
 
     { // Mandates: is_constructible_v<decay_t<F>, F>
@@ -55,8 +54,7 @@ void f() {
 
       static_cast<void>(std::async(F{}));
       // expected-error@*:* {{static assertion failed}}
-      // expected-error@*:* {{no matching constructor for initialization}}
-      // expected-error@*:* 0-1 {{call to deleted constructor}}
+      // expected-error@*:* 0-2 {{call to deleted constructor}}
     }
 
     { // Mandates: (is_constructible_v<decay_t<Args>, Args> && ...)
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/assign.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/assign.compile.pass.cpp
index abd37ea0d55dd..d38c5a772433f 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/assign.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/assign.compile.pass.cpp
@@ -13,6 +13,7 @@
 // lock_guard& operator=(lock_guard const&) = delete;
 
 #include <mutex>
+#include <type_traits>
 
 #include "types.h"
 
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/copy.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/copy.compile.pass.cpp
index 2a5973726ff1d..05291244221a2 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/copy.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/copy.compile.pass.cpp
@@ -13,6 +13,7 @@
 // lock_guard(lock_guard const&) = delete;
 
 #include <mutex>
+#include <type_traits>
 
 #include "types.h"
 
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp
index c0cb7d4ddd27a..caefc319f9d1c 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp
@@ -13,6 +13,7 @@
 // unique_lock& operator=(unique_lock const&) = delete;
 
 #include <mutex>
+#include <type_traits>
 
 #include "checking_mutex.h"
 
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp
index 2846b24125e78..e69a57e3c9dd3 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp
@@ -13,6 +13,7 @@
 // unique_lock(unique_lock const&) = delete;
 
 #include <mutex>
+#include <type_traits>
 
 #include "checking_mutex.h"
 
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp
index e2ffbf4a23a9c..8d645481a955d 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp
@@ -15,6 +15,7 @@
 #include <cassert>
 #include <memory>
 #include <mutex>
+#include <utility>
 
 #include "checking_mutex.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp
index 3e89e6c66bf3e..a4655798ba978 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp
@@ -16,6 +16,7 @@
 #include <cassert>
 #include <memory>
 #include <mutex>
+#include <utility>
 
 #include "checking_mutex.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp
index a7724504a667c..b8e14b8e39482 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp
@@ -15,6 +15,7 @@
 #include <cassert>
 #include <memory>
 #include <mutex>
+#include <utility>
 
 #include "checking_mutex.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp
index f00614015bbc3..99d2e92c2bf92 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp
@@ -15,6 +15,7 @@
 #include <cassert>
 #include <memory>
 #include <mutex>
+#include <utility>
 
 #include "checking_mutex.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
index 3542a40d25d39..ef1ca3c1eb953 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
@@ -15,6 +15,7 @@
 #include <cassert>
 #include <mutex>
 #include <type_traits>
+#include <utility>
 
 #include "checking_mutex.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp
index 11a674a55392f..7b93e77ab1d5e 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp
@@ -14,6 +14,7 @@
 
 #include <cassert>
 #include <mutex>
+#include <utility>
 
 #include "checking_mutex.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp
index 6a63b65bf148e..c916d4f83c7b2 100644
--- a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp
@@ -68,9 +68,9 @@ void test() {
     Arg x;
     auto f = std::bind_back([](const Arg&) {}, x);
     // expected-error-re@*:* {{static assertion failed{{.*}}bind_back requires all decay_t<Args> to be constructible from respective Args}}
-    // expected-error@*:* {{no matching constructor for initialization}}
     // expected-error@*:* 0-1{{call to deleted constructor of 'F'}}
-    // expected-error@*:* 0-1{{call to deleted constructor of 'Arg'}}
+    // expected-error@*:* 0-2{{call to deleted constructor of 'Arg'}}
+    // expected-error@*:* {{no matching constructor}}
   }
 
   { // Mandates: (is_move_constructible_v<decay_t<Args>> && ...)
diff --git a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp
index d7ed90f87562b..185c13cc37bf1 100644
--- a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp
@@ -35,7 +35,7 @@ void test() {
     Arg arg;
     auto _ = std::bind_front<AnyArgs{}>(arg);
     // expected-error@*:* {{static assertion failed due to requirement 'is_constructible_v<Arg, Arg &>': bind_front requires all decay_t<Args> to be constructible from respective Args}}
-    // expected-error@*:* 0-1{{call to deleted constructor of 'Arg'}}
+    // expected-error@*:* 0-2{{call to deleted constructor of 'Arg'}}
   }
 
   { // (is_move_constructible_v<BoundArgs> && ...) is true



More information about the libcxx-commits mailing list