[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