[libcxx-commits] [libcxx] [libc++] P2255R2: Add deleted tuple constructor overloads (PR #205379)

Yihan Wang via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 12 21:35:04 PDT 2026


https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/205379

>From 865c5a96e4f7699d8ecc5a6317aba888d8795269 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 24 Jun 2026 00:51:43 +0800
Subject: [PATCH 01/13] [libc++] P2255R2: Add deleted tuple constructor
 overloads

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/docs/Status/Cxx23Papers.csv            |   2 +-
 libcxx/include/tuple                          | 247 ++++++++++++++++--
 ...5_tuple_ref_binding_diagnostics.verify.cpp |  24 +-
 .../ref_constructs_from_temporary.verify.cpp  |  74 ++++++
 4 files changed, 309 insertions(+), 38 deletions(-)
 create mode 100644 libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/ref_constructs_from_temporary.verify.cpp

diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 739f0ecab37e7..e2e7c679be7b7 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -43,7 +43,7 @@
 "`P0627R6 <https://wg21.link/P0627R6>`__","Function to mark unreachable code","2022-02 (Virtual)","|Complete|","15","`#105175 <https://github.com/llvm/llvm-project/issues/105175>`__",""
 "`P1206R7 <https://wg21.link/P1206R7>`__","``ranges::to``: A function to convert any range to a container","2022-02 (Virtual)","|Complete|","17","`#105176 <https://github.com/llvm/llvm-project/issues/105176>`__",""
 "`P1413R3 <https://wg21.link/P1413R3>`__","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","2022-02 (Virtual)","|Complete|","","`#105177 <https://github.com/llvm/llvm-project/issues/105177>`__","``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but clang doesn't issue a diagnostic for deprecated using template declarations."
-"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","`#105180 <https://github.com/llvm/llvm-project/issues/105180>`__","Implemented the type traits only."
+"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","`#105180 <https://github.com/llvm/llvm-project/issues/105180>`__","Implemented the type traits and changes to tuple constructors only."
 "`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","`#105182 <https://github.com/llvm/llvm-project/issues/105182>`__",""
 "`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 <https://github.com/llvm/llvm-project/issues/105183>`__",""
 "`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Complete|","23","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__",""
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 8f43006521dda..912b49c2b97de 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -616,21 +616,55 @@ public:
               _Not<_IsThisTuple<_Up...> >, // extension to allow mis-behaved user constructors
               is_constructible<_Tp, _Up>... > {};
 
-  template <class... _Up,
-            __enable_if_t< _And< _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> >::value,
-                           int> = 0>
+  template <class... _Up>
+  struct _EnableUTypesCtorBase
+      : _And<_BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> > {};
+
+  template <bool, class... _Up>
+  struct _EnableUTypesCtorNoDangling : false_type {};
+
+#    if _LIBCPP_STD_VER >= 23
+  template <bool, class... _Up>
+  struct _CtorCreatesDanglingReference : false_type {};
+
+  template <class... _Up>
+  struct _CtorCreatesDanglingReference<true, _Up...>
+      : _Or<_BoolConstant<__reference_constructs_from_temporary_v<_Tp, _Up&&> >...> {};
+
+  template <class... _Up>
+  struct _EnableUTypesCtorNoDangling<true, _Up...> : _Not<_CtorCreatesDanglingReference<true, _Up...> > {};
+
+  template <class... _Up>
+  struct _EnableDanglingUTypesCtor : _CtorCreatesDanglingReference<_EnableUTypesCtorBase<_Up...>::value, _Up...> {};
+#    else
+  template <class... _Up>
+  struct _EnableUTypesCtorNoDangling<true, _Up...> : true_type {};
+#    endif // _LIBCPP_STD_VER >= 23
+
+  template <class... _Up>
+  struct _EnableNonDanglingUTypesCtor
+      : _EnableUTypesCtorNoDangling<_EnableUTypesCtorBase<_Up...>::value, _Up...> {};
+
+  template <class... _Up, __enable_if_t< _EnableNonDanglingUTypesCtor<_Up...>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(_Up&&... __u) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
       : __base_(__forward_args{}, std::forward<_Up>(__u)...) {}
 
-  template <class _Alloc,
-            class... _Up,
-            __enable_if_t< _And< _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> >::value,
-                           int> = 0>
+  template <class _Alloc, class... _Up, __enable_if_t< _EnableNonDanglingUTypesCtor<_Up...>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
       : __base_(allocator_arg_t(), __a, __forward_args{}, std::forward<_Up>(__u)...) {}
 
+#    if _LIBCPP_STD_VER >= 23
+  template <class... _Up, __enable_if_t< _EnableDanglingUTypesCtor<_Up...>::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
+      tuple(_Up&&...) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) = delete;
+
+  template <class _Alloc, class... _Up, __enable_if_t< _EnableDanglingUTypesCtor<_Up...>::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
+      tuple(allocator_arg_t, const _Alloc&, _Up&&...) = delete;
+#    endif // _LIBCPP_STD_VER >= 23
+
   // Copy and move constructors (including the allocator_arg_t variants)
   tuple(const tuple&) = default;
   tuple(tuple&&)      = default;
@@ -672,58 +706,134 @@ public:
                      _Not<is_convertible<_OtherTuple, _Tp> >...,
                      _Not<is_constructible<_Tp, _OtherTuple> >... > > > {};
 
-  template <class... _Up, __enable_if_t< _And< _EnableCtorFromUTypesTuple<const tuple<_Up...>&> >::value, int> = 0>
+  template <bool, class _OtherTuple>
+  struct _EnableCtorFromUTypesTupleNoDangling : false_type {};
+
+#    if _LIBCPP_STD_VER >= 23
+  template <bool, class _OtherTuple, class _DecayedOtherTuple = __remove_cvref_t<_OtherTuple>, class = void>
+  struct _CtorFromUTypesTupleCreatesDanglingReference : false_type {};
+
+  template <class _OtherTuple, class... _Up>
+  struct _CtorFromUTypesTupleCreatesDanglingReference<
+      true,
+      _OtherTuple,
+      tuple<_Up...>,
+      __enable_if_t<sizeof...(_Up) == sizeof...(_Tp)> >
+      : _Or<_BoolConstant<__reference_constructs_from_temporary_v<_Tp, __copy_cvref_t<_OtherTuple, _Up> > >...> {};
+
+  template <class _OtherTuple>
+  struct _EnableCtorFromUTypesTupleNoDangling<true, _OtherTuple>
+      : _Not<_CtorFromUTypesTupleCreatesDanglingReference<true, _OtherTuple> > {};
+
+  template <class _OtherTuple>
+  struct _EnableDanglingCtorFromUTypesTuple
+      : _CtorFromUTypesTupleCreatesDanglingReference<_EnableCtorFromUTypesTuple<_OtherTuple>::value, _OtherTuple> {};
+#    else
+  template <class _OtherTuple>
+  struct _EnableCtorFromUTypesTupleNoDangling<true, _OtherTuple> : true_type {};
+#    endif // _LIBCPP_STD_VER >= 23
+
+  template <class _OtherTuple>
+  struct _EnableNonDanglingCtorFromUTypesTuple
+      : _EnableCtorFromUTypesTupleNoDangling<_EnableCtorFromUTypesTuple<_OtherTuple>::value, _OtherTuple> {};
+
+  template <class... _Up,
+            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(const tuple<_Up...>& __t) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value)
       : __base_(__from_tuple(), __t) {}
 
   template <class... _Up,
             class _Alloc,
-            __enable_if_t< _And< _EnableCtorFromUTypesTuple<const tuple<_Up...>&> >::value, int> = 0>
+            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t)
       : __base_(allocator_arg_t(), __a, __from_tuple(), __t) {}
 
 #    if _LIBCPP_STD_VER >= 23
+  template <class... _Up,
+            __enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
+      tuple(const tuple<_Up...>&) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value) = delete;
+
+  template <class... _Up,
+            class _Alloc,
+            __enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
+      tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&) = delete;
+
   // tuple(tuple<U...>&) constructors (including allocator_arg_t variants)
 
-  template <class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  template <class... _Up, enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>& __t)
       : __base_(__from_tuple(), __t) {}
 
-  template <class _Alloc, class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  template <class... _Up, enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>&) = delete;
+
+  template <class _Alloc,
+            class... _Up,
+            enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), __t) {}
+
+  template <class _Alloc,
+            class... _Up,
+            enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value)
+      tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
   // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants)
-  template <class... _Up, __enable_if_t< _And< _EnableCtorFromUTypesTuple<tuple<_Up...>&&> >::value, int> = 0>
+  template <class... _Up,
+            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(tuple<_Up...>&& __t) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
       : __base_(__from_tuple(), std::move(__t)) {}
 
   template <class _Alloc,
             class... _Up,
-            __enable_if_t< _And< _EnableCtorFromUTypesTuple<tuple<_Up...>&&> >::value, int> = 0>
+            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t)
       : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__t)) {}
 
 #    if _LIBCPP_STD_VER >= 23
+  template <class... _Up, __enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
+      tuple(tuple<_Up...>&&) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) = delete;
+
+  template <class _Alloc,
+            class... _Up,
+            __enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
+      tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&&) = delete;
+
   // tuple(const tuple<U...>&&) constructors (including allocator_arg_t variants)
 
-  template <class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  template <class... _Up,
+            enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(const tuple<_Up...>&& __t)
       : __base_(__from_tuple(), std::move(__t)) {}
 
+  template <class... _Up, enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
+      tuple(const tuple<_Up...>&&) = delete;
+
   template <class _Alloc,
             class... _Up,
