[libc++][tuple.apply] Implement P2255R2 make_from_tuple part. (#152867)

Implement  P2255R2 tuple.apply part wording for `std::make_from_tuple`.
```
Mandates: If tuple_size_v<remove_reference_t<Tuple>> is 1, then reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))> is false.
```

Fixes #154274

---------

Signed-off-by: yronglin <yronglin777@gmail.com>
This commit is contained in:
yronglin 2025-08-19 18:14:13 +08:00 committed by GitHub
parent 0e93dbc6b1
commit 57bf5dd7a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 3 deletions

View File

@ -1432,6 +1432,7 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t,
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
_LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
#endif // _LIBCPP_STD_VER >= 20
#undef _LIBCPP_NOEXCEPT_RETURN
template <class _Tp, class _Tuple,
class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
@ -1451,10 +1452,19 @@ template <class _Tp, class _Tuple>
#else
template <class _Tp, class _Tuple, class = enable_if_t<__can_make_from_tuple<_Tp, _Tuple>>> // strengthen
#endif // _LIBCPP_STD_VER >= 20
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
_LIBCPP_NOEXCEPT_RETURN(std::__make_from_tuple_impl<_Tp>(
std::forward<_Tuple>(__t), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))
# undef _LIBCPP_NOEXCEPT_RETURN
noexcept(noexcept(std::__make_from_tuple_impl<_Tp>(std::forward<_Tuple>(__t),
make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))) {
#if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
if constexpr (tuple_size_v<remove_reference_t<_Tuple>> == 1) {
static_assert(!std::reference_constructs_from_temporary_v<_Tp, decltype(std::get<0>(std::declval<_Tuple>()))>,
"Attempted construction of reference element binds to a temporary whose lifetime has ended");
}
#endif // _LIBCPP_STD_VER >= 23
return std::__make_from_tuple_impl<_Tp>(
std::forward<_Tuple>(__t), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>());
}
# endif // _LIBCPP_STD_VER >= 17

View File

@ -286,6 +286,8 @@ LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<float, std::tuple<double>>);
} // namespace LWG3528
static_assert(LWG3528::can_make_from_tuple<int, std::tuple<>>);
int main(int, char**)
{
test_constexpr_construction();

View File

@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// 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++23
// <tuple>
// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
// Mandates: If tuple_size_v<remove_reference_t<Tuple>> is 1, then reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))> is false.
#include <tuple>
#include <utility>
#include "test_macros.h"
void test() {
// FreeBSD ci use clang 19.1.1, which hasn't implement __reference_constructs_from_temporary.
// The static_assert inner std::make_from_tuple will not triggered.
#if __has_builtin(__reference_constructs_from_temporary)
// expected-error@*:* {{static assertion failed}}
#endif
// Turns to an error since C++26 (Disallow Binding a Returned Glvalue to a Temporary https://wg21.link/P2748R5).
#if TEST_STD_VER >= 26
// expected-error@tuple:* {{returning reference to local temporary object}}
#else
// expected-warning@tuple:* {{returning reference to local temporary object}}
#endif
std::ignore = std::make_from_tuple<const int&>(std::tuple<char>{});
}