Skip to content

Conversation

@frederick-vs-ja
Copy link
Contributor

Implements parts for std::pair from P2255R2 "A type trait to detect reference binding to temporary".

Fixes #129051.

@frederick-vs-ja frederick-vs-ja requested a review from a team as a code owner October 20, 2025 07:58
@frederick-vs-ja frederick-vs-ja added libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. c++23 labels Oct 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 20, 2025

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

Changes

Implements parts for std::pair from P2255R2 "A type trait to detect reference binding to temporary".

Fixes #129051.


Patch is 31.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/164214.diff

11 Files Affected:

  • (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1)
  • (modified) libcxx/include/__utility/pair.h (+68-8)
  • (modified) libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp (+1-1)
  • (modified) libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp (+1-1)
  • (modified) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp (+11-1)
  • (added) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp (+225)
  • (modified) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_move.pass.cpp (+8)
  • (modified) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_const_ref.pass.cpp (+12-1)
  • (modified) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_move.pass.cpp (+10)
  • (modified) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_U_V_ref.pass.cpp (+8)
  • (modified) libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_like.pass.cpp (+46)
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 3a87e64339e1f..030f85e1315ab 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 ``std::pair`` 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)","|Partial|","","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__","Only ``ranges::iota`` is implemented."
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 33694c52430f1..7ab475a49ab38 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -36,6 +36,7 @@
 #include <__type_traits/is_swappable.h>
 #include <__type_traits/is_trivially_relocatable.h>
 #include <__type_traits/nat.h>
+#include <__type_traits/reference_constructs_from_temporary.h>
 #include <__type_traits/unwrap_ref.h>
 #include <__utility/declval.h>
 #include <__utility/forward.h>
@@ -68,9 +69,23 @@ struct __check_pair_construction {
 
   template <class _U1, class _U2>
   static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() {
+#  if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+    return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
+           !reference_constructs_from_temporary_v<_T1, _U1&&> && !reference_constructs_from_temporary_v<_T2, _U2&&>;
+#  else
     return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
+#  endif
   }
 
+#  if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  template <class _U1, class _U2>
+  static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructor_deleted() {
+    return is_constructible_v<_T1, _U1> && is_constructible_v<_T2, _U2> &&
+           (reference_constructs_from_temporary_v<_T1, _U1&&> || reference_constructs_from_temporary_v<_T2, _U2&&>);
+    return is_constructible<_T1, _U1>::value && is_constructible<_T2, _U2>::value;
+  }
+#  endif
+
   template <class _U1, class _U2>
   static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() {
     return is_convertible<_U1, _T1>::value && is_convertible<_U2, _T2>::value;
@@ -157,14 +172,20 @@ struct pair
       class _U1,
       class _U2,
 #  endif
-      __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0 >
+      __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0 >
   _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
+  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
       pair(_U1&& __u1, _U2&& __u2) noexcept(is_nothrow_constructible<first_type, _U1>::value &&
                                             is_nothrow_constructible<second_type, _U2>::value)
       : first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {
   }
 
+#  if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  template <class _U1 = _T1, class _U2 = _T2>
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
+  explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>()) pair(_U1&&, _U2&&) = delete;
+#  endif
+
 #  if _LIBCPP_STD_VER >= 23
   template <class _U1,
             class _U2,
@@ -173,6 +194,12 @@ struct pair
       pair(pair<_U1, _U2>& __p) noexcept((is_nothrow_constructible<first_type, _U1&>::value &&
                                           is_nothrow_constructible<second_type, _U2&>::value))
       : first(__p.first), second(__p.second) {}
+
+#    if __has_builtin(__reference_constructs_from_temporary)
+  template <class _U1, class _U2>
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1&, _U2&>())
+  explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>&) = delete;
+#    endif
 #  endif
 
   template <
@@ -186,15 +213,30 @@ struct pair
                                                is_nothrow_constructible<second_type, _U2 const&>::value)
       : first(__p.first), second(__p.second) {}
 
-  template <class _U1,
-            class _U2,
-            __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1, _U2>(), int> = 0>
+#  if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  template <class _U1, class _U2>
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1&, const _U2&>())
+  explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&, const _U2&>())
+      pair(const pair<_U1, _U2>&) = delete;
+#  endif
+
+  template <
+      class _U1,
+      class _U2,
+      __enable_if_t<__check_pair_construction<_T1, _T2>::template __is_pair_constructible<_U1&&, _U2&&>(), int> = 0>
   _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1, _U2>())
