[clang] [libcxx] [libc++] Implement LWG3528 (`make_from_tuple` can perform (the equivalent of) a C-style cast) (PR #85263)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 21 16:39:50 PDT 2024


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

>From fc8c1a24f09c8860269fbdcfb0b285ffd19f427c Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 15 Mar 2024 00:48:08 +0800
Subject: [PATCH 01/11] [libc++] Implement LWG3528 (`make_from_tuple` can
 perform (the equivalent of) a C-style cast)

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/docs/Status/Cxx23Issues.csv            |  2 +-
 libcxx/include/tuple                          | 12 ++-
 .../tuple.apply/make_from_tuple.verify.cpp    | 74 +++++++++++++++++++
 3 files changed, 85 insertions(+), 3 deletions(-)
 create mode 100644 libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp

diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index e00345533b865d..0fd58649b0cf64 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -77,7 +77,7 @@
 `3523 <https://wg21.link/LWG3523>`__,"``iota_view::sentinel`` is not always ``iota_view``'s sentinel","June 2021","","","|ranges|"
 `3526 <https://wg21.link/LWG3526>`__,"Return types of ``uses_allocator_construction_args`` unspecified","June 2021","",""
 `3527 <https://wg21.link/LWG3527>`__,"``uses_allocator_construction_args`` handles rvalue pairs of rvalue references incorrectly","June 2021","",""
-`3528 <https://wg21.link/LWG3528>`__,"``make_from_tuple`` can perform (the equivalent of) a C-style cast","June 2021","",""
+`3528 <https://wg21.link/LWG3528>`__,"``make_from_tuple`` can perform (the equivalent of) a C-style cast","June 2021","|Complete|","19.0"
 `3529 <https://wg21.link/LWG3529>`__,"``priority_queue(first, last)`` should construct ``c`` with ``(first, last)``","June 2021","|Complete|","14.0"
 `3530 <https://wg21.link/LWG3530>`__,"``BUILTIN-PTR-MEOW`` should not opt the type out of syntactic checks","June 2021","",""
 `3532 <https://wg21.link/LWG3532>`__,"``split_view<V, P>::inner-iterator<true>::operator++(int)`` should depend on ``Base``","June 2021","","","|ranges|"
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 8808db6739fb9b..1ef546c5b2153d 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1423,8 +1423,16 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) apply(_Fn&& __f, _Tuple&&
         typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
 
 template <class _Tp, class _Tuple, size_t... _Idx>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
-    _LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
+inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>) 
+  noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
+#if _LIBCPP_STD_VER >= 20
+  requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>
+#endif
+{
+  static_assert(is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>, 
+                "Cannot constructible target type from the fields of the argument tuple.");
+  return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
+}
 
 template <class _Tp, class _Tuple>
 inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp
new file mode 100644
index 00000000000000..9bdca4dc7813cb
--- /dev/null
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <tuple>
+
+// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
+
+#include <tuple>
+
+int main() {
+  // clang-format off
+#if _LIBCPP_STD_VER <= 20
+  // reinterpret_cast
+  {
+    struct B { int b; } b;
+    std::tuple<B *> t{&b};
+    auto a = std::make_from_tuple<int *>(t); // expected-error-re@*:* {{static assertion failed {{.*}}Cannot constructible target type from the fields of the argument tuple.}}
+    (void)a;
+  }
+
+  // const_cast
+  {
+    const char *str = "Hello";
+    std::tuple<const char *> t{str};
+    auto a = std::make_from_tuple<char *>(t); // expected-error-re@*:* {{static assertion failed {{.*}}Cannot constructible target type from the fields of the argument tuple.}}
+    (void)a;
+  }
+
+  // static_cast
+  {
+    struct B {};
+    struct C : public B {} c;
+    B &br = c;
+    std::tuple<const B&> t{br};
+    auto a = std::make_from_tuple<const C&>(t); // expected-error-re@*:* {{static assertion failed {{.*}}Cannot constructible target type from the fields of the argument tuple.}}
+    (void)a;
+  }
+#else
+  // reinterpret_cast
+  {
+    struct B { int b; } b;
+    std::tuple<B *> t{&b};
+    auto a = std::make_from_tuple<int *>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
+    (void)a;
+  }
+
+  // const_cast
+  {
+    const char *str = "Hello";
+    std::tuple<const char *> t{str};
+    auto a = std::make_from_tuple<char *>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
+    (void)a;
+  }
+
+  // static_cast
+  {
+    struct B {};
+    struct C : public B {} c;
+    B &br = c;
+    std::tuple<const B &> t{br};
+    auto a = std::make_from_tuple<const C&>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
+    (void)a;
+  }
+#endif
+  // clang-format on
+  return 0;
+}