-            enable_if_t< _EnableCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+            enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, const tuple<_Up...>&& __t)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__t)) {}
+
+  template <class _Alloc,
+            class... _Up,
+            enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
+      tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
   // tuple(const pair<U1, U2>&) constructors (including allocator_arg_t variants)
@@ -741,6 +851,34 @@ public:
   template <class _Pair>
   struct _EnableCtorFromPair : _CtorPredicateFromPair<is_constructible, _Pair> {};
 
+  template <bool, class _Pair>
+  struct _EnableCtorFromPairNoDangling : false_type {};
+
+#    if _LIBCPP_STD_VER >= 23
+  template <bool, class _Pair, class _DecayedPair = __remove_cvref_t<_Pair>, class _Tuple = tuple>
+  struct _CtorFromPairCreatesDanglingReference : false_type {};
+
+  template <class _Pair, class _Up1, class _Up2, class _Tp1, class _Tp2>
+  struct _CtorFromPairCreatesDanglingReference<true, _Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2> >
+      : _Or<
+            _BoolConstant<__reference_constructs_from_temporary_v<_Tp1, __copy_cvref_t<_Pair, _Up1> > >,
+            _BoolConstant<__reference_constructs_from_temporary_v<_Tp2, __copy_cvref_t<_Pair, _Up2> > > > {};
+
+  template <class _Pair>
+  struct _EnableCtorFromPairNoDangling<true, _Pair> : _Not<_CtorFromPairCreatesDanglingReference<true, _Pair> > {};
+
+  template <class _Pair>
+  struct _EnableDanglingCtorFromPair
+      : _CtorFromPairCreatesDanglingReference<_EnableCtorFromPair<_Pair>::value, _Pair> {};
+#    else
+  template <class _Pair>
+  struct _EnableCtorFromPairNoDangling<true, _Pair> : true_type {};
+#    endif // _LIBCPP_STD_VER >= 23
+
+  template <class _Pair>
+  struct _EnableNonDanglingCtorFromPair
+      : _EnableCtorFromPairNoDangling<_EnableCtorFromPair<_Pair>::value, _Pair> {};
+
   template <class _Pair>
   struct _NothrowConstructibleFromPair : _CtorPredicateFromPair<is_nothrow_constructible, _Pair> {};
 
@@ -754,7 +892,7 @@ public:
   template <class _Up1,
             class _Up2,
             template <class...> class _And                                                   = _And,
-            __enable_if_t< _And< _EnableCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
+            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(const pair<_Up1, _Up2>& __p) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value)
@@ -764,35 +902,64 @@ public:
             class _Up1,
             class _Up2,
             template <class...> class _And                                                   = _And,
-            __enable_if_t< _And< _EnableCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
+            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p)
       : __base_(allocator_arg_t(), __a, __from_tuple(), __p) {}
 
 #    if _LIBCPP_STD_VER >= 23
+  template <class _Up1,
+            class _Up2,
+            template <class...> class _And                                                    = _And,
+            __enable_if_t< _And< _EnableDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
+      tuple(const pair<_Up1, _Up2>&) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value) =
+          delete;
+
+  template <class _Alloc,
+            class _Up1,
+            class _Up2,
+            template <class...> class _And                                                    = _And,
+            __enable_if_t< _And< _EnableDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
+      tuple(allocator_arg_t, const _Alloc&, const pair<_Up1, _Up2>&) = delete;
+
   // tuple(pair<U1, U2>&) constructors (including allocator_arg_t variants)
 
-  template <class _U1, class _U2, enable_if_t< _EnableCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr>
+  template <class _U1, class _U2, enable_if_t< _EnableNonDanglingCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(pair<_U1, _U2>& __p)
       : __base_(__from_tuple(), __p) {}
 
+  template <class _U1, class _U2, enable_if_t< _EnableDanglingCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
+      tuple(pair<_U1, _U2>&) = delete;
+
   template <class _Alloc,
             class _U1,
             class _U2,
-            enable_if_t< _EnableCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr>
+            enable_if_t< _EnableNonDanglingCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), __p) {}
-#    endif
+
+  template <class _Alloc,
+            class _U1,
+            class _U2,
+            enable_if_t< _EnableDanglingCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
+      tuple(allocator_arg_t, const _Alloc&, pair<_U1, _U2>&) = delete;
+#    endif // _LIBCPP_STD_VER >= 23
 
   // tuple(pair<U1, U2>&&) constructors (including allocator_arg_t variants)
 
   template <class _Up1,
             class _Up2,
             template <class...> class _And                                              = _And,
-            __enable_if_t< _And< _EnableCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
+            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(pair<_Up1, _Up2>&& __p) noexcept(_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value)
@@ -802,27 +969,59 @@ public:
             class _Up1,
             class _Up2,
             template <class...> class _And                                              = _And,
-            __enable_if_t< _And< _EnableCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
+            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p)
       : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__p)) {}
 
 #    if _LIBCPP_STD_VER >= 23
+  template <class _Up1,
+            class _Up2,
+            template <class...> class _And                                               = _And,
+            __enable_if_t< _And< _EnableDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
+      tuple(pair<_Up1, _Up2>&&) noexcept(_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value) = delete;
+
+  template <class _Alloc,
+            class _Up1,
+            class _Up2,
+            template <class...> class _And                                               = _And,
+            __enable_if_t< _And< _EnableDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, long> = 0>
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
+      tuple(allocator_arg_t, const _Alloc&, pair<_Up1, _Up2>&&) = delete;
+
   // tuple(const pair<U1, U2>&&) constructors (including allocator_arg_t variants)
 
-  template <class _U1, class _U2, enable_if_t< _EnableCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  template <class _U1,
+            class _U2,
+            enable_if_t< _EnableNonDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(const pair<_U1, _U2>&& __p)
       : __base_(__from_tuple(), std::move(__p)) {}
 
+  template <class _U1,
+            class _U2,
+            enable_if_t< _EnableDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
+      tuple(const pair<_U1, _U2>&&) = delete;
+
   template <class _Alloc,
             class _U1,
             class _U2,
-            enable_if_t< _EnableCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+            enable_if_t< _EnableNonDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, const pair<_U1, _U2>&& __p)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__p)) {}
+
+  template <class _Alloc,
+            class _U1,
+            class _U2,
+            enable_if_t< _EnableDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
+      tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
   // [tuple.assign]
diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
index a1a80483c4487..a44a38e3e17ed 100644
--- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
+++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03
+// REQUIRES: std-at-least-c++23
 
 // <tuple>
 
@@ -39,36 +40,33 @@ template <class ...Args>
 void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {}
 
 void f() {
-  // Test that we emit our diagnostic from the library.
-  // expected-error at tuple:* 8 {{Attempted construction of reference element binds to a temporary whose lifetime has ended}}
-
-  // Good news everybody! Clang now diagnoses this for us!
-  // expected-error at tuple:* 0+ {{reference member '__value_' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+  // Test that the public constructors are deleted when constructing a reference
+  // element would bind to a temporary.
 
   {
-    F<int, const std::string&>(std::make_tuple(1, "abc")); // expected-note 1 {{requested here}}
+    F<int, const std::string&>(std::make_tuple(1, "abc")); // expected-error {{deleted}}
   }
   {
-    std::tuple<int, const std::string&> t(1, "a"); // expected-note 1 {{requested here}}
+    std::tuple<int, const std::string&> t(1, "a"); // expected-error {{deleted}}
   }
   {
-    F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc")); // expected-note 1 {{requested here}}
+    F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc")); // expected-error {{deleted}}
   }
   {
     ConvertsTo<int&> ct;
-    std::tuple<const long&, int> t(ct, 42); // expected-note {{requested here}}
+    std::tuple<const long&, int> t(ct, 42); // expected-error {{deleted}}
   }
   {
     ConvertsTo<int> ct;
-    std::tuple<int const&, void*> t(ct, nullptr); // expected-note {{requested here}}
+    std::tuple<int const&, void*> t(ct, nullptr); // expected-error {{deleted}}
   }
   {
     ConvertsTo<Derived> ct;
-    std::tuple<Base const&, int> t(ct, 42); // expected-note {{requested here}}
+    std::tuple<Base const&, int> t(ct, 42); // expected-error {{deleted}}
   }
   {
     std::allocator<int> alloc;
-    std::tuple<std::string &&> t2("hello"); // expected-note {{requested here}}
-    std::tuple<std::string &&> t3(std::allocator_arg, alloc, "hello"); // expected-note {{requested here}}
+    std::tuple<std::string&&> t2("hello"); // expected-error {{deleted}}
+    std::tuple<std::string&&> t3(std::allocator_arg, alloc, "hello"); // expected-error {{deleted}}
   }
 }
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/ref_constructs_from_temporary.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/ref_constructs_from_temporary.verify.cpp
new file mode 100644
index 0000000000000..c7a5f4e247f3b
--- /dev/null
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/ref_constructs_from_temporary.verify.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <tuple>
+
+// tuple(UTypes&&... u);
+// tuple(tuple<UTypes...>& u);
+// tuple(const tuple<UTypes...>& u);
+// tuple(tuple<UTypes...>&& u);
+// tuple(const tuple<UTypes...>&& u);
+// tuple(pair<U1, U2>& u);
+// tuple(const pair<U1, U2>& u);
+// tuple(pair<U1, U2>&& u);
+// tuple(const pair<U1, U2>&& u);
+//
+// The constructors above are defined as deleted if reference_constructs_from_temporary_v
+// is true for one of the corresponding tuple elements.
+
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+struct X {
+  X(int);
+};
+
+static_assert(std::is_constructible_v<std::tuple<const X&>, X&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&>, int>);
+static_assert(!std::is_constructible_v<std::tuple<const X&>, std::tuple<int>&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&>, const std::tuple<int>&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&>, std::tuple<int>&&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&>, const std::tuple<int>&&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&, int>, std::pair<int, int>&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&, int>, const std::pair<int, int>&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&, int>, std::pair<int, int>&&>);
+static_assert(!std::is_constructible_v<std::tuple<const X&, int>, const std::pair<int, int>&&>);
+
+void test() {
+  std::allocator<int> alloc;
+  std::tuple<int> t(1);
+  const std::tuple<int> ct(1);
+  std::pair<int, int> p(1, 2);
+  const std::pair<int, int> cp(1, 2);
+
+  // expected-error-re@*:* 18 {{call to deleted constructor of 'std::tuple<{{.*}}>'}}
+  std::tuple<const X&> utypes(1);
+  std::tuple<const X&> alloc_utypes(std::allocator_arg, alloc, 1);
+
+  std::tuple<const X&> tuple_lvalue(t);
+  std::tuple<const X&> alloc_tuple_lvalue(std::allocator_arg, alloc, t);
+  std::tuple<const X&> const_tuple_lvalue(ct);
+  std::tuple<const X&> alloc_const_tuple_lvalue(std::allocator_arg, alloc, ct);
+  std::tuple<const X&> tuple_rvalue(std::tuple<int>{1});
+  std::tuple<const X&> alloc_tuple_rvalue(std::allocator_arg, alloc, std::tuple<int>{1});
+  std::tuple<const X&> const_tuple_rvalue(std::move(ct));
+  std::tuple<const X&> alloc_const_tuple_rvalue(std::allocator_arg, alloc, std::move(ct));
+
+  std::tuple<const X&, int> pair_lvalue(p);
+  std::tuple<const X&, int> alloc_pair_lvalue(std::allocator_arg, alloc, p);
+  std::tuple<const X&, int> const_pair_lvalue(cp);
+  std::tuple<const X&, int> alloc_const_pair_lvalue(std::allocator_arg, alloc, cp);
+  std::tuple<const X&, int> pair_rvalue(std::pair<int, int>{1, 2});
+  std::tuple<const X&, int> alloc_pair_rvalue(std::allocator_arg, alloc, std::pair<int, int>{1, 2});
+  std::tuple<const X&, int> const_pair_rvalue(std::move(cp));
+  std::tuple<const X&, int> alloc_const_pair_rvalue(std::allocator_arg, alloc, std::move(cp));
+}

