diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -20,7 +20,7 @@ .. table:: Current Status :name: feature-status-table :widths: auto - + ================================================= ================= Macro Name Value ================================================= ================= @@ -197,6 +197,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,44 @@ #endif // !_LIBCPP_CXX03_LANG +#if _LIBCPP_STD_VER > 17 + +template +_LIBCPP_INLINE_VISIBILITY constexpr auto __to_array(_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...>) + -> array, _Size> { + return {{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>()); +} + +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>()); +} + +#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 @@ -100,6 +100,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 @@ -231,6 +232,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,39 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" + +int main(int, char**) { + { + char source[3][6] = {"hi", "world"}; + std::to_array(source); // expected-error {{here}} + } + + { + 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; + std::to_array(mo); // expected-error {{no matching function}} + + const move_only cmo; + std::to_array(std::move(cmo)); // expected-error {{no matching function}} + } + + 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,114 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" + +int main(int, char**) { + // Test deduced type. + { + auto arr = std::to_array({1, 2, 3}); + static_assert(std::is_same_v >, ""); + 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}); + static_assert(std::is_same_v, ""); + 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"); + static_assert(std::is_same_v >, ""); + 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); + static_assert(std::is_same_v >, ""); + 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)); + static_assert(std::is_same_v >, ""); + 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]; + }; + + 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); + } + + // Test C99 compound literal. + { + auto arr = std::to_array((int[]){3, 4}); + static_assert(std::is_same_v >, ""); + assert(arr[0] == 3); + assert(arr[1] == 4); + } + + // Test explicit type. + { + auto arr = std::to_array({1, 2, 3}); + static_assert(std::is_same_v >, ""); + 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}}); + static_assert(std::is_same_v >, ""); + assert(arr[0].a == 3); + assert(arr[0].b == .1); + } + + 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 @@ -87,6 +87,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] @@ -397,6 +398,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 @@ -785,6 +790,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 @@ -1377,6 +1386,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" @@ -2116,6 +2129,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 @@ -578,6 +578,12 @@ }, "headers": ["numeric"], }, + {"name": "__cpp_lib_to_array", + "values": { + "c++2a": 201907L, + }, + "headers": ["array"], + }, ]], key=lambda tc: tc["name"]) def get_std_dialects(): @@ -969,7 +975,7 @@ .. table:: Current Status :name: feature-status-table :widths: auto - + {status_tables} """.format(status_tables=create_table(get_status_table(), 4)) 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