[gcc r16-8602] libstdc++: Implement structured binding support for integer_sequence

Tomasz Kaminski tkaminsk@gcc.gnu.org
Tue Apr 14 10:56:20 GMT 2026


https://gcc.gnu.org/g:6159bfcf8b5852417519cf4181bf0ff8907ac0ca

commit r16-8602-g6159bfcf8b5852417519cf4181bf0ff8907ac0ca
Author: Matthias Wippich <mfwippich@gmail.com>
Date:   Thu Apr 9 04:41:31 2026 +0200

    libstdc++: Implement structured binding support for integer_sequence
    
    This implements P1789R3 Library Support for Expansion Statements.
    https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/utility.h (std::tuple_size, std::tuple_element):
            Add partial specializations for integer_sequence.
            (std::get(integer_sequence<_Tp, _Idx...>)): Define.
            * include/bits/version.def (integer_sequence): Bump to 202511L.
            * include/bits/version.h: Regenerate.
            * testsuite/20_util/integer_sequence/tuple_access.cc: New test.
            * testsuite/20_util/integer_sequence/tuple_access_neg.cc: New test.
            * testsuite/experimental/feat-cxx14.cc: Updated check for
            __cpp_lib_integer_sequence value.
    
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
    Co-authored-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
    Signed-off-by: Matthias Wippich <mfwippich@gmail.com>

Diff:
---
 libstdc++-v3/include/bits/utility.h                |  36 ++++++
 libstdc++-v3/include/bits/version.def              |   5 +
 libstdc++-v3/include/bits/version.h                |   7 +-
 .../20_util/integer_sequence/tuple_access.cc       | 143 +++++++++++++++++++++
 .../20_util/integer_sequence/tuple_access_neg.cc   |  22 ++++
 libstdc++-v3/testsuite/experimental/feat-cxx14.cc  |   4 +-
 6 files changed, 214 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h
index 93e9e9f9dba2..74ae04d6bd2e 100644
--- a/libstdc++-v3/include/bits/utility.h
+++ b/libstdc++-v3/include/bits/utility.h
@@ -481,6 +481,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static constexpr size_t size() noexcept { return sizeof...(_Idx); }
     };
 