>From 14d6e7168e52c3236685dc3d947a37d9926bf8a2 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 15 Mar 2024 00:54:47 +0800
Subject: [PATCH 02/11] Add comment after #endif

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

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 1ef546c5b2153d..0839fa7d1280a0 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1427,7 +1427,7 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t,
   noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
 #if _LIBCPP_STD_VER >= 20
   requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>
-#endif
+#endif // _LIBCPP_STD_VER >= 20
 {
   static_assert(is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>, 
                 "Cannot constructible target type from the fields of the argument tuple.");

>From 14ae30770795c9d06ca83b23bf903922965b6ea0 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 15 Mar 2024 20:59:40 +0800
Subject: [PATCH 03/11] Address comments and uses SFINAE to remove the function
 from the overload set

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple                          | 16 ++++++-----
 .../tuple.apply/make_from_tuple.verify.cpp    | 28 -------------------
 2 files changed, 9 insertions(+), 35 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 0839fa7d1280a0..4d0e89d74ba14b 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1422,17 +1422,19 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) apply(_Fn&& __f, _Tuple&&
         std::forward<_Tuple>(__t),
         typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
 
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp, class _Tuple, size_t... _Idx>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>) 
+inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
   noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
-#if _LIBCPP_STD_VER >= 20
-  requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>
-#endif // _LIBCPP_STD_VER >= 20
-{
-  static_assert(is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>, 
-                "Cannot constructible target type from the fields of the argument tuple.");
+  requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...> {
   return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
 }
+#else
+template <class _Tp, class _Tuple, size_t... _Idx>
+inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>, 
+    enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
+    _LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
+#endif // _LIBCPP_STD_VER >= 20
 
 template <class _Tp, class _Tuple>
 inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp
index 9bdca4dc7813cb..d5905404d43a35 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp
@@ -16,33 +16,6 @@
 
 int main() {
   // clang-format off
-#if _LIBCPP_STD_VER <= 20
-  // reinterpret_cast
-  {
-    struct B { int b; } b;
-    std::tuple<B *> t{&b};
-    auto a = std::make_from_tuple<int *>(t); // expected-error-re@*:* {{static assertion failed {{.*}}Cannot constructible target type from the fields of the argument tuple.}}
-    (void)a;
-  }
-
-  // const_cast
-  {
-    const char *str = "Hello";
-    std::tuple<const char *> t{str};
-    auto a = std::make_from_tuple<char *>(t); // expected-error-re@*:* {{static assertion failed {{.*}}Cannot constructible target type from the fields of the argument tuple.}}
-    (void)a;
-  }
-
-  // static_cast
-  {
-    struct B {};
-    struct C : public B {} c;
-    B &br = c;
-    std::tuple<const B&> t{br};
-    auto a = std::make_from_tuple<const C&>(t); // expected-error-re@*:* {{static assertion failed {{.*}}Cannot constructible target type from the fields of the argument tuple.}}
-    (void)a;
-  }
-#else
   // reinterpret_cast
   {
     struct B { int b; } b;
@@ -68,7 +41,6 @@ int main() {
     auto a = std::make_from_tuple<const C&>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
     (void)a;
   }
-#endif
   // clang-format on
   return 0;
 }

>From 6f4ad45219b8b437489da8222cfc353f67aa584b Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 19 Mar 2024 21:46:50 +0800
Subject: [PATCH 04/11] Add SFINAE based test

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../tuple.apply/make_from_tuple.pass.cpp      | 28 +++++++++++
 .../tuple.apply/make_from_tuple.verify.cpp    | 46 -------------------
 2 files changed, 28 insertions(+), 46 deletions(-)
 delete mode 100644 libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp

diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index e3a21149c21e4c..1ff148f0cfb00d 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -195,6 +195,34 @@ void test_noexcept() {
     }
 }
 
+namespace LWG3528 {
+template <class _Tp, class _Tuple, class = std::void_t<>>
+struct can_make_from_tuple : std::false_type {};
+template <class _Tp, class _Tuple>
+struct can_make_from_tuple<
+    _Tp,
+    _Tuple,
+    std::void_t<decltype(std::__make_from_tuple_impl<_Tp>(
+        std::declval<_Tuple>(),
+        std::declval<
+            typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<_Tuple>>>::type>()))>>
+    : std::true_type {};
+
+struct A {
+    int a;
+};
+struct B : public A {};
+
+// reinterpret_cast
+static_assert(!can_make_from_tuple<int*, std::tuple<A*>>::value);
+
+// const_cast
+static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>::value);
+
+// static_cast
+static_assert(!can_make_from_tuple<const B&, std::tuple<const A&>>::value);
+} // namespace LWG3528
+
 int main(int, char**)
 {
     test_constexpr_construction();
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp
deleted file mode 100644
index d5905404d43a35..00000000000000
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.verify.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14
-
-// <tuple>
-
-// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
-
-#include <tuple>
-
-int main() {
-  // clang-format off
-  // reinterpret_cast
-  {
-    struct B { int b; } b;
-    std::tuple<B *> t{&b};
-    auto a = std::make_from_tuple<int *>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
-    (void)a;
-  }
-
-  // const_cast
-  {
-    const char *str = "Hello";
-    std::tuple<const char *> t{str};
-    auto a = std::make_from_tuple<char *>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
-    (void)a;
-  }
-
-  // static_cast
-  {
-    struct B {};
-    struct C : public B {} c;
-    B &br = c;
-    std::tuple<const B &> t{br};
-    auto a = std::make_from_tuple<const C&>(t); // expected-error-re@*:*2 {{no matching function for call to{{.*}}}}
-    (void)a;
-  }
-  // clang-format on
-  return 0;
-}

>From b5b0cc080a9587e1fdd2c44a887d6df57a74f0e9 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 19 Mar 2024 21:52:37 +0800
Subject: [PATCH 05/11] Format

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index 1ff148f0cfb00d..fef3e389390fee 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -209,7 +209,7 @@ struct can_make_from_tuple<
     : std::true_type {};
 
 struct A {
-    int a;
+  int a;
 };
 struct B : public A {};
 

>From d46837885ebf1beb9fc2ce9f58f9d6adef37cf89 Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 19 Mar 2024 22:25:41 +0800
Subject: [PATCH 06/11] Fix test failure

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 clang/lib/Frontend/TextDiagnosticPrinter.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index b2fb762537573e..83e6d1446d7d22 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -108,6 +108,7 @@ static void printDiagnosticOptions(raw_ostream &OS,
 
 void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
                                              const Diagnostic &Info) {
+  abort();
   // Default implementation (Warnings/errors count).
   DiagnosticConsumer::HandleDiagnostic(Level, Info);
 

>From 34666461f7cb880fa8b1510df97506099831c38b Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 19 Mar 2024 22:29:23 +0800
Subject: [PATCH 07/11] Revert "Fix test failure"

This reverts commit d46837885ebf1beb9fc2ce9f58f9d6adef37cf89.
---
 clang/lib/Frontend/TextDiagnosticPrinter.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 83e6d1446d7d22..b2fb762537573e 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -108,7 +108,6 @@ static void printDiagnosticOptions(raw_ostream &OS,
 
 void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
                                              const Diagnostic &Info) {
-  abort();
   // Default implementation (Warnings/errors count).
   DiagnosticConsumer::HandleDiagnostic(Level, Info);
 

>From 290260dfa0a1f666135d249f4f504d7601f0050c Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Tue, 19 Mar 2024 22:29:42 +0800
Subject: [PATCH 08/11] Fix test failure

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index fef3e389390fee..347934a478de69 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -220,7 +220,7 @@ static_assert(!can_make_from_tuple<int*, std::tuple<A*>>::value);
 static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>::value);
 
 // static_cast
-static_assert(!can_make_from_tuple<const B&, std::tuple<const A&>>::value);
+static_assert(!can_make_from_tuple<const B*, std::tuple<const A*>>::value);
 } // namespace LWG3528
 
 int main(int, char**)

>From 4ff01715d26aa1ecb831c24044faa28d59ab01bd Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Wed, 20 Mar 2024 21:25:10 +0800
Subject: [PATCH 09/11] Make a SFINAE based test

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 .../tuple.apply/make_from_tuple.pass.cpp      | 51 ++++++++++++++-----
 1 file changed, 37 insertions(+), 14 deletions(-)

diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index 347934a478de69..68f12623423bbf 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -196,31 +196,54 @@ void test_noexcept() {
 }
 
 namespace LWG3528 {
-template <class _Tp, class _Tuple, class = std::void_t<>>
-struct can_make_from_tuple : std::false_type {};
-template <class _Tp, class _Tuple>
-struct can_make_from_tuple<
-    _Tp,
-    _Tuple,
-    std::void_t<decltype(std::__make_from_tuple_impl<_Tp>(
-        std::declval<_Tuple>(),
-        std::declval<
-            typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<_Tuple>>>::type>()))>>
-    : std::true_type {};
+template <class T, class Tuple>
+auto test(T&&, Tuple&& t)
+    -> decltype(std::__make_from_tuple_impl<T>(
+                    t, typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<Tuple>>>::type{}),
+                uint8_t()) {
+  return 0;
+}
+template <class T, class Tuple>
+uint32_t test(...) {
+  return 0;
+}
+
+template <class T, class Tuple>
+static constexpr bool can_make_from_tuple = std::is_same_v<decltype(test<T, Tuple>(T{}, Tuple{})), uint8_t>;
 
 struct A {
   int a;
 };
 struct B : public A {};
 
+struct C {
+  C(const B&) {}
+};
+
+enum class D {
+  ONE,
+  TWO,
+};
+
 // reinterpret_cast
-static_assert(!can_make_from_tuple<int*, std::tuple<A*>>::value);
+static_assert(!can_make_from_tuple<int*, std::tuple<A*>>);
+static_assert(can_make_from_tuple<A*, std::tuple<A*>>);
 
 // const_cast
-static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>::value);
+static_assert(!can_make_from_tuple<char*, std::tuple<const char*>>);
+static_assert(!can_make_from_tuple<volatile char*, std::tuple<const volatile char*>>);
+static_assert(can_make_from_tuple<volatile char*, std::tuple<volatile char*>>);
+static_assert(can_make_from_tuple<char*, std::tuple<char*>>);
+static_assert(can_make_from_tuple<const char*, std::tuple<char*>>);
+static_assert(can_make_from_tuple<const volatile char*, std::tuple<volatile char*>>);
 
 // static_cast
-static_assert(!can_make_from_tuple<const B*, std::tuple<const A*>>::value);
+static_assert(!can_make_from_tuple<int, std::tuple<D>>);
+static_assert(!can_make_from_tuple<D, std::tuple<int>>);
+static_assert(can_make_from_tuple<long, std::tuple<int>>);
+static_assert(can_make_from_tuple<double, std::tuple<float>>);
+static_assert(can_make_from_tuple<float, std::tuple<double>>);
+
 } // namespace LWG3528
 
 int main(int, char**)

