[libcxx-commits] [libcxx] [libc++] Implement P1789R3: Library Support for Expansion Statements (PR #167184)

Matthias Wippich via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 23 08:04:10 PST 2025


https://github.com/Tsche updated https://github.com/llvm/llvm-project/pull/167184

>From 6026f6ad21a090aafe751489befbdab8b98d6886 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:10:28 +0100
Subject: [PATCH 01/19] [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, 117 insertions(+), 7 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 4a82461b80534..32911d0f64449 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 82271be7a22ab..ef1eb69faee72 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -52,6 +52,7 @@ Implemented Papers
 - P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
 - P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
 - P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
+- P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167184>`__)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 3687e3dac2a8f..22be2e2fb40a6 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -169,7 +169,7 @@
 "`P3819R0 <https://wg21.link/P3819R0>`__","Remove ``evaluation_exception()`` from contract-violation handling for C++26","2025-11 (Kona)","","","`#171280 <https://github.com/llvm/llvm-project/issues/171280>`__",""
 "`P3612R1 <https://wg21.link/P3612R1>`__","Harmonize proxy-reference operations (LWG 3638 and 4187)","2025-11 (Kona)","","","`#171281 <https://github.com/llvm/llvm-project/issues/171281>`__",""
 "`P3778R0 <https://wg21.link/P3778R0>`__","Fix for ``type_order`` template definition","2025-11 (Kona)","","","`#171284 <https://github.com/llvm/llvm-project/issues/171284>`__",""
-"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements","2025-11 (Kona)","","","`#167268 <https://github.com/llvm/llvm-project/issues/167268>`__",""
+"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements","2025-11 (Kona)","|Complete|","22","`#167268 <https://github.com/llvm/llvm-project/issues/167268>`__",""
 "`P3922R1 <https://wg21.link/P3922R1>`__","Missing deduction guide from ``simd::mask`` to ``simd::vec``","2025-11 (Kona)","","","`#171285 <https://github.com/llvm/llvm-project/issues/171285>`__",""
 "`P3878R1 <https://wg21.link/P3878R1>`__","Standard library hardening should not use the 'observe' semantic","2025-11 (Kona)","","","`#171286 <https://github.com/llvm/llvm-project/issues/171286>`__",""
 "`P3887R1 <https://wg21.link/P3887R1>`__","Make ``when_all`` a Ronseal Algorithm","2025-11 (Kona)","","","`#171289 <https://github.com/llvm/llvm-project/issues/171289>`__",""
diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index 9450d526ed32c..6c688ef018af6 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
@@ -70,6 +75,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 f959c0ab227ac..12cd691fae2d5 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>
@@ -583,6 +583,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 28fae95c1c1f7..b3b424a1d77ce 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 ff965aaa4ff89..753cfb7547e7e 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 7f346b255e521bbd835e491a3ea14dd72d8b0c0f Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:31:03 +0100
Subject: [PATCH 02/19] 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 753cfb7547e7e..f61d6f991cb15 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 9a1e54229708b1953955a913c003aad9bc256aa7 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:37:19 +0100
Subject: [PATCH 03/19] regenerate <version>

---
 libcxx/include/version | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/version b/libcxx/include/version
index 12cd691fae2d5..ab781466f5ed5 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>
@@ -583,7 +584,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 4ee911f69076533596faf8515fa6083f6be1078c Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sat, 8 Nov 2025 23:58:48 +0100
Subject: [PATCH 04/19] 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 41222218ca42e2b22262e19470301aba1120fc2b Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 9 Nov 2025 06:45:16 +0100
Subject: [PATCH 05/19] apply review comments

---
 libcxx/include/__utility/integer_sequence.h   |  4 +--
 .../intseq.binding/integer_seq.pass.cpp       | 35 +++++++++----------
 2 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index 6c688ef018af6..336f55adf401b 100644
--- a/libcxx/include/__utility/integer_sequence.h
+++ b/libcxx/include/__utility/integer_sequence.h
@@ -78,7 +78,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...>> {
@@ -97,7 +97,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 b34fb3c47faa92f73e66d1a98b97b7e0b172e959 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 9 Nov 2025 06:48:46 +0100
Subject: [PATCH 06/19] 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 22750c8fd305a5146e0f6a47181d7d1522583b0d Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 9 Nov 2025 07:36:32 +0100
Subject: [PATCH 07/19] 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)}}

