diff --git a/libcxx/include/array b/libcxx/include/array --- a/libcxx/include/array +++ b/libcxx/include/array @@ -482,37 +482,42 @@ #if _LIBCPP_STD_VER > 17 template -_LIBCPP_INLINE_VISIBILITY constexpr auto __to_array(_Tp (&__arr)[_Size], - index_sequence<_Index...>) +_LIBCPP_INLINE_VISIBILITY constexpr auto +__to_array_lvalue_impl(_Tp (&__arr)[_Size], index_sequence<_Index...>) -> array, _Size> { return {{__arr[_Index]...}}; } template -_LIBCPP_INLINE_VISIBILITY constexpr auto __to_array(_Tp(&&__arr)[_Size], - index_sequence<_Index...>) +_LIBCPP_INLINE_VISIBILITY constexpr auto +__to_array_rvalue_impl(_Tp(&&__arr)[_Size], index_sequence<_Index...>) -> array, _Size> { - return {{move(__arr[_Index])...}}; + return {{_VSTD::move(__arr[_Index])...}}; } template -_LIBCPP_INLINE_VISIBILITY constexpr auto to_array(_Tp (&__arr)[_Size]) noexcept( - is_nothrow_constructible_v< - _Tp, _Tp&>) // FIXME: Standard does not say anything about noexcept. -{ - static_assert(!is_array_v<_Tp>); - static_assert(is_constructible_v<_Tp, _Tp&>); - return __to_array(__arr, make_index_sequence<_Size>()); +_LIBCPP_INLINE_VISIBILITY constexpr auto to_array(_Tp (&__arr)[_Size]) + -> array, _Size> { + static_assert( + !is_array_v<_Tp>, + "[array.creation]/1: to_array does not accept multidimensional arrays."); + static_assert( + is_constructible_v<_Tp, _Tp&>, + "[array.creation]/1: to_array requires copy constructible elements."); + return __to_array_lvalue_impl(__arr, make_index_sequence<_Size>()); } template _LIBCPP_INLINE_VISIBILITY constexpr auto to_array(_Tp(&&__arr)[_Size]) - noexcept(is_nothrow_move_constructible_v< - _Tp>) // FIXME: Standard does not say anything about noexcept. -{ - static_assert(!is_array_v<_Tp>); - static_assert(is_move_constructible_v<_Tp>); - return __to_array(std::move(__arr), make_index_sequence<_Size>()); + -> array, _Size> { + static_assert( + !is_array_v<_Tp>, + "[array.creation]/4: to_array does not accept multidimensional arrays."); + static_assert( + is_move_constructible_v<_Tp>, + "[array.creation]/4: to_array requires move constructible elements."); + return __to_array_rvalue_impl(_VSTD::move(__arr), + make_index_sequence<_Size>()); } #endif // _LIBCPP_STD_VER > 17 diff --git a/libcxx/test/std/containers/sequences/array/array.creation/to_array.fail.cpp b/libcxx/test/std/containers/sequences/array/array.creation/to_array.fail.cpp --- a/libcxx/test/std/containers/sequences/array/array.creation/to_array.fail.cpp +++ b/libcxx/test/std/containers/sequences/array/array.creation/to_array.fail.cpp @@ -10,10 +10,9 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 #include -#include -#include #include "test_macros.h" +#include "MoveOnly.h" int main(int, char**) { { @@ -22,16 +21,12 @@ } { - struct move_only { - constexpr move_only(int i = 0) : i(i) {} - constexpr move_only(move_only&& m) : i(m.i + 1) {} - int i; - }; - - move_only mo; + MoveOnly mo[] = {MoveOnly{3}}; std::to_array(mo); // expected-error {{no matching function}} + } - const move_only cmo; + { + const MoveOnly cmo[] = {MoveOnly{3}}; std::to_array(std::move(cmo)); // expected-error {{no matching function}} } diff --git a/libcxx/test/std/containers/sequences/array/array.creation/to_array.pass.cpp b/libcxx/test/std/containers/sequences/array/array.creation/to_array.pass.cpp --- a/libcxx/test/std/containers/sequences/array/array.creation/to_array.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/array.creation/to_array.pass.cpp @@ -11,15 +11,15 @@ #include #include -#include #include "test_macros.h" +#include "MoveOnly.h" int main(int, char**) { // Test deduced type. { auto arr = std::to_array({1, 2, 3}); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0] == 1); assert(arr[1] == 2); assert(arr[2] == 3); @@ -28,7 +28,7 @@ { const long l1 = 42; auto arr = std::to_array({1L, 4L, 9L, l1}); - static_assert(std::is_same_v, ""); + ASSERT_SAME_TYPE(decltype(arr)::value_type, long); static_assert(arr.size() == 4, ""); assert(arr[0] == 1); assert(arr[1] == 4); @@ -38,7 +38,7 @@ { auto arr = std::to_array("meow"); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0] == 'm'); assert(arr[1] == 'e'); assert(arr[2] == 'o'); @@ -49,7 +49,7 @@ { double source[3] = {4.0, 5.0, 6.0}; auto arr = std::to_array(source); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0] == 4.0); assert(arr[1] == 5.0); assert(arr[2] == 6.0); @@ -58,33 +58,25 @@ { double source[3] = {4.0, 5.0, 6.0}; auto arr = std::to_array(std::move(source)); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0] == 4.0); assert(arr[1] == 5.0); assert(arr[2] == 6.0); } { - struct move_only { - constexpr move_only(int i = 0) : i(i) {} - constexpr move_only(move_only&& m) : i(m.i + 1) {} - int i; - }; - struct some_move_only { - move_only m[3]; - }; + MoveOnly source[] = {MoveOnly{0}, MoveOnly{1}, MoveOnly{2}}; - auto arr = std::to_array(some_move_only{{0, 1, 2}}.m); - static_assert(std::is_same_v >, ""); - assert(arr[0].i == 1); - assert(arr[1].i == 2); - assert(arr[2].i == 3); + auto arr = std::to_array(std::move(source)); + ASSERT_SAME_TYPE(decltype(arr), std::array); + for (int i = 0; i < 3; ++i) + assert(arr[i].get() == i && source[i].get() == 0); } // Test C99 compound literal. { auto arr = std::to_array((int[]){3, 4}); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0] == 3); assert(arr[1] == 4); } @@ -92,7 +84,7 @@ // Test explicit type. { auto arr = std::to_array({1, 2, 3}); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0] == 1); assert(arr[1] == 2); assert(arr[2] == 3); @@ -105,10 +97,18 @@ }; auto arr = std::to_array({{3, .1}}); - static_assert(std::is_same_v >, ""); + ASSERT_SAME_TYPE(decltype(arr), std::array); assert(arr[0].a == 3); assert(arr[0].b == .1); } + // Test constexpr. + { + constexpr std::array arr = std::to_array({1, 2, 3}); + static_assert(arr[0] == 1); + static_assert(arr[1] == 2); + static_assert(arr[2] == 3); + } + return 0; }