>From 923070351574ac62f126e48166a1a1c7a6f39b6a Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Thu, 21 Mar 2024 23:21:12 +0800
Subject: [PATCH 10/11] Add constraint to std::make_from_tuple

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple                          | 27 +++++++++++--------
 .../tuple.apply/make_from_tuple.pass.cpp      |  5 +---
 2 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 415521a523e238..c3da08ed6ca5a0 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1377,25 +1377,30 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) apply(_Fn&& __f, _Tuple&&
         std::forward<_Tuple>(__t),
         typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
 
-#if _LIBCPP_STD_VER >= 20
 template <class _Tp, class _Tuple, size_t... _Idx>
 inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
-  noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
-  requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...> {
-  return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
-}
-#else
-template <class _Tp, class _Tuple, size_t... _Idx>
-inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>, 
-    enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
     _LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
-#endif // _LIBCPP_STD_VER >= 20
 
+template <class _Tp, class _Tuple, 
+          class _Seq = typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type, class = void>
+inline constexpr bool __can_make_from_tuple = false;
+
+template <class _Tp, class _Tuple, size_t... _Idx>
+inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, __tuple_indices<_Idx...>, 
+    enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::declval<_Tuple>()))...>>> = true;
+
+// Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9, 
+// the standard allows to impose requirements, we constraint std::make_from_tuple but not touch std::__make_from_tuple_impl 
+// to make std::make_from_tuple SFINAE friendly and also avoid worse diagnostic messages.
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp, class _Tuple>
+  requires __can_make_from_tuple<_Tp, _Tuple> // strengthen
+#else
+template <class _Tp, class _Tuple, class = enable_if_t<__can_make_from_tuple<_Tp, _Tuple>>> // strengthen
+#endif // _LIBCPP_STD_VER >= 20
 inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
     _LIBCPP_NOEXCEPT_RETURN(std::__make_from_tuple_impl<_Tp>(
         std::forward<_Tuple>(__t), typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
-
 #    undef _LIBCPP_NOEXCEPT_RETURN
 
 #  endif // _LIBCPP_STD_VER >= 17
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index 68f12623423bbf..9c4a29a2c0de28 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -197,10 +197,7 @@ void test_noexcept() {
 
 namespace LWG3528 {
 template <class T, class Tuple>
-auto test(T&&, Tuple&& t)
-    -> decltype(std::__make_from_tuple_impl<T>(
-                    t, typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<Tuple>>>::type{}),
-                uint8_t()) {
+auto test(T&&, Tuple&& t) -> decltype(std::make_from_tuple<T>(t), uint8_t()) {
   return 0;
 }
 template <class T, class Tuple>

>From e19dda8e27fda737f881356ad6b855fd21c4013e Mon Sep 17 00:00:00 2001
From: yronglin <yronglin777 at gmail.com>
Date: Fri, 22 Mar 2024 07:38:56 +0800
Subject: [PATCH 11/11] Keep constraints of std::__make_from_tuple_impl

Signed-off-by: yronglin <yronglin777 at gmail.com>
---
 libcxx/include/tuple                          | 14 +++++-
 .../tuple.apply/make_from_tuple.pass.cpp      | 46 +++++++++++++++++--
 2 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index c3da08ed6ca5a0..b8d3836ac2fefd 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1377,9 +1377,19 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) apply(_Fn&& __f, _Tuple&&
         std::forward<_Tuple>(__t),
         typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type{}))
 
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp, class _Tuple, size_t... _Idx>
 inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>)
+  noexcept(noexcept(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...)))
+  requires is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...> {
+  return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...);
+}
+#else
+template <class _Tp, class _Tuple, size_t... _Idx>
+inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>, 
+    enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
     _LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
