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.

Closes #167268

@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

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions ,cpp,h -- libcxx/test/std/utilities/intseq/intseq.binding/structured_binding.pass.cpp libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp libcxx/include/__utility/integer_sequence.h libcxx/include/utility libcxx/include/version libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.compile.pass.cpp libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
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 4702fbe98..5da84e3a2 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,7 +22,7 @@
 
 void test_structured_bindings() {
   auto [elt0, elt1, elt2, elt3] = std::make_index_sequence<4>();
-  
+
   assert(elt0 == 0);
   assert(elt1 == 1);
   assert(elt2 == 2);

@H-G-Hristov
Copy link
Contributor

Thank your for working on this. I think it is possible also to add a functional test too to demonstrate the feature?.

@Tsche
Copy link
Contributor Author

Tsche commented Nov 10, 2025

Thank your for working on this. I think it is possible also to add a functional test too to demonstrate the feature?.

Unfortunately not at this time. To properly showcase the structured binding use-case we need P2686, for the expansion statement one we need P1306. From what I can tell clang currently supports neither.

@frederick-vs-ja
Copy link
Contributor

Thank your for working on this. I think it is possible also to add a functional test too to demonstrate the feature?.

Unfortunately not at this time. To properly showcase the structured binding use-case we need P2686, for the expansion statement one we need P1306. From what I can tell clang currently supports neither.

I think it's still worthwhile testing "plain" (non-constexpr) structured bindings and structured binding packs.

@Tsche
Copy link
Contributor Author

Tsche commented Nov 10, 2025

Thank your for working on this. I think it is possible also to add a functional test too to demonstrate the feature?.

Unfortunately not at this time. To properly showcase the structured binding use-case we need P2686, for the expansion statement one we need P1306. From what I can tell clang currently supports neither.

I think it's still worthwhile testing "plain" (non-constexpr) structured bindings and structured binding packs.

It turns out P2686 is partially implemented. We do not yet seem to be able to retrieve values in a constant evaluated expression, so I'm using plain assert for now. I left a note.

Edit:
Nevermind, that caused unexpected test failures. I've dropped constexpr for now.

Comment on lines +23 to +54
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);

auto [... size4] = std::make_index_sequence<4>();
static_assert(sizeof...(size4) == 4);

assert(size4...[0] == 0);
assert(size4...[1] == 1);
assert(size4...[2] == 2);
assert(size4...[3] == 3);
}
#endif

int main(int, char**) {
test_structured_bindings();
#if __cpp_structured_bindings >= 202411L
test_p1061_structured_bindings();
#endif
return 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should test both constant evaluation and runtime behavior.

Also, it seems simpler to put the test case for structured binding packs into an immediately invoked lambda expression to avoid duplicated macro guards.

Suggested change
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);
auto [... size4] = std::make_index_sequence<4>();
static_assert(sizeof...(size4) == 4);
assert(size4...[0] == 0);
assert(size4...[1] == 1);
assert(size4...[2] == 2);
assert(size4...[3] == 3);
}
#endif
int main(int, char**) {
test_structured_bindings();
#if __cpp_structured_bindings >= 202411L
test_p1061_structured_bindings();
#endif
return 0;
}
constexpr bool test() {
auto [elt0, elt1, elt2, elt3] = std::make_index_sequence<4>();
assert(elt0 == 0);
assert(elt1 == 1);
assert(elt2 == 2);
assert(elt3 == 3);
[]<typename...> {
#if __cpp_structured_bindings >= 202411L
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();
static_assert(test());
return 0;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe just merge the two tests files? WDYT?

#include <type_traits>
#include <utility>

constexpr void test() {
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
constexpr void test() {
void test() {

I think this won't be necessary if you declare constexpr locally and won't be extending the test to do the runtime checks..

Comment on lines +58 to +59
constexpr std::same_as<int> decltype(auto) r = get<0>(seq4);
static_assert(r == 9);
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace line 51 with this one as they are doing the same test.

Suggested change
constexpr std::same_as<int> decltype(auto) r = get<0>(seq4);
static_assert(r == 9);

Comment on lines +13 to +18
// 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;
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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;
// <describe what's being tested>

I think you should rename this file to "general.pass.cpp".
libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.compile.pass.cpp -> libcxx/test/std/utilities/intseq/intseq.binding/binding.compile.pass.cpp
libcxx/test/std/utilities/intseq/intseq.binding/tuple_interface.verify.cpp ->
libcxx/test/std/utilities/intseq/intseq.binding/binding.verify.cpp
Which is closer to the convention of how test named: the path consists of the sections in the Standard + function names, etc.

assert(elt3 == 3);
}

#if __cpp_structured_bindings >= 202411L
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually guard with a macro TEST_HAS_<FEATURE_NAME> declared in test_macros.h. I'm not sure if it is totally necessary doing it for a single case but you should at least a TODO to remind to remove this check and maybe list the unsupported compilers.

Suggested change
#if __cpp_structured_bindings >= 202411L
// TODO: Remove...

I guess having a TEST_HAS_ macro declared in test_macros.h will be easier to spot and clean-up.


// std::get
constexpr static size4 seq4{};
static_assert(get<0>(seq4) == 9);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static_assert(get<0>(seq4) == 9);
constexpr std::same_as<int> decltype(auto) r = get<0>(seq4);
static_assert(r == 9);

Comment on lines +30 to +33
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: std::integer_sequence<int> empty; or (void)std::get<0>(`std::integer_sequence{});

};

template <size_t _Ip, class _Tp, _Tp... _Indices>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept {
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_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 {

I think we can mark get as [[nodiscard]]. A test should be added to /libcxx/test/libcxx/utilities/intseq/nodiscard.verify.cpp

@Zingam
Copy link
Contributor

Zingam commented Nov 11, 2025

Thank your for working on this. I think it is possible also to add a functional test too to demonstrate the feature?.

Unfortunately not at this time. To properly showcase the structured binding use-case we need P2686, for the expansion statement one we need P1306. From what I can tell clang currently supports neither.

For the record: #165195 P1306 is in progress.

# endif // _LIBCPP_STD_VER >= 20

# if _LIBCPP_STD_VER >= 26
// structured binding support for integer_sequence
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Suggested change
// structured binding support for integer_sequence
// [intseq.binding] Structured binding support

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P1789R3: Library Support for Expansion Statements

6 participants