>From 00ae58d734c93a97e277faaa1fbb189f1fb1b196 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 10 Nov 2025 08:23:02 +0100
Subject: [PATCH 08/19] add github issue to documentation, sort includes, minor
 style changes

---
 libcxx/include/__utility/integer_sequence.h     | 17 +++++++----------
 .../intseq.binding/integer_seq.compile.pass.cpp |  7 +++++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index 336f55adf401b..af38e311b98ef 100644
--- a/libcxx/include/__utility/integer_sequence.h
+++ b/libcxx/include/__utility/integer_sequence.h
@@ -11,13 +11,10 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
+#include <__tuple/tuple_element.h>
+#include <__tuple/tuple_size.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
@@ -77,23 +74,23 @@ _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>
+template <class _Tp, _Tp... _Indices>
 struct tuple_size<integer_sequence<_Tp, _Indices...>> : integral_constant<size_t, sizeof...(_Indices)> {};
 
-template <size_t _Ip, typename _Tp, _Tp... _Indices>
+template <size_t _Ip, class _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>
+template <size_t _Ip, class _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 {
+template <size_t _Ip, class _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];
 }
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
index 4d23f2c03e77b..27597ea9b6044 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
@@ -19,12 +19,13 @@
 // template<size_t I, class T, T... Values>
 //   constexpr T get(integer_sequence<T, Values...>) noexcept;
 
+#include <cassert>
 #include <tuple>
-#include <utility>
 #include <type_traits>