>From 9d2d66b76aba200e90d0c67b487c13abb81f585e Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 24 Jun 2026 00:56:58 +0800
Subject: [PATCH 02/13] Format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple                          | 62 ++++++++-----------
 ...5_tuple_ref_binding_diagnostics.verify.cpp |  2 +-
 2 files changed, 26 insertions(+), 38 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 912b49c2b97de..edeb97aa9de80 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -617,8 +617,7 @@ public:
               is_constructible<_Tp, _Up>... > {};
 
   template <class... _Up>
-  struct _EnableUTypesCtorBase
-      : _And<_BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> > {};
+  struct _EnableUTypesCtorBase : _And<_BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> > {};
 
   template <bool, class... _Up>
   struct _EnableUTypesCtorNoDangling : false_type {};
@@ -642,8 +641,7 @@ public:
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class... _Up>
-  struct _EnableNonDanglingUTypesCtor
-      : _EnableUTypesCtorNoDangling<_EnableUTypesCtorBase<_Up...>::value, _Up...> {};
+  struct _EnableNonDanglingUTypesCtor : _EnableUTypesCtorNoDangling<_EnableUTypesCtorBase<_Up...>::value, _Up...> {};
 
   template <class... _Up, __enable_if_t< _EnableNonDanglingUTypesCtor<_Up...>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
@@ -714,11 +712,10 @@ public:
   struct _CtorFromUTypesTupleCreatesDanglingReference : false_type {};
 
   template <class _OtherTuple, class... _Up>
-  struct _CtorFromUTypesTupleCreatesDanglingReference<
-      true,
-      _OtherTuple,
-      tuple<_Up...>,
-      __enable_if_t<sizeof...(_Up) == sizeof...(_Tp)> >
+  struct _CtorFromUTypesTupleCreatesDanglingReference< true,
+                                                       _OtherTuple,
+                                                       tuple<_Up...>,
+                                                       __enable_if_t<sizeof...(_Up) == sizeof...(_Tp)> >
       : _Or<_BoolConstant<__reference_constructs_from_temporary_v<_Tp, __copy_cvref_t<_OtherTuple, _Up> > >...> {};
 
   template <class _OtherTuple>
@@ -737,8 +734,7 @@ public:
   struct _EnableNonDanglingCtorFromUTypesTuple
       : _EnableCtorFromUTypesTupleNoDangling<_EnableCtorFromUTypesTuple<_OtherTuple>::value, _OtherTuple> {};
 
-  template <class... _Up,
-            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, int> = 0>
+  template <class... _Up, __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(const tuple<_Up...>& __t) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value)
       : __base_(__from_tuple(), __t) {}
@@ -751,8 +747,7 @@ public:
       : __base_(allocator_arg_t(), __a, __from_tuple(), __t) {}
 
 #    if _LIBCPP_STD_VER >= 23
-  template <class... _Up,
-            __enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, long> = 0>
+  template <class... _Up, __enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, long> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(const tuple<_Up...>&) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value) = delete;
 
@@ -786,8 +781,7 @@ public:
 #    endif // _LIBCPP_STD_VER >= 23
 
   // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants)
-  template <class... _Up,
-            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, int> = 0>
+  template <class... _Up, __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(tuple<_Up...>&& __t) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
       : __base_(__from_tuple(), std::move(__t)) {}
@@ -812,8 +806,7 @@ public:
 
   // tuple(const tuple<U...>&&) constructors (including allocator_arg_t variants)
 
-  template <class... _Up,
-            enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  template <class... _Up, enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(const tuple<_Up...>&& __t)
       : __base_(__from_tuple(), std::move(__t)) {}
@@ -860,24 +853,22 @@ public:
 
   template <class _Pair, class _Up1, class _Up2, class _Tp1, class _Tp2>
   struct _CtorFromPairCreatesDanglingReference<true, _Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2> >
-      : _Or<
-            _BoolConstant<__reference_constructs_from_temporary_v<_Tp1, __copy_cvref_t<_Pair, _Up1> > >,
-            _BoolConstant<__reference_constructs_from_temporary_v<_Tp2, __copy_cvref_t<_Pair, _Up2> > > > {};
+      : _Or< _BoolConstant<__reference_constructs_from_temporary_v<_Tp1, __copy_cvref_t<_Pair, _Up1> > >,
+             _BoolConstant<__reference_constructs_from_temporary_v<_Tp2, __copy_cvref_t<_Pair, _Up2> > > > {};
 
   template <class _Pair>
   struct _EnableCtorFromPairNoDangling<true, _Pair> : _Not<_CtorFromPairCreatesDanglingReference<true, _Pair> > {};
 
   template <class _Pair>
-  struct _EnableDanglingCtorFromPair
-      : _CtorFromPairCreatesDanglingReference<_EnableCtorFromPair<_Pair>::value, _Pair> {};
+  struct _EnableDanglingCtorFromPair : _CtorFromPairCreatesDanglingReference<_EnableCtorFromPair<_Pair>::value, _Pair> {
+  };
 #    else
   template <class _Pair>
   struct _EnableCtorFromPairNoDangling<true, _Pair> : true_type {};
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class _Pair>
-  struct _EnableNonDanglingCtorFromPair
-      : _EnableCtorFromPairNoDangling<_EnableCtorFromPair<_Pair>::value, _Pair> {};
+  struct _EnableNonDanglingCtorFromPair : _EnableCtorFromPairNoDangling<_EnableCtorFromPair<_Pair>::value, _Pair> {};
 
   template <class _Pair>
   struct _NothrowConstructibleFromPair : _CtorPredicateFromPair<is_nothrow_constructible, _Pair> {};
@@ -891,7 +882,7 @@ public:
 
   template <class _Up1,
             class _Up2,
-            template <class...> class _And                                                   = _And,
+            template <class...> class _And                                                              = _And,
             __enable_if_t< _And< _EnableNonDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
@@ -901,7 +892,7 @@ public:
   template <class _Alloc,
             class _Up1,
             class _Up2,
-            template <class...> class _And                                                   = _And,
+            template <class...> class _And                                                              = _And,
             __enable_if_t< _And< _EnableNonDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
@@ -911,17 +902,16 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class _Up1,
             class _Up2,
-            template <class...> class _And                                                    = _And,
+            template <class...> class _And                                                            = _And,
             __enable_if_t< _And< _EnableDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, long> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
-      tuple(const pair<_Up1, _Up2>&) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value) =
-          delete;
+      tuple(const pair<_Up1, _Up2>&) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value) = delete;
 
   template <class _Alloc,
             class _Up1,
             class _Up2,
-            template <class...> class _And                                                    = _And,
+            template <class...> class _And                                                            = _And,
             __enable_if_t< _And< _EnableDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, long> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
@@ -958,7 +948,7 @@ public:
 
   template <class _Up1,
             class _Up2,
-            template <class...> class _And                                              = _And,
+            template <class...> class _And                                                         = _And,
             __enable_if_t< _And< _EnableNonDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
@@ -968,7 +958,7 @@ public:
   template <class _Alloc,
             class _Up1,
             class _Up2,
-            template <class...> class _And                                              = _And,
+            template <class...> class _And                                                         = _And,
             __enable_if_t< _And< _EnableNonDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
@@ -978,7 +968,7 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class _Up1,
             class _Up2,