+  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
       pair(pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, _U1&&>::value &&
                                           is_nothrow_constructible<second_type, _U2&&>::value)
       : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {}
 
+#  if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  template <class _U1, class _U2>
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<_U1 &&, _U2 &&>())
+  explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<_U1&&, _U2&&>())
+      pair(pair<_U1, _U2>&&) = delete;
+#  endif
+
 #  if _LIBCPP_STD_VER >= 23
   template <
       class _U1,
@@ -206,16 +248,34 @@ struct pair
       pair(const pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible<first_type, const _U1&&>::value &&
                                                 is_nothrow_constructible<second_type, const _U2&&>::value)
       : first(std::move(__p.first)), second(std::move(__p.second)) {}
+
+#    if __has_builtin(__reference_constructs_from_temporary)
+  template <class _U1, class _U2>
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<const _U1 &&, const _U2 &&>())
+  explicit(!__check_pair_construction<_T1, _T2>::template __is_implicit<const _U1&&, const _U2&&>())
+      pair(const pair<_U1, _U2>&&) = delete;
+#    endif
 #  endif
 
 #  if _LIBCPP_STD_VER >= 23
   template <__pair_like_no_subrange _PairLike>
-    requires(is_constructible_v<first_type, decltype(std::get<0>(std::declval<_PairLike &&>()))> &&
-             is_constructible_v<second_type, decltype(std::get<1>(std::declval<_PairLike &&>()))>)
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructible<
+                decltype(std::get<0>(std::declval<_PairLike &&>())),
+                decltype(std::get<1>(std::declval<_PairLike &&>()))>())
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(
       !is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
       !is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>) pair(_PairLike&& __p)
       : first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {}
+
+#    if __has_builtin(__reference_constructs_from_temporary)
+  template <__pair_like_no_subrange _PairLike>
+    requires(__check_pair_construction<_T1, _T2>::template __is_pair_constructor_deleted<
+                decltype(std::get<0>(std::declval<_PairLike &&>())),
+                decltype(std::get<1>(std::declval<_PairLike &&>()))>())
+  explicit(!is_convertible_v<decltype(std::get<0>(std::declval<_PairLike&&>())), first_type> ||
+           !is_convertible_v<decltype(std::get<1>(std::declval<_PairLike&&>())), second_type>)
+      pair(_PairLike&&) = delete;
+#    endif
 #  endif
 
   template <class... _Args1, class... _Args2>
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp
index 5712493740bc8..626f6ad64c635 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/flat.map.observers/comp.pass.cpp
@@ -35,7 +35,7 @@ constexpr bool test() {
     assert(kc(1, 2));
     assert(!kc(2, 1));
     auto vc = m.value_comp();
-    ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, 2), std::make_pair(1, 2))), bool);
+    ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, '2'), std::make_pair(1, '2'))), bool);
     assert(vc({1, '2'}, {2, '1'}));
     assert(!vc({2, '1'}, {1, '2'}));
   }
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
index 070fbb0244e63..2b52b4722f347 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/flat.multimap.observers/comp.pass.cpp
@@ -36,7 +36,7 @@ constexpr bool test() {
     assert(kc(1, 2));
     assert(!kc(2, 1));
     auto vc = m.value_comp();
-    ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, 2), std::make_pair(1, 2))), bool);
+    ASSERT_SAME_TYPE(decltype(vc(std::make_pair(1, '2'), std::make_pair(1, '2'))), bool);
     assert(vc({1, '2'}, {2, '1'}));
     assert(!vc({2, '1'}, {1, '2'}));
   }
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp
index 33b5711e22183..63b254d102041 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.U_V.pass.cpp
@@ -139,5 +139,15 @@ int main(int, char**)
     }
 #endif // TEST_STD_VER > 20
 
