libstdc++: Implement P1789R3: structured bindings for std::integer_sequence

Message ID 20260405123322.3064791-2-ivan.lazaric1@gmail.com
State New
Headers
Series libstdc++: Implement P1789R3: structured bindings for std::integer_sequence |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 fail Test failed

Commit Message

Ivan Lazaric April 5, 2026, 12:33 p.m. UTC
  https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf

P1789 enables accessing the sequence values through structured bindings.
```
auto [...values] = std::make_index_sequence<10>{};
// values is a pack of size 10, and elements 0, 1, 2, ..., 9
```

Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
Feature-test macro integer_sequence has been bumped to 202511L.

libstdc++-v3/ChangeLog:

	* include/bits/utility.h:
        Implement structured bindings protocol for std::integer_sequence.
	* include/bits/version.def: Bump integer_sequence feature-test macro.
	* include/bits/version.h: Regenerate.
	* testsuite/20_util/integer_sequence/structured_binding.cc: New test.

Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
---
Fixed a missing `std::` on `size_t` , thanks Linaro.
Extended the test.

Only part that fails is the last block in `test_basic()`
I am pretty sure that's because of:
```
static constexpr int&& x = 1;
static_assert(x == 1); // fails, would've worked if it was `const int&&` or `const int&`
```

https://godbolt.org/z/jM18sv5nh

 libstdc++-v3/include/bits/utility.h           | 28 ++++++++
 libstdc++-v3/include/bits/version.def         |  5 ++
 libstdc++-v3/include/bits/version.h           |  7 +-
 .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
 4 files changed, 111 insertions(+), 1 deletion(-)
 create mode 100644 libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
  

Comments

Matthias Wippich April 5, 2026, 6:33 p.m. UTC | #1
>Will post an updated patch, but wouldn’t pre-CWG3135 wording also work, due to lifetime extension?
Without the changes from cwg3135, this cannot interact well with p2686
constexpr structured bindings. The non-constexpr case should be fine.
That's very unfortunate since the intended use is with p2686 constexpr
bindings + p1061 pack-introducing bindings - therefore, implementing
p1789 without first addressing cwg3135 seems moot to me.

As Tomasz mentioned, I already submitted a patch for this end of last
year but waited to see whether we fix p1789 by addressing the core
language defect or by changing the library specification instead.
Since cwg3135 is accepted now, I was going to update it as soon as
Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).

Since your patch seems to be in better shape than mine, I do not mind
abandoning the previous patch in favor of this one. @Tomasz: Which one
do you want to go ahead with? Does the release target change depending
on which one is used or is it going to be GCC 17 either way?



On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com> wrote:
>
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>
> P1789 enables accessing the sequence values through structured bindings.
> ```
> auto [...values] = std::make_index_sequence<10>{};
> // values is a pack of size 10, and elements 0, 1, 2, ..., 9
> ```
>
> Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
> Feature-test macro integer_sequence has been bumped to 202511L.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/utility.h:
>         Implement structured bindings protocol for std::integer_sequence.
>         * include/bits/version.def: Bump integer_sequence feature-test macro.
>         * include/bits/version.h: Regenerate.
>         * testsuite/20_util/integer_sequence/structured_binding.cc: New test.
>
> Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> ---
> Fixed a missing `std::` on `size_t` , thanks Linaro.
> Extended the test.
>
> Only part that fails is the last block in `test_basic()`
> I am pretty sure that's because of:
> ```
> static constexpr int&& x = 1;
> static_assert(x == 1); // fails, would've worked if it was `const int&&` or `const int&`
> ```
>
> https://godbolt.org/z/jM18sv5nh
>
>  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
>  libstdc++-v3/include/bits/version.def         |  5 ++
>  libstdc++-v3/include/bits/version.h           |  7 +-
>  .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
>  4 files changed, 111 insertions(+), 1 deletion(-)
>  create mode 100644 libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>
> diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h
> index bd6b18d54dd..159884dd814 100644
> --- a/libstdc++-v3/include/bits/utility.h
> +++ b/libstdc++-v3/include/bits/utility.h
> @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        static constexpr size_t size() noexcept { return sizeof...(_Idx); }
>      };
>
> +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
> +    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>
> +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> new file mode 100644
> index 00000000000..18cbcae53e5
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> @@ -0,0 +1,72 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <utility>
> +#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 );
> +
> +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 );
> +
> +using IS3 = std::integer_sequence<char>;
> +static_assert( std::tuple_size_v<IS3> == 0 );
> +
> +template<typename = void>
> +constexpr bool
> +test_basic()
> +{
> +  {
> +    auto [...elems] = std::make_index_sequence<10>{};
> +
> +    static_assert( sizeof...(elems) == 10 );
> +
> +    VERIFY( elems...[0] == 0 );
> +    VERIFY( elems...[3] == 3 );
> +    VERIFY( elems...[9] == 9 );
> +  }
> +
> +  {
> +    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 );
> +
> +    // these fail
> +    static_assert( elems...[0] == 2 );
> +    static_assert( elems...[1] == 4 );
> +    static_assert( elems...[2] == 8 );
> +    static_assert( elems...[3] == 16 );
> +  }
> +
> +  return true;
> +}
> +
> +static_assert( test_basic() );
> --
> 2.43.0
>
  
Ivan Lazaric April 5, 2026, 8:48 p.m. UTC | #2
Clarifying, I implemented this for myself locally because it was useful
in some reflection related code. I searched through my email for
patches for this proposal, but it seems I haven’t been subscribed for long
enough to find yours. It seemed simple enough so I cleaned it up a bit
and posted.

You seem to have better understanding of the general situation here,
so IMO it would be better for me to drop the work and let you continue.
If you wish to use any snippets from what I posted, feel free.

I built locally with Jakubs patch, and the noted failures now pass.
Something that still fails though, which is explicitly mentioned in paper:

    template for (constexpr auto index : std::make_index_sequence<20>{})
        static_assert( index + 1 ); // error, not a constant expression

Desugared a bit (also fails):

  {
    constexpr auto&& [a, b, c] = std::make_index_sequence<3>{};

    static_assert( a == 0 );
    static_assert( b == 1 );
    static_assert( c == 2 );
  }

Please verify this, as I could be missing some patches

On Sun, Apr 5, 2026 at 8:33 PM Matthias Wippich <mfwippich@gmail.com> wrote:

