Skip to content

Commit 57bf5dd

Browse files
authored
[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 <[email protected]>
1 parent 0e93dbc commit 57bf5dd

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

libcxx/include/tuple

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,7 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp __make_from_tuple_impl(_Tuple&& __t,
14321432
enable_if_t<is_constructible_v<_Tp, decltype(std::get<_Idx>(std::forward<_Tuple>(__t)))...>> * = nullptr)
14331433
_LIBCPP_NOEXCEPT_RETURN(_Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...))
14341434
#endif // _LIBCPP_STD_VER >= 20
1435+
#undef _LIBCPP_NOEXCEPT_RETURN
14351436

14361437
template <class _Tp, class _Tuple,
14371438
class _Seq = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>, class = void>
@@ -1451,10 +1452,19 @@ template <class _Tp, class _Tuple>
14511452
#else
14521453
template <class _Tp, class _Tuple, class = enable_if_t<__can_make_from_tuple<_Tp, _Tuple>>> // strengthen
14531454
#endif // _LIBCPP_STD_VER >= 20
1455+
14541456
inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t)
1455-
_LIBCPP_NOEXCEPT_RETURN(std::__make_from_tuple_impl<_Tp>(
1456-
std::forward<_Tuple>(__t), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))
1457-
# undef _LIBCPP_NOEXCEPT_RETURN
1457+
noexcept(noexcept(std::__make_from_tuple_impl<_Tp>(std::forward<_Tuple>(__t),
1458+
make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))) {
1459+
#if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary)
1460+
if constexpr (tuple_size_v<remove_reference_t<_Tuple>> == 1) {
1461+
static_assert(!std::reference_constructs_from_temporary_v<_Tp, decltype(std::get<0>(std::declval<_Tuple>()))>,
1462+
"Attempted construction of reference element binds to a temporary whose lifetime has ended");
1463+
}
1464+
#endif // _LIBCPP_STD_VER >= 23
1465+
return std::__make_from_tuple_impl<_Tp>(
1466+
std::forward<_Tuple>(__t), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>());
1467+
}
14581468

14591469
# endif // _LIBCPP_STD_VER >= 17
14601470

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ LIBCPP_STATIC_ASSERT(can_make_from_tuple_impl<float, std::tuple<double>>);
286286

287287
} // namespace LWG3528
288288

289+
static_assert(LWG3528::can_make_from_tuple<int, std::tuple<>>);
290+
289291
int main(int, char**)
290292
{
291293
test_constexpr_construction();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: std-at-least-c++23
10+
11+
// <tuple>
12+
13+
// template <class T, class Tuple> constexpr T make_from_tuple(Tuple&&);
14+
// 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.
15+
16+
#include <tuple>
17+
#include <utility>
18+
19+
#include "test_macros.h"
20+
21+
void test() {
22+
// FreeBSD ci use clang 19.1.1, which hasn't implement __reference_constructs_from_temporary.
23+
// The static_assert inner std::make_from_tuple will not triggered.
24+
#if __has_builtin(__reference_constructs_from_temporary)
25+
// expected-error@*:* {{static assertion failed}}
26+
#endif
27+
28+
// Turns to an error since C++26 (Disallow Binding a Returned Glvalue to a Temporary https://wg21.link/P2748R5).
29+
#if TEST_STD_VER >= 26
30+
// expected-error@tuple:* {{returning reference to local temporary object}}
31+
#else
32+
// expected-warning@tuple:* {{returning reference to local temporary object}}
33+
#endif
34+
std::ignore = std::make_from_tuple<const int&>(std::tuple<char>{});
35+
}

0 commit comments

Comments
 (0)