public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-5338] libstdc++: Include std::ranges::subrange definition in <tuple> [PR102301]
@ 2023-01-24 23:51 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2023-01-24 23:51 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:33ed11085837e9492c6ed512931f5b6375c68ee7

commit r13-5338-g33ed11085837e9492c6ed512931f5b6375c68ee7
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Jan 23 12:25:36 2023 +0000

    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.

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h            |  2 +-
 libstdc++-v3/include/std/tuple                     | 16 ++++++--
 .../20_util/tuple/make_from_tuple/dangling_ref.cc  |  5 +++
 .../20_util/tuple/make_from_tuple/tuple_like.cc    | 43 ++++++++++++++++++++++
 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 26b3a983f72..86952b34096 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 3d82ed1c370..c773b3a348b 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 00000000000..7958ec888a3
--- /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 00000000000..de694554d86
--- /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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-01-24 23:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-24 23:51 [gcc r13-5338] libstdc++: Include std::ranges::subrange definition in <tuple> [PR102301] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).