Skip to content

Conversation

@Tsche
Copy link
Contributor

@Tsche Tsche commented Nov 8, 2025

P1789R3 was accepted for C++26 through LWG motion 14 at the 2025 Kona meeting. This patch implements it, along with tests and documentation changes.

@Tsche Tsche requested a review from a team as a code owner November 8, 2025 22:23
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 8, 2025

@llvm/pr-subscribers-libcxx

Author: None (Tsche)

Changes

P1789R3 was accepted for C++26 through LWG motion 14 at the 2025 Kona meeting. This patch implements it, along with tests and documentation changes.


Full diff: https://github.com/llvm/llvm-project/pull/167184.diff

10 Files Affected:

  • (modified) libcxx/docs/FeatureTestMacroTable.rst (+2)
  • (modified) libcxx/docs/ReleaseNotes/22.rst (+1)
  • (modified) libcxx/docs/Status/Cxx2cPapers.csv (+2)
  • (modified) libcxx/include/__utility/integer_sequence.h (+29)
  • (modified) libcxx/include/version (+3-1)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp (+2-2)
  • (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+2-2)
  • (added) libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.pass.cpp (+49)
  • (added) libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp (+24)
  • (modified) libcxx/utils/generate_feature_test_macro_components.py (+4-1)
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"],
         },
         {

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

✅ With the latest revision this PR passed the Python code formatter.

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants