[libcxx-commits] [libcxx] [libc++] P1789R3: Library Support for Expansion Statements (PR #167184)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Nov 8 22:36:51 PST 2025
https://github.com/Tsche updated https://github.com/llvm/llvm-project/pull/167184
>From 032858a20aa33fda5370315e7eed7b946c1543be Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:10:28 +0100
Subject: [PATCH 1/7] [libc++] P1789R3: Library Support for Expansion
Statements
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +
libcxx/docs/ReleaseNotes/22.rst | 1 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +
libcxx/include/__utility/integer_sequence.h | 29 +++++++++++
libcxx/include/version | 4 +-
.../utility.version.compile.pass.cpp | 4 +-
.../version.version.compile.pass.cpp | 4 +-
.../intseq.binding/integer_seq.pass.cpp | 49 +++++++++++++++++++
.../intseq.binding/integer_seq.verify.cpp | 24 +++++++++
.../generate_feature_test_macro_components.py | 5 +-
10 files changed, 118 insertions(+), 6 deletions(-)
create mode 100644 libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
create mode 100644 libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
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..685e7a22be28a 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 <https://llvm.org/PR118377>`__)
- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
+- P1789R3: Library Support for Expansion Statements
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index e0e47b864d38f..7347408fbb3c1 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -157,3 +157,5 @@
"`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","","`#148182 <https://github.com/llvm/llvm-project/issues/148182>`__",""
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","","`#148183 <https://github.com/llvm/llvm-project/issues/148183>`__",""
"","","","","","",""
+"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements`","2025-11 (Kona)","|Complete|","22","",""
+"","","","","","",""
diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index 329826ae5eda2..8889c1196a450 100644
--- a/libcxx/include/__utility/integer_sequence.h
+++ b/libcxx/include/__utility/integer_sequence.h
@@ -13,6 +13,11 @@
#include <__cstddef/size_t.h>
#include <__type_traits/is_integral.h>
+#if _LIBCPP_STD_VER >= 26
+# include <__tuple/tuple_element.h>
+# include <__tuple/tuple_size.h>
+#endif
+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
@@ -67,6 +72,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 <typename _Tp, _Tp... _Indices>
+struct tuple_size<integer_sequence<_Tp, _Indices...>> : public integral_constant<size_t, sizeof...(_Indices)> {};
+
+template <size_t _Ip, typename _Tp, _Tp... _Indices>
+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 <size_t _Ip, typename _Tp, _Tp... _Indices>
+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 <size_t _Ip, typename _Tp, _Tp... _Indices>
+_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 >= 20
+
# endif // _LIBCPP_STD_VER >= 14
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/version b/libcxx/include/version
index b0030602f854a..c9a4c58a9a289 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -141,7 +141,7 @@ __cpp_lib_incomplete_container_elements 201505L <forward_list> <
__cpp_lib_inplace_vector 202406L <inplace_vector>
__cpp_lib_int_pow2 202002L <bit>
__cpp_lib_integer_comparison_functions 202002L <utility>
-__cpp_lib_integer_sequence 201304L <utility>
+__cpp_lib_integer_sequence 202511L <utility>
__cpp_lib_integral_constant_callable 201304L <type_traits>
__cpp_lib_interpolate 201902L <cmath> <numeric>
__cpp_lib_invoke 201411L <functional>
@@ -582,6 +582,8 @@ __cpp_lib_void_t 201411L <type_traits>
// # 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/integer_seq.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
new file mode 100644
index 0000000000000..8deda77419e66
--- /dev/null
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// <utility>
+
+// structured binding support for integer_sequence
+
+#include <tuple>
+#include <utility>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+int main(int, char**)
+{
+ using empty = std::integer_sequence<int>;
+ using size4 = std::integer_sequence<int, 9, 8, 7, 2>;
+
+ static_assert ( std::tuple_size_v<empty> == 0, "empty size wrong" );
+ static_assert ( std::tuple_size_v<const empty> == 0, "empty size wrong" );
+
+ static_assert ( std::tuple_size_v<size4> == 4, "size4 size wrong" );
+ static_assert ( std::tuple_size_v<const size4> == 4, "size4 size wrong" );
+
+ static_assert ( std::is_same_v<std::tuple_element_t<0, size4>, int>, "size4 type wrong" );
+ static_assert ( std::is_same_v<std::tuple_element_t<1, size4>, int>, "size4 type wrong" );
+ static_assert ( std::is_same_v<std::tuple_element_t<2, size4>, int>, "size4 type wrong" );
+ static_assert ( std::is_same_v<std::tuple_element_t<3, size4>, int>, "size4 type wrong" );
+
+ static_assert ( std::is_same_v<std::tuple_element_t<0, const size4>, int>, "const4 type wrong" );
+ static_assert ( std::is_same_v<std::tuple_element_t<1, const size4>, int>, "const4 type wrong" );
+ static_assert ( std::is_same_v<std::tuple_element_t<2, const size4>, int>, "const4 type wrong" );
+ static_assert ( std::is_same_v<std::tuple_element_t<3, const size4>, int>, "const4 type wrong" );
+
+ constexpr static size4 seq4{};
+ static_assert ( get<0> (seq4) == 9, "size4 element 0 wrong" );
+ static_assert ( get<1> (seq4) == 8, "size4 element 1 wrong" );
+ static_assert ( get<2> (seq4) == 7, "size4 element 2 wrong" );
+ static_assert ( get<3> (seq4) == 2, "size4 element 3 wrong" );
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
new file mode 100644
index 0000000000000..9c93d11b28ceb
--- /dev/null
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// <utility>
+
+// Expect failures for tuple_element and get with empty integer_sequence
+
+#include <utility>
+
+void f() {
+ using test1 = typename std::tuple_element<0, std::integer_sequence<int>>::type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (std::integer_sequence)}}
+ using test2 = typename std::tuple_element<0, const std::integer_sequence<int>>::type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (const std::integer_sequence)}}
+
+ auto empty = std::integer_sequence<int>();
+ // 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..914172410e332 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"],
},
{
>From 74023193c4fb9560f991d25c5ac19f6a86d471be Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:31:03 +0100
Subject: [PATCH 2/7] fix formatting issues
---
.../intseq.binding/integer_seq.pass.cpp | 51 +++++++++----------
.../intseq.binding/integer_seq.verify.cpp | 14 ++---
.../generate_feature_test_macro_components.py | 2 +-
3 files changed, 34 insertions(+), 33 deletions(-)
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
index 8deda77419e66..7220bccb601a8 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
@@ -18,32 +18,31 @@
#include "test_macros.h"
-int main(int, char**)
-{
- using empty = std::integer_sequence<int>;
- using size4 = std::integer_sequence<int, 9, 8, 7, 2>;
-
- static_assert ( std::tuple_size_v<empty> == 0, "empty size wrong" );
- static_assert ( std::tuple_size_v<const empty> == 0, "empty size wrong" );
-
- static_assert ( std::tuple_size_v<size4> == 4, "size4 size wrong" );
- static_assert ( std::tuple_size_v<const size4> == 4, "size4 size wrong" );
-
- static_assert ( std::is_same_v<std::tuple_element_t<0, size4>, int>, "size4 type wrong" );
- static_assert ( std::is_same_v<std::tuple_element_t<1, size4>, int>, "size4 type wrong" );
- static_assert ( std::is_same_v<std::tuple_element_t<2, size4>, int>, "size4 type wrong" );
- static_assert ( std::is_same_v<std::tuple_element_t<3, size4>, int>, "size4 type wrong" );
-
- static_assert ( std::is_same_v<std::tuple_element_t<0, const size4>, int>, "const4 type wrong" );
- static_assert ( std::is_same_v<std::tuple_element_t<1, const size4>, int>, "const4 type wrong" );
- static_assert ( std::is_same_v<std::tuple_element_t<2, const size4>, int>, "const4 type wrong" );
- static_assert ( std::is_same_v<std::tuple_element_t<3, const size4>, int>, "const4 type wrong" );
-
- constexpr static size4 seq4{};
- static_assert ( get<0> (seq4) == 9, "size4 element 0 wrong" );
- static_assert ( get<1> (seq4) == 8, "size4 element 1 wrong" );
- static_assert ( get<2> (seq4) == 7, "size4 element 2 wrong" );
- static_assert ( get<3> (seq4) == 2, "size4 element 3 wrong" );
+int main(int, char**) {
+ using empty = std::integer_sequence<int>;
+ using size4 = std::integer_sequence<int, 9, 8, 7, 2>;
+
+ static_assert(std::tuple_size_v<empty> == 0, "empty size wrong");
+ static_assert(std::tuple_size_v<const empty> == 0, "empty size wrong");
+
+ static_assert(std::tuple_size_v<size4> == 4, "size4 size wrong");
+ static_assert(std::tuple_size_v<const size4> == 4, "size4 size wrong");
+
+ static_assert(std::is_same_v<std::tuple_element_t<0, size4>, int>, "size4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<1, size4>, int>, "size4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<2, size4>, int>, "size4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<3, size4>, int>, "size4 type wrong");
+
+ static_assert(std::is_same_v<std::tuple_element_t<0, const size4>, int>, "const4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<1, const size4>, int>, "const4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<2, const size4>, int>, "const4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<3, const size4>, int>, "const4 type wrong");
+
+ constexpr static size4 seq4{};
+ static_assert(get<0>(seq4) == 9, "size4 element 0 wrong");
+ static_assert(get<1>(seq4) == 8, "size4 element 1 wrong");
+ static_assert(get<2>(seq4) == 7, "size4 element 2 wrong");
+ static_assert(get<3>(seq4) == 2, "size4 element 3 wrong");
return 0;
}
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
index 9c93d11b28ceb..5863a692ad5a3 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
@@ -14,11 +14,13 @@
#include <utility>
void f() {
- using test1 = typename std::tuple_element<0, std::integer_sequence<int>>::type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (std::integer_sequence)}}
- using test2 = typename std::tuple_element<0, const std::integer_sequence<int>>::type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (const std::integer_sequence)}}
+ using test1 = typename std::tuple_element<0, std::integer_sequence<int>>::
+ type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (std::integer_sequence)}}
+ using test2 = typename std::tuple_element<0, const std::integer_sequence<int>>::
+ type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (const std::integer_sequence)}}
- auto empty = std::integer_sequence<int>();
- // 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);
+ auto empty = std::integer_sequence<int>();
+ // 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 914172410e332..7b29cee34f765 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -766,7 +766,7 @@ def add_version_header(tc):
"name": "__cpp_lib_integer_sequence",
"values": {
"c++14": 201304,
- "c++26": 202511, # P1789R3 Library Support for Expansion Statements
+ "c++26": 202511, # P1789R3 Library Support for Expansion Statements
},
"headers": ["utility"],
},
>From 350a3a1cda9d23a5b1465503a94024e529fed48d Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:37:19 +0100
Subject: [PATCH 3/7] regenerate <version>
---
libcxx/include/version | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/version b/libcxx/include/version
index c9a4c58a9a289..3a2d38623a36f 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -142,6 +142,7 @@ __cpp_lib_inplace_vector 202406L <inplace_vector>
__cpp_lib_int_pow2 202002L <bit>
__cpp_lib_integer_comparison_functions 202002L <utility>
__cpp_lib_integer_sequence 202511L <utility>
+ 201304L // C++14
__cpp_lib_integral_constant_callable 201304L <type_traits>
__cpp_lib_interpolate 201902L <cmath> <numeric>
__cpp_lib_invoke 201411L <functional>
@@ -582,7 +583,7 @@ __cpp_lib_void_t 201411L <type_traits>
// # define __cpp_lib_generate_random 202403L
// # define __cpp_lib_hazard_pointer 202306L
// # define __cpp_lib_inplace_vector 202406L
-# undef __cpp_lib_integer_sequence
+# 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)
>From fd296c5fc984fb3c12d02083a2fc57e354a131d5 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:58:48 +0100
Subject: [PATCH 4/7] fix failing test
---
.../std/utilities/intseq/intseq.binding/integer_seq.verify.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
index 5863a692ad5a3..e25d95fbda32e 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
@@ -21,6 +21,6 @@ void f() {
auto empty = std::integer_sequence<int>();
// 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}}
+ // expected-error-re@*:* {{invalid index 0 for pack {{.*}} of size 0}}
(void)std::get<0>(empty);
}
>From e309910569bf663630a8e081736a17c54bb31d36 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 9 Nov 2025 06:45:16 +0100
Subject: [PATCH 5/7] apply review comments
---
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/include/__utility/integer_sequence.h | 4 +--
.../intseq.binding/integer_seq.pass.cpp | 35 +++++++++----------
3 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 7347408fbb3c1..81604230d651f 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -157,5 +157,5 @@
"`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","","`#148182 <https://github.com/llvm/llvm-project/issues/148182>`__",""
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","","`#148183 <https://github.com/llvm/llvm-project/issues/148183>`__",""
"","","","","","",""
-"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements`","2025-11 (Kona)","|Complete|","22","",""
+"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements","2025-11 (Kona)","|Complete|","22","",""
"","","","","","",""
diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index 8889c1196a450..a950431f1b480 100644
--- a/libcxx/include/__utility/integer_sequence.h
+++ b/libcxx/include/__utility/integer_sequence.h
@@ -75,7 +75,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __for_each_index_sequence(index_sequence<_I
# if _LIBCPP_STD_VER >= 26
// structured binding support for integer_sequence
template <typename _Tp, _Tp... _Indices>
-struct tuple_size<integer_sequence<_Tp, _Indices...>> : public integral_constant<size_t, sizeof...(_Indices)> {};
+struct tuple_size<integer_sequence<_Tp, _Indices...>> : integral_constant<size_t, sizeof...(_Indices)> {};
template <size_t _Ip, typename _Tp, _Tp... _Indices>
struct tuple_element<_Ip, integer_sequence<_Tp, _Indices...>> {
@@ -94,7 +94,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) _NOE
static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::get<> (std::integer_sequence)");
return _Indices...[_Ip];
}
-# endif // _LIBCPP_STD_VER >= 20
+# endif // _LIBCPP_STD_VER >= 26
# endif // _LIBCPP_STD_VER >= 14
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
index 7220bccb601a8..fc3f039c1d265 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
@@ -20,29 +20,28 @@
int main(int, char**) {
using empty = std::integer_sequence<int>;
+ static_assert(std::tuple_size_v<empty> == 0);
+ static_assert(std::tuple_size_v<const empty> == 0);
+
using size4 = std::integer_sequence<int, 9, 8, 7, 2>;
+ static_assert(std::tuple_size_v<size4> == 4);
+ static_assert(std::tuple_size_v<const size4> == 4);
- static_assert(std::tuple_size_v<empty> == 0, "empty size wrong");
- static_assert(std::tuple_size_v<const empty> == 0, "empty size wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<0, size4>, int>);
+ static_assert(std::is_same_v<std::tuple_element_t<1, size4>, int>);
+ static_assert(std::is_same_v<std::tuple_element_t<2, size4>, int>);
+ static_assert(std::is_same_v<std::tuple_element_t<3, size4>, int>);
- static_assert(std::tuple_size_v<size4> == 4, "size4 size wrong");
- static_assert(std::tuple_size_v<const size4> == 4, "size4 size wrong");
-
- static_assert(std::is_same_v<std::tuple_element_t<0, size4>, int>, "size4 type wrong");
- static_assert(std::is_same_v<std::tuple_element_t<1, size4>, int>, "size4 type wrong");
- static_assert(std::is_same_v<std::tuple_element_t<2, size4>, int>, "size4 type wrong");
- static_assert(std::is_same_v<std::tuple_element_t<3, size4>, int>, "size4 type wrong");
-
- static_assert(std::is_same_v<std::tuple_element_t<0, const size4>, int>, "const4 type wrong");
- static_assert(std::is_same_v<std::tuple_element_t<1, const size4>, int>, "const4 type wrong");
- static_assert(std::is_same_v<std::tuple_element_t<2, const size4>, int>, "const4 type wrong");
- static_assert(std::is_same_v<std::tuple_element_t<3, const size4>, int>, "const4 type wrong");
+ static_assert(std::is_same_v<std::tuple_element_t<0, const size4>, int>);
+ static_assert(std::is_same_v<std::tuple_element_t<1, const size4>, int>);
+ static_assert(std::is_same_v<std::tuple_element_t<2, const size4>, int>);
+ static_assert(std::is_same_v<std::tuple_element_t<3, const size4>, int>);
constexpr static size4 seq4{};
- static_assert(get<0>(seq4) == 9, "size4 element 0 wrong");
- static_assert(get<1>(seq4) == 8, "size4 element 1 wrong");
- static_assert(get<2>(seq4) == 7, "size4 element 2 wrong");
- static_assert(get<3>(seq4) == 2, "size4 element 3 wrong");
+ static_assert(get<0>(seq4) == 9);
+ static_assert(get<1>(seq4) == 8);
+ static_assert(get<2>(seq4) == 7);
+ static_assert(get<3>(seq4) == 2);
return 0;
}
>From a795b2c0a188198b253f0a1a139afed990002d1a Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 9 Nov 2025 06:48:46 +0100
Subject: [PATCH 6/7] remove extraneous space
---
.../std/utilities/intseq/intseq.binding/integer_seq.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
index fc3f039c1d265..c5baba7a101d9 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
@@ -22,7 +22,7 @@ int main(int, char**) {
using empty = std::integer_sequence<int>;
static_assert(std::tuple_size_v<empty> == 0);
static_assert(std::tuple_size_v<const empty> == 0);
-
+
using size4 = std::integer_sequence<int, 9, 8, 7, 2>;
static_assert(std::tuple_size_v<size4> == 4);
static_assert(std::tuple_size_v<const size4> == 4);
>From 2a238dcfb2c148e0c5a15fd8c503a2156cf9664e Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 9 Nov 2025 07:36:32 +0100
Subject: [PATCH 7/7] address more review comments
---
libcxx/include/utility | 12 ++++++++++++
...seq.pass.cpp => integer_seq.compile.pass.cpp} | 16 ++++++++++------
.../intseq/intseq.binding/integer_seq.verify.cpp | 16 ++++++++++++----
3 files changed, 34 insertions(+), 10 deletions(-)
rename libcxx/test/std/utilities/intseq/intseq.binding/{integer_seq.pass.cpp => integer_seq.compile.pass.cpp} (78%)
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<size_t N>
template<class... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
+template<class T, T... Values> // C++26
+ struct tuple_size<integer_sequence<T, Values...>>;
+
+template<size_t I, class T, T... Values> // C++26
+ struct tuple_element<I, integer_sequence<T, Values...>>;
+
+template<size_t I, class T, T... Values> // C++26
+ struct tuple_element<I, const integer_sequence<T, Values...>>;
+
+template<size_t I, class T, T... Values> // C++26
+ constexpr T get(integer_sequence<T, Values...>) noexcept;
+
template<class T, class U=T>
constexpr T exchange(T& obj, U&& new_value) // constexpr in C++17, noexcept in C++23
noexcept(is_nothrow_move_constructible<T>::value && is_nothrow_assignable<T&, U>::value);
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
similarity index 78%
rename from libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
rename to libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
index c5baba7a101d9..4d23f2c03e77b 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
@@ -7,18 +7,24 @@
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++26
+
// <utility>
-// structured binding support for integer_sequence
+// template<class T, T... Values>
+// struct tuple_size<integer_sequence<T, Values...>>;
+// template<size_t I, class T, T... Values>
+// struct tuple_element<I, integer_sequence<T, Values...>>;
+// template<size_t I, class T, T... Values>
+// struct tuple_element<I, const integer_sequence<T, Values...>>;
+// template<size_t I, class T, T... Values>
+// constexpr T get(integer_sequence<T, Values...>) noexcept;
#include <tuple>
#include <utility>
#include <type_traits>
#include <cassert>
-#include "test_macros.h"
-
-int main(int, char**) {
+constexpr void test() {
using empty = std::integer_sequence<int>;
static_assert(std::tuple_size_v<empty> == 0);
static_assert(std::tuple_size_v<const empty> == 0);
@@ -42,6 +48,4 @@ int main(int, char**) {
static_assert(get<1>(seq4) == 8);
static_assert(get<2>(seq4) == 7);
static_assert(get<3>(seq4) == 2);
-
- return 0;
}
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
index e25d95fbda32e..3e9d8d7d18dfc 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
@@ -7,17 +7,25 @@
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++26
+
// <utility>
+// template<size_t I, class T, T... Values>
+// struct tuple_element<I, integer_sequence<T, Values...>>;
+// template<size_t I, class T, T... Values>
+// struct tuple_element<I, const integer_sequence<T, Values...>>;
+// template<size_t I, class T, T... Values>
+// constexpr T get(integer_sequence<T, Values...>) noexcept;
+
// Expect failures for tuple_element and get with empty integer_sequence
#include <utility>
void f() {
- using test1 = typename std::tuple_element<0, std::integer_sequence<int>>::
- type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (std::integer_sequence)}}
- using test2 = typename std::tuple_element<0, const std::integer_sequence<int>>::
- type; // expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (const std::integer_sequence)}}
+ // 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<int>>;
+ // 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<int>>;
auto empty = std::integer_sequence<int>();
// expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::get<> (std::integer_sequence)}}
More information about the libcxx-commits
mailing list