+#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
+  /** @brief Structured binding support for `integer_sequence`
+
+    * @since C++26
+    * @{
+    */
+  /// Structured binding support
+  template<typename _Tp, _Tp... _Idx>
+    struct tuple_size<integer_sequence<_Tp, _Idx...>>
+    : integral_constant<size_t, sizeof...(_Idx)> { };
+
+  template<size_t __i, class _Tp, _Tp... _Idx>
+    struct tuple_element<__i, integer_sequence<_Tp, _Idx...>>
+    {
+      static_assert(__i < sizeof...(_Idx));
+      using type = _Tp;
+    };
+
+  template<size_t __i, class _Tp, _Tp... _Idx>
+    struct tuple_element<__i, const integer_sequence<_Tp, _Idx...>>
+    {
+      static_assert(__i < sizeof...(_Idx));
+      using type = _Tp;
+    };
+
+  template<size_t __i, class _Tp, _Tp... _Idx>
+    [[nodiscard]]
+    constexpr _Tp
+    get(integer_sequence<_Tp, _Idx...>) noexcept
+    {
+      static_assert(__i < sizeof...(_Idx));
+      return _Idx...[__i];
+    }
+    /// @}
+#endif // __glibcxx_integer_sequence >= 202511L
+
   /// Alias template make_integer_sequence
   template<typename _Tp, _Tp _Num>
     using make_integer_sequence
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index b88d9c3483f8..7aaf150d0875 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -184,6 +184,11 @@ ftms = {
 
 ftms = {
   name = integer_sequence;
+  values = {
+    v = 202511;
+    cxxmin = 26;
+    extra_cond = "__cpp_pack_indexing";
+  };
   values = {
     v = 201304;
     cxxmin = 14;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 24ec0175e1e4..b247662f089e 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -186,7 +186,12 @@
 #undef __glibcxx_want_exchange_function
 
 #if !defined(__cpp_lib_integer_sequence)
-# if (__cplusplus >= 201402L)
+# if (__cplusplus >  202302L) && (__cpp_pack_indexing)
+#  define __glibcxx_integer_sequence 202511L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_integer_sequence)
+#   define __cpp_lib_integer_sequence 202511L
+#  endif
+# elif (__cplusplus >= 201402L)
 #  define __glibcxx_integer_sequence 201304L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_integer_sequence)
 #   define __cpp_lib_integer_sequence 201304L
diff --git a/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
new file mode 100644
index 000000000000..afa644e7dab7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access.cc
@@ -0,0 +1,143 @@
+// { dg-do compile { target c++26 } }
+
+#include <utility>
+#include <tuple>
+#include <testsuite_hooks.h>
+
+#if __cpp_lib_integer_sequence < 202511L
+# error "Feature-test macro __cpp_lib_integer_sequence is incorrect"
+#endif
+
+constexpr auto
+destructure_sum(auto seq)
+{
+  auto [...elems] = seq;
+  return (0 + ... + elems);
+}
+
+using IS1 = std::make_index_sequence<10>;
+static_assert( std::tuple_size_v<IS1> == 10 );
+static_assert( std::is_same_v<std::tuple_element_t<3, IS1>, std::size_t> );
+static_assert( std::get<7>(IS1{}) == 7 );
+static_assert( destructure_sum(IS1{}) == 45 );
+static_assert( noexcept(get<0>(IS1{})) );
+
+using IS2 = std::integer_sequence<int, 42, 101, -13>;
+static_assert( std::tuple_size_v<IS2> == 3 );
+static_assert( std::is_same_v<std::tuple_element_t<1, IS2>, int> );
+static_assert( std::get<2>(IS2{}) == -13 );
+static_assert( destructure_sum(IS2{}) == 130 );
+static_assert( noexcept(get<0>(IS2{})) );
+
+using IS3 = std::integer_sequence<char>;
+static_assert( std::tuple_size_v<IS3> == 0 );
+
+using IS4 = std::integer_sequence<int, 1, 2>;
+static_assert( !std::is_constructible_v<std::pair<int, int>, IS4> );
+static_assert( !std::is_constructible_v<std::tuple<int, int>, IS4> );
+
+template<typename = void>
+constexpr bool
+test_basic()
+{
+  {
+    auto [...elems] = std::make_index_sequence<0>{};
+    static_assert( sizeof...(elems) == 0 );
+  }
+
+  {
+    auto [...elems] = std::integer_sequence<int, 3, 5, 7, 11>{};
+
+    static_assert( sizeof...(elems) == 4 );
+
+    VERIFY( elems...[0] == 3 );
+    VERIFY( elems...[1] == 5 );
+    VERIFY( elems...[2] == 7 );
+    VERIFY( elems...[3] == 11 );
+  }
+
+  {
+    static constexpr auto [...elems] = std::integer_sequence<short, 2, 4, 8, 16>{};
+
+    static_assert( sizeof...(elems) == 4 );
+
+    static_assert( elems...[0] == 2 );
+    static_assert( elems...[1] == 4 );
+    static_assert( elems...[2] == 8 );
+    static_assert( elems...[3] == 16 );
+  }
+
+  {
+    constexpr auto [...elems] = std::integer_sequence<int, 1, 8, 2, 11>{};
+
+    static_assert( sizeof...(elems) == 4 );
+
+    static_assert( elems...[0] == 1 );
+    static_assert( elems...[1] == 8 );
+    static_assert( elems...[2] == 2 );
+    static_assert( elems...[3] == 11 );
+  }
+
+  {
+    static constexpr auto&& [...elems] = std::integer_sequence<short, 2, 4, 8, 16>{};
+
+    static_assert( sizeof...(elems) == 4 );
+
+    static_assert( elems...[0] == 2 );
+    static_assert( elems...[1] == 4 );
+    static_assert( elems...[2] == 8 );
+    static_assert( elems...[3] == 16 );
+  }
+
+  /* Unimplemented, see PR117784
+  {
+    constexpr auto&& [...elems] = std::integer_sequence<int, 1, 8, 2, 11>{};
+
+    static_assert( sizeof...(elems) == 4 );
+
+    static_assert( elems...[0] == 1 );
+    static_assert( elems...[1] == 8 );
+    static_assert( elems...[2] == 2 );
+    static_assert( elems...[3] == 11 );
+  }
+  */
+
+  {
+    auto idx = 0;
+    static constexpr auto seq = std::make_index_sequence<4>{};
+    template for (constexpr auto elem : seq)
+      {
+	VERIFY( elem == idx );
+	++idx;
+      }
+    VERIFY( idx == 4 );
+  }
+
+
+  /* Unimplemented, see PR117784
+  {
+    auto idx = 0;
+    constexpr auto seq = std::make_index_sequence<4>{};
+    template for (constexpr auto elem : seq)
+      {
+	VERIFY( elem == idx );
+	++idx;
+      }
+    VERIFY( idx == 4 );
+  }
+   
+  {
+    auto idx = 0;
+    template for (constexpr auto elem : std::make_index_sequence<4>{})
+      {
+	VERIFY( elem == idx );
+	++idx;
+      }
+    VERIFY( idx == 4 );
+  }
+  */
+
+  return true;
+}
+
+static_assert( test_basic() );
diff --git a/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc
new file mode 100644
index 000000000000..8640114e7d3d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/integer_sequence/tuple_access_neg.cc
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++26 } }
+
+#include <utility>
+
+using empty = std::integer_sequence<int>;
+static_assert( std::is_same_v<std::tuple_element_t<0, empty>, int> ); // { dg-error "here" }
+static_assert( std::is_same_v<std::tuple_element_t<0, const empty>, int> ); // { dg-error "here" }
+
+using size4 = std::integer_sequence<int, 1, 9, 7, 15>;
+static_assert( std::is_same_v<std::tuple_element_t<4, size4>, int> ); // { dg-error "here" }
+static_assert( std::is_same_v<std::tuple_element_t<4, const size4>, int> ); // { dg-error "here" }
+
+void
+test()
+{
+  (void)std::get<0>(empty{}); // { dg-error "here" }
+  (void)std::get<4>(size4{}); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "cannot index an empty pack" "" { target *-*-* } 0 }
+// { dg-error "pack index '.' is out of range for pack of length" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/experimental/feat-cxx14.cc b/libstdc++-v3/testsuite/experimental/feat-cxx14.cc
index c009062b55cd..4cc56c5f76ec 100644
--- a/libstdc++-v3/testsuite/experimental/feat-cxx14.cc
+++ b/libstdc++-v3/testsuite/experimental/feat-cxx14.cc
@@ -18,8 +18,8 @@
 
 #ifndef  __cpp_lib_integer_sequence
 #  error "__cpp_lib_integer_sequence"
-#elif  __cpp_lib_integer_sequence != 201304
-#  error "__cpp_lib_integer_sequence != 201304"
+#elif  __cpp_lib_integer_sequence < 201304
+#  error "__cpp_lib_integer_sequence < 201304"
 #endif
 
 #ifndef  __cpp_lib_exchange_function


More information about the Libstdc++-cvs mailing list