Skip to content
Open
2 changes: 2 additions & 0 deletions libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_inplace_vector`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_integer_sequence`` ``202511L``
---------------------------------------------------------- -----------------
``__cpp_lib_is_sufficiently_aligned`` ``202411L``
---------------------------------------------------------- -----------------
``__cpp_lib_is_virtual_base_of`` ``202406L``
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/22.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Implemented Papers
- P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
- P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167268>`__)

Improvements and New Features
-----------------------------
Expand Down
2 changes: 2 additions & 0 deletions libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,5 @@
"`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","","`#148182 <https://github.com/llvm/llvm-project/issues/148182>`__",""
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","","`#148183 <https://github.com/llvm/llvm-project/issues/148183>`__",""
"","","","","","",""
"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements","2025-11 (Kona)","|Complete|","22","`#167268 <https://github.com/llvm/llvm-project/issues/167268>`__",""
"","","","","","",""
26 changes: 26 additions & 0 deletions libcxx/include/__utility/integer_sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include <__config>
#include <__cstddef/size_t.h>
#include <__tuple/tuple_element.h>
#include <__tuple/tuple_size.h>
#include <__type_traits/is_integral.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand Down Expand Up @@ -67,6 +69,30 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __for_each_index_sequence(index_sequence<_I
}
# endif // _LIBCPP_STD_VER >= 20

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

Choose a reason for hiding this comment

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

Nit:

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

template <class _Tp, _Tp... _Indices>
struct tuple_size<integer_sequence<_Tp, _Indices...>> : integral_constant<size_t, sizeof...(_Indices)> {};

template <size_t _Ip, class _Tp, _Tp... _Indices>
struct tuple_element<_Ip, integer_sequence<_Tp, _Indices...>> {
static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::tuple_element<> (std::integer_sequence)");
using type _LIBCPP_NODEBUG = _Tp;
};

template <size_t _Ip, class _Tp, _Tp... _Indices>
struct tuple_element<_Ip, const integer_sequence<_Tp, _Indices...>> {
static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::tuple_element<> (const std::integer_sequence)");
using type _LIBCPP_NODEBUG = _Tp;
};

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

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

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

