diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index d5ed9188b1b23..349164a96de87 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -474,6 +474,8 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_inplace_vector`` *unimplemented* ---------------------------------------------------------- ----------------- + ``__cpp_lib_integer_sequence`` ``202511L`` + ---------------------------------------------------------- ----------------- ``__cpp_lib_is_sufficiently_aligned`` ``202411L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_is_virtual_base_of`` ``202406L`` diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index a6a0ac8670fb5..08062e4305206 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -48,6 +48,7 @@ Implemented Papers - P2835R7: Expose ``std::atomic_ref``'s object address (`Github `__) - P2944R3: Comparisons for ``reference_wrapper`` (`Github `__) - P3168R2: Give ``std::optional`` Range Support (`Github `__) +- P1789R3: Library Support for Expansion Statements (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index e0e47b864d38f..c7690f20adba3 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -157,3 +157,5 @@ "`P3552R3 `__","Add a Coroutine Task Type","2025-06 (Sofia)","","","`#148182 `__","" "`P1317R2 `__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","","`#148183 `__","" "","","","","","","" +"`P1789R3 `__","Library Support for Expansion Statements","2025-11 (Kona)","|Complete|","22","`#167268 `__","" +"","","","","","","" diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h index 329826ae5eda2..c2284b901f3a3 100644 --- a/libcxx/include/__utility/integer_sequence.h +++ b/libcxx/include/__utility/integer_sequence.h @@ -11,6 +11,8 @@ #include <__config> #include <__cstddef/size_t.h> +#include <__tuple/tuple_element.h> +#include <__tuple/tuple_size.h> #include <__type_traits/is_integral.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -67,6 +69,30 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __for_each_index_sequence(index_sequence<_I } # endif // _LIBCPP_STD_VER >= 20 +# if _LIBCPP_STD_VER >= 26 +// structured binding support for integer_sequence +template +struct tuple_size> : integral_constant {}; + +template +struct tuple_element<_Ip, integer_sequence<_Tp, _Indices...>> { + static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::tuple_element<> (std::integer_sequence)"); + using type _LIBCPP_NODEBUG = _Tp; +}; + +template +struct tuple_element<_Ip, const integer_sequence<_Tp, _Indices...>> { + static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::tuple_element<> (const std::integer_sequence)"); + using type _LIBCPP_NODEBUG = _Tp; +}; + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept { + static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::get<> (std::integer_sequence)"); + return _Indices...[_Ip]; +} +# endif // _LIBCPP_STD_VER >= 26 + # endif // _LIBCPP_STD_VER >= 14 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/utility b/libcxx/include/utility index bc4eaf6a0cd02..1b19243afca1b 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -216,6 +216,18 @@ template template using index_sequence_for = make_index_sequence; +template // C++26 + struct tuple_size>; + +template // C++26 + struct tuple_element>; + +template // C++26 + struct tuple_element>; + +template // C++26 + constexpr T get(integer_sequence) noexcept; + template constexpr T exchange(T& obj, U&& new_value) // constexpr in C++17, noexcept in C++23 noexcept(is_nothrow_move_constructible::value && is_nothrow_assignable::value); diff --git a/libcxx/include/version b/libcxx/include/version index b0030602f854a..3a2d38623a36f 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -141,7 +141,8 @@ __cpp_lib_incomplete_container_elements 201505L < __cpp_lib_inplace_vector 202406L __cpp_lib_int_pow2 202002L __cpp_lib_integer_comparison_functions 202002L -__cpp_lib_integer_sequence 201304L +__cpp_lib_integer_sequence 202511L + 201304L // C++14 __cpp_lib_integral_constant_callable 201304L __cpp_lib_interpolate 201902L __cpp_lib_invoke 201411L @@ -582,6 +583,8 @@ __cpp_lib_void_t 201411L // # define __cpp_lib_generate_random 202403L // # define __cpp_lib_hazard_pointer 202306L // # define __cpp_lib_inplace_vector 202406L +# undef __cpp_lib_integer_sequence +# define __cpp_lib_integer_sequence 202511L # define __cpp_lib_is_sufficiently_aligned 202411L # if __has_builtin(__builtin_is_virtual_base_of) # define __cpp_lib_is_virtual_base_of 202406L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp index b882a5df04ae3..1d82ef9ec0e86 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp @@ -432,8 +432,8 @@ # ifndef __cpp_lib_integer_sequence # error "__cpp_lib_integer_sequence should be defined in c++26" # endif -# if __cpp_lib_integer_sequence != 201304L -# error "__cpp_lib_integer_sequence should have the value 201304L in c++26" +# if __cpp_lib_integer_sequence != 202511L +# error "__cpp_lib_integer_sequence should have the value 202511L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 8189c5c4e5985..355ca57bac64c 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -7156,8 +7156,8 @@ # ifndef __cpp_lib_integer_sequence # error "__cpp_lib_integer_sequence should be defined in c++26" # endif -# if __cpp_lib_integer_sequence != 201304L -# error "__cpp_lib_integer_sequence should have the value 201304L in c++26" +# if __cpp_lib_integer_sequence != 202511L +# error "__cpp_lib_integer_sequence should have the value 202511L in c++26" # endif # ifndef __cpp_lib_integral_constant_callable diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp new file mode 100644 index 0000000000000..4702fbe989cd0 --- /dev/null +++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// struct tuple_element>; +// template +// struct tuple_element>; +// template +// constexpr T get(integer_sequence) noexcept; + +#include +#include + +void test_structured_bindings() { + auto [elt0, elt1, elt2, elt3] = std::make_index_sequence<4>(); + + assert(elt0 == 0); + assert(elt1 == 1); + assert(elt2 == 2); + assert(elt3 == 3); +} + +#if __cpp_structured_bindings >= 202411L +template +void test_p1061_structured_bindings() { + auto [... empty] = std::make_index_sequence<0>(); + static_assert(sizeof...(empty) == 0); + + auto [... size4] = std::make_index_sequence<4>(); + static_assert(sizeof...(size4) == 4); + + assert(size4...[0] == 0); + assert(size4...[1] == 1); + assert(size4...[2] == 2); + assert(size4...[3] == 3); +} +#endif + +int main(int, char**) { + test_structured_bindings(); +#if __cpp_structured_bindings >= 202411L + test_p1061_structured_bindings(); +#endif + return 0; +} diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp new file mode 100644 index 0000000000000..84282d987919f --- /dev/null +++ b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// struct tuple_size>; +// template +// struct tuple_element>; +// template +// struct tuple_element>; +// template +// constexpr T get(integer_sequence) noexcept; + +#include +#include +#include +#include +#include + +constexpr void test() { + // std::tuple_size_v + using empty = std::integer_sequence; + static_assert(std::tuple_size_v == 0); + static_assert(std::tuple_size_v == 0); + + using size4 = std::integer_sequence; + static_assert(std::tuple_size_v == 4); + static_assert(std::tuple_size_v == 4); + + // std::tuple_element_t + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, int>); + + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, int>); + + // std::get + constexpr static size4 seq4{}; + static_assert(get<0>(seq4) == 9); + static_assert(get<1>(seq4) == 8); + static_assert(get<2>(seq4) == 7); + static_assert(get<3>(seq4) == 2); + + static_assert(noexcept(get<0>(seq4))); + + constexpr std::same_as decltype(auto) r = get<0>(seq4); + static_assert(r == 9); +} diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp new file mode 100644 index 0000000000000..3e9d8d7d18dfc --- /dev/null +++ b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++26 + +// + +// template +// struct tuple_element>; +// template +// struct tuple_element>; +// template +// constexpr T get(integer_sequence) noexcept; + +// Expect failures for tuple_element and get with empty integer_sequence + +#include + +void f() { + // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (std::integer_sequence)}} + using test1 = std::tuple_element_t<0, std::integer_sequence>; + // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (const std::integer_sequence)}} + using test2 = std::tuple_element_t<0, const std::integer_sequence>; + + auto empty = std::integer_sequence(); + // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::get<> (std::integer_sequence)}} + // expected-error-re@*:* {{invalid index 0 for pack {{.*}} of size 0}} + (void)std::get<0>(empty); +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 22209f53d50d7..7b29cee34f765 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -764,7 +764,10 @@ def add_version_header(tc): }, { "name": "__cpp_lib_integer_sequence", - "values": {"c++14": 201304}, + "values": { + "c++14": 201304, + "c++26": 202511, # P1789R3 Library Support for Expansion Statements + }, "headers": ["utility"], }, {