-            template <class...> class _And                                               = _And,
+            template <class...> class _And                                                       = _And,
             __enable_if_t< _And< _EnableDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, long> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
@@ -987,7 +977,7 @@ public:
   template <class _Alloc,
             class _Up1,
             class _Up2,
-            template <class...> class _And                                               = _And,
+            template <class...> class _And                                                       = _And,
             __enable_if_t< _And< _EnableDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, long> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
@@ -1002,9 +992,7 @@ public:
       tuple(const pair<_U1, _U2>&& __p)
       : __base_(__from_tuple(), std::move(__p)) {}
 
-  template <class _U1,
-            class _U2,
-            enable_if_t< _EnableDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  template <class _U1, class _U2, enable_if_t< _EnableDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(const pair<_U1, _U2>&&) = delete;
 
diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
index a44a38e3e17ed..15d032fbb3a7a 100644
--- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
+++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
@@ -66,7 +66,7 @@ void f() {
   }
   {
     std::allocator<int> alloc;
-    std::tuple<std::string&&> t2("hello"); // expected-error {{deleted}}
+    std::tuple<std::string&&> t2("hello");                            // expected-error {{deleted}}
     std::tuple<std::string&&> t3(std::allocator_arg, alloc, "hello"); // expected-error {{deleted}}
   }
 }

>From 8520af98734cd4100ebad837b70a7f69985fb937 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 29 Jun 2026 09:41:49 -0700
Subject: [PATCH 03/13] [libc++] Refine the implementation use template
 variable and make reference_constructs_from_temporary SFINAE friendly

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../reference_constructs_from_temporary.h     |  15 +-
 libcxx/include/tuple                          | 240 ++++++++----------
 2 files changed, 126 insertions(+), 129 deletions(-)

diff --git a/libcxx/include/__type_traits/reference_constructs_from_temporary.h b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
index a8325620414ea..c18723fb77d81 100644
--- a/libcxx/include/__type_traits/reference_constructs_from_temporary.h
+++ b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__type_traits/integral_constant.h>
+#include <__type_traits/is_reference.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -30,8 +31,20 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_tempo
 
 #endif
 
+// A non-reference type can never bind to a temporary, so the result is always `false` for such a
+// `_Tp`. We short-circuit before reaching the builtin because Clang's `__reference_constructs_from_temporary`
+// eagerly instantiates the construction of `_Up` (including the element's constructor exception
+// specification) even when `_Tp` is not a reference, which can hard-error on misbehaved types.
+//
+// https://godbolt.org/z/WMTK5cMa4
+//
+// TODO: remove this guard once the Clang builtin short-circuits on a non-reference first operand.
+template <class _Tp, class _Up, bool = is_reference<_Tp>::value>
+inline const bool __reference_constructs_from_temporary_v = false;
+
 template <class _Tp, class _Up>
-inline const bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up);
+inline const bool __reference_constructs_from_temporary_v<_Tp, _Up, true> =
+    __reference_constructs_from_temporary(_Tp, _Up);
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index edeb97aa9de80..609cdf1f93dc4 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -623,42 +623,60 @@ public:
   struct _EnableUTypesCtorNoDangling : false_type {};
 
 #    if _LIBCPP_STD_VER >= 23
-  template <bool, class... _Up>
-  struct _CtorCreatesDanglingReference : false_type {};
-
   template <class... _Up>
-  struct _CtorCreatesDanglingReference<true, _Up...>
-      : _Or<_BoolConstant<__reference_constructs_from_temporary_v<_Tp, _Up&&> >...> {};
+  static constexpr bool __has_danglings() {
+    // The fold expands `_Tp` and `_Up` in lockstep, so it is only well-formed when the packs have
+    // equal length. The discarded branch is not instantiated when the lengths differ.
+    if constexpr (sizeof...(_Up) == sizeof...(_Tp))
+      return (__reference_constructs_from_temporary_v<_Tp, _Up&&> || ...);
+    else
+      return false;
+  }
 
-  template <class... _Up>
-  struct _EnableUTypesCtorNoDangling<true, _Up...> : _Not<_CtorCreatesDanglingReference<true, _Up...> > {};
+  template <class _Tuple,
+            class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
+  static inline constexpr bool __has_danglings_from_tuple_like = false;
+
+  template <class _Tuple, size_t... _Idx>
+  static inline constexpr bool __has_danglings_from_tuple_like<_Tuple, index_sequence<_Idx...>,
+    enable_if_t<__has_danglings<decltype(std::get<_Idx>(std::declval<_Tuple>()))...>()>> = true;
 
   template <class... _Up>
-  struct _EnableDanglingUTypesCtor : _CtorCreatesDanglingReference<_EnableUTypesCtorBase<_Up...>::value, _Up...> {};
-#    else
+  static inline constexpr bool __has_danglings_from_utypes =
+      _EnableUTypesCtorBase<_Up...>::value && __has_danglings<_Up...>();
+
   template <class... _Up>
-  struct _EnableUTypesCtorNoDangling<true, _Up...> : true_type {};
+  static inline constexpr bool __has_no_danglings_from_utypes =
+      _EnableUTypesCtorBase<_Up...>::value && !__has_danglings<_Up...>();
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class... _Up>
-  struct _EnableNonDanglingUTypesCtor : _EnableUTypesCtorNoDangling<_EnableUTypesCtorBase<_Up...>::value, _Up...> {};
+  static inline constexpr bool __enable_utypes_constructor_no_dangling() {
+#    if _LIBCPP_STD_VER >= 23
+    return __has_no_danglings_from_utypes<_Up...>;
+#    else
+    return _EnableUTypesCtorBase<_Up...>::value;
+#    endif // _LIBCPP_STD_VER >= 23
+  }
 
-  template <class... _Up, __enable_if_t< _EnableNonDanglingUTypesCtor<_Up...>::value, int> = 0>
+  template <class... _Up, __enable_if_t< __enable_utypes_constructor_no_dangling<_Up...>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(_Up&&... __u) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
       : __base_(__forward_args{}, std::forward<_Up>(__u)...) {}
 
-  template <class _Alloc, class... _Up, __enable_if_t< _EnableNonDanglingUTypesCtor<_Up...>::value, int> = 0>
+  template <class _Alloc, class... _Up, __enable_if_t< __enable_utypes_constructor_no_dangling<_Up...>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
       : __base_(allocator_arg_t(), __a, __forward_args{}, std::forward<_Up>(__u)...) {}
 
 #    if _LIBCPP_STD_VER >= 23
-  template <class... _Up, __enable_if_t< _EnableDanglingUTypesCtor<_Up...>::value, long> = 0>
+  template <class... _Up>
+    requires __has_danglings_from_utypes<_Up...>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(_Up&&...) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) = delete;
 
-  template <class _Alloc, class... _Up, __enable_if_t< _EnableDanglingUTypesCtor<_Up...>::value, long> = 0>
+  template <class _Alloc, class... _Up>
+    requires __has_danglings_from_utypes<_Up...>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, _Up&&...) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
@@ -708,123 +726,116 @@ public:
   struct _EnableCtorFromUTypesTupleNoDangling : false_type {};
 
 #    if _LIBCPP_STD_VER >= 23
-  template <bool, class _OtherTuple, class _DecayedOtherTuple = __remove_cvref_t<_OtherTuple>, class = void>
-  struct _CtorFromUTypesTupleCreatesDanglingReference : false_type {};
-
-  template <class _OtherTuple, class... _Up>
-  struct _CtorFromUTypesTupleCreatesDanglingReference< true,
-                                                       _OtherTuple,
-                                                       tuple<_Up...>,
-                                                       __enable_if_t<sizeof...(_Up) == sizeof...(_Tp)> >
-      : _Or<_BoolConstant<__reference_constructs_from_temporary_v<_Tp, __copy_cvref_t<_OtherTuple, _Up> > >...> {};
-
   template <class _OtherTuple>
-  struct _EnableCtorFromUTypesTupleNoDangling<true, _OtherTuple>
-      : _Not<_CtorFromUTypesTupleCreatesDanglingReference<true, _OtherTuple> > {};
+  static inline constexpr bool __has_danglings_from_utypes_tuple =
+      _EnableCtorFromUTypesTuple<_OtherTuple>::value && __has_danglings_from_tuple_like<_OtherTuple>;
 
   template <class _OtherTuple>
-  struct _EnableDanglingCtorFromUTypesTuple
-      : _CtorFromUTypesTupleCreatesDanglingReference<_EnableCtorFromUTypesTuple<_OtherTuple>::value, _OtherTuple> {};
-#    else
-  template <class _OtherTuple>
-  struct _EnableCtorFromUTypesTupleNoDangling<true, _OtherTuple> : true_type {};
+  static inline constexpr bool __has_no_danglings_from_utypes_tuple =
+      _EnableCtorFromUTypesTuple<_OtherTuple>::value && !__has_danglings_from_tuple_like<_OtherTuple>;
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class _OtherTuple>
-  struct _EnableNonDanglingCtorFromUTypesTuple
-      : _EnableCtorFromUTypesTupleNoDangling<_EnableCtorFromUTypesTuple<_OtherTuple>::value, _OtherTuple> {};
+  static inline constexpr bool __enable_utypes_tuple_constructor_no_dangling() {
+#    if _LIBCPP_STD_VER >= 23
+    return __has_no_danglings_from_utypes_tuple<_OtherTuple>;
+#    else
+    return _EnableCtorFromUTypesTuple<_OtherTuple>::value;
+#    endif // _LIBCPP_STD_VER >= 23
+  }
 