> >Will post an updated patch, but wouldn’t pre-CWG3135 wording also work,
> due to lifetime extension?
> Without the changes from cwg3135, this cannot interact well with p2686
> constexpr structured bindings. The non-constexpr case should be fine.
> That's very unfortunate since the intended use is with p2686 constexpr
> bindings + p1061 pack-introducing bindings - therefore, implementing
> p1789 without first addressing cwg3135 seems moot to me.
>
> As Tomasz mentioned, I already submitted a patch for this end of last
> year but waited to see whether we fix p1789 by addressing the core
> language defect or by changing the library specification instead.
> Since cwg3135 is accepted now, I was going to update it as soon as
> Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
>
> Since your patch seems to be in better shape than mine, I do not mind
> abandoning the previous patch in favor of this one. @Tomasz: Which one
> do you want to go ahead with? Does the release target change depending
> on which one is used or is it going to be GCC 17 either way?
>
>
>
> On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
> wrote:
> >
> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
> >
> > P1789 enables accessing the sequence values through structured bindings.
> > ```
> > auto [...values] = std::make_index_sequence<10>{};
> > // values is a pack of size 10, and elements 0, 1, 2, ..., 9
> > ```
> >
> > Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
> > Feature-test macro integer_sequence has been bumped to 202511L.
> >
> > libstdc++-v3/ChangeLog:
> >
> >         * include/bits/utility.h:
> >         Implement structured bindings protocol for std::integer_sequence.
> >         * include/bits/version.def: Bump integer_sequence feature-test
> macro.
> >         * include/bits/version.h: Regenerate.
> >         * testsuite/20_util/integer_sequence/structured_binding.cc: New
> test.
> >
> > Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> > ---
> > Fixed a missing `std::` on `size_t` , thanks Linaro.
> > Extended the test.
> >
> > Only part that fails is the last block in `test_basic()`
> > I am pretty sure that's because of:
> > ```
> > static constexpr int&& x = 1;
> > static_assert(x == 1); // fails, would've worked if it was `const int&&`
> or `const int&`
> > ```
> >
> > https://godbolt.org/z/jM18sv5nh
> >
> >  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
> >  libstdc++-v3/include/bits/version.def         |  5 ++
> >  libstdc++-v3/include/bits/version.h           |  7 +-
> >  .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
> >  4 files changed, 111 insertions(+), 1 deletion(-)
> >  create mode 100644
> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> >
> > diff --git a/libstdc++-v3/include/bits/utility.h
> b/libstdc++-v3/include/bits/utility.h
> > index bd6b18d54dd..159884dd814 100644
> > --- a/libstdc++-v3/include/bits/utility.h
> > +++ b/libstdc++-v3/include/bits/utility.h
> > @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >        static constexpr size_t size() noexcept { return sizeof...(_Idx);
> }
> >      };
> >
> > +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
> > +    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>
> > +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> > new file mode 100644
> > index 00000000000..18cbcae53e5
> > --- /dev/null
> > +++
> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> > @@ -0,0 +1,72 @@
> > +// { dg-do compile { target c++26 } }
> > +
> > +#include <utility>
> > +#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 );
> > +
> > +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 );
> > +
> > +using IS3 = std::integer_sequence<char>;
> > +static_assert( std::tuple_size_v<IS3> == 0 );
> > +
> > +template<typename = void>
> > +constexpr bool
> > +test_basic()
> > +{
> > +  {
> > +    auto [...elems] = std::make_index_sequence<10>{};
> > +
> > +    static_assert( sizeof...(elems) == 10 );
> > +
> > +    VERIFY( elems...[0] == 0 );
> > +    VERIFY( elems...[3] == 3 );
> > +    VERIFY( elems...[9] == 9 );
> > +  }
> > +
> > +  {
> > +    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 );
> > +
> > +    // these fail
> > +    static_assert( elems...[0] == 2 );
> > +    static_assert( elems...[1] == 4 );
> > +    static_assert( elems...[2] == 8 );
> > +    static_assert( elems...[3] == 16 );
> > +  }
> > +
> > +  return true;
> > +}
> > +
> > +static_assert( test_basic() );
> > --
> > 2.43.0
> >
>
  
Daniel Krügler April 6, 2026, 8:35 a.m. UTC | #3
Am So., 5. Apr. 2026 um 22:49 Uhr schrieb Ivan Lazaric <
ivan.lazaric1@gmail.com>:

> Clarifying, I implemented this for myself locally because it was useful
> in some reflection related code. I searched through my email for
> patches for this proposal, but it seems I haven’t been subscribed for long
> enough to find yours. It seemed simple enough so I cleaned it up a bit
> and posted.
>
> You seem to have better understanding of the general situation here,
> so IMO it would be better for me to drop the work and let you continue.
> If you wish to use any snippets from what I posted, feel free.
>
> I built locally with Jakubs patch, and the noted failures now pass.
> Something that still fails though, which is explicitly mentioned in paper:
>
>     template for (constexpr auto index : std::make_index_sequence<20>{})
>         static_assert( index + 1 ); // error, not a constant expression
>
> Desugared a bit (also fails):
>
>   {
>     constexpr auto&& [a, b, c] = std::make_index_sequence<3>{};
>
>     static_assert( a == 0 );
>     static_assert( b == 1 );
>     static_assert( c == 2 );
>   }
>
> Please verify this, as I could be missing some patches
>
This is CWG 3135 (
https://cplusplus.github.io/CWG/issues/cwg_active.html#3135), which was
accepted in Croydon, but presumably not yet  implemented in gcc.

- Daniel


>
> On Sun, Apr 5, 2026 at 8:33 PM Matthias Wippich <mfwippich@gmail.com>
> wrote:
>
>> >Will post an updated patch, but wouldn’t pre-CWG3135 wording also work,
>> due to lifetime extension?
>> Without the changes from cwg3135, this cannot interact well with p2686
>> constexpr structured bindings. The non-constexpr case should be fine.
>> That's very unfortunate since the intended use is with p2686 constexpr
>> bindings + p1061 pack-introducing bindings - therefore, implementing
>> p1789 without first addressing cwg3135 seems moot to me.
>>
>> As Tomasz mentioned, I already submitted a patch for this end of last
>> year but waited to see whether we fix p1789 by addressing the core
>> language defect or by changing the library specification instead.
>> Since cwg3135 is accepted now, I was going to update it as soon as
>> Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
>>
>> Since your patch seems to be in better shape than mine, I do not mind
>> abandoning the previous patch in favor of this one. @Tomasz: Which one
>> do you want to go ahead with? Does the release target change depending
>> on which one is used or is it going to be GCC 17 either way?
>>
>>
>>
>> On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
>> wrote:
>> >
>> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>> >
>> > P1789 enables accessing the sequence values through structured bindings.
>> > ```
>> > auto [...values] = std::make_index_sequence<10>{};
>> > // values is a pack of size 10, and elements 0, 1, 2, ..., 9
>> > ```
>> >
>> > Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
>> > Feature-test macro integer_sequence has been bumped to 202511L.
>> >
>> > libstdc++-v3/ChangeLog:
>> >
>> >         * include/bits/utility.h:
>> >         Implement structured bindings protocol for
>> std::integer_sequence.
>> >         * include/bits/version.def: Bump integer_sequence feature-test
>> macro.
>> >         * include/bits/version.h: Regenerate.
>> >         * testsuite/20_util/integer_sequence/structured_binding.cc: New
>> test.
>> >
>> > Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
>> > ---
>> > Fixed a missing `std::` on `size_t` , thanks Linaro.
>> > Extended the test.
>> >
>> > Only part that fails is the last block in `test_basic()`
>> > I am pretty sure that's because of:
>> > ```
>> > static constexpr int&& x = 1;
>> > static_assert(x == 1); // fails, would've worked if it was `const
>> int&&` or `const int&`
>> > ```
>> >
>> > https://godbolt.org/z/jM18sv5nh
>> >
>> >  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
>> >  libstdc++-v3/include/bits/version.def         |  5 ++
>> >  libstdc++-v3/include/bits/version.h           |  7 +-
>> >  .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
>> >  4 files changed, 111 insertions(+), 1 deletion(-)
>> >  create mode 100644
>> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>> >
>> > diff --git a/libstdc++-v3/include/bits/utility.h
>> b/libstdc++-v3/include/bits/utility.h
>> > index bd6b18d54dd..159884dd814 100644
>> > --- a/libstdc++-v3/include/bits/utility.h
>> > +++ b/libstdc++-v3/include/bits/utility.h
>> > @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> >        static constexpr size_t size() noexcept { return
>> sizeof...(_Idx); }
>> >      };
>> >
>> > +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
>> > +    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>
>> > +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>> > new file mode 100644
>> > index 00000000000..18cbcae53e5
>> > --- /dev/null
>> > +++
>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>> > @@ -0,0 +1,72 @@
>> > +// { dg-do compile { target c++26 } }
>> > +
>> > +#include <utility>
>> > +#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 );
>> > +
>> > +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 );
>> > +
>> > +using IS3 = std::integer_sequence<char>;
>> > +static_assert( std::tuple_size_v<IS3> == 0 );
>> > +
>> > +template<typename = void>
>> > +constexpr bool
>> > +test_basic()
>> > +{
>> > +  {
>> > +    auto [...elems] = std::make_index_sequence<10>{};
>> > +
>> > +    static_assert( sizeof...(elems) == 10 );
>> > +
>> > +    VERIFY( elems...[0] == 0 );
>> > +    VERIFY( elems...[3] == 3 );
>> > +    VERIFY( elems...[9] == 9 );
>> > +  }
>> > +
>> > +  {
>> > +    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 );
>> > +
>> > +    // these fail
>> > +    static_assert( elems...[0] == 2 );
>> > +    static_assert( elems...[1] == 4 );
>> > +    static_assert( elems...[2] == 8 );
>> > +    static_assert( elems...[3] == 16 );
>> > +  }
>> > +
>> > +  return true;
>> > +}
>> > +
>> > +static_assert( test_basic() );
>> > --
>> > 2.43.0
>> >
>>
>
  
Ivan Lazaric April 6, 2026, 4:22 p.m. UTC | #4
I don’t think CWG3135 is sufficient for the template for snippet

In following snippets assume type S is basically std::make_index_sequence<1>

template for version:

  { // version 1
    template for (constexpr auto index : S{}) { }
  }

Desugared through https://eel.is/c++draft/stmt.expand#5.3 :

  { // version 2
    constexpr auto&& [a] = S{};
  }

Desugared and trimmed, https://eel.is/c++draft/dcl.struct.bind#1 :

  { // version 3
    constexpr auto&& foo = S{};
  }

The last one is not affected by CWG3135, and fails to compile, because the
materialized temporary is not constexpr
https://godbolt.org/z/s18G5G657

On Mon, Apr 6, 2026 at 10:35 AM Daniel Krügler <daniel.kruegler@gmail.com>
wrote:

> Am So., 5. Apr. 2026 um 22:49 Uhr schrieb Ivan Lazaric <
> ivan.lazaric1@gmail.com>:
>
>> Clarifying, I implemented this for myself locally because it was useful
>> in some reflection related code. I searched through my email for
>> patches for this proposal, but it seems I haven’t been subscribed for long
>> enough to find yours. It seemed simple enough so I cleaned it up a bit
>> and posted.
>>
>> You seem to have better understanding of the general situation here,
>> so IMO it would be better for me to drop the work and let you continue.
>> If you wish to use any snippets from what I posted, feel free.
>>
>> I built locally with Jakubs patch, and the noted failures now pass.
>> Something that still fails though, which is explicitly mentioned in paper:
>>
>>     template for (constexpr auto index : std::make_index_sequence<20>{})
>>         static_assert( index + 1 ); // error, not a constant expression
>>
>> Desugared a bit (also fails):
>>
>>   {
>>     constexpr auto&& [a, b, c] = std::make_index_sequence<3>{};
>>
>>     static_assert( a == 0 );
>>     static_assert( b == 1 );
>>     static_assert( c == 2 );
>>   }
>>
>> Please verify this, as I could be missing some patches
>>
> This is CWG 3135 (
> https://cplusplus.github.io/CWG/issues/cwg_active.html#3135), which was
> accepted in Croydon, but presumably not yet  implemented in gcc.
>
> - Daniel
>
>
>>
>> On Sun, Apr 5, 2026 at 8:33 PM Matthias Wippich <mfwippich@gmail.com>
>> wrote:
>>
>>> >Will post an updated patch, but wouldn’t pre-CWG3135 wording also work,
>>> due to lifetime extension?
>>> Without the changes from cwg3135, this cannot interact well with p2686
>>> constexpr structured bindings. The non-constexpr case should be fine.
>>> That's very unfortunate since the intended use is with p2686 constexpr
>>> bindings + p1061 pack-introducing bindings - therefore, implementing
>>> p1789 without first addressing cwg3135 seems moot to me.
>>>
>>> As Tomasz mentioned, I already submitted a patch for this end of last
>>> year but waited to see whether we fix p1789 by addressing the core
>>> language defect or by changing the library specification instead.
>>> Since cwg3135 is accepted now, I was going to update it as soon as
>>> Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
>>>
>>> Since your patch seems to be in better shape than mine, I do not mind
>>> abandoning the previous patch in favor of this one. @Tomasz: Which one
>>> do you want to go ahead with? Does the release target change depending
>>> on which one is used or is it going to be GCC 17 either way?
>>>
>>>
>>>
>>> On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
>>> wrote:
>>> >
>>> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>>> >
>>> > P1789 enables accessing the sequence values through structured
>>> bindings.
>>> > ```
>>> > auto [...values] = std::make_index_sequence<10>{};
>>> > // values is a pack of size 10, and elements 0, 1, 2, ..., 9
>>> > ```
>>> >
>>> > Corresponding C++ draft commit:
>>> 3d71a838ed2a1689dd329f964ec4d58152487151
>>> > Feature-test macro integer_sequence has been bumped to 202511L.
>>> >
>>> > libstdc++-v3/ChangeLog:
>>> >
>>> >         * include/bits/utility.h:
>>> >         Implement structured bindings protocol for
>>> std::integer_sequence.
>>> >         * include/bits/version.def: Bump integer_sequence feature-test
>>> macro.
>>> >         * include/bits/version.h: Regenerate.
>>> >         * testsuite/20_util/integer_sequence/structured_binding.cc:
>>> New test.
>>> >
>>> > Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
>>> > ---
>>> > Fixed a missing `std::` on `size_t` , thanks Linaro.
>>> > Extended the test.
>>> >
>>> > Only part that fails is the last block in `test_basic()`
>>> > I am pretty sure that's because of:
>>> > ```
>>> > static constexpr int&& x = 1;
>>> > static_assert(x == 1); // fails, would've worked if it was `const
>>> int&&` or `const int&`
>>> > ```
>>> >
>>> > https://godbolt.org/z/jM18sv5nh
>>> >
>>> >  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
>>> >  libstdc++-v3/include/bits/version.def         |  5 ++
>>> >  libstdc++-v3/include/bits/version.h           |  7 +-
>>> >  .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
>>> >  4 files changed, 111 insertions(+), 1 deletion(-)
>>> >  create mode 100644
>>> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>> >
>>> > diff --git a/libstdc++-v3/include/bits/utility.h
>>> b/libstdc++-v3/include/bits/utility.h
>>> > index bd6b18d54dd..159884dd814 100644
>>> > --- a/libstdc++-v3/include/bits/utility.h
>>> > +++ b/libstdc++-v3/include/bits/utility.h
>>> > @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>> >        static constexpr size_t size() noexcept { return
>>> sizeof...(_Idx); }
>>> >      };
>>> >
>>> > +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
>>> > +    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>
>>> > +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
>>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>> > new file mode 100644
>>> > index 00000000000..18cbcae53e5
>>> > --- /dev/null
>>> > +++
>>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>> > @@ -0,0 +1,72 @@
>>> > +// { dg-do compile { target c++26 } }
>>> > +
>>> > +#include <utility>
>>> > +#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 );
>>> > +
>>> > +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 );
>>> > +
>>> > +using IS3 = std::integer_sequence<char>;
>>> > +static_assert( std::tuple_size_v<IS3> == 0 );
>>> > +
>>> > +template<typename = void>
>>> > +constexpr bool
>>> > +test_basic()
>>> > +{
>>> > +  {
>>> > +    auto [...elems] = std::make_index_sequence<10>{};
>>> > +
>>> > +    static_assert( sizeof...(elems) == 10 );
>>> > +
>>> > +    VERIFY( elems...[0] == 0 );
>>> > +    VERIFY( elems...[3] == 3 );
>>> > +    VERIFY( elems...[9] == 9 );
>>> > +  }
>>> > +
>>> > +  {
>>> > +    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 );
>>> > +
>>> > +    // these fail
>>> > +    static_assert( elems...[0] == 2 );
>>> > +    static_assert( elems...[1] == 4 );
>>> > +    static_assert( elems...[2] == 8 );
>>> > +    static_assert( elems...[3] == 16 );
>>> > +  }
>>> > +
>>> > +  return true;
>>> > +}
>>> > +
>>> > +static_assert( test_basic() );
>>> > --
>>> > 2.43.0
>>> >
>>>
>>
  
Tomasz Kaminski April 7, 2026, 6:13 a.m. UTC | #5
On Mon, Apr 6, 2026 at 6:22 PM Ivan Lazaric <ivan.lazaric1@gmail.com> wrote:

> I don’t think CWG3135 is sufficient for the template for snippet
>
> In following snippets assume type S is basically
> std::make_index_sequence<1>
>
> template for version:
>
>   { // version 1
>     template for (constexpr auto index : S{}) { }
>   }
>
> Desugared through https://eel.is/c++draft/stmt.expand#5.3 :
>
>   { // version 2
>     constexpr auto&& [a] = S{};
>   }
>
> Desugared and trimmed, https://eel.is/c++draft/dcl.struct.bind#1 :
>
>   { // version 3
>     constexpr auto&& foo = S{};
>   }
>
> The last one is not affected by CWG3135, and fails to compile, because the
> materialized temporary is not constexpr
> https://godbolt.org/z/s18G5G657
>
It seems like we need equivalent of
https://cplusplus.github.io/CWG/issues/cwg_active.html#3131 but for
structured binding case.


