[libcxx-commits] [libcxx] [libc++][type_traits] Implements "A type trait to detect reference binding to temporary" (PR #128649)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Wed Feb 26 01:49:40 PST 2025


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/128649

>From ab218834c60aa52950974223d3b5387d288ce99e Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 24 Feb 2025 16:54:16 +0200
Subject: [PATCH 1/2] [libc++][type_traits] Implements "A type trait to detect
 reference binding to temporary"

Implements partially: P2255R2: A type trait to detect reference binding to temporary
https://github.com/llvm/llvm-project/issues/105180

https://eel.is/c++draft/meta.type.synop
https://eel.is/c++draft/meta.unary.prop

Implented type traits:
- [x] `reference_constructs_from_temporary`
- [x] `reference_converts_from_temporary`
---
 libcxx/docs/Status/Cxx23Papers.csv            |   2 +-
 libcxx/include/CMakeLists.txt                 |   2 +
 .../reference_constructs_from_temporary.h     |  42 ++++++
 .../reference_converts_from_temporary.h       |  42 ++++++
 libcxx/include/module.modulemap               |   8 ++
 libcxx/include/type_traits                    |  14 ++
 libcxx/modules/std/type_traits.inc            |  16 ++-
 ...ference_constructs_from_temporary.pass.cpp | 121 +++++++++++++++++
 ...reference_converts_from_temporary.pass.cpp | 124 ++++++++++++++++++
 9 files changed, 366 insertions(+), 5 deletions(-)
 create mode 100644 libcxx/include/__type_traits/reference_constructs_from_temporary.h
 create mode 100644 libcxx/include/__type_traits/reference_converts_from_temporary.h
 create mode 100644 libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
 create mode 100644 libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp

diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index bfaa63a7c224e..0f3db57788b49 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",""
 "`P1206R7 <https://wg21.link/P1206R7>`__","``ranges::to``: A function to convert any range to a container","2022-02 (Virtual)","|Complete|","17",""
 "`P1413R3 <https://wg21.link/P1413R3>`__","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","2022-02 (Virtual)","|Complete|","","``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)","","",""
+"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only."
 "`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16",""
 "`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19",""
 "`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index ee1d7b872b364..d7c36d6b438fb 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -867,6 +867,8 @@ set(files
   __type_traits/negation.h
   __type_traits/promote.h
   __type_traits/rank.h
+  __type_traits/reference_constructs_from_temporary.h
+  __type_traits/reference_converts_from_temporary.h
   __type_traits/remove_all_extents.h
   __type_traits/remove_const.h
   __type_traits/remove_const_ref.h
diff --git a/libcxx/include/__type_traits/reference_constructs_from_temporary.h b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
new file mode 100644
index 0000000000000..c7475c45bbe64
--- /dev/null
+++ b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
+#define _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_CXX03_LANG)
+
+template <class _Tp, class _Up>
+inline constexpr bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up);
+
+#  if _LIBCPP_STD_VER >= 23
+
+template <class _Tp, class _Up>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_constructs_from_temporary
+    : public bool_constant<__reference_constructs_from_temporary(_Tp, _Up)> {};
+
+template <class _Tp, class _Up>
+_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_temporary_v =
+    __reference_constructs_from_temporary_v<_Tp, _Up>;
+
+#  endif
+
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
diff --git a/libcxx/include/__type_traits/reference_converts_from_temporary.h b/libcxx/include/__type_traits/reference_converts_from_temporary.h
new file mode 100644
index 0000000000000..f194d97dcd633
--- /dev/null
+++ b/libcxx/include/__type_traits/reference_converts_from_temporary.h
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARARY_H
+#define _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARARY_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_CXX03_LANG) && __has_builtin(__reference_converts_from_temporary)
+
+template <class _Tp, class _Up>
+inline constexpr bool __reference_converts_from_temporary_v = __reference_converts_from_temporary(_Tp, _Up);
+
+#  if _LIBCPP_STD_VER >= 23
+
+template <class _Tp, class _Up>
+struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_converts_from_temporary
+    : public bool_constant<__reference_converts_from_temporary(_Tp, _Up)> {};
+
+template <class _Tp, class _Up>
+_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_converts_from_temporary_v =
+    __reference_converts_from_temporary_v<_Tp, _Up>;
+
+#  endif
+
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARARY_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 0f2016e7f5d15..ed757aa734c8c 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -369,6 +369,14 @@ module std_core [system] {
     module negation                                   { header "__type_traits/negation.h" }
     module promote                                    { header "__type_traits/promote.h" }
     module rank                                       { header "__type_traits/rank.h" }
+    module reference_constructs_from_temporary {
+      header "__type_traits/reference_constructs_from_temporary.h"
+      export std_core.type_traits.integral_constant
+    }
+    module reference_converts_from_temporary {
+      header "__type_traits/reference_converts_from_temporary.h"
+      export std_core.type_traits.integral_constant
+    }
     module remove_all_extents                         { header "__type_traits/remove_all_extents.h" }
     module remove_const_ref                           { header "__type_traits/remove_const_ref.h" }
     module remove_const                               { header "__type_traits/remove_const.h" }
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index ffcddb0176615..2c1b163cc66a0 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -143,6 +143,9 @@ namespace std
 
     template<class T> struct has_unique_object_representations;         // C++17
 
+    template<class T, class U> struct reference_constructs_from_temporary; // Since C++23
+    template<class T, class U> struct reference_converts_from_temporary;   // Since C++23
+
     // Relationships between types:
     template <class T, class U> struct is_same;
     template <class Base, class Derived> struct is_base_of;
@@ -382,6 +385,12 @@ namespace std
         = has_virtual_destructor<T>::value;                              // C++17
       template<class T> inline constexpr bool has_unique_object_representations_v // C++17
         = has_unique_object_representations<T>::value;
+      template<class T, class U>
+        constexpr bool reference_constructs_from_temporary_v
+          = reference_constructs_from_temporary<T, U>::value;            // Since C++23
+      template<class T, class U>
+        constexpr bool reference_converts_from_temporary_v
+          = reference_converts_from_temporary<T, U>::value;              // Since C++23
 
       // See C++14 20.10.5, type property queries
       template <class T> inline constexpr size_t alignment_of_v
@@ -524,6 +533,11 @@ namespace std
 #  if _LIBCPP_STD_VER >= 23
 #    include <__type_traits/is_implicit_lifetime.h>
 #  endif
+// C++23 but private declarations are available in C++11.
+#  if !defined(_LIBCPP_CXX03_LANG)
+#    include <__type_traits/reference_constructs_from_temporary.h>
+#    include <__type_traits/reference_converts_from_temporary.h>
+#  endif
 
 #  include <version>
 
diff --git a/libcxx/modules/std/type_traits.inc b/libcxx/modules/std/type_traits.inc
index f544f95c7aaaa..79c64f1cd9d96 100644
--- a/libcxx/modules/std/type_traits.inc
+++ b/libcxx/modules/std/type_traits.inc
@@ -106,8 +106,12 @@ export namespace std {
 
   using std::has_unique_object_representations;
 
-  // using std::reference_constructs_from_temporary;
-  // using std::reference_converts_from_temporary;
+#if _LIBCPP_STD_VER >= 23
+  using std::reference_constructs_from_temporary;
+#  if __has_builtin(__reference_converts_from_temporary)
+  using std::reference_converts_from_temporary;
+#  endif
+#endif
 
   // [meta.unary.prop.query], type property queries
   using std::alignment_of;
@@ -284,8 +288,12 @@ export namespace std {
   using std::is_unbounded_array_v;
   using std::is_unsigned_v;
   using std::is_volatile_v;
-  // using std::reference_constructs_from_temporary_v;
-  // using std::reference_converts_from_temporary_v;
+#if _LIBCPP_STD_VER >= 23
+  using std::reference_constructs_from_temporary_v;
+#  if __has_builtin(__reference_converts_from_temporary)
+  using std::reference_converts_from_temporary_v;
+#  endif
+#endif
 
   // [meta.unary.prop.query], type property queries
   using std::alignment_of_v;
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
new file mode 100644
index 0000000000000..d1ef96c2347e3
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
@@ -0,0 +1,121 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <type_traits>
+
+// template<class T, class U> struct reference_constructs_from_temporary;
+
+// template<class T, class U>
+// constexpr bool reference_constructs_from_temporary_v
+//   = reference_constructs_from_temporary<T, U>::value;
+
+#include <cassert>
+#include <type_traits>
+
+struct NonPOD {
+  NonPOD(int);
+};
+enum Enum { EV };
+struct POD {
+  Enum e;
+  int i;
+  float f;
+  NonPOD* p;
+};
+// Not PODs
+struct Derives : POD {};
+
+template <class T, class RefType = T&>
+struct ConvertsToRef {
+  operator RefType() const { return static_cast<RefType>(obj); }
+  mutable T obj = 42;
+};
+template <class T, class RefType = T&>
+class ConvertsToRefPrivate {
+  operator RefType() const { return static_cast<RefType>(obj); }
+  mutable T obj = 42;
+};
+
+struct ExplicitConversionRvalueRef {
+  operator int();
+  explicit operator int&&();
+};
+
+struct ExplicitConversionRef {
+  operator int();
+  explicit operator int&();
+};
+
+template <typename T, typename U, bool Expected>
+constexpr void test_reference_constructs_from_temporary() {
+  assert((std::reference_constructs_from_temporary<T, U>::value == Expected));
+  assert((std::reference_constructs_from_temporary_v<T, U> == Expected));
+}
+
+constexpr bool test() {
+  test_reference_constructs_from_temporary<int&, int&, false>();
+  test_reference_constructs_from_temporary<int&, int&, false>();
+  test_reference_constructs_from_temporary<int&, int&&, false>();
+
+  test_reference_constructs_from_temporary<const int&, int&, false>();
+  test_reference_constructs_from_temporary<const int&, const int&, false>();
+  test_reference_constructs_from_temporary<const int&, int&&, false>();
+
+  test_reference_constructs_from_temporary<int&, long&, false>(); // doesn't construct
+
+  test_reference_constructs_from_temporary<const int&, long&, true>();
+  test_reference_constructs_from_temporary<const int&, long&&, true>();
+  test_reference_constructs_from_temporary<int&&, long&, true>();
+
+  using LRef    = ConvertsToRef<int, int&>;
+  using RRef    = ConvertsToRef<int, int&&>;
+  using CLRef   = ConvertsToRef<int, const int&>;
+  using LongRef = ConvertsToRef<long, long&>;
+
+  assert((std::is_constructible_v<int&, LRef>));
+  test_reference_constructs_from_temporary<int&, LRef, false>();
+
+  assert((std::is_constructible_v<int&&, RRef>));
+  test_reference_constructs_from_temporary<int&&, RRef, false>();
+
+  assert((std::is_constructible_v<const int&, CLRef>));
+  test_reference_constructs_from_temporary<int&&, CLRef, false>();
+
+  assert((std::is_constructible_v<const int&, LongRef>));
+  test_reference_constructs_from_temporary<const int&, LongRef, true>();
+  test_reference_constructs_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
+
+  // Test that it doesn't accept non-reference types as input.
+  test_reference_constructs_from_temporary<int, long, false>();
+
+  test_reference_constructs_from_temporary<const int&, long, true>();
+
+  // Additional checks
+  test_reference_constructs_from_temporary<POD const&, Derives, true>();
+  test_reference_constructs_from_temporary<int&&, int, true>();
+  test_reference_constructs_from_temporary<const int&, int, true>();
+  test_reference_constructs_from_temporary<int&&, int&&, false>();
+  test_reference_constructs_from_temporary<const int&, int&&, false>();
+  test_reference_constructs_from_temporary<int&&, long&&, true>();
+  test_reference_constructs_from_temporary<int&&, long, true>();
+
+  test_reference_constructs_from_temporary<int&, ExplicitConversionRef, false>();
+  test_reference_constructs_from_temporary<const int&, ExplicitConversionRef, false>();
+  test_reference_constructs_from_temporary<int&&, ExplicitConversionRvalueRef, false>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
new file mode 100644
index 0000000000000..931e7eccbd87f
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
@@ -0,0 +1,124 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// These compilers don't support std::reference_converts_from_temporary yet.
+// UNSUPPORTED: android, apple-clang-15, apple-clang-16.1, apple-clang-16.2, clang-19
+
+// <type_traits>
+
+// template<class T, class U> struct reference_converts_from_temporary;
+
+// template<class T, class U>
+// constexpr bool reference_converts_from_temporary_v
+//   = reference_converts_from_temporary<T, U>::value;
+
+#include <cassert>
+#include <type_traits>
+
+struct NonPOD {
+  NonPOD(int);
+};
+enum Enum { EV };
+struct POD {
+  Enum e;
+  int i;
+  float f;
+  NonPOD* p;
+};
+// Not PODs
+struct Derives : POD {};
+
+template <class T, class RefType = T&>
+struct ConvertsToRef {
+  operator RefType() const { return static_cast<RefType>(obj); }
+  mutable T obj = 42;
+};
+template <class T, class RefType = T&>
+class ConvertsToRefPrivate {
+  operator RefType() const { return static_cast<RefType>(obj); }
+  mutable T obj = 42;
+};
+
+struct ExplicitConversionRvalueRef {
+  operator int();
+  explicit operator int&&();
+};
+
+struct ExplicitConversionRef {
+  operator int();
+  explicit operator int&();
+};
+
+template <typename T, typename U, bool Expected>
+constexpr void test_reference_converts_from_temporary() {
+  assert((std::reference_converts_from_temporary<T, U>::value == Expected));
+  assert((std::reference_converts_from_temporary_v<T, U> == Expected));
+}
+
+constexpr bool test() {
+  test_reference_converts_from_temporary<int&, int&, false>();
+  test_reference_converts_from_temporary<int&, int&, false>();
+  test_reference_converts_from_temporary<int&, int&&, false>();
+
+  test_reference_converts_from_temporary<const int&, int&, false>();
+  test_reference_converts_from_temporary<const int&, const int&, false>();
+  test_reference_converts_from_temporary<const int&, int&&, false>();
+
+  test_reference_converts_from_temporary<int&, long&, false>(); // doesn't construct
+
+  test_reference_converts_from_temporary<const int&, long&, true>();
+  test_reference_converts_from_temporary<const int&, long&&, true>();
+  test_reference_converts_from_temporary<int&&, long&, true>();
+
+  using LRef    = ConvertsToRef<int, int&>;
+  using RRef    = ConvertsToRef<int, int&&>;
+  using CLRef   = ConvertsToRef<int, const int&>;
+  using LongRef = ConvertsToRef<long, long&>;
+
+  assert((std::is_constructible_v<int&, LRef>));
+  test_reference_converts_from_temporary<int&, LRef, false>();
+
+  assert((std::is_constructible_v<int&&, RRef>));
+  test_reference_converts_from_temporary<int&&, RRef, false>();
+
+  assert((std::is_constructible_v<const int&, CLRef>));
+  test_reference_converts_from_temporary<int&&, CLRef, false>();
+
+  assert((std::is_constructible_v<const int&, LongRef>));
+  test_reference_converts_from_temporary<const int&, LongRef, true>();
+  test_reference_converts_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
+
+  // Test that it doesn't accept non-reference types as input.
+  test_reference_converts_from_temporary<int, long, false>();
+
+  test_reference_converts_from_temporary<const int&, long, true>();
+
+  // Additional checks
+  test_reference_converts_from_temporary<POD const&, Derives, true>();
+  test_reference_converts_from_temporary<int&&, int, true>();
+  test_reference_converts_from_temporary<const int&, int, true>();
+  test_reference_converts_from_temporary<int&&, int&&, false>();
+  test_reference_converts_from_temporary<const int&, int&&, false>();
+  test_reference_converts_from_temporary<int&&, long&&, true>();
+  test_reference_converts_from_temporary<int&&, long, true>();
+
+  test_reference_converts_from_temporary<int&, ExplicitConversionRef, false>();
+  test_reference_converts_from_temporary<const int&, ExplicitConversionRef, true>();
+  test_reference_converts_from_temporary<int&&, ExplicitConversionRvalueRef, true>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 016d341ad9d42dfcdcc8628b7ff0c7ca63409711 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 26 Feb 2025 11:49:21 +0200
Subject: [PATCH 2/2] Address comments

---
 .../__type_traits/reference_constructs_from_temporary.h   | 6 +-----
 .../__type_traits/reference_converts_from_temporary.h     | 4 +++-
 libcxx/include/type_traits                                | 8 +++-----
 .../reference_constructs_from_temporary.pass.cpp          | 4 ++++
 .../reference_converts_from_temporary.pass.cpp            | 6 +++++-
 5 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/__type_traits/reference_constructs_from_temporary.h b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
index c7475c45bbe64..8314cfaf7f208 100644
--- a/libcxx/include/__type_traits/reference_constructs_from_temporary.h
+++ b/libcxx/include/__type_traits/reference_constructs_from_temporary.h
@@ -18,10 +18,8 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if !defined(_LIBCPP_CXX03_LANG)
-
 template <class _Tp, class _Up>
-inline constexpr bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up);
+const bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up);
 
 #  if _LIBCPP_STD_VER >= 23
 
@@ -35,8 +33,6 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_tempo
 
 #  endif
 
-#endif
-
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARARY_H
diff --git a/libcxx/include/__type_traits/reference_converts_from_temporary.h b/libcxx/include/__type_traits/reference_converts_from_temporary.h
index f194d97dcd633..fb26a89ffd109 100644
--- a/libcxx/include/__type_traits/reference_converts_from_temporary.h
+++ b/libcxx/include/__type_traits/reference_converts_from_temporary.h
@@ -18,7 +18,9 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if !defined(_LIBCPP_CXX03_LANG) && __has_builtin(__reference_converts_from_temporary)
+#if __has_builtin(__reference_converts_from_temporary) ||                                                              \
+    (defined(_LIBCPP_COMPILER_CLANG_BASED) && (__clang_major__ >= 19) && (__clang_minor__ >= 1) &&                     \
+     (__clang_patchlevel__ >= 2))
 
 template <class _Tp, class _Up>
 inline constexpr bool __reference_converts_from_temporary_v = __reference_converts_from_temporary(_Tp, _Up);
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index 2c1b163cc66a0..25020213bacfb 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -533,11 +533,9 @@ namespace std
 #  if _LIBCPP_STD_VER >= 23
 #    include <__type_traits/is_implicit_lifetime.h>
 #  endif
-// C++23 but private declarations are available in C++11.
-#  if !defined(_LIBCPP_CXX03_LANG)
-#    include <__type_traits/reference_constructs_from_temporary.h>
-#    include <__type_traits/reference_converts_from_temporary.h>
-#  endif
+// C++23 but private declarations are available in previous standards.
+#  include <__type_traits/reference_constructs_from_temporary.h>
+#  include <__type_traits/reference_converts_from_temporary.h>
 
 #  include <version>
 
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
index d1ef96c2347e3..84cd8528596d1 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp
@@ -19,6 +19,8 @@
 #include <cassert>
 #include <type_traits>
 
+#include "test_macros.h"
+
 struct NonPOD {
   NonPOD(int);
 };
@@ -90,7 +92,9 @@ constexpr bool test() {
 
   assert((std::is_constructible_v<const int&, LongRef>));
   test_reference_constructs_from_temporary<const int&, LongRef, true>();
+#ifndef TEST_COMPILER_GCC
   test_reference_constructs_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
+#endif
 
   // Test that it doesn't accept non-reference types as input.
   test_reference_constructs_from_temporary<int, long, false>();
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
index 931e7eccbd87f..f128861861c54 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp
@@ -9,7 +9,7 @@
 // REQUIRES: std-at-least-c++23
 
 // These compilers don't support std::reference_converts_from_temporary yet.
-// UNSUPPORTED: android, apple-clang-15, apple-clang-16.1, apple-clang-16.2, clang-19
+// UNSUPPORTED: android, apple-clang, clang-19.1.1
 
 // <type_traits>
 
@@ -22,6 +22,8 @@
 #include <cassert>
 #include <type_traits>
 
+#include "test_macros.h"
+
 struct NonPOD {
   NonPOD(int);
 };
@@ -93,7 +95,9 @@ constexpr bool test() {
 
   assert((std::is_constructible_v<const int&, LongRef>));
   test_reference_converts_from_temporary<const int&, LongRef, true>();
+#ifndef TEST_COMPILER_GCC
   test_reference_converts_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
+#endif
 
   // Test that it doesn't accept non-reference types as input.
   test_reference_converts_from_temporary<int, long, false>();



More information about the libcxx-commits mailing list