-  template <class... _Up, __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, int> = 0>
+  template <class... _Up,
+            __enable_if_t< __enable_utypes_tuple_constructor_no_dangling<const tuple<_Up...>&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(const tuple<_Up...>& __t) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value)
       : __base_(__from_tuple(), __t) {}
 
   template <class... _Up,
             class _Alloc,
-            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, int> = 0>
+            __enable_if_t< __enable_utypes_tuple_constructor_no_dangling<const tuple<_Up...>&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t)
       : __base_(allocator_arg_t(), __a, __from_tuple(), __t) {}
 
 #    if _LIBCPP_STD_VER >= 23
-  template <class... _Up, __enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, long> = 0>
+  template <class... _Up>
+    requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(const tuple<_Up...>&) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value) = delete;
 
-  template <class... _Up,
-            class _Alloc,
-            __enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&>::value, long> = 0>
+  template <class... _Up, class _Alloc>
+    requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&) = delete;
 
   // tuple(tuple<U...>&) constructors (including allocator_arg_t variants)
 
-  template <class... _Up, enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  template <class... _Up>
+    requires __has_no_danglings_from_utypes_tuple<tuple<_Up...>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>& __t)
       : __base_(__from_tuple(), __t) {}
 
-  template <class... _Up, enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  template <class... _Up>
+    requires __has_danglings_from_utypes_tuple<tuple<_Up...>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>&) = delete;
 
-  template <class _Alloc,
-            class... _Up,
-            enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  template <class _Alloc, class... _Up>
+    requires __has_no_danglings_from_utypes_tuple<tuple<_Up...>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), __t) {}
 
-  template <class _Alloc,
-            class... _Up,
-            enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr>
+  template <class _Alloc, class... _Up>
+    requires __has_danglings_from_utypes_tuple<tuple<_Up...>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
   // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants)
-  template <class... _Up, __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, int> = 0>
+  template <class... _Up, __enable_if_t< __enable_utypes_tuple_constructor_no_dangling<tuple<_Up...>&&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(tuple<_Up...>&& __t) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
       : __base_(__from_tuple(), std::move(__t)) {}
 
   template <class _Alloc,
             class... _Up,
-            __enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, int> = 0>
+            __enable_if_t< __enable_utypes_tuple_constructor_no_dangling<tuple<_Up...>&&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t)
       : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__t)) {}
 
 #    if _LIBCPP_STD_VER >= 23
-  template <class... _Up, __enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, long> = 0>
+  template <class... _Up>
+    requires __has_danglings_from_utypes_tuple<tuple<_Up...>&&>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(tuple<_Up...>&&) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) = delete;
 
-  template <class _Alloc,
-            class... _Up,
-            __enable_if_t< _EnableDanglingCtorFromUTypesTuple<tuple<_Up...>&&>::value, long> = 0>
+  template <class _Alloc, class... _Up>
+    requires __has_danglings_from_utypes_tuple<tuple<_Up...>&&>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&&) = delete;
 
   // tuple(const tuple<U...>&&) constructors (including allocator_arg_t variants)
 
-  template <class... _Up, enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  template <class... _Up>
+    requires __has_no_danglings_from_utypes_tuple<const tuple<_Up...>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(const tuple<_Up...>&& __t)
       : __base_(__from_tuple(), std::move(__t)) {}
 
-  template <class... _Up, enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  template <class... _Up>
+    requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(const tuple<_Up...>&&) = delete;
 
-  template <class _Alloc,
-            class... _Up,
-            enable_if_t< _EnableNonDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  template <class _Alloc, class... _Up>
+    requires __has_no_danglings_from_utypes_tuple<const tuple<_Up...>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, const tuple<_Up...>&& __t)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__t)) {}
 
-  template <class _Alloc,
-            class... _Up,
-            enable_if_t< _EnableDanglingCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr>
+  template <class _Alloc, class... _Up>
+    requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
@@ -844,31 +855,24 @@ public:
   template <class _Pair>
   struct _EnableCtorFromPair : _CtorPredicateFromPair<is_constructible, _Pair> {};
 
-  template <bool, class _Pair>
-  struct _EnableCtorFromPairNoDangling : false_type {};
-
 #    if _LIBCPP_STD_VER >= 23
-  template <bool, class _Pair, class _DecayedPair = __remove_cvref_t<_Pair>, class _Tuple = tuple>
-  struct _CtorFromPairCreatesDanglingReference : false_type {};
-
-  template <class _Pair, class _Up1, class _Up2, class _Tp1, class _Tp2>
-  struct _CtorFromPairCreatesDanglingReference<true, _Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2> >
-      : _Or< _BoolConstant<__reference_constructs_from_temporary_v<_Tp1, __copy_cvref_t<_Pair, _Up1> > >,
-             _BoolConstant<__reference_constructs_from_temporary_v<_Tp2, __copy_cvref_t<_Pair, _Up2> > > > {};
-
   template <class _Pair>
-  struct _EnableCtorFromPairNoDangling<true, _Pair> : _Not<_CtorFromPairCreatesDanglingReference<true, _Pair> > {};
+  static inline constexpr bool __has_danglings_from_utypes_pair =
+      _EnableCtorFromPair<_Pair>::value && __has_danglings_from_tuple_like<_Pair>;
 
   template <class _Pair>
-  struct _EnableDanglingCtorFromPair : _CtorFromPairCreatesDanglingReference<_EnableCtorFromPair<_Pair>::value, _Pair> {
-  };
-#    else
-  template <class _Pair>
-  struct _EnableCtorFromPairNoDangling<true, _Pair> : true_type {};
+  static inline constexpr bool __has_no_danglings_from_utypes_pair =
+      _EnableCtorFromPair<_Pair>::value && !__has_danglings_from_tuple_like<_Pair>;
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class _Pair>
-  struct _EnableNonDanglingCtorFromPair : _EnableCtorFromPairNoDangling<_EnableCtorFromPair<_Pair>::value, _Pair> {};
+  static inline constexpr bool __enable_utypes_pair_constructor_no_dangling() {
+#    if _LIBCPP_STD_VER >= 23
+    return _EnableCtorFromPair<_Pair>::value && __has_no_danglings_from_utypes_pair<_Pair>;
+#    else
+    return _EnableCtorFromPair<_Pair>::value;
+#    endif // _LIBCPP_STD_VER >= 23
+  }
 
   template <class _Pair>
   struct _NothrowConstructibleFromPair : _CtorPredicateFromPair<is_nothrow_constructible, _Pair> {};
@@ -882,8 +886,7 @@ public:
 
   template <class _Up1,
             class _Up2,
-            template <class...> class _And                                                              = _And,
-            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
+            __enable_if_t<__enable_utypes_pair_constructor_no_dangling<const pair<_Up1, _Up2>&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(const pair<_Up1, _Up2>& __p) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value)
@@ -892,54 +895,46 @@ public:
   template <class _Alloc,
             class _Up1,
             class _Up2,
-            template <class...> class _And                                                              = _And,
-            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, int> = 0>
+            __enable_if_t<__enable_utypes_pair_constructor_no_dangling<const pair<_Up1, _Up2>&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p)
       : __base_(allocator_arg_t(), __a, __from_tuple(), __p) {}
 
 #    if _LIBCPP_STD_VER >= 23
-  template <class _Up1,
-            class _Up2,
-            template <class...> class _And                                                            = _And,
-            __enable_if_t< _And< _EnableDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, long> = 0>
+  template <class _Up1, class _Up2>
+    requires __has_danglings_from_utypes_pair<const pair<_Up1, _Up2>&>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(const pair<_Up1, _Up2>&) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value) = delete;
 
-  template <class _Alloc,
-            class _Up1,
-            class _Up2,
-            template <class...> class _And                                                            = _And,
-            __enable_if_t< _And< _EnableDanglingCtorFromPair<const pair<_Up1, _Up2>&> >::value, long> = 0>
+  template <class _Alloc, class _Up1, class _Up2>
+    requires __has_danglings_from_utypes_pair<const pair<_Up1, _Up2>&>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(allocator_arg_t, const _Alloc&, const pair<_Up1, _Up2>&) = delete;
 
   // tuple(pair<U1, U2>&) constructors (including allocator_arg_t variants)
 
-  template <class _U1, class _U2, enable_if_t< _EnableNonDanglingCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr>
+  template <class _U1, class _U2>
+    requires __has_no_danglings_from_utypes_pair<pair<_U1, _U2>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(pair<_U1, _U2>& __p)
       : __base_(__from_tuple(), __p) {}
 
-  template <class _U1, class _U2, enable_if_t< _EnableDanglingCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr>
+  template <class _U1, class _U2>
+    requires __has_danglings_from_utypes_pair<pair<_U1, _U2>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(pair<_U1, _U2>&) = delete;
 
-  template <class _Alloc,
-            class _U1,
-            class _U2,
-            enable_if_t< _EnableNonDanglingCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr>
+  template <class _Alloc, class _U1, class _U2>
+    requires __has_no_danglings_from_utypes_pair<std::pair<_U1, _U2>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), __p) {}
 
-  template <class _Alloc,
-            class _U1,
-            class _U2,
-            enable_if_t< _EnableDanglingCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr>
+  template <class _Alloc, class _U1, class _U2>
+    requires __has_danglings_from_utypes_pair<std::pair<_U1, _U2>&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(allocator_arg_t, const _Alloc&, pair<_U1, _U2>&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
@@ -948,8 +943,7 @@ public:
 
   template <class _Up1,
             class _Up2,
-            template <class...> class _And                                                         = _And,
-            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
+            __enable_if_t< __enable_utypes_pair_constructor_no_dangling<pair<_Up1, _Up2>&&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(pair<_Up1, _Up2>&& __p) noexcept(_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value)
@@ -958,56 +952,46 @@ public:
   template <class _Alloc,
             class _Up1,
             class _Up2,
-            template <class...> class _And                                                         = _And,
-            __enable_if_t< _And< _EnableNonDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, int> = 0>
+            __enable_if_t< __enable_utypes_pair_constructor_no_dangling<pair<_Up1, _Up2>&&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p)
       : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__p)) {}
 
 #    if _LIBCPP_STD_VER >= 23