-#include <cassert>
+#include <utility>
 
 constexpr void test() {
+  // std::tuple_size_v
   using empty = std::integer_sequence<int>;
   static_assert(std::tuple_size_v<empty> == 0);
   static_assert(std::tuple_size_v<const empty> == 0);
@@ -33,6 +34,7 @@ constexpr void test() {
   static_assert(std::tuple_size_v<size4> == 4);
   static_assert(std::tuple_size_v<const size4> == 4);
 
+  // std::tuple_element_t
   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>);
@@ -43,6 +45,7 @@ constexpr void test() {
   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>);
 
+  // std::get
   constexpr static size4 seq4{};
   static_assert(get<0>(seq4) == 9);
   static_assert(get<1>(seq4) == 8);

>From af09adaef6737d2aa0ffda6dce57790523d4aa63 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 10 Nov 2025 08:24:02 +0100
Subject: [PATCH 09/19] rename tests

---
 .../{integer_seq.compile.pass.cpp => binding.compile.pass.cpp}    | 0
 .../intseq.binding/{integer_seq.verify.cpp => binding.verify.cpp} | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename libcxx/test/std/utilities/intseq/intseq.binding/{integer_seq.compile.pass.cpp => binding.compile.pass.cpp} (100%)
 rename libcxx/test/std/utilities/intseq/intseq.binding/{integer_seq.verify.cpp => binding.verify.cpp} (100%)

diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/binding.compile.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.compile.pass.cpp
rename to libcxx/test/std/utilities/intseq/intseq.binding/binding.compile.pass.cpp
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/binding.verify.cpp
similarity index 100%
rename from libcxx/test/std/utilities/intseq/intseq.binding/integer_seq.verify.cpp
rename to libcxx/test/std/utilities/intseq/intseq.binding/binding.verify.cpp

>From a5871cc2ede6d034c7cdb396c7b8a660ddc92435 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 10 Nov 2025 15:03:41 +0100
Subject: [PATCH 10/19] rename tests, add noexceptness and return type checks,
 add structured binding test

---
 .../structured_binding.pass.cpp               | 41 +++++++++++++++++++
 ...s.cpp => tuple_interface.compile.pass.cpp} |  6 +++
 ....verify.cpp => tuple_interface.verify.cpp} |  0
 3 files changed, 47 insertions(+)
 create mode 100644 libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
 rename libcxx/test/std/utilities/intseq/intseq.binding/{binding.compile.pass.cpp => tuple_interface.compile.pass.cpp} (93%)
 rename libcxx/test/std/utilities/intseq/intseq.binding/{binding.verify.cpp => tuple_interface.verify.cpp} (100%)

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..d993f38c91f0e
--- /dev/null
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+// 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 <cassert>
+#include <utility>
+
+template <typename...>
+void test_structured_bindings() {
+  constexpr static auto [...empty] = std::make_index_sequence<0>();
+  static_assert(sizeof...(empty) == 0);
+
+  constexpr static auto [...size4] = std::make_index_sequence<4>();
+  static_assert(sizeof...(size4) == 4);
+
+  // these cannot yet be static_asserts
+  assert(size4...[0] == 0);
+  assert(size4...[1] == 1);
+  assert(size4...[2] == 2);
+  assert(size4...[3] == 3);
+}
+
+int main(int, char**) {
+  test_structured_bindings();
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/binding.compile.pass.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp
similarity index 93%
rename from libcxx/test/std/utilities/intseq/intseq.binding/binding.compile.pass.cpp
rename to libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp
index 27597ea9b6044..84282d987919f 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/binding.compile.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp
@@ -20,6 +20,7 @@
 //   constexpr T get(integer_sequence<T, Values...>) noexcept;
 
 #include <cassert>
+#include <concepts>
 #include <tuple>
 #include <type_traits>
 #include <utility>
@@ -51,4 +52,9 @@ constexpr void test() {
   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<int> decltype(auto) r = get<0>(seq4);
+  static_assert(r == 9);
 }
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/binding.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp
similarity index 100%
rename from libcxx/test/std/utilities/intseq/intseq.binding/binding.verify.cpp
rename to libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp

>From 4bb0481a88c5e6d7b818bc11a00672b18ceb67ff Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 10 Nov 2025 15:09:00 +0100
Subject: [PATCH 11/19] fix formatting issues

---
 .../intseq/intseq.binding/structured_binding.pass.cpp         | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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
index d993f38c91f0e..8c951f2619dcd 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -22,10 +22,10 @@
 
 template <typename...>
 void test_structured_bindings() {
-  constexpr static auto [...empty] = std::make_index_sequence<0>();
+  constexpr static auto [... empty] = std::make_index_sequence<0>();
   static_assert(sizeof...(empty) == 0);
 
-  constexpr static auto [...size4] = std::make_index_sequence<4>();
+  constexpr static auto [... size4] = std::make_index_sequence<4>();
   static_assert(sizeof...(size4) == 4);
 
   // these cannot yet be static_asserts

>From b2ccb843d20dcb5be22cf3e6a6d31ddb27dbe35a Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 10 Nov 2025 18:01:49 +0100
Subject: [PATCH 12/19] drop constexpr

---
 .../intseq/intseq.binding/structured_binding.pass.cpp        | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

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
index 8c951f2619dcd..f0af9af89bc1a 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -22,13 +22,12 @@
 
 template <typename...>
 void test_structured_bindings() {
-  constexpr static auto [... empty] = std::make_index_sequence<0>();
+  auto [... empty] = std::make_index_sequence<0>();
   static_assert(sizeof...(empty) == 0);
 
-  constexpr static auto [... size4] = std::make_index_sequence<4>();
+  auto [... size4] = std::make_index_sequence<4>();
   static_assert(sizeof...(size4) == 4);
 
-  // these cannot yet be static_asserts
   assert(size4...[0] == 0);
   assert(size4...[1] == 1);
   assert(size4...[2] == 2);

>From 79bf2e23a838df283f5a1018b4b774959fff909b Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 10 Nov 2025 23:33:42 +0100
Subject: [PATCH 13/19] guard p1061 structured bindings behind FTM, add
 structured binding test case

---
 .../intseq.binding/structured_binding.pass.cpp   | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

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
index f0af9af89bc1a..4702fbe989cd0 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -20,8 +20,18 @@
 #include <cassert>
 #include <utility>
 
-template <typename...>
 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 <typename...>
+void test_p1061_structured_bindings() {
   auto [... empty] = std::make_index_sequence<0>();
   static_assert(sizeof...(empty) == 0);
 
@@ -33,8 +43,12 @@ void test_structured_bindings() {
   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;
 }

>From f50a1ac94f229e4ad4065a96db8eb3a16fff4e51 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Fri, 14 Nov 2025 01:44:17 +0100
Subject: [PATCH 14/19] make get nodiscard, add nodiscard test, clean up tests

---
 libcxx/include/__utility/integer_sequence.h   |  4 +-
 .../intseq.binding/nodiscard.verify.cpp       | 23 ++++++++++++
 .../structured_binding.pass.cpp               | 37 +++++++++----------
 .../tuple_interface.compile.pass.cpp          | 10 ++---
 .../intseq.binding/tuple_interface.verify.cpp |  2 +-
 5 files changed, 48 insertions(+), 28 deletions(-)
 create mode 100644 libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp

diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h
index af38e311b98ef..a84f572c3339c 100644
--- a/libcxx/include/__utility/integer_sequence.h
+++ b/libcxx/include/__utility/integer_sequence.h
@@ -73,7 +73,7 @@ _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
+// [intseq.binding], structured binding support
 template <class _Tp, _Tp... _Indices>
 struct tuple_size<integer_sequence<_Tp, _Indices...>> : integral_constant<size_t, sizeof...(_Indices)> {};
 
@@ -90,7 +90,7 @@ struct tuple_element<_Ip, const integer_sequence<_Tp, _Indices...>> {
 };
 
 template <size_t _Ip, class _Tp, _Tp... _Indices>
-_LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept {
+[[nodiscard]] _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];
 }
diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp b/libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..82c0ed1aee175
--- /dev/null
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+// template<size_t I, class T, T... Values>
+//   [[nodiscard]] constexpr T get(integer_sequence<T, Values...>) noexcept;
+
+// check that get is marked [[nodiscard]]
+
+#include <utility>
+
+void f() {
+  std::index_sequence<1> seq;
+  get<0>(seq);    // expected-warning {{ignoring return value of function}}
+}
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
index 4702fbe989cd0..3d6745bf17a73 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -20,35 +20,34 @@
 #include <cassert>
 #include <utility>
 
-void test_structured_bindings() {
+constexpr bool 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 <typename...>
-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);
-}
+  []<typename...> {
+    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
 
+  return true;
+}
+
 int main(int, char**) {
   test_structured_bindings();
-#if __cpp_structured_bindings >= 202411L
-  test_p1061_structured_bindings();
-#endif
+  static_assert(test_structured_bindings());
   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
index 84282d987919f..026f20eb8c09f 100644
--- 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
@@ -25,7 +25,7 @@
 #include <type_traits>
 #include <utility>
 
-constexpr void test() {
+void test() {
   // std::tuple_size_v
   using empty = std::integer_sequence<int>;
   static_assert(std::tuple_size_v<empty> == 0);
@@ -47,14 +47,12 @@ constexpr void test() {
   static_assert(std::is_same_v<std::tuple_element_t<3, const size4>, int>);
 
   // std::get
-  constexpr static size4 seq4{};
-  static_assert(get<0>(seq4) == 9);
+  constexpr static size4 seq4;
+  constexpr std::same_as<int> decltype(auto) elt0 = get<0>(seq4);
+  static_assert(elt0 == 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<int> 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
index 3e9d8d7d18dfc..d5be826f52c12 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp
@@ -27,7 +27,7 @@ void f() {
   // 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>();
+  std::integer_sequence<int> empty;
   // 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);

>From 3a169cef95820380d3fb2f88d424a7cfd8e17e0e Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 14 Dec 2025 22:21:54 +0100
Subject: [PATCH 15/19] move nodiscard test to test/libcxx, fixup tests names

---
 .../utilities/intseq/intseq.binding/nodiscard.verify.cpp    | 2 +-
 .../intseq/intseq.binding/structured_binding.pass.cpp       | 6 +++---
 .../intseq/intseq.binding/tuple_interface.verify.cpp        | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
 rename libcxx/test/{std => libcxx}/utilities/intseq/intseq.binding/nodiscard.verify.cpp (98%)

diff --git a/libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
similarity index 98%
rename from libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp
rename to libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
index 82c0ed1aee175..f930a400ea635 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
@@ -17,7 +17,7 @@
 
 #include <utility>
 
-void f() {
+void test() {
   std::index_sequence<1> seq;
   get<0>(seq);    // expected-warning {{ignoring return value of function}}
 }
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
index 3d6745bf17a73..3f52f18282543 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -20,7 +20,7 @@
 #include <cassert>
 #include <utility>
 
-constexpr bool test_structured_bindings() {
+constexpr bool test() {
   auto [elt0, elt1, elt2, elt3] = std::make_index_sequence<4>();
 
   assert(elt0 == 0);
@@ -47,7 +47,7 @@ constexpr bool test_structured_bindings() {
 }
 
 int main(int, char**) {
-  test_structured_bindings();
-  static_assert(test_structured_bindings());
+  test();
+  static_assert(test());
   return 0;
 }
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
index d5be826f52c12..a1c894e985729 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp
@@ -21,7 +21,7 @@
 
 #include <utility>
 
-void f() {
+void test() {
   // 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)}}

>From 444e1d44f9b20a4e68151b1ca9c64c3accaad551 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Sun, 14 Dec 2025 22:30:32 +0100
Subject: [PATCH 16/19] rerun formatter

---
 .../libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
index f930a400ea635..0e88871020906 100644
--- a/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
@@ -19,5 +19,5 @@
 
 void test() {
   std::index_sequence<1> seq;
-  get<0>(seq);    // expected-warning {{ignoring return value of function}}
+  get<0>(seq); // expected-warning {{ignoring return value of function}}
 }

>From 4c500a267bd123bc932c165f23f709d3f75be294 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Mon, 15 Dec 2025 07:16:45 +0100
Subject: [PATCH 17/19] add todo

---
 .../utilities/intseq/intseq.binding/structured_binding.pass.cpp  | 1 +
 1 file changed, 1 insertion(+)

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
index 3f52f18282543..650e0d651ea7d 100644
--- a/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
+++ b/libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp
@@ -28,6 +28,7 @@ constexpr bool test() {
   assert(elt2 == 2);
   assert(elt3 == 3);
 
+// TODO: remove this macro guard once GCC16 is available
 #if __cpp_structured_bindings >= 202411L
   []<typename...> {
     auto [... empty] = std::make_index_sequence<0>();

>From 3b945133552ebb4f2ba96e75437f3d6bfef7b249 Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Tue, 16 Dec 2025 05:50:03 +0100
Subject: [PATCH 18/19] fold intseq.binding/nodiscard.verify.cpp into
 nodiscard.verify.cpp

---
 .../intseq.binding/nodiscard.verify.cpp       | 23 -------------------
 .../utilities/intseq/nodiscard.verify.cpp     |  3 +++
 2 files changed, 3 insertions(+), 23 deletions(-)
 delete mode 100644 libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp

diff --git a/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
deleted file mode 100644
index 0e88871020906..0000000000000
--- a/libcxx/test/libcxx/utilities/intseq/intseq.binding/nodiscard.verify.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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>
-
-// template<size_t I, class T, T... Values>
-//   [[nodiscard]] constexpr T get(integer_sequence<T, Values...>) noexcept;
-
-// check that get is marked [[nodiscard]]
-
-#include <utility>
-
-void test() {
-  std::index_sequence<1> seq;
-  get<0>(seq); // expected-warning {{ignoring return value of function}}
-}
diff --git a/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp
index 4ca52ace08dd3..8d2f35cadc553 100644
--- a/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp
@@ -18,4 +18,7 @@ void test() {
   std::integer_sequence<int, 49, 82, 94> seq;
 
   seq.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 26
+  get<0>(seq); // expected-warning {{ignoring return value of function}}
+#endif
 }

>From 50eae4abdd1fc6e6166e64083f288fc9e9e736ca Mon Sep 17 00:00:00 2001
From: Tsche <che at pydong.org>
Date: Tue, 16 Dec 2025 19:22:45 +0100
Subject: [PATCH 19/19] add test_macro.h include

---
 libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp
index 8d2f35cadc553..811759f37823c 100644
--- a/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp
@@ -14,6 +14,8 @@
 
 #include <utility>
 
+#include "test_macros.h"
+
 void test() {
   std::integer_sequence<int, 49, 82, 94> seq;
 



More information about the libcxx-commits mailing list