Suggested change
_LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept {
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept {

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

static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::get<> (std::integer_sequence)");
return _Indices...[_Ip];
}
# endif // _LIBCPP_STD_VER >= 26

# endif // _LIBCPP_STD_VER >= 14

_LIBCPP_END_NAMESPACE_STD
Expand Down
12 changes: 12 additions & 0 deletions libcxx/include/utility
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,18 @@ template<size_t N>
template<class... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
template<class T, T... Values> // C++26
struct tuple_size<integer_sequence<T, Values...>>;
template<size_t I, class T, T... Values> // C++26
struct tuple_element<I, integer_sequence<T, Values...>>;
template<size_t I, class T, T... Values> // C++26
struct tuple_element<I, const integer_sequence<T, Values...>>;
template<size_t I, class T, T... Values> // C++26
constexpr T get(integer_sequence<T, Values...>) noexcept;
template<class T, class U=T>
constexpr T exchange(T& obj, U&& new_value) // constexpr in C++17, noexcept in C++23
noexcept(is_nothrow_move_constructible<T>::value && is_nothrow_assignable<T&, U>::value);
Expand Down
5 changes: 4 additions & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ __cpp_lib_incomplete_container_elements 201505L <forward_list> <
__cpp_lib_inplace_vector 202406L <inplace_vector>
__cpp_lib_int_pow2 202002L <bit>
__cpp_lib_integer_comparison_functions 202002L <utility>
__cpp_lib_integer_sequence 201304L <utility>
__cpp_lib_integer_sequence 202511L <utility>
201304L // C++14
__cpp_lib_integral_constant_callable 201304L <type_traits>
__cpp_lib_interpolate 201902L <cmath> <numeric>
__cpp_lib_invoke 201411L <functional>
Expand Down Expand Up @@ -582,6 +583,8 @@ __cpp_lib_void_t 201411L <type_traits>
// # define __cpp_lib_generate_random 202403L
// # define __cpp_lib_hazard_pointer 202306L
// # define __cpp_lib_inplace_vector 202406L
# undef __cpp_lib_integer_sequence
# define __cpp_lib_integer_sequence 202511L
# define __cpp_lib_is_sufficiently_aligned 202411L
# if __has_builtin(__builtin_is_virtual_base_of)
# define __cpp_lib_is_virtual_base_of 202406L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@
# ifndef __cpp_lib_integer_sequence
# error "__cpp_lib_integer_sequence should be defined in c++26"
# endif
# if __cpp_lib_integer_sequence != 201304L
# error "__cpp_lib_integer_sequence should have the value 201304L in c++26"
# if __cpp_lib_integer_sequence != 202511L
# error "__cpp_lib_integer_sequence should have the value 202511L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7156,8 +7156,8 @@
# ifndef __cpp_lib_integer_sequence
# error "__cpp_lib_integer_sequence should be defined in c++26"
# endif
# if __cpp_lib_integer_sequence != 201304L
# error "__cpp_lib_integer_sequence should have the value 201304L in c++26"
# if __cpp_lib_integer_sequence != 202511L
# error "__cpp_lib_integer_sequence should have the value 202511L in c++26"
# endif

# ifndef __cpp_lib_integral_constant_callable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// REQUIRES: std-at-least-c++26

// <utility>

// template<class T, T... Values>
// struct tuple_size<integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// struct tuple_element<I, integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// struct tuple_element<I, const integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// constexpr T get(integer_sequence<T, Values...>) noexcept;

#include <cassert>
#include <tuple>
#include <type_traits>
#include <utility>

constexpr void test() {
// std::tuple_size_v
using empty = std::integer_sequence<int>;
static_assert(std::tuple_size_v<empty> == 0);
static_assert(std::tuple_size_v<const empty> == 0);

using size4 = std::integer_sequence<int, 9, 8, 7, 2>;
static_assert(std::tuple_size_v<size4> == 4);
static_assert(std::tuple_size_v<const size4> == 4);

// std::tuple_element_t
static_assert(std::is_same_v<std::tuple_element_t<0, size4>, int>);
static_assert(std::is_same_v<std::tuple_element_t<1, size4>, int>);
static_assert(std::is_same_v<std::tuple_element_t<2, size4>, int>);
static_assert(std::is_same_v<std::tuple_element_t<3, size4>, int>);

static_assert(std::is_same_v<std::tuple_element_t<0, const size4>, int>);
static_assert(std::is_same_v<std::tuple_element_t<1, const size4>, int>);
static_assert(std::is_same_v<std::tuple_element_t<2, const size4>, int>);
static_assert(std::is_same_v<std::tuple_element_t<3, const size4>, int>);

// std::get
constexpr static size4 seq4{};
static_assert(get<0>(seq4) == 9);
static_assert(get<1>(seq4) == 8);
static_assert(get<2>(seq4) == 7);
static_assert(get<3>(seq4) == 2);
}
34 changes: 34 additions & 0 deletions libcxx/test/std/utilities/intseq/intseq.binding/binding.verify.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// REQUIRES: std-at-least-c++26

// <utility>

// template<size_t I, class T, T... Values>
// struct tuple_element<I, integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// struct tuple_element<I, const integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// constexpr T get(integer_sequence<T, Values...>) noexcept;

// Expect failures for tuple_element and get with empty integer_sequence

#include <utility>

void f() {
// expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (std::integer_sequence)}}
using test1 = std::tuple_element_t<0, std::integer_sequence<int>>;
// expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::tuple_element<> (const std::integer_sequence)}}
using test2 = std::tuple_element_t<0, const std::integer_sequence<int>>;

auto empty = std::integer_sequence<int>();
// expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::get<> (std::integer_sequence)}}
// expected-error-re@*:* {{invalid index 0 for pack {{.*}} of size 0}}
(void)std::get<0>(empty);
}
5 changes: 4 additions & 1 deletion libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,10 @@ def add_version_header(tc):
},
{
"name": "__cpp_lib_integer_sequence",
"values": {"c++14": 201304},
"values": {
"c++14": 201304,
"c++26": 202511, # P1789R3 Library Support for Expansion Statements
},
"headers": ["utility"],
},
{
Expand Down
Loading