[libc++] Implement P1789R3: Library Support for Expansion Statements (#167184)
[P1789R3](https://isocpp.org/files/papers/P1789R3.pdf) was accepted for C++26 through LWG motion 14 at the 2025 Kona meeting. This patch implements it, along with tests and documentation changes. Closes #167268 --------- Co-authored-by: Tsche <che@pydong.org>
This commit is contained in:
parent
f4bd619e85
commit
617b446176
@ -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``
|
||||
|
||||
@ -53,6 +53,7 @@ Implemented Papers
|
||||
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
|
||||
- P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
|
||||
- P3836R2: Make ``optional<T&>`` trivially copyable (`Github <https://llvm.org/PR171275>`__)
|
||||
- P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167184>`__)
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
||||
@ -169,7 +169,7 @@
|
||||
"`P3819R0 <https://wg21.link/P3819R0>`__","Remove ``evaluation_exception()`` from contract-violation handling for C++26","2025-11 (Kona)","","","`#171280 <https://github.com/llvm/llvm-project/issues/171280>`__",""
|
||||
"`P3612R1 <https://wg21.link/P3612R1>`__","Harmonize proxy-reference operations (LWG 3638 and 4187)","2025-11 (Kona)","","","`#171281 <https://github.com/llvm/llvm-project/issues/171281>`__",""
|
||||
"`P3778R0 <https://wg21.link/P3778R0>`__","Fix for ``type_order`` template definition","2025-11 (Kona)","","","`#171284 <https://github.com/llvm/llvm-project/issues/171284>`__",""
|
||||
"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements","2025-11 (Kona)","","","`#167268 <https://github.com/llvm/llvm-project/issues/167268>`__",""
|
||||
"`P1789R3 <https://wg21.link/P1789R3>`__","Library Support for Expansion Statements","2025-11 (Kona)","|Complete|","22","`#167268 <https://github.com/llvm/llvm-project/issues/167268>`__",""
|
||||
"`P3922R1 <https://wg21.link/P3922R1>`__","Missing deduction guide from ``simd::mask`` to ``simd::vec``","2025-11 (Kona)","","","`#171285 <https://github.com/llvm/llvm-project/issues/171285>`__",""
|
||||
"`P3878R1 <https://wg21.link/P3878R1>`__","Standard library hardening should not use the 'observe' semantic","2025-11 (Kona)","","","`#171286 <https://github.com/llvm/llvm-project/issues/171286>`__",""
|
||||
"`P3887R1 <https://wg21.link/P3887R1>`__","Make ``when_all`` a Ronseal Algorithm","2025-11 (Kona)","","","`#171289 <https://github.com/llvm/llvm-project/issues/171289>`__",""
|
||||
|
||||
|
@ -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)
|
||||
@ -70,6 +72,30 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __for_each_index_sequence(index_sequence<_I
|
||||
}
|
||||
# endif // _LIBCPP_STD_VER >= 20
|
||||
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
// [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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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>
|
||||
@ -583,6 +584,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
|
||||
|
||||
@ -14,8 +14,13 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
void test() {
|
||||
std::integer_sequence<int, 49, 82, 94> seq;
|
||||
|
||||
seq.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
#if TEST_STD_VER >= 26
|
||||
get<0>(seq); // expected-warning {{ignoring return value of function}}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<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 <utility>
|
||||
|
||||
constexpr bool test() {
|
||||
auto [elt0, elt1, elt2, elt3] = std::make_index_sequence<4>();
|
||||
|
||||
assert(elt0 == 0);
|
||||
assert(elt1 == 1);
|
||||
assert(elt2 == 2);
|
||||
assert(elt3 == 3);
|
||||
|
||||
// TODO: remove this macro guard once GCC16 is available
|
||||
#if __cpp_structured_bindings >= 202411L
|
||||
[]<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();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@ -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)));
|
||||
}
|
||||
@ -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 test() {
|
||||
// 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);
|
||||
}
|
||||
@ -764,7 +764,10 @@ feature_test_macros = [
|
||||
},
|
||||
{
|
||||
"name": "__cpp_lib_integer_sequence",
|
||||
"values": {"c++14": 201304},
|
||||
"values": {
|
||||
"c++14": 201304,
|
||||
"c++26": 202511, # P1789R3 Library Support for Expansion Statements
|
||||
},
|
||||
"headers": ["utility"],
|
||||
},
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user