[libc++] Fix tuple_cat for element with unconstrained constructor#122433
Merged
[libc++] Fix tuple_cat for element with unconstrained constructor#122433
tuple_cat for element with unconstrained constructor#122433Conversation
Currently, when the result type is 1-`tuple`, `tuple_cat` possibly tests an undesired constructor of the element, due to conversion from the reference tuple to the result type. If the element type has an unconstrained constructor template, there can be extraneous hard error which shouldn't happen. This patch introduces a helper function template `__tuple_cat_select_element_wise` to select the element-wise constructor template of `tuple`, which can avoid such error.
Member
|
@llvm/pr-subscribers-libcxx Author: A. Jiang (frederick-vs-ja) ChangesCurrently, when the result type is 1- This patch introduces a helper function template Fixes #41034. Full diff: https://github.com/llvm/llvm-project/pull/122433.diff 2 Files Affected:
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index aca14ba408d314..9728c8c3b99314 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -1338,12 +1338,25 @@ struct __tuple_cat<tuple<_Types...>, __tuple_indices<_I0...>, __tuple_indices<_J
}
};
+template <class _TupleDst, class _TupleSrc, size_t... _Indices>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _TupleDst
+__tuple_cat_select_element_wise(_TupleSrc&& __src, __tuple_indices<_Indices...>) {
+ static_assert(tuple_size<_TupleDst>::value == tuple_size<_TupleSrc>::value,
+ "misuse of __tuple_cat_select_element_wise with tuples of different sizes");
+ return _TupleDst(std::get<_Indices>(std::forward<_TupleSrc>(__src))...);
+}
+
template <class _Tuple0, class... _Tuples>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __tuple_cat_return<_Tuple0, _Tuples...>::type
tuple_cat(_Tuple0&& __t0, _Tuples&&... __tpls) {
- using _T0 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple0>;
- return __tuple_cat<tuple<>, __tuple_indices<>, typename __make_tuple_indices<tuple_size<_T0>::value>::type>()(
- tuple<>(), std::forward<_Tuple0>(__t0), std::forward<_Tuples>(__tpls)...);
+ using _T0 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple0>;
+ using _TRet _LIBCPP_NODEBUG = typename __tuple_cat_return<_Tuple0, _Tuples...>::type;
+ using _T0Indices _LIBCPP_NODEBUG = typename __make_tuple_indices<tuple_size<_T0>::value>::type;
+ using _TRetIndices _LIBCPP_NODEBUG = typename __make_tuple_indices<tuple_size<_TRet>::value>::type;
+ return std::__tuple_cat_select_element_wise<_TRet>(
+ __tuple_cat<tuple<>, __tuple_indices<>, _T0Indice>()(
+ tuple<>(), std::forward<_Tuple0>(__t0), std::forward<_Tuples>(__tpls)...),
+ _TRetIndice());
}
template <class... _Tp, class _Alloc>
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp
index 00c9d27ccc6d05..3f978f99c2cb47 100644
--- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp
+++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp
@@ -31,6 +31,70 @@ template<typename ...Ts>
void forward_as_tuple(Ts...) = delete;
}
+// https://github.com/llvm/llvm-project/issues/41034
+struct Unconstrained {
+ int data;
+ template <typename Arg>
+ TEST_CONSTEXPR_CXX14 Unconstrained(Arg arg) : data(arg) {}
+};
+
+TEST_CONSTEXPR_CXX14 std::tuple<Unconstrained> test_cat_unary_lvalue() {
+ auto tup = std::tuple<Unconstrained>(Unconstrained(5));
+ return std::tuple_cat(tup);
+}
+
+TEST_CONSTEXPR_CXX14 std::tuple<Unconstrained> test_cat_unary_rvalue() {
+ return std::tuple_cat(std::tuple<Unconstrained>(Unconstrained(6)));
+}
+
+TEST_CONSTEXPR_CXX14 std::tuple<Unconstrained> test_cat_unary_and_nullary() {
+ return std::tuple_cat(std::tuple<Unconstrained>(Unconstrained(7)), std::tuple<>());
+}
+
+#if TEST_STD_VER >= 17
+constexpr auto test_cat_unary_lvalue_ctad() {
+ auto tup = std::tuple(Unconstrained(8));
+ return std::tuple_cat(tup);
+}
+
+constexpr auto test_cat_unary_rvalue_ctad() { return std::tuple_cat(std::tuple(Unconstrained(9))); }
+
+constexpr auto test_cat_unary_and_nullary_ctad() { return std::tuple_cat(std::tuple(Unconstrained(10)), std::tuple()); }
+#endif
+
+TEST_CONSTEXPR_CXX14 bool test_tuple_cat_with_unconstrained_constructor() {
+ {
+ auto tup = test_cat_unary_lvalue();
+ assert(std::get<0>(tup).data == 5);
+ }
+ {
+ auto tup = test_cat_unary_rvalue();
+ assert(std::get<0>(tup).data == 6);
+ }
+ {
+ auto tup = test_cat_unary_and_nullary();
+ assert(std::get<0>(tup).data == 7);
+ }
+#if TEST_STD_VER >= 17
+ {
+ auto tup = test_cat_unary_lvalue_ctad();
+ ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>);
+ assert(std::get<0>(tup).data == 8);
+ }
+ {
+ auto tup = test_cat_unary_rvalue_ctad();
+ ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>);
+ assert(std::get<0>(tup).data == 9);
+ }
+ {
+ auto tup = test_cat_unary_and_nullary_ctad();
+ ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>);
+ assert(std::get<0>(tup).data == 10);
+ }
+#endif
+ return true;
+}
+
int main(int, char**)
{
{
@@ -270,5 +334,13 @@ int main(int, char**)
assert(std::get<0>(t).i == 1);
assert(std::get<0>(t2).i == 1);
}
- return 0;
+ // See https://github.com/llvm/llvm-project/issues/41034
+ {
+ test_tuple_cat_with_unconstrained_constructor();
+#if TEST_STD_VER >= 14
+ static_assert(test_tuple_cat_with_unconstrained_constructor(), "");
+#endif
+ }
+
+ return 0;
}
|
ldionne
approved these changes
Jan 13, 2025
Member
ldionne
left a comment
There was a problem hiding this comment.
LGTM with minor testing request.
ldionne
approved these changes
Jan 14, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Currently, when the result type is 1-
tuple,tuple_catpossibly tests an undesired constructor of the element, due to conversion from the reference tuple to the result type. If the element type has an unconstrained constructor template, there can be extraneous hard error which shouldn't happen.This patch introduces a helper function template
__tuple_cat_select_element_wiseto select the element-wise constructor template oftuple, which can avoid such error.Fixes #41034.