diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -199,6 +199,8 @@ ``__cpp_lib_ranges`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_three_way_comparison`` *unimplemented* + ------------------------------------------------- ----------------- + ``__cpp_lib_to_array`` ``201907L`` ================================================= ================= diff --git a/libcxx/include/array b/libcxx/include/array --- a/libcxx/include/array +++ b/libcxx/include/array @@ -479,6 +479,47 @@ #endif // !_LIBCPP_CXX03_LANG +#if _LIBCPP_STD_VER > 17 + +template +_LIBCPP_INLINE_VISIBILITY constexpr array, _Size> +__to_array_lvalue_impl(_Tp (&__arr)[_Size], index_sequence<_Index...>) { + return {{__arr[_Index]...}}; +} + +template +_LIBCPP_INLINE_VISIBILITY constexpr array, _Size> +__to_array_rvalue_impl(_Tp(&&__arr)[_Size], index_sequence<_Index...>) { + return {{_VSTD::move(__arr[_Index])...}}; +} + +template +_LIBCPP_INLINE_VISIBILITY constexpr array, _Size> +to_array(_Tp (&__arr)[_Size]) noexcept(is_nothrow_constructible_v<_Tp, _Tp&>) { + 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 array, _Size> +to_array(_Tp(&&__arr)[_Size]) noexcept(is_nothrow_move_constructible_v<_Tp>) { + 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 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_ARRAY diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -101,6 +101,7 @@ __cpp_lib_string_udls 201304L __cpp_lib_string_view 201606L __cpp_lib_three_way_comparison 201711L +__cpp_lib_to_array 201907L __cpp_lib_to_chars 201611L __cpp_lib_transformation_trait_aliases 201304L __cpp_lib_transparent_operators 201510L @@ -233,6 +234,7 @@ # endif // # define __cpp_lib_list_remove_return_type 201806L // # define __cpp_lib_ranges 201811L +# define __cpp_lib_to_array 201907L // # define __cpp_lib_three_way_comparison 201711L #endif 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/array/array.creation/to_array.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14, c++17 + +#include + +#include "test_macros.h" +#include "MoveOnly.h" + +int main(int, char**) { + { + char source[3][6] = {"hi", "world"}; + std::to_array(source); // expected-error {{here}} + } + + { + MoveOnly mo[] = {MoveOnly{3}}; + std::to_array(mo); // expected-error {{here}} + } + + { + const MoveOnly cmo[] = {MoveOnly{3}}; + std::to_array(std::move(cmo)); // expected-error {{here}} + } + + return 0; +} 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/array/array.creation/to_array.pass.cpp @@ -0,0 +1,122 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14, c++17 + +// template +// constexpr auto to_array(T (&arr)[Size]) +// -> array, Size>; + +// template +// constexpr auto to_array(T (&&arr)[Size]) +// -> array, Size>; + +#include +#include + +#include "test_macros.h" +#include "MoveOnly.h" + +int main(int, char**) { + // Test deduced type. + { + auto arr = std::to_array({1, 2, 3}); + ASSERT_SAME_TYPE(decltype(arr), std::array); + assert(arr[0] == 1); + assert(arr[1] == 2); + assert(arr[2] == 3); + } + + { + const long l1 = 42; + auto arr = std::to_array({1L, 4L, 9L, l1}); + ASSERT_SAME_TYPE(decltype(arr)::value_type, long); + static_assert(arr.size() == 4, ""); + assert(arr[0] == 1); + assert(arr[1] == 4); + assert(arr[2] == 9); + assert(arr[3] == l1); + } + + { + auto arr = std::to_array("meow"); + ASSERT_SAME_TYPE(decltype(arr), std::array); + assert(arr[0] == 'm'); + assert(arr[1] == 'e'); + assert(arr[2] == 'o'); + assert(arr[3] == 'w'); + assert(arr[4] == '\0'); + } + + { + double source[3] = {4.0, 5.0, 6.0}; + auto arr = std::to_array(source); + ASSERT_SAME_TYPE(decltype(arr), std::array); + assert(arr[0] == 4.0); + assert(arr[1] == 5.0); + assert(arr[2] == 6.0); + } + + { + double source[3] = {4.0, 5.0, 6.0}; + auto arr = std::to_array(std::move(source)); + ASSERT_SAME_TYPE(decltype(arr), std::array); + assert(arr[0] == 4.0); + assert(arr[1] == 5.0); + assert(arr[2] == 6.0); + } + + { + MoveOnly source[] = {MoveOnly{0}, MoveOnly{1}, MoveOnly{2}}; + + 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}); + ASSERT_SAME_TYPE(decltype(arr), std::array); + assert(arr[0] == 3); + assert(arr[1] == 4); + } + + // Test explicit type. + { + auto arr = std::to_array({1, 2, 3}); + ASSERT_SAME_TYPE(decltype(arr), std::array); + assert(arr[0] == 1); + assert(arr[1] == 2); + assert(arr[2] == 3); + } + + { + struct A { + int a; + double b; + }; + + auto arr = std::to_array({{3, .1}}); + 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; +} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp @@ -17,6 +17,7 @@ __cpp_lib_array_constexpr 201603L [C++17] __cpp_lib_constexpr_misc 201811L [C++2a] __cpp_lib_nonmember_container_access 201411L [C++17] + __cpp_lib_to_array 201907L [C++2a] */ #include @@ -36,6 +37,10 @@ # error "__cpp_lib_nonmember_container_access should not be defined before c++17" # endif +# ifdef __cpp_lib_to_array +# error "__cpp_lib_to_array should not be defined before c++2a" +# endif + #elif TEST_STD_VER == 14 # ifdef __cpp_lib_array_constexpr @@ -50,6 +55,10 @@ # error "__cpp_lib_nonmember_container_access should not be defined before c++17" # endif +# ifdef __cpp_lib_to_array +# error "__cpp_lib_to_array should not be defined before c++2a" +# endif + #elif TEST_STD_VER == 17 # ifndef __cpp_lib_array_constexpr @@ -70,6 +79,10 @@ # error "__cpp_lib_nonmember_container_access should have the value 201411L in c++17" # endif +# ifdef __cpp_lib_to_array +# error "__cpp_lib_to_array should not be defined before c++2a" +# endif + #elif TEST_STD_VER > 17 # ifndef __cpp_lib_array_constexpr @@ -99,6 +112,13 @@ # error "__cpp_lib_nonmember_container_access should have the value 201411L in c++2a" # endif +# ifndef __cpp_lib_to_array +# error "__cpp_lib_to_array should be defined in c++2a" +# endif +# if __cpp_lib_to_array != 201907L +# error "__cpp_lib_to_array should have the value 201907L in c++2a" +# endif + #endif // TEST_STD_VER > 17 int main(int, char**) { return 0; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -88,6 +88,7 @@ __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] __cpp_lib_three_way_comparison 201711L [C++2a] + __cpp_lib_to_array 201907L [C++2a] __cpp_lib_to_chars 201611L [C++17] __cpp_lib_transformation_trait_aliases 201304L [C++14] __cpp_lib_transparent_operators 201210L [C++14] @@ -402,6 +403,10 @@ # error "__cpp_lib_three_way_comparison should not be defined before c++2a" # endif +# ifdef __cpp_lib_to_array +# error "__cpp_lib_to_array should not be defined before c++2a" +# endif + # ifdef __cpp_lib_to_chars # error "__cpp_lib_to_chars should not be defined before c++17" # endif @@ -794,6 +799,10 @@ # error "__cpp_lib_three_way_comparison should not be defined before c++2a" # endif +# ifdef __cpp_lib_to_array +# error "__cpp_lib_to_array should not be defined before c++2a" +# endif + # ifdef __cpp_lib_to_chars # error "__cpp_lib_to_chars should not be defined before c++17" # endif @@ -1390,6 +1399,10 @@ # error "__cpp_lib_three_way_comparison should not be defined before c++2a" # endif +# ifdef __cpp_lib_to_array +# error "__cpp_lib_to_array should not be defined before c++2a" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++17" @@ -2136,6 +2149,13 @@ # endif # endif +# ifndef __cpp_lib_to_array +# error "__cpp_lib_to_array should be defined in c++2a" +# endif +# if __cpp_lib_to_array != 201907L +# error "__cpp_lib_to_array should have the value 201907L in c++2a" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_to_chars # error "__cpp_lib_to_chars should be defined in c++2a" diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -586,6 +586,12 @@ }, "headers": ["bit"], }, + {"name": "__cpp_lib_to_array", + "values": { + "c++2a": 201907L, + }, + "headers": ["array"], + }, ]], key=lambda tc: tc["name"]) def get_std_dialects(): diff --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html --- a/libcxx/www/cxx2a_status.html +++ b/libcxx/www/cxx2a_status.html @@ -157,7 +157,7 @@ P1464R1LWGMandating the Standard Library: Clause 22 - Iterators libraryKonaComplete9.0 - P0325LWGto_array from LFTS with updatesCologne + P0325LWGto_array from LFTS with updatesCologneComplete10.0 P0408LWGEfficient Access to basic_stringbuf ’s BufferCologne P0466LWGLayout-compatibility and Pointer-interconvertibility TraitsCologne P0553LWGBit operationsCologneComplete9.0