diff --git a/libcxx/include/tuple b/libcxx/include/tuple index aca14ba408d31..9728c8c3b9931 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -1338,12 +1338,25 @@ struct __tuple_cat, __tuple_indices<_I0...>, __tuple_indices<_J } }; +template +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 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_indices<>, typename __make_tuple_indices::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::value>::type; + using _TRetIndices _LIBCPP_NODEBUG = typename __make_tuple_indices::value>::type; + return std::__tuple_cat_select_element_wise<_TRet>( + __tuple_cat, __tuple_indices<>, _T0Indice>()( + tuple<>(), std::forward<_Tuple0>(__t0), std::forward<_Tuples>(__tpls)...), + _TRetIndice()); } template 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 00c9d27ccc6d0..3f978f99c2cb4 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 void forward_as_tuple(Ts...) = delete; } +// https://github.com/llvm/llvm-project/issues/41034 +struct Unconstrained { + int data; + template + TEST_CONSTEXPR_CXX14 Unconstrained(Arg arg) : data(arg) {} +}; + +TEST_CONSTEXPR_CXX14 std::tuple test_cat_unary_lvalue() { + auto tup = std::tuple(Unconstrained(5)); + return std::tuple_cat(tup); +} + +TEST_CONSTEXPR_CXX14 std::tuple test_cat_unary_rvalue() { + return std::tuple_cat(std::tuple(Unconstrained(6))); +} + +TEST_CONSTEXPR_CXX14 std::tuple test_cat_unary_and_nullary() { + return std::tuple_cat(std::tuple(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); + assert(std::get<0>(tup).data == 8); + } + { + auto tup = test_cat_unary_rvalue_ctad(); + ASSERT_SAME_TYPE(decltype(tup), std::tuple); + assert(std::get<0>(tup).data == 9); + } + { + auto tup = test_cat_unary_and_nullary_ctad(); + ASSERT_SAME_TYPE(decltype(tup), std::tuple); + 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; }