>
> On Mon, Apr 6, 2026 at 10:35 AM Daniel Krügler <daniel.kruegler@gmail.com>
> wrote:
>
>> Am So., 5. Apr. 2026 um 22:49 Uhr schrieb Ivan Lazaric <
>> ivan.lazaric1@gmail.com>:
>>
>>> Clarifying, I implemented this for myself locally because it was useful
>>> in some reflection related code. I searched through my email for
>>> patches for this proposal, but it seems I haven’t been subscribed for
>>> long
>>> enough to find yours. It seemed simple enough so I cleaned it up a bit
>>> and posted.
>>>
>>> You seem to have better understanding of the general situation here,
>>> so IMO it would be better for me to drop the work and let you continue.
>>> If you wish to use any snippets from what I posted, feel free.
>>>
>>> I built locally with Jakubs patch, and the noted failures now pass.
>>> Something that still fails though, which is explicitly mentioned in
>>> paper:
>>>
>>>     template for (constexpr auto index : std::make_index_sequence<20>{})
>>>         static_assert( index + 1 ); // error, not a constant expression
>>>
>>> Desugared a bit (also fails):
>>>
>>>   {
>>>     constexpr auto&& [a, b, c] = std::make_index_sequence<3>{};
>>>
>>>     static_assert( a == 0 );
>>>     static_assert( b == 1 );
>>>     static_assert( c == 2 );
>>>   }
>>>
>>> Please verify this, as I could be missing some patches
>>>
>> This is CWG 3135 (
>> https://cplusplus.github.io/CWG/issues/cwg_active.html#3135), which was
>> accepted in Croydon, but presumably not yet  implemented in gcc.
>>
>> - Daniel
>>
>>
>>>
>>> On Sun, Apr 5, 2026 at 8:33 PM Matthias Wippich <mfwippich@gmail.com>
>>> wrote:
>>>
>>>> >Will post an updated patch, but wouldn’t pre-CWG3135 wording also
>>>> work, due to lifetime extension?
>>>> Without the changes from cwg3135, this cannot interact well with p2686
>>>> constexpr structured bindings. The non-constexpr case should be fine.
>>>> That's very unfortunate since the intended use is with p2686 constexpr
>>>> bindings + p1061 pack-introducing bindings - therefore, implementing
>>>> p1789 without first addressing cwg3135 seems moot to me.
>>>>
>>>> As Tomasz mentioned, I already submitted a patch for this end of last
>>>> year but waited to see whether we fix p1789 by addressing the core
>>>> language defect or by changing the library specification instead.
>>>> Since cwg3135 is accepted now, I was going to update it as soon as
>>>> Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
>>>>
>>>> Since your patch seems to be in better shape than mine, I do not mind
>>>> abandoning the previous patch in favor of this one. @Tomasz: Which one
>>>> do you want to go ahead with? Does the release target change depending
>>>> on which one is used or is it going to be GCC 17 either way?
>>>>
>>>>
>>>>
>>>> On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
>>>> wrote:
>>>> >
>>>> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>>>> >
>>>> > P1789 enables accessing the sequence values through structured
>>>> bindings.
>>>> > ```
>>>> > auto [...values] = std::make_index_sequence<10>{};
>>>> > // values is a pack of size 10, and elements 0, 1, 2, ..., 9
>>>> > ```
>>>> >
>>>> > Corresponding C++ draft commit:
>>>> 3d71a838ed2a1689dd329f964ec4d58152487151
>>>> > Feature-test macro integer_sequence has been bumped to 202511L.
>>>> >
>>>> > libstdc++-v3/ChangeLog:
>>>> >
>>>> >         * include/bits/utility.h:
>>>> >         Implement structured bindings protocol for
>>>> std::integer_sequence.
>>>> >         * include/bits/version.def: Bump integer_sequence
>>>> feature-test macro.
>>>> >         * include/bits/version.h: Regenerate.
>>>> >         * testsuite/20_util/integer_sequence/structured_binding.cc:
>>>> New test.
>>>> >
>>>> > Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
>>>> > ---
>>>> > Fixed a missing `std::` on `size_t` , thanks Linaro.
>>>> > Extended the test.
>>>> >
>>>> > Only part that fails is the last block in `test_basic()`
>>>> > I am pretty sure that's because of:
>>>> > ```
>>>> > static constexpr int&& x = 1;
>>>> > static_assert(x == 1); // fails, would've worked if it was `const
>>>> int&&` or `const int&`
>>>> > ```
>>>> >
>>>> > https://godbolt.org/z/jM18sv5nh
>>>> >
>>>> >  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
>>>> >  libstdc++-v3/include/bits/version.def         |  5 ++
>>>> >  libstdc++-v3/include/bits/version.h           |  7 +-
>>>> >  .../integer_sequence/structured_binding.cc    | 72
>>>> +++++++++++++++++++
>>>> >  4 files changed, 111 insertions(+), 1 deletion(-)
>>>> >  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>>> >
>>>> > diff --git a/libstdc++-v3/include/bits/utility.h
>>>> b/libstdc++-v3/include/bits/utility.h
>>>> > index bd6b18d54dd..159884dd814 100644
>>>> > --- a/libstdc++-v3/include/bits/utility.h
>>>> > +++ b/libstdc++-v3/include/bits/utility.h
>>>> > @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>> >        static constexpr size_t size() noexcept { return
>>>> sizeof...(_Idx); }
>>>> >      };
>>>> >
>>>> > +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
>>>> > +    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>
>>>> > +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
>>>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>>> > new file mode 100644
>>>> > index 00000000000..18cbcae53e5
>>>> > --- /dev/null
>>>> > +++
>>>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>>> > @@ -0,0 +1,72 @@
>>>> > +// { dg-do compile { target c++26 } }
>>>> > +
>>>> > +#include <utility>
>>>> > +#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 );
>>>> > +
>>>> > +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 );
>>>> > +
>>>> > +using IS3 = std::integer_sequence<char>;
>>>> > +static_assert( std::tuple_size_v<IS3> == 0 );
>>>> > +
>>>> > +template<typename = void>
>>>> > +constexpr bool
>>>> > +test_basic()
>>>> > +{
>>>> > +  {
>>>> > +    auto [...elems] = std::make_index_sequence<10>{};
>>>> > +
>>>> > +    static_assert( sizeof...(elems) == 10 );
>>>> > +
>>>> > +    VERIFY( elems...[0] == 0 );
>>>> > +    VERIFY( elems...[3] == 3 );
>>>> > +    VERIFY( elems...[9] == 9 );
>>>> > +  }
>>>> > +
>>>> > +  {
>>>> > +    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 );
>>>> > +
>>>> > +    // these fail
>>>> > +    static_assert( elems...[0] == 2 );
>>>> > +    static_assert( elems...[1] == 4 );
>>>> > +    static_assert( elems...[2] == 8 );
>>>> > +    static_assert( elems...[3] == 16 );
>>>> > +  }
>>>> > +
>>>> > +  return true;
>>>> > +}
>>>> > +
>>>> > +static_assert( test_basic() );
>>>> > --
>>>> > 2.43.0
>>>> >
>>>>
>>>
  
Tim Song April 8, 2026, 2:21 a.m. UTC | #6
Is this not the unimplemented local constexpr reference part of P2686R4?

On Tue, Apr 7, 2026 at 1:13 AM Tomasz Kaminski <tkaminsk@redhat.com> wrote:

>
>
> On Mon, Apr 6, 2026 at 6:22 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
> wrote:
>
>> I don’t think CWG3135 is sufficient for the template for snippet
>>
>> In following snippets assume type S is basically
>> std::make_index_sequence<1>
>>
>> template for version:
>>
>>   { // version 1
>>     template for (constexpr auto index : S{}) { }
>>   }
>>
>> Desugared through https://eel.is/c++draft/stmt.expand#5.3 :
>>
>>   { // version 2
>>     constexpr auto&& [a] = S{};
>>   }
>>
>> Desugared and trimmed, https://eel.is/c++draft/dcl.struct.bind#1 :
>>
>>   { // version 3
>>     constexpr auto&& foo = S{};
>>   }
>>
>> The last one is not affected by CWG3135, and fails to compile, because
>> the materialized temporary is not constexpr
>> https://godbolt.org/z/s18G5G657
>>
> It seems like we need equivalent of
> https://cplusplus.github.io/CWG/issues/cwg_active.html#3131 but for
> structured binding case.
>
>
>>
>> On Mon, Apr 6, 2026 at 10:35 AM Daniel Krügler <daniel.kruegler@gmail.com>
>> wrote:
>>
>>> Am So., 5. Apr. 2026 um 22:49 Uhr schrieb Ivan Lazaric <
>>> ivan.lazaric1@gmail.com>:
>>>
>>>> Clarifying, I implemented this for myself locally because it was useful
>>>> in some reflection related code. I searched through my email for
>>>> patches for this proposal, but it seems I haven’t been subscribed for
>>>> long
>>>> enough to find yours. It seemed simple enough so I cleaned it up a bit
>>>> and posted.
>>>>
>>>> You seem to have better understanding of the general situation here,
>>>> so IMO it would be better for me to drop the work and let you continue.
>>>> If you wish to use any snippets from what I posted, feel free.
>>>>
>>>> I built locally with Jakubs patch, and the noted failures now pass.
>>>> Something that still fails though, which is explicitly mentioned in
>>>> paper:
>>>>
>>>>     template for (constexpr auto index : std::make_index_sequence<20>{})
>>>>         static_assert( index + 1 ); // error, not a constant expression
>>>>
>>>> Desugared a bit (also fails):
>>>>
>>>>   {
>>>>     constexpr auto&& [a, b, c] = std::make_index_sequence<3>{};
>>>>
>>>>     static_assert( a == 0 );
>>>>     static_assert( b == 1 );
>>>>     static_assert( c == 2 );
>>>>   }
>>>>
>>>> Please verify this, as I could be missing some patches
>>>>
>>> This is CWG 3135 (
>>> https://cplusplus.github.io/CWG/issues/cwg_active.html#3135), which was
>>> accepted in Croydon, but presumably not yet  implemented in gcc.
>>>
>>> - Daniel
>>>
>>>
>>>>
>>>> On Sun, Apr 5, 2026 at 8:33 PM Matthias Wippich <mfwippich@gmail.com>
>>>> wrote:
>>>>
>>>>> >Will post an updated patch, but wouldn’t pre-CWG3135 wording also
>>>>> work, due to lifetime extension?
>>>>> Without the changes from cwg3135, this cannot interact well with p2686
>>>>> constexpr structured bindings. The non-constexpr case should be fine.
>>>>> That's very unfortunate since the intended use is with p2686 constexpr
>>>>> bindings + p1061 pack-introducing bindings - therefore, implementing
>>>>> p1789 without first addressing cwg3135 seems moot to me.
>>>>>
>>>>> As Tomasz mentioned, I already submitted a patch for this end of last
>>>>> year but waited to see whether we fix p1789 by addressing the core
>>>>> language defect or by changing the library specification instead.
>>>>> Since cwg3135 is accepted now, I was going to update it as soon as
>>>>> Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
>>>>>
>>>>> Since your patch seems to be in better shape than mine, I do not mind
>>>>> abandoning the previous patch in favor of this one. @Tomasz: Which one
>>>>> do you want to go ahead with? Does the release target change depending
>>>>> on which one is used or is it going to be GCC 17 either way?
>>>>>
>>>>>
>>>>>
>>>>> On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
>>>>> wrote:
>>>>> >
>>>>> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>>>>> >
>>>>> > P1789 enables accessing the sequence values through structured
>>>>> bindings.
>>>>> > ```
>>>>> > auto [...values] = std::make_index_sequence<10>{};
>>>>> > // values is a pack of size 10, and elements 0, 1, 2, ..., 9
>>>>> > ```
>>>>> >
>>>>> > Corresponding C++ draft commit:
>>>>> 3d71a838ed2a1689dd329f964ec4d58152487151
>>>>> > Feature-test macro integer_sequence has been bumped to 202511L.
>>>>> >
>>>>> > libstdc++-v3/ChangeLog:
>>>>> >
>>>>> >         * include/bits/utility.h:
>>>>> >         Implement structured bindings protocol for
>>>>> std::integer_sequence.
>>>>> >         * include/bits/version.def: Bump integer_sequence
>>>>> feature-test macro.
>>>>> >         * include/bits/version.h: Regenerate.
>>>>> >         * testsuite/20_util/integer_sequence/structured_binding.cc:
>>>>> New test.
>>>>> >
>>>>> > Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
>>>>> > ---
>>>>> > Fixed a missing `std::` on `size_t` , thanks Linaro.
>>>>> > Extended the test.
>>>>> >
>>>>> > Only part that fails is the last block in `test_basic()`
>>>>> > I am pretty sure that's because of:
>>>>> > ```
>>>>> > static constexpr int&& x = 1;
>>>>> > static_assert(x == 1); // fails, would've worked if it was `const
>>>>> int&&` or `const int&`
>>>>> > ```
>>>>> >
>>>>> > https://godbolt.org/z/jM18sv5nh
>>>>> >
>>>>> >  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
>>>>> >  libstdc++-v3/include/bits/version.def         |  5 ++
>>>>> >  libstdc++-v3/include/bits/version.h           |  7 +-
>>>>> >  .../integer_sequence/structured_binding.cc    | 72
>>>>> +++++++++++++++++++
>>>>> >  4 files changed, 111 insertions(+), 1 deletion(-)
>>>>> >  create mode 100644
>>>>> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>>>> >
>>>>> > diff --git a/libstdc++-v3/include/bits/utility.h
>>>>> b/libstdc++-v3/include/bits/utility.h
>>>>> > index bd6b18d54dd..159884dd814 100644
>>>>> > --- a/libstdc++-v3/include/bits/utility.h
>>>>> > +++ b/libstdc++-v3/include/bits/utility.h
>>>>> > @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>> >        static constexpr size_t size() noexcept { return
>>>>> sizeof...(_Idx); }
>>>>> >      };
>>>>> >
>>>>> > +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
>>>>> > +    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>
>>>>> > +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
>>>>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>>>> > new file mode 100644
>>>>> > index 00000000000..18cbcae53e5
>>>>> > --- /dev/null
>>>>> > +++
>>>>> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>>>>> > @@ -0,0 +1,72 @@
>>>>> > +// { dg-do compile { target c++26 } }
>>>>> > +
>>>>> > +#include <utility>
>>>>> > +#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 );
>>>>> > +
>>>>> > +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 );
>>>>> > +
>>>>> > +using IS3 = std::integer_sequence<char>;
>>>>> > +static_assert( std::tuple_size_v<IS3> == 0 );
>>>>> > +
>>>>> > +template<typename = void>
>>>>> > +constexpr bool
>>>>> > +test_basic()
>>>>> > +{
>>>>> > +  {
>>>>> > +    auto [...elems] = std::make_index_sequence<10>{};
>>>>> > +
>>>>> > +    static_assert( sizeof...(elems) == 10 );
>>>>> > +
>>>>> > +    VERIFY( elems...[0] == 0 );
>>>>> > +    VERIFY( elems...[3] == 3 );
>>>>> > +    VERIFY( elems...[9] == 9 );
>>>>> > +  }
>>>>> > +
>>>>> > +  {
>>>>> > +    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 );
>>>>> > +
>>>>> > +    // these fail
>>>>> > +    static_assert( elems...[0] == 2 );
>>>>> > +    static_assert( elems...[1] == 4 );
>>>>> > +    static_assert( elems...[2] == 8 );
>>>>> > +    static_assert( elems...[3] == 16 );
>>>>> > +  }
>>>>> > +
>>>>> > +  return true;
>>>>> > +}
>>>>> > +
>>>>> > +static_assert( test_basic() );
>>>>> > --
>>>>> > 2.43.0
>>>>> >
>>>>>
>>>>
  