-  template <class _Up1,
-            class _Up2,
-            template <class...> class _And                                                       = _And,
-            __enable_if_t< _And< _EnableDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, long> = 0>
+  template <class _Up1, class _Up2>
+    requires __has_danglings_from_utypes_pair<pair<_Up1, _Up2>&&>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(pair<_Up1, _Up2>&&) noexcept(_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value) = delete;
 
-  template <class _Alloc,
-            class _Up1,
-            class _Up2,
-            template <class...> class _And                                                       = _And,
-            __enable_if_t< _And< _EnableDanglingCtorFromPair<pair<_Up1, _Up2>&&> >::value, long> = 0>
+  template <class _Alloc, class _Up1, class _Up2>
+    requires __has_danglings_from_utypes_pair<pair<_Up1, _Up2>&&>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(allocator_arg_t, const _Alloc&, pair<_Up1, _Up2>&&) = delete;
 
   // tuple(const pair<U1, U2>&&) constructors (including allocator_arg_t variants)
 
-  template <class _U1,
-            class _U2,
-            enable_if_t< _EnableNonDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  template <class _U1, class _U2>
+    requires __has_no_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(const pair<_U1, _U2>&& __p)
       : __base_(__from_tuple(), std::move(__p)) {}
 
-  template <class _U1, class _U2, enable_if_t< _EnableDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  template <class _U1, class _U2>
+    requires __has_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(const pair<_U1, _U2>&&) = delete;
 
-  template <class _Alloc,
-            class _U1,
-            class _U2,
-            enable_if_t< _EnableNonDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  template <class _Alloc, class _U1, class _U2>
+    requires __has_no_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(allocator_arg_t, const _Alloc& __alloc, const pair<_U1, _U2>&& __p)
       : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__p)) {}
 
-  template <class _Alloc,
-            class _U1,
-            class _U2,
-            enable_if_t< _EnableDanglingCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr>
+  template <class _Alloc, class _U1, class _U2>
+    requires __has_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23

>From f8ba2c9c885db176fef5158cd1602b9beaa293ac Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 29 Jun 2026 09:46:03 -0700
Subject: [PATCH 04/13] [libc++] Enable test for all language modes

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
index 15d032fbb3a7a..0e9992194f03c 100644
--- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
+++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03
-// REQUIRES: std-at-least-c++23
 
 // <tuple>
 

>From 3d87818fe02261235ef78f2f638b5a6dba300edb Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 29 Jun 2026 10:06:24 -0700
Subject: [PATCH 05/13] Remove unnecessary for deleted ctors

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple | 46 +++++++++++++++++---------------------------
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 609cdf1f93dc4..687192b6ffead 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -672,13 +672,12 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class... _Up>
     requires __has_danglings_from_utypes<_Up...>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
+  explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(_Up&&...) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) = delete;
 
   template <class _Alloc, class... _Up>
     requires __has_danglings_from_utypes<_Up...>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
-      tuple(allocator_arg_t, const _Alloc&, _Up&&...) = delete;
+  explicit(!_And<is_convertible<_Up, _Tp>...>::value) tuple(allocator_arg_t, const _Alloc&, _Up&&...) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
   // Copy and move constructors (including the allocator_arg_t variants)
@@ -760,12 +759,12 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class... _Up>
     requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
+  explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(const tuple<_Up...>&) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value) = delete;
 
   template <class... _Up, class _Alloc>
     requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
+  explicit(!_And<is_convertible<const _Up&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&) = delete;
 
   // tuple(tuple<U...>&) constructors (including allocator_arg_t variants)
@@ -777,7 +776,7 @@ public:
 
   template <class... _Up>
     requires __has_danglings_from_utypes_tuple<tuple<_Up...>&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>&) = delete;
+  explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>&) = delete;
 
   template <class _Alloc, class... _Up>
     requires __has_no_danglings_from_utypes_tuple<tuple<_Up...>&>
@@ -787,8 +786,7 @@ public:
 
   template <class _Alloc, class... _Up>
     requires __has_danglings_from_utypes_tuple<tuple<_Up...>&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<_Up&, _Tp>...>::value)
-      tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&) = delete;
+  explicit(!_And<is_convertible<_Up&, _Tp>...>::value) tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
   // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants)
@@ -807,13 +805,12 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class... _Up>
     requires __has_danglings_from_utypes_tuple<tuple<_Up...>&&>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
+  explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(tuple<_Up...>&&) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) = delete;
 
   template <class _Alloc, class... _Up>
     requires __has_danglings_from_utypes_tuple<tuple<_Up...>&&>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
-      tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&&) = delete;
+  explicit(!_And<is_convertible<_Up, _Tp>...>::value) tuple(allocator_arg_t, const _Alloc&, tuple<_Up...>&&) = delete;
 
   // tuple(const tuple<U...>&&) constructors (including allocator_arg_t variants)
 
@@ -825,8 +822,7 @@ public:
 
   template <class... _Up>
     requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
-      tuple(const tuple<_Up...>&&) = delete;
+  explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value) tuple(const tuple<_Up...>&&) = delete;
 
   template <class _Alloc, class... _Up>
     requires __has_no_danglings_from_utypes_tuple<const tuple<_Up...>&&>
@@ -836,7 +832,7 @@ public:
 
   template <class _Alloc, class... _Up>
     requires __has_danglings_from_utypes_tuple<const tuple<_Up...>&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
+  explicit(!_And<is_convertible<const _Up&&, _Tp>...>::value)
       tuple(allocator_arg_t, const _Alloc&, const tuple<_Up...>&&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
@@ -904,14 +900,12 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class _Up1, class _Up2>
     requires __has_danglings_from_utypes_pair<const pair<_Up1, _Up2>&>
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
+  explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(const pair<_Up1, _Up2>&) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value) = delete;
 
   template <class _Alloc, class _Up1, class _Up2>
     requires __has_danglings_from_utypes_pair<const pair<_Up1, _Up2>&>
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
+  explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value)
       tuple(allocator_arg_t, const _Alloc&, const pair<_Up1, _Up2>&) = delete;
 
   // tuple(pair<U1, U2>&) constructors (including allocator_arg_t variants)
@@ -924,8 +918,7 @@ public:
 
   template <class _U1, class _U2>
     requires __has_danglings_from_utypes_pair<pair<_U1, _U2>&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
-      tuple(pair<_U1, _U2>&) = delete;
+  explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value) tuple(pair<_U1, _U2>&) = delete;
 
   template <class _Alloc, class _U1, class _U2>
     requires __has_no_danglings_from_utypes_pair<std::pair<_U1, _U2>&>
@@ -935,7 +928,7 @@ public:
 
   template <class _Alloc, class _U1, class _U2>
     requires __has_danglings_from_utypes_pair<std::pair<_U1, _U2>&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
+  explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value)
       tuple(allocator_arg_t, const _Alloc&, pair<_U1, _U2>&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 
@@ -961,14 +954,12 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class _Up1, class _Up2>
     requires __has_danglings_from_utypes_pair<pair<_Up1, _Up2>&&>
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
+  explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(pair<_Up1, _Up2>&&) noexcept(_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value) = delete;
 
   template <class _Alloc, class _Up1, class _Up2>
     requires __has_danglings_from_utypes_pair<pair<_Up1, _Up2>&&>
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
+  explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value)
       tuple(allocator_arg_t, const _Alloc&, pair<_Up1, _Up2>&&) = delete;
 
   // tuple(const pair<U1, U2>&&) constructors (including allocator_arg_t variants)
@@ -981,8 +972,7 @@ public:
 
   template <class _U1, class _U2>
     requires __has_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
-      tuple(const pair<_U1, _U2>&&) = delete;
+  explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value) tuple(const pair<_U1, _U2>&&) = delete;
 
   template <class _Alloc, class _U1, class _U2>
     requires __has_no_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
@@ -992,7 +982,7 @@ public:
 
   template <class _Alloc, class _U1, class _U2>
     requires __has_danglings_from_utypes_pair<const pair<_U1, _U2>&&>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
+  explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value)
       tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&&) = delete;
 #    endif // _LIBCPP_STD_VER >= 23
 

>From 8ff04dd78e88eafd4876196dd6c88a02b061da0f Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 29 Jun 2026 10:13:12 -0700
Subject: [PATCH 06/13] Format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 687192b6ffead..7f444a5333f75 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -633,13 +633,14 @@ public:
       return false;
   }
 
-  template <class _Tuple,
-            class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
+  template <class _Tuple, class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
   static inline constexpr bool __has_danglings_from_tuple_like = false;
 
   template <class _Tuple, size_t... _Idx>
-  static inline constexpr bool __has_danglings_from_tuple_like<_Tuple, index_sequence<_Idx...>,
-    enable_if_t<__has_danglings<decltype(std::get<_Idx>(std::declval<_Tuple>()))...>()>> = true;
+  static inline constexpr bool __has_danglings_from_tuple_like<
+      _Tuple,
+      index_sequence<_Idx...>,
+      enable_if_t<__has_danglings<decltype(std::get<_Idx>(std::declval<_Tuple>()))...>()>> = true;
 
   template <class... _Up>
   static inline constexpr bool __has_danglings_from_utypes =

