diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2023-01-23 12:25:36 +0000 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2023-01-24 23:46:42 +0000 |
commit | 33ed11085837e9492c6ed512931f5b6375c68ee7 (patch) | |
tree | 932b6d07d732b53668256cffd03f12457db7bdf2 | |
parent | aba6416e95ab4138a0ecab0fd51e7e9329d74a45 (diff) | |
download | gcc-33ed11085837e9492c6ed512931f5b6375c68ee7.zip gcc-33ed11085837e9492c6ed512931f5b6375c68ee7.tar.gz gcc-33ed11085837e9492c6ed512931f5b6375c68ee7.tar.bz2 |
libstdc++: Include std::ranges::subrange definition in <tuple> [PR102301]
In order for std::make_from_tuple to work with tuple-like types, the
overloads of std::get for those types must have been declared before the
definition of std::make_from_tuple. That means we need to include the
definition of std::ranges::subrange in <tuple>.
The definitions of std::pair and its overloads of std::get are already
included in <tuple>. We provide forward declarations of std::array and
its std::get overloads in <tuple>. We could just declare subrange
without defining it, and give ranges::get a non-deduced return type,
like so:
namespace ranges
{
enum class subrange_kind : bool { unsized, sized};
template<input_or_output_iterator I, sentinel_for<I> S,
subrange_kind K>
requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)
class subrange;
template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
requires (_Num < 2)
constexpr __conditional_t<_Num == 0, _It, _Sent>
get(const subrange<_It, _Sent, _Kind>& __r);
template<size_t _Num, class _It, class _Sent, subrange_kind _Kind>
requires (_Num < 2)
constexpr __conditional_t<_Num == 0, _It, _Sent>
get(subrange<_It, _Sent, _Kind>&& __r)
}
using ranges::get;
It is a bit late in the GCC 13 dev cycle to do this, so just include the
right headers for now.
Also add the dangling check to std::make_from_tuple added by P2255.
libstdc++-v3/ChangeLog:
PR libstdc++/102301
* include/bits/ranges_base.h: Include <bits/stl_iterator.h> for
std::make_reverse_iterator.
* include/std/tuple: Include <bits/ranges_util.h> for subrange.
(make_from_tuple): Add static assertion from P2255 to diagnose
dangling references.
* testsuite/20_util/tuple/make_from_tuple/dangling_ref.cc: New test.
* testsuite/20_util/tuple/make_from_tuple/tuple_like.cc: New test.
4 files changed, 61 insertions, 5 deletions
diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 26b3a98..86952b3 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -34,7 +34,7 @@ #if __cplusplus > 201703L #include <initializer_list> -#include <bits/iterator_concepts.h> +#include <bits/stl_iterator.h> #include <ext/numeric_traits.h> #include <bits/max_size_type.h> diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 3d82ed1..c773b3a 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -37,10 +37,11 @@ #include <bits/stl_pair.h> // for std::pair #include <bits/uses_allocator.h> // for std::allocator_arg_t -#include <bits/utility.h> // for std::get, std::tuple_size etc. +#include <bits/utility.h> // for std::tuple_size etc. #include <bits/invoke.h> // for std::__invoke #if __cplusplus > 201703L # include <compare> +# include <bits/ranges_util.h> // for std::ranges::subrange # define __cpp_lib_constexpr_tuple 201811L #endif @@ -2312,9 +2313,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION make_from_tuple(_Tuple&& __t) noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) { - return __make_from_tuple_impl<_Tp>( - std::forward<_Tuple>(__t), - make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{}); + constexpr size_t __n = tuple_size_v<remove_reference_t<_Tuple>>; +#if __has_builtin(__reference_constructs_from_temporary) + if constexpr (__n == 1) + { + using _Elt = decltype(std::get<0>(std::declval<_Tuple>())); + static_assert(!__reference_constructs_from_temporary(_Tp, _Elt)); + } +#endif + return __make_from_tuple_impl<_Tp>(std::forward<_Tuple>(__t), + make_index_sequence<__n>{}); } #endif // C++17 diff --git a/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/dangling_ref.cc b/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/dangling_ref.cc new file mode 100644 index 0000000..7958ec8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/dangling_ref.cc @@ -0,0 +1,5 @@ +// { dg-do compile { target c++17 } } +#include <tuple> +std::tuple<short> f(); +auto t = std::make_from_tuple<const int&>(f()); // { dg-error "here" } +// { dg-error "static assertion failed" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/tuple_like.cc b/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/tuple_like.cc new file mode 100644 index 0000000..de69455 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/tuple_like.cc @@ -0,0 +1,43 @@ +// { dg-do compile { target c++17 } } + +#include <tuple> +#include <utility> + +struct Two +{ + Two(const char*, int); +}; + +void +test_pair() +{ + auto two = std::make_from_tuple<Two>(std::pair("one", 2)); + static_assert(std::is_same_v<decltype(two), Two>, "make from pair"); +} + +#include <array> + +struct Three +{ + Three(int, int, int); +}; + +void +test_array() +{ + Three three = std::make_from_tuple<Three>(std::array<int, 3>{{1, 2, 3}}); + static_assert(std::is_same_v<decltype(three), Three>, "make from array"); +} + +#if __cplusplus >= 202002L +#include <vector> +#include <ranges> + +void +test_subrange() // PR libstdc++/102301 +{ + auto r = std::views::iota(0, 5); + auto v = std::make_from_tuple<std::vector<int>>(std::ranges::subrange(r)); + static_assert(std::is_same_v<decltype(v), std::vector<int>>, "from subrange"); +} +#endif |