Jakub Jelinek April 8, 2026, 5:32 a.m. UTC | #7
On Tue, Apr 07, 2026 at 09:21:25PM -0500, Tim Song wrote:
> Is this not the unimplemented local constexpr reference part of P2686R4?

If it is accepted with static constexpr auto&& foo = S{}; instead,
then likely yes.

	Jakub
  
Jonathan Wakely April 8, 2026, 10:08 a.m. UTC | #8
On Sun, 5 Apr 2026, 19:33 Matthias Wippich, <mfwippich@gmail.com> wrote:

> >Will post an updated patch, but wouldn’t pre-CWG3135 wording also work,
> due to lifetime extension?
> Without the changes from cwg3135, this cannot interact well with p2686
> constexpr structured bindings. The non-constexpr case should be fine.
> That's very unfortunate since the intended use is with p2686 constexpr
> bindings + p1061 pack-introducing bindings - therefore, implementing
> p1789 without first addressing cwg3135 seems moot to me.
>
> As Tomasz mentioned, I already submitted a patch for this end of last
> year but waited to see whether we fix p1789 by addressing the core
> language defect or by changing the library specification instead.
> Since cwg3135 is accepted now, I was going to update it as soon as
> Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
>
> Since your patch seems to be in better shape than mine, I do not mind
> abandoning the previous patch in favor of this one. @Tomasz: Which one
> do you want to go ahead with? Does the release target change depending
> on which one is used or is it going to be GCC 17 either way?
>

Since this only adds some small additions to C++26 mode I think this would
still be ok for GCC 16 if we're quick.



>
>
> On Sun, Apr 5, 2026 at 1:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com>
> wrote:
> >
> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
> >
> > P1789 enables accessing the sequence values through structured bindings.
> > ```
> > auto [...values] = std::make_index_sequence<10>{};
> > // values is a pack of size 10, and elements 0, 1, 2, ..., 9
> > ```
> >
> > Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
> > Feature-test macro integer_sequence has been bumped to 202511L.
> >
> > libstdc++-v3/ChangeLog:
> >
> >         * include/bits/utility.h:
> >         Implement structured bindings protocol for std::integer_sequence.
> >         * include/bits/version.def: Bump integer_sequence feature-test
> macro.
> >         * include/bits/version.h: Regenerate.
> >         * testsuite/20_util/integer_sequence/structured_binding.cc: New
> test.
> >
> > Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> > ---
> > Fixed a missing `std::` on `size_t` , thanks Linaro.
> > Extended the test.
> >
> > Only part that fails is the last block in `test_basic()`
> > I am pretty sure that's because of:
> > ```
> > static constexpr int&& x = 1;
> > static_assert(x == 1); // fails, would've worked if it was `const int&&`
> or `const int&`
> > ```
> >
> > https://godbolt.org/z/jM18sv5nh
> >
> >  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
> >  libstdc++-v3/include/bits/version.def         |  5 ++
> >  libstdc++-v3/include/bits/version.h           |  7 +-
> >  .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
> >  4 files changed, 111 insertions(+), 1 deletion(-)
> >  create mode 100644
> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> >
> > diff --git a/libstdc++-v3/include/bits/utility.h
> b/libstdc++-v3/include/bits/utility.h
> > index bd6b18d54dd..159884dd814 100644
> > --- a/libstdc++-v3/include/bits/utility.h
> > +++ b/libstdc++-v3/include/bits/utility.h
> > @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >        static constexpr size_t size() noexcept { return sizeof...(_Idx);
> }
> >      };
> >
> > +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
> > +    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>
> > +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> > new file mode 100644
> > index 00000000000..18cbcae53e5
> > --- /dev/null
> > +++
> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> > @@ -0,0 +1,72 @@
> > +// { dg-do compile { target c++26 } }
> > +
> > +#include <utility>
> > +#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 );
> > +
> > +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 );
> > +
> > +using IS3 = std::integer_sequence<char>;
> > +static_assert( std::tuple_size_v<IS3> == 0 );
> > +
> > +template<typename = void>
> > +constexpr bool
> > +test_basic()
> > +{
> > +  {
> > +    auto [...elems] = std::make_index_sequence<10>{};
> > +
> > +    static_assert( sizeof...(elems) == 10 );
> > +
> > +    VERIFY( elems...[0] == 0 );
> > +    VERIFY( elems...[3] == 3 );
> > +    VERIFY( elems...[9] == 9 );
> > +  }
> > +
> > +  {
> > +    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 );
> > +
> > +    // these fail
> > +    static_assert( elems...[0] == 2 );
> > +    static_assert( elems...[1] == 4 );
> > +    static_assert( elems...[2] == 8 );
> > +    static_assert( elems...[3] == 16 );
> > +  }
> > +
> > +  return true;
> > +}
> > +
> > +static_assert( test_basic() );
> > --
> > 2.43.0
> >
>
  