>From bb0fa0f1cbee157e39dd52b254da55b2bb59fa5d Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Mon, 29 Jun 2026 10:20:32 -0700
Subject: [PATCH 07/13] Remove unnecessary comments

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 7f444a5333f75..22641af8f494c 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -625,8 +625,6 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class... _Up>
   static constexpr bool __has_danglings() {
-    // The fold expands `_Tp` and `_Up` in lockstep, so it is only well-formed when the packs have
-    // equal length. The discarded branch is not instantiated when the lengths differ.
     if constexpr (sizeof...(_Up) == sizeof...(_Tp))
       return (__reference_constructs_from_temporary_v<_Tp, _Up&&> || ...);
     else

>From 70175b01fa43cb47b44ef3974124e5d3e8366476 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 30 Jun 2026 00:06:59 -0700
Subject: [PATCH 08/13] [libc++] Fix hard error in deleted dangling ctor
 constraints

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 22641af8f494c..0a95aa635663d 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -640,13 +640,25 @@ public:
       index_sequence<_Idx...>,
       enable_if_t<__has_danglings<decltype(std::get<_Idx>(std::declval<_Tuple>()))...>()>> = true;
 
+  template <bool __dangles, class _CtorEnabled>
+  static inline constexpr bool __check_danglings_from_constructor = false;
+
+  template <class _CtorEnabled>
+  static inline constexpr bool __check_danglings_from_constructor<true, _CtorEnabled> = _CtorEnabled::value;
+
+  template <bool __dangles, class _CtorEnabled>
+  static inline constexpr bool __check_no_danglings_from_constructor = _CtorEnabled::value;
+
+  template <class _CtorEnabled>
+  static inline constexpr bool __check_no_danglings_from_constructor<true, _CtorEnabled> = false;
+
   template <class... _Up>
   static inline constexpr bool __has_danglings_from_utypes =
-      _EnableUTypesCtorBase<_Up...>::value && __has_danglings<_Up...>();
+      __check_danglings_from_constructor<__has_danglings<_Up...>(), _EnableUTypesCtorBase<_Up...> >;
 
   template <class... _Up>
   static inline constexpr bool __has_no_danglings_from_utypes =
-      _EnableUTypesCtorBase<_Up...>::value && !__has_danglings<_Up...>();
+      __check_no_danglings_from_constructor<__has_danglings<_Up...>(), _EnableUTypesCtorBase<_Up...> >;
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class... _Up>
@@ -726,11 +738,13 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class _OtherTuple>
   static inline constexpr bool __has_danglings_from_utypes_tuple =
-      _EnableCtorFromUTypesTuple<_OtherTuple>::value && __has_danglings_from_tuple_like<_OtherTuple>;
+      __check_danglings_from_constructor<__has_danglings_from_tuple_like<_OtherTuple>,
+                                         _EnableCtorFromUTypesTuple<_OtherTuple> >;
 
   template <class _OtherTuple>
   static inline constexpr bool __has_no_danglings_from_utypes_tuple =
-      _EnableCtorFromUTypesTuple<_OtherTuple>::value && !__has_danglings_from_tuple_like<_OtherTuple>;
+      __check_no_danglings_from_constructor<__has_danglings_from_tuple_like<_OtherTuple>,
+                                            _EnableCtorFromUTypesTuple<_OtherTuple> >;
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class _OtherTuple>
@@ -853,11 +867,11 @@ public:
 #    if _LIBCPP_STD_VER >= 23
   template <class _Pair>
   static inline constexpr bool __has_danglings_from_utypes_pair =
-      _EnableCtorFromPair<_Pair>::value && __has_danglings_from_tuple_like<_Pair>;
+      __check_danglings_from_constructor<__has_danglings_from_tuple_like<_Pair>, _EnableCtorFromPair<_Pair> >;
 
   template <class _Pair>
   static inline constexpr bool __has_no_danglings_from_utypes_pair =
-      _EnableCtorFromPair<_Pair>::value && !__has_danglings_from_tuple_like<_Pair>;
+      __check_no_danglings_from_constructor<__has_danglings_from_tuple_like<_Pair>, _EnableCtorFromPair<_Pair> >;
 #    endif // _LIBCPP_STD_VER >= 23
 
   template <class _Pair>

>From d59c4503c1096aac398768060bb6fda5809325cf Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 30 Jun 2026 00:57:48 -0700
Subject: [PATCH 09/13] Fix modules build and don't depends tuple_size_v

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 0a95aa635663d..a2a72cc352f86 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -631,14 +631,16 @@ public:
       return false;
   }
 
-  template <class _Tuple, class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
+  template <class _Source, class _DecayedSource = __remove_cvref_t<_Source> >
   static inline constexpr bool __has_danglings_from_tuple_like = false;
 
-  template <class _Tuple, size_t... _Idx>
-  static inline constexpr bool __has_danglings_from_tuple_like<
-      _Tuple,
-      index_sequence<_Idx...>,
-      enable_if_t<__has_danglings<decltype(std::get<_Idx>(std::declval<_Tuple>()))...>()>> = true;
+  template <class _Source, class... _Up>
+  static inline constexpr bool __has_danglings_from_tuple_like<_Source, tuple<_Up...> > =
+      __has_danglings<__copy_cvref_t<_Source, _Up>...>();
+
+  template <class _Source, class _U1, class _U2>
+  static inline constexpr bool __has_danglings_from_tuple_like<_Source, pair<_U1, _U2> > =
+      __has_danglings<__copy_cvref_t<_Source, _U1>, __copy_cvref_t<_Source, _U2> >();
 
   template <bool __dangles, class _CtorEnabled>
   static inline constexpr bool __check_danglings_from_constructor = false;