+#endif // _LIBCPP_STD_VER >= 20
 
 template <class _Tp, class _Tuple, 
           class _Seq = typename __make_tuple_indices<tuple_size_v<remove_reference_t<_Tuple>>>::type, class = void>
@@ -1390,8 +1400,8 @@ inline constexpr bool __can_make_from_tuple<_Tp, _Tuple, __tuple_indices<_Idx...
     enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::declval<_Tuple>()))...>>> = true;
 
 // Based on LWG3528(https://wg21.link/LWG3528) and http://eel.is/c++draft/description#structure.requirements-9, 
-// the standard allows to impose requirements, we constraint std::make_from_tuple but not touch std::__make_from_tuple_impl 
-// to make std::make_from_tuple SFINAE friendly and also avoid worse diagnostic messages.
+// the standard allows to impose requirements, we constraint std::make_from_tuple to make std::make_from_tuple 
+// SFINAE friendly and also avoid worse diagnostic messages.
 #if _LIBCPP_STD_VER >= 20
 template <class _Tp, class _Tuple>
   requires __can_make_from_tuple<_Tp, _Tuple> // strengthen
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
index 9c4a29a2c0de28..d7374351afa8bf 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
@@ -197,16 +197,33 @@ void test_noexcept() {
 
 namespace LWG3528 {
 template <class T, class Tuple>
-auto test(T&&, Tuple&& t) -> decltype(std::make_from_tuple<T>(t), uint8_t()) {
+auto test_make_from_tuple(T&&, Tuple&& t) -> decltype(std::make_from_tuple<T>(t), uint8_t()) {
   return 0;
 }
 template <class T, class Tuple>
-uint32_t test(...) {
+uint32_t test_make_from_tuple(...) {
   return 0;
 }
 
 template <class T, class Tuple>
-static constexpr bool can_make_from_tuple = std::is_same_v<decltype(test<T, Tuple>(T{}, Tuple{})), uint8_t>;
+static constexpr bool can_make_from_tuple =
+    std::is_same_v<decltype(test_make_from_tuple<T, Tuple>(T{}, Tuple{})), uint8_t>;
+
+template <class T, class Tuple>
+auto test_make_from_tuple_impl(T&&, Tuple&& t)
+    -> decltype(std::__make_from_tuple_impl<T>(
+                    t, typename std::__make_tuple_indices< std::tuple_size_v<std::remove_reference_t<Tuple>>>::type{}),
+                uint8_t()) {
+  return 0;
+}
+template <class T, class Tuple>
+uint32_t test_make_from_tuple_impl(...) {
+  return 0;
+}
+
+template <class T, class Tuple>
+static constexpr bool can_make_from_tuple_impl =
+    std::is_same_v<decltype(test_make_from_tuple_impl<T, Tuple>(T{}, Tuple{})), uint8_t>;
 
 struct A {
   int a;
@@ -222,6 +239,8 @@ enum class D {
   TWO,
 };
 
+// Test std::make_from_tuple constraints.
+
 // reinterpret_cast
 static_assert(!can_make_from_tuple<int*, std::tuple<A*>>);
 static_assert(can_make_from_tuple<A*, std::tuple<A*>>);
@@ -241,6 +260,27 @@ static_assert(can_make_from_tuple<long, std::tuple<int>>);
 static_assert(can_make_from_tuple<double, std::tuple<float>>);
 static_assert(can_make_from_tuple<float, std::tuple<double>>);
 
+// Test std::__make_from_tuple_impl constraints.
+
+// reinterpret_cast
+static_assert(!can_make_from_tuple_impl<int*, std::tuple<A*>>);
+static_assert(can_make_from_tuple_impl<A*, std::tuple<A*>>);
+
+// const_cast
+static_assert(!can_make_from_tuple_impl<char*, std::tuple<const char*>>);
+static_assert(!can_make_from_tuple_impl<volatile char*, std::tuple<const volatile char*>>);
+static_assert(can_make_from_tuple_impl<volatile char*, std::tuple<volatile char*>>);
+static_assert(can_make_from_tuple_impl<char*, std::tuple<char*>>);
+static_assert(can_make_from_tuple_impl<const char*, std::tuple<char*>>);
+static_assert(can_make_from_tuple_impl<const volatile char*, std::tuple<volatile char*>>);
+
+// static_cast
+static_assert(!can_make_from_tuple_impl<int, std::tuple<D>>);
+static_assert(!can_make_from_tuple_impl<D, std::tuple<int>>);
+static_assert(can_make_from_tuple_impl<long, std::tuple<int>>);
+static_assert(can_make_from_tuple_impl<double, std::tuple<float>>);
+static_assert(can_make_from_tuple_impl<float, std::tuple<double>>);
+
 } // namespace LWG3528
 
 int main(int, char**)



More information about the cfe-commits mailing list