Jakub Jelinek April 8, 2026, 10:11 a.m. UTC | #9
On Wed, Apr 08, 2026 at 11:08:30AM +0100, Jonathan Wakely wrote:
> On Sun, 5 Apr 2026, 19:33 Matthias Wippich, <mfwippich@gmail.com> wrote:
> 
> > >Will post an updated patch, but wouldn’t pre-CWG3135 wording also work,
> > due to lifetime extension?
> > Without the changes from cwg3135, this cannot interact well with p2686
> > constexpr structured bindings. The non-constexpr case should be fine.
> > That's very unfortunate since the intended use is with p2686 constexpr
> > bindings + p1061 pack-introducing bindings - therefore, implementing
> > p1789 without first addressing cwg3135 seems moot to me.
> >
> > As Tomasz mentioned, I already submitted a patch for this end of last
> > year but waited to see whether we fix p1789 by addressing the core
> > language defect or by changing the library specification instead.
> > Since cwg3135 is accepted now, I was going to update it as soon as
> > Jakub's patch for cwg3135 from 2 days ago is merged (so tests pass).
> >
> > Since your patch seems to be in better shape than mine, I do not mind
> > abandoning the previous patch in favor of this one. @Tomasz: Which one
> > do you want to go ahead with? Does the release target change depending
> > on which one is used or is it going to be GCC 17 either way?
> >
> 
> Since this only adds some small additions to C++26 mode I think this would
> still be ok for GCC 16 if we're quick.

Note, the cwg3135 change is already in - r16-8520

	Jakub
  
Tomasz Kaminski April 8, 2026, 11:52 a.m. UTC | #10
Matthias, Ivan
Could any of you prepare revision with changes listed below?

On Sun, Apr 5, 2026 at 2:38 PM Ivan Lazaric <ivan.lazaric1@gmail.com> wrote:

> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1789r3.pdf
>
> P1789 enables accessing the sequence values through structured bindings.
> ```
> auto [...values] = std::make_index_sequence<10>{};
> // values is a pack of size 10, and elements 0, 1, 2, ..., 9
> ```
>
> Corresponding C++ draft commit: 3d71a838ed2a1689dd329f964ec4d58152487151
> Feature-test macro integer_sequence has been bumped to 202511L.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/utility.h:
>         Implement structured bindings protocol for std::integer_sequence.
>         * include/bits/version.def: Bump integer_sequence feature-test
> macro.
>         * include/bits/version.h: Regenerate.
>         * testsuite/20_util/integer_sequence/structured_binding.cc: New
> test.
>
> Signed-off-by: Ivan Lazaric <ivan.lazaric1@gmail.com>
> ---
> Fixed a missing `std::` on `size_t` , thanks Linaro.
> Extended the test.
>
> Only part that fails is the last block in `test_basic()`
> I am pretty sure that's because of:
> ```
> static constexpr int&& x = 1;
> static_assert(x == 1); // fails, would've worked if it was `const int&&`
> or `const int&`
> ```
>
> https://godbolt.org/z/jM18sv5nh
>
>  libstdc++-v3/include/bits/utility.h           | 28 ++++++++
>  libstdc++-v3/include/bits/version.def         |  5 ++
>  libstdc++-v3/include/bits/version.h           |  7 +-
>  .../integer_sequence/structured_binding.cc    | 72 +++++++++++++++++++
>  4 files changed, 111 insertions(+), 1 deletion(-)
>  create mode 100644
> libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
>
Rename the file to tuple_access.

>
> diff --git a/libstdc++-v3/include/bits/utility.h
> b/libstdc++-v3/include/bits/utility.h
> index bd6b18d54dd..159884dd814 100644
> --- a/libstdc++-v3/include/bits/utility.h
> +++ b/libstdc++-v3/include/bits/utility.h
> @@ -150,6 +150,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        static constexpr size_t size() noexcept { return sizeof...(_Idx); }
>      };
>
> +#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
> +    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>
> +      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc
> b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> new file mode 100644
> index 00000000000..18cbcae53e5
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
> @@ -0,0 +1,72 @@
> +// { dg-do compile { target c++26 } }
> +
> +#include <utility>
> +#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 );
> +
> +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 );
> +
> +using IS3 = std::integer_sequence<char>;
> +static_assert( std::tuple_size_v<IS3> == 0 );
>
Could you add an static assert checking that pair<int, int> and tuple<int,
int,int>
are not cosntructible from integer_sequence<int of 2 and tree elements?
Because
it is not tuple-like.


> +
> +template<typename = void>
> +constexpr bool
> +test_basic()
> +{
> +  {
> +    auto [...elems] = std::make_index_sequence<10>{};
> +
> +    static_assert( sizeof...(elems) == 10 );
> +
> +    VERIFY( elems...[0] == 0 );
> +    VERIFY( elems...[3] == 3 );
> +    VERIFY( elems...[9] == 9 );
> +  }
> +
> +  {
> +    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>{};
>
Could you also add the version with non-static constexpr local variable?
And add additional test for template-for.
For cases that do not compile, please comment them out and add link
to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117784?

> +
> +    static_assert( sizeof...(elems) == 4 );
> +
> +    // these fail
> +    static_assert( elems...[0] == 2 );
> +    static_assert( elems...[1] == 4 );
> +    static_assert( elems...[2] == 8 );
> +    static_assert( elems...[3] == 16 );
> +  }
> +
> +  return true;
> +}
> +
> +static_assert( test_basic() );
>



> --
> 2.43.0
>
>
  

Patch

diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h
index bd6b18d54dd..159884dd814 100644
--- a/libstdc++-v3/include/bits/utility.h
+++ b/libstdc++-v3/include/bits/utility.h
@@ -150,6 +150,34 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static constexpr size_t size() noexcept { return sizeof...(_Idx); }
     };
 
+#if __glibcxx_integer_sequence >= 202511L // C++ >= 26
+    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>
+      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 1265f01757c..81ec5723844 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 00f352089f7..cde4fa839db 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/structured_binding.cc b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
new file mode 100644
index 00000000000..18cbcae53e5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/integer_sequence/structured_binding.cc
@@ -0,0 +1,72 @@ 
+// { dg-do compile { target c++26 } }
+
+#include <utility>
+#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 );
+
+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 );
+
+using IS3 = std::integer_sequence<char>;
+static_assert( std::tuple_size_v<IS3> == 0 );
+
+template<typename = void>
+constexpr bool
+test_basic()
+{
+  {
+    auto [...elems] = std::make_index_sequence<10>{};
+
+    static_assert( sizeof...(elems) == 10 );
+
+    VERIFY( elems...[0] == 0 );
+    VERIFY( elems...[3] == 3 );
+    VERIFY( elems...[9] == 9 );
+  }
+
+  {
+    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 );
+
+    // these fail
+    static_assert( elems...[0] == 2 );
+    static_assert( elems...[1] == 4 );
+    static_assert( elems...[2] == 8 );
+    static_assert( elems...[3] == 16 );
+  }
+
+  return true;
+}
+
+static_assert( test_basic() );