>From 958f25ad57ee72b3ef853b69856e04be8cba2477 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 30 Jun 2026 02:36:45 -0700
Subject: [PATCH 10/13] Fix test

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 ...5_tuple_ref_binding_diagnostics.verify.cpp | 34 ++++++++++---------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
index 0e9992194f03c..3c2cee9f16153 100644
--- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
+++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
@@ -39,33 +39,35 @@ template <class ...Args>
 void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {}
 
 void f() {
-  // Test that the public constructors are deleted when constructing a reference
-  // element would bind to a temporary.
+  // Constructing a reference element that would bind to a temporary is rejected. Since C++23
+  // ([tuple.cnstr]) the offending constructors are deleted, so the error is reported at the call;
+  // before C++23 the bind is caught by a static_assert in the library (with Clang additionally
+  // diagnosing the dangling reference member).
+#if TEST_STD_VER >= 23
+  // expected-error@*:* 8 {{deleted}}
+#else
+  // expected-error at tuple:* 8 {{Attempted construction of reference element binds to a temporary whose lifetime has ended}}
+  // expected-error at tuple:* 0+ {{reference member '__value_' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
 
-  {
-    F<int, const std::string&>(std::make_tuple(1, "abc")); // expected-error {{deleted}}
-  }
-  {
-    std::tuple<int, const std::string&> t(1, "a"); // expected-error {{deleted}}
-  }
-  {
-    F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc")); // expected-error {{deleted}}
-  }
+  { F<int, const std::string&>(std::make_tuple(1, "abc")); }
+  { std::tuple<int, const std::string&> t(1, "a"); }
+  { F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc")); }
   {
     ConvertsTo<int&> ct;
-    std::tuple<const long&, int> t(ct, 42); // expected-error {{deleted}}
+    std::tuple<const long&, int> t(ct, 42);
   }
   {
     ConvertsTo<int> ct;
-    std::tuple<int const&, void*> t(ct, nullptr); // expected-error {{deleted}}
+    std::tuple<int const&, void*> t(ct, nullptr);
   }
   {
     ConvertsTo<Derived> ct;
-    std::tuple<Base const&, int> t(ct, 42); // expected-error {{deleted}}
+    std::tuple<Base const&, int> t(ct, 42);
   }
   {
     std::allocator<int> alloc;
-    std::tuple<std::string&&> t2("hello");                            // expected-error {{deleted}}
-    std::tuple<std::string&&> t3(std::allocator_arg, alloc, "hello"); // expected-error {{deleted}}
+    std::tuple<std::string&&> t2("hello");
+    std::tuple<std::string&&> t3(std::allocator_arg, alloc, "hello");
   }
 }

>From 2979a29eea2fdbe5591a618ace2c28b81b97cc75 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 30 Jun 2026 03:38:32 -0700
Subject: [PATCH 11/13] Format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../PR20855_tuple_ref_binding_diagnostics.verify.cpp | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
index 3c2cee9f16153..26fc99ae7bbac 100644
--- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
+++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
@@ -50,9 +50,15 @@ void f() {
   // expected-error at tuple:* 0+ {{reference member '__value_' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
 #endif
 
-  { F<int, const std::string&>(std::make_tuple(1, "abc")); }
-  { std::tuple<int, const std::string&> t(1, "a"); }
-  { F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc")); }
+  {
+    F<int, const std::string&>(std::make_tuple(1, "abc"));
+  }
+  {
+    std::tuple<int, const std::string&> t(1, "a");
+  }
+  {
+    F<int, const std::string&>(std::tuple<int, const std::string&>(1, "abc"));
+  }
   {
     ConvertsTo<int&> ct;
     std::tuple<const long&, int> t(ct, 42);

>From d3a513dc07967195de656085104a942d5e84db31 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 2 Jul 2026 04:22:09 -0700
Subject: [PATCH 12/13] Avoid workaround for
 reference_constructs_from_temporary builtin, it's fixed in clang-23; we will
 skip the related test for older version clang

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../reference_constructs_from_temporary.h         | 15 +--------------
 .../PR23256_constrain_UTypes_ctor.pass.cpp        |  5 +++++
 .../tuple.cnstr/convert_const_move.pass.cpp       |  7 ++++++-
 .../tuple/tuple.tuple/tuple.cnstr/move.pass.cpp   |  4 ++++
 4 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/libcxx/include/__type_traits/reference_constructs_from_temporary.h b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
index c18723fb77d81..a8325620414ea 100644
--- a/libcxx/include/__type_traits/reference_constructs_from_temporary.h
+++ b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
@@ -11,7 +11,6 @@
 
 #include <__config>
 #include <__type_traits/integral_constant.h>
-#include <__type_traits/is_reference.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -31,20 +30,8 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_tempo
 
 #endif
 
-// A non-reference type can never bind to a temporary, so the result is always `false` for such a
-// `_Tp`. We short-circuit before reaching the builtin because Clang's `__reference_constructs_from_temporary`
-// eagerly instantiates the construction of `_Up` (including the element's constructor exception
-// specification) even when `_Tp` is not a reference, which can hard-error on misbehaved types.
-//
-// https://godbolt.org/z/WMTK5cMa4
-//
-// TODO: remove this guard once the Clang builtin short-circuits on a non-reference first operand.
-template <class _Tp, class _Up, bool = is_reference<_Tp>::value>
-inline const bool __reference_constructs_from_temporary_v = false;
-
 template <class _Tp, class _Up>
-inline const bool __reference_constructs_from_temporary_v<_Tp, _Up, true> =
-    __reference_constructs_from_temporary(_Tp, _Up);
+inline const bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up);
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
index ebc31ce01cfc7..893987ce5f587 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
@@ -64,6 +64,9 @@ struct ExplicitUnconstrainedCtor {
 int main(int, char**) {
     typedef UnconstrainedCtor A;
     typedef ExplicitUnconstrainedCtor ExplicitA;
+
+// Remove this guard when compiler versions older than clang 23 are no longer supported.
+#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
     {
         static_assert(std::is_copy_constructible<std::tuple<A>>::value, "");
         static_assert(std::is_move_constructible<std::tuple<A>>::value, "");
@@ -92,6 +95,8 @@ int main(int, char**) {
             std::tuple<ExplicitA> &&
         >::value, "");
     }
+#endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
+
     {
         std::tuple<A&&> t(std::forward_as_tuple(A{}));
         ((void)t);
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp
index 8f778f3fcf3a4..a8ed156a2fc33 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp
@@ -113,6 +113,9 @@ constexpr bool test() {
 
   // These two test points cause gcc to ICE
 #if !defined(TEST_COMPILER_GCC)
+
+// Remove this guard when compiler versions older than clang 23 are no longer supported.
+#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
   // sizeof...(Types) == 1 && is_convertible_v<decltype(u), T>
   {
     const std::tuple<CvtFromConstTupleRefRef> t1{};
@@ -126,7 +129,9 @@ constexpr bool test() {
     std::tuple<ConvertibleFrom<ExplicitCtrFromConstTupleRefRef>> t2{std::move(t1)};
     assert(!constMoveCtrCalled(std::get<0>(t2).v));
   }
-#endif
+#endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
+
+#endif // !defined(TEST_COMPILER_GCC)
 
   return true;
 }
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
index d6c192d2e0543..b3982795bf6c8 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
@@ -111,6 +111,8 @@ int main(int, char**)
         assert(std::get<1>(t) == 1);
         assert(std::get<2>(t) == 2);
     }
+// Remove this guard when compiler versions older than clang 23 are no longer supported.
+#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
     // A bug in tuple caused __tuple_leaf to use its explicit converting constructor
     //  as its move constructor. This tests that ConstructsWithTupleLeaf is not called
     // (w/ __tuple_leaf)
@@ -119,6 +121,8 @@ int main(int, char**)
         d_t d((ConstructsWithTupleLeaf()));
         d_t d2(static_cast<d_t &&>(d));
     }
+#endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
+
     {
         test_sfinae<move_only_ebo>();
         test_sfinae<move_only_large>();

>From cc1c1669478fbcf815cfa48b9f94ccef44f51743 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 2 Jul 2026 04:26:44 -0700
Subject: [PATCH 13/13] Format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../PR23256_constrain_UTypes_ctor.pass.cpp    | 63 +++++++++----------
 .../tuple.cnstr/convert_const_move.pass.cpp   |  4 +-
 .../tuple.tuple/tuple.cnstr/move.pass.cpp     | 24 +++----
 3 files changed, 43 insertions(+), 48 deletions(-)

diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
index 893987ce5f587..a7f15e1612157 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
@@ -67,42 +67,37 @@ int main(int, char**) {
 
 // Remove this guard when compiler versions older than clang 23 are no longer supported.
 #if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
-    {
-        static_assert(std::is_copy_constructible<std::tuple<A>>::value, "");
-        static_assert(std::is_move_constructible<std::tuple<A>>::value, "");
-        static_assert(std::is_copy_constructible<std::tuple<ExplicitA>>::value, "");
-        static_assert(std::is_move_constructible<std::tuple<ExplicitA>>::value, "");
-    }
-    {
-        static_assert(std::is_constructible<
-            std::tuple<A>,
-            std::allocator_arg_t, std::allocator<int>,
-            std::tuple<A> const&
-        >::value, "");
-        static_assert(std::is_constructible<
-            std::tuple<A>,
-            std::allocator_arg_t, std::allocator<int>,
-            std::tuple<A> &&
-        >::value, "");
-        static_assert(std::is_constructible<
-            std::tuple<ExplicitA>,
-            std::allocator_arg_t, std::allocator<int>,
-            std::tuple<ExplicitA> const&
-        >::value, "");
-        static_assert(std::is_constructible<
-            std::tuple<ExplicitA>,
-            std::allocator_arg_t, std::allocator<int>,
-            std::tuple<ExplicitA> &&
-        >::value, "");
-    }
+  {
+    static_assert(std::is_copy_constructible<std::tuple<A>>::value, "");
+    static_assert(std::is_move_constructible<std::tuple<A>>::value, "");
+    static_assert(std::is_copy_constructible<std::tuple<ExplicitA>>::value, "");
+    static_assert(std::is_move_constructible<std::tuple<ExplicitA>>::value, "");
+  }
+  {
+    static_assert(
+        std::is_constructible< std::tuple<A>, std::allocator_arg_t, std::allocator<int>, std::tuple<A> const& >::value,
+        "");
+    static_assert(
+        std::is_constructible< std::tuple<A>, std::allocator_arg_t, std::allocator<int>, std::tuple<A>&& >::value, "");
+    static_assert(std::is_constructible< std::tuple<ExplicitA>,
+                                         std::allocator_arg_t,
+                                         std::allocator<int>,
+                                         std::tuple<ExplicitA> const& >::value,
+                  "");
+    static_assert(std::is_constructible< std::tuple<ExplicitA>,
+                                         std::allocator_arg_t,
+                                         std::allocator<int>,
+                                         std::tuple<ExplicitA>&& >::value,
+                  "");
+  }
 #endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
 
-    {
-        std::tuple<A&&> t(std::forward_as_tuple(A{}));
-        ((void)t);
-        std::tuple<ExplicitA&&> t2(std::forward_as_tuple(ExplicitA{}));
-        ((void)t2);
-    }
+  {
+    std::tuple<A&&> t(std::forward_as_tuple(A{}));
+    ((void)t);
+    std::tuple<ExplicitA&&> t2(std::forward_as_tuple(ExplicitA{}));
+    ((void)t2);
+  }
 
   return 0;
 }
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp
index a8ed156a2fc33..383627f965137 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp
@@ -115,7 +115,7 @@ constexpr bool test() {
 #if !defined(TEST_COMPILER_GCC)
 
 // Remove this guard when compiler versions older than clang 23 are no longer supported.
-#if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
+#  if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
   // sizeof...(Types) == 1 && is_convertible_v<decltype(u), T>
   {
     const std::tuple<CvtFromConstTupleRefRef> t1{};
@@ -129,7 +129,7 @@ constexpr bool test() {
     std::tuple<ConvertibleFrom<ExplicitCtrFromConstTupleRefRef>> t2{std::move(t1)};
     assert(!constMoveCtrCalled(std::get<0>(t2).v));
   }
-#endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
+#  endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
 
 #endif // !defined(TEST_COMPILER_GCC)
 
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
index b3982795bf6c8..99fe11a085c99 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
@@ -113,20 +113,20 @@ int main(int, char**)
     }
 // Remove this guard when compiler versions older than clang 23 are no longer supported.
 #if defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
-    // A bug in tuple caused __tuple_leaf to use its explicit converting constructor
-    //  as its move constructor. This tests that ConstructsWithTupleLeaf is not called
-    // (w/ __tuple_leaf)
-    {
-        typedef std::tuple<ConstructsWithTupleLeaf> d_t;
-        d_t d((ConstructsWithTupleLeaf()));
-        d_t d2(static_cast<d_t &&>(d));
-    }
+  // A bug in tuple caused __tuple_leaf to use its explicit converting constructor
+  //  as its move constructor. This tests that ConstructsWithTupleLeaf is not called
+  // (w/ __tuple_leaf)
+  {
+    typedef std::tuple<ConstructsWithTupleLeaf> d_t;
+    d_t d((ConstructsWithTupleLeaf()));
+    d_t d2(static_cast<d_t&&>(d));
+  }
 #endif // defined(TEST_CLANG_VER) && TEST_CLANG_VER >= 2300
 
-    {
-        test_sfinae<move_only_ebo>();
-        test_sfinae<move_only_large>();
-    }
+  {
+    test_sfinae<move_only_ebo>();
+    test_sfinae<move_only_large>();
+  }
 
   return 0;
 }



More information about the libcxx-commits mailing list