-    return 0;
+// Test construction prohibition of introduced by https://wg21.link/P2255R2.
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  test_sfinae<int&&, char, false>();
+  test_sfinae<const int&, char, false>();
+  test_sfinae<ConvertingType&&, int, false>();
+  test_sfinae<const ConvertingType&, char, false>();
+  test_sfinae<ExplicitTypes::ConvertingType&&, int, false>();
+  test_sfinae<const ExplicitTypes::ConvertingType&, int, false>();
+#endif // TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+
+  return 0;
 }
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp
new file mode 100644
index 0000000000000..0b1bfc097965b
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.deleted.verify.cpp
@@ -0,0 +1,225 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++11
+
+// <utility>
+
+// template <class T1, class T2> struct pair
+
+// template<class U1 = T1, class U2 = T2>
+//   constexpr explicit(see below) pair(U1&& x, U2&& y);            // since C++11
+
+// The constructor is defined as deleted if
+// reference_constructs_from_temporary_v<first_type, U1&&> || reference_constructs_from_temporary_v<second_type, U2>
+// is true. (since C++23)
+
+// template<class U1, class U2>
+//   constexpr explicit(see below) pair(pair<U1, U2>& p);           // since C++23
+// template<class U1, class U2>
+//   constexpr explicit(see below) pair(const pair<U1, U2>& p);     // since C++11
+// template<class U1, class U2>
+//   constexpr explicit(see below) pair(pair<U1, U2>&& p);          // since C++11
+// template<class U1, class U2>
+//   constexpr explicit(see below) pair(const pair<U1, U2>&& p);    // since C++23
+// template<pair-like P>
+//   constexpr explicit(see below) pair(P&& p);                     // since C++23
+
+// The constructor is defined as deleted if
+// reference_constructs_from_temporary_v<first_type, decltype(get<0>(FWD(p)))> ||
+// reference_constructs_from_temporary_v<second_type, decltype(get<1>(FWD(p)))>
+// is true. (since C++23)
+
+// Such reference binding used to cause hard error for these constructors before C++23 due to CWG1696.
+
+#include <array>
+#include <complex>
+#include <tuple>
+#include <utility>
+
+#include "test_macros.h"
+
+void verify_two_arguments() {
+  std::pair<const long&, int&&> p1{'a', 'b'};
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+  // expected-error@-5 {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+
+#if TEST_STD_VER >= 23
+  std::pair<const long, int&&> p2({42L}, 'c');
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long, int &&>'}}
+#  else
+  // expected-error@-4 {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+
+  std::pair<const long&, int> p3{'d', {}};
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int>'}}
+#  else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+#endif
+}
+
+void verify_pair_const_lvalue() {
+  const std::pair<char, int> src1{'a', 'b'};
+  std::pair<const long&, const int&> dst1 = src1;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &>'}}
+#else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+
+  const std::pair<long, char> src2{'a', 'b'};
+  std::pair<const long&, const int&> dst2 = src2;
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &>'}}
+#else
+  // expected-error@-4 {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+}
+
+void verify_pair_rvalue() {
+  std::pair<char, int> src1{'a', 'b'};
+  std::pair<const long&, int&&> dst1 = std::move(src1);
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+
+  std::pair<long, char> src2{'a', 'b'};
+  std::pair<const long&, int&&> dst2 = std::move(src2);
+#if TEST_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#else
+  // expected-error@-4 {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#endif
+}
+
+#if TEST_STD_VER >= 23
+void verify_pair_lvalue() {
+  std::pair<char, int> src1{'a', 'b'};
+  std::pair<const long&, int&> dst1 = src1;
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &>'}}
+#  else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+
+  std::pair<long, char> src2{'a', 'b'};
+  std::pair<const long&, int&&> dst2 = src2;
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#  else
+  // expected-error@-4 {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+}
+
+void verify_pair_const_rvalue() {
+  const std::pair<char, int> src1{'a', 'b'};
+  std::pair<const long&, const int&&> dst1 = std::move(src1);
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &&>'}}
+#  else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+
+  const std::pair<long, char> src2{'a', 'b'};
+  std::pair<const long&, const int&&> dst2 = std::move(src2);
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &&>'}}
+#  else
+  // expected-error@-4 {{reference member 'second' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+}
+
+void verify_pair_like() {
+  std::pair<const long&, int&&> p1 = std::make_tuple('a', int{'b'});
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, const int &&>'}}
+#  else
+  // expected-error@-4 {{reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+#  endif
+
+  std::pair<const long&, int&&> p2 = std::make_tuple(long{'a'}, 'b');
+#  if __has_builtin(__reference_constructs_from_temporary)
+  // expected-error@-2 {{call to deleted constructor of 'std::pair<const long &, int &&>'}}
+#  else
...
[truncated]

@frederick-vs-ja frederick-vs-ja force-pushed the p2255r2-pair branch 2 times, most recently from 8e3073b to 0e5e36c Compare October 20, 2025 08:40
#include <__config>
#include <__cstddef/size_t.h>
#include <__fwd/array.h>
#include <__fwd/complex.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems necessary for Clang module builds to find the std::get overloads for complex (added in C++26), which interacts with the constructors from pair-like types.

Implements parts for `std::pair` from P2255R2 "A type trait to detect
reference binding to temporary".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++23 libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[libc++] P2255R2: Changes to Standard library components - pair

2 participants