Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
// [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>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept {
static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::get<> (std::integer_sequence)");
return _Indices...[_Ip];
}
# 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,23 @@
//===----------------------------------------------------------------------===//
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't a standard test, so it should go in test/libcxx.

//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

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

// <utility>

// template<size_t I, class T, T... Values>
// [[nodiscard]] constexpr T get(integer_sequence<T, Values...>) noexcept;

// check that get is marked [[nodiscard]]

#include <utility>

void f() {
std::index_sequence<1> seq;
get<0>(seq); // expected-warning {{ignoring return value of function}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// 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;
Comment on lines +13 to +18
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

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

Suggested change
// template<size_t I, class T, T... Values>
// struct tuple_element<I, integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// struct tuple_element<I, const integer_sequence<T, Values...>>;
// template<size_t I, class T, T... Values>
// constexpr T get(integer_sequence<T, Values...>) noexcept;
// <describe what's being tested>

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


#include <cassert>
#include <utility>

constexpr bool test_structured_bindings() {
auto [elt0, elt1, elt2, elt3] = std::make_index_sequence<4>();

assert(elt0 == 0);
assert(elt1 == 1);
assert(elt2 == 2);
assert(elt3 == 3);

#if __cpp_structured_bindings >= 202411L
Copy link
Contributor

@Zingam Zingam Nov 11, 2025

Choose a reason for hiding this comment

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

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

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

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

[]<typename...> {
auto [... empty] = std::make_index_sequence<0>();
static_assert(sizeof...(empty) == 0);

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

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

return true;
}

int main(int, char**) {
test_structured_bindings();
static_assert(test_structured_bindings());
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// 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 <concepts>
#include <tuple>
#include <type_traits>
#include <utility>

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;
constexpr std::same_as<int> decltype(auto) elt0 = get<0>(seq4);
static_assert(elt0 == 9);
static_assert(get<1>(seq4) == 8);
static_assert(get<2>(seq4) == 7);
static_assert(get<3>(seq4) == 2);

static_assert(noexcept(get<0>(seq4)));
}
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>>;

std::integer_sequence<int> empty;
// expected-error-re@*:* {{static assertion failed{{.*}}Index out of bounds in std::get<> (std::integer_sequence)}}
// expected-error-re@*:* {{invalid index 0 for pack {{.*}} of size 0}}
(void)std::get<0>(empty);
}
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