[committed] libstdc++: Issues with range access CPOs (P2091R0)

Message ID 20200220135844.GA1862757@redhat.com
State New
Headers show
Series
  • [committed] libstdc++: Issues with range access CPOs (P2091R0)
Related show

Commit Message

Jonathan Wakely Feb. 20, 2020, 1:58 p.m.
This changes how arrays of unknown bound and/or incomplete element type
are handled.

	* include/bits/range_access.h (ranges::begin): Reject array of
	incomplete type.
	(ranges::end, ranges::size): Require arrays to be bounded.
	(ranges::data): Require lvalue or borrowed_range.
	(ranges::iterator_t): Remove constraint.
	* testsuite/std/ranges/access/begin.cc: Do not check array of
	incomplete type.
	* testsuite/std/ranges/access/begin_neg.cc: New test.
	* testsuite/std/ranges/access/end_neg.cc: Adjust expected error.
	* testsuite/std/ranges/access/size_neg.cc: Adjust expected error.
	* testsuite/std/ranges/access/ssize.cc: Do not check array of
	incomplete type.

Tested powerpc64le-linux, committed to master.
commit e817c23f6806a6b9201a0a1f77b51cb863af51e9
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Feb 20 13:20:44 2020 +0000

    libstdc++: Issues with range access CPOs (P2091R0)
    
    This changes how arrays of unknown bound and/or incomplete element type
    are handled.
    
            * include/bits/range_access.h (ranges::begin): Reject array of
            incomplete type.
            (ranges::end, ranges::size): Require arrays to be bounded.
            (ranges::data): Require lvalue or borrowed_range.
            (ranges::iterator_t): Remove constraint.
            * testsuite/std/ranges/access/begin.cc: Do not check array of
            incomplete type.
            * testsuite/std/ranges/access/begin_neg.cc: New test.
            * testsuite/std/ranges/access/end_neg.cc: Adjust expected error.
            * testsuite/std/ranges/access/size_neg.cc: Adjust expected error.
            * testsuite/std/ranges/access/ssize.cc: Do not check array of
            incomplete type.

Patch

diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index e7a19305d23..eb91ade35ff 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -382,8 +382,8 @@  namespace ranges
 	  { __decay_copy(__t.begin()) } -> input_or_output_iterator;
 	};
 
-    template<typename _Tp> void begin(_Tp&&) = delete;
-    template<typename _Tp> void begin(initializer_list<_Tp>&&) = delete;
+    void begin(auto&) = delete;
+    void begin(const auto&) = delete;
 
     template<typename _Tp>
       concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>>
@@ -417,7 +417,9 @@  namespace ranges
 	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
 	    {
 	      static_assert(is_lvalue_reference_v<_Tp>);
-	      return __t;
+	      using _Up = remove_all_extents_t<remove_reference_t<_Tp>>;
+	      static_assert(sizeof(_Up) != 0, "not array of incomplete type");
+	      return __t + 0;
 	    }
 	  else if constexpr (__member_begin<_Tp>)
 	    return __t.begin();
@@ -433,8 +435,8 @@  namespace ranges
 	    -> sentinel_for<decltype(_Begin{}(std::forward<_Tp>(__t)))>;
 	};
 
-    template<typename _Tp> void end(_Tp&&) = delete;
-    template<typename _Tp> void end(initializer_list<_Tp>&&) = delete;
+    void end(auto&) = delete;
+    void end(const auto&) = delete;
 
     template<typename _Tp>
       concept __adl_end = __class_or_enum<remove_reference_t<_Tp>>
@@ -451,7 +453,7 @@  namespace ranges
 	static constexpr bool
 	_S_noexcept()
 	{
-	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
+	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    return true;
 	  else if constexpr (__member_end<_Tp>)
 	    return noexcept(__decay_copy(std::declval<_Tp&>().end()));
@@ -461,15 +463,14 @@  namespace ranges
 
     public:
       template<__maybe_borrowed_range _Tp>
-	requires is_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
+	requires is_bounded_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
 	|| __adl_end<_Tp>
 	constexpr auto
 	operator()(_Tp&& __t) const noexcept(_S_noexcept<_Tp>())
 	{
-	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
+	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    {
 	      static_assert(is_lvalue_reference_v<_Tp>);
-	      static_assert(is_bounded_array_v<remove_reference_t<_Tp>>);
 	      return __t + extent_v<remove_reference_t<_Tp>>;
 	    }
 	  else if constexpr (__member_end<_Tp>)
@@ -519,7 +520,8 @@  namespace ranges
 	  { __decay_copy(__t.rbegin()) } -> input_or_output_iterator;
 	};
 
-    template<typename _Tp> void rbegin(_Tp&&) = delete;
+    void rbegin(auto&) = delete;
+    void rbegin(const auto&) = delete;
 
     template<typename _Tp>
       concept __adl_rbegin = __class_or_enum<remove_reference_t<_Tp>>
@@ -582,7 +584,8 @@  namespace ranges
 	    -> sentinel_for<decltype(_RBegin{}(__t))>;
 	};
 
-    template<typename _Tp> void rend(_Tp&&) = delete;
+    void rend(auto&) = delete;
+    void rend(const auto&) = delete;
 
     template<typename _Tp>
       concept __adl_rend = __class_or_enum<remove_reference_t<_Tp>>
@@ -664,7 +667,8 @@  namespace ranges
 	    -> __detail::__is_integer_like;
 	};
 
-    template<typename _Tp> void size(_Tp&&) = delete;
+    void size(auto&) = delete;
+    void size(const auto&) = delete;
 
     template<typename _Tp>
       concept __adl_size = __class_or_enum<remove_reference_t<_Tp>>
@@ -691,7 +695,7 @@  namespace ranges
 	static constexpr bool
 	_S_noexcept()
 	{
-	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
+	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    return true;
 	  else if constexpr (__member_size<_Tp>)
 	    return noexcept(__decay_copy(std::declval<_Tp>().size()));
@@ -704,14 +708,13 @@  namespace ranges
 
     public:
       template<typename _Tp>
-	requires is_array_v<remove_reference_t<_Tp>>
+	requires is_bounded_array_v<remove_reference_t<_Tp>>
 	  || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>())
 	{
-	  if constexpr (is_array_v<remove_reference_t<_Tp>>)
+	  if constexpr (is_bounded_array_v<remove_reference_t<_Tp>>)
 	    {
-	      static_assert(is_bounded_array_v<remove_reference_t<_Tp>>);
 	      return extent_v<remove_reference_t<_Tp>>;
 	    }
 	  else if constexpr (__member_size<_Tp>)
@@ -826,7 +829,8 @@  namespace ranges
 	}
 
     public:
-      template<typename _Tp> requires __member_data<_Tp> || __begin_data<_Tp>
+      template<__maybe_borrowed_range _Tp>
+	requires __member_data<_Tp> || __begin_data<_Tp>
 	constexpr auto
 	operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>())
 	{
@@ -881,8 +885,8 @@  namespace ranges
     concept borrowed_range
       = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
 
-  template<range _Range>
-    using iterator_t = decltype(ranges::begin(std::declval<_Range&>()));
+  template<typename _Tp>
+    using iterator_t = decltype(ranges::begin(std::declval<_Tp&>()));
 
   template<range _Range>
     using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));
diff --git a/libstdc++-v3/testsuite/std/ranges/access/begin.cc b/libstdc++-v3/testsuite/std/ranges/access/begin.cc
index b6801552c60..9cbdfe25a22 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/begin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/begin.cc
@@ -36,10 +36,10 @@  test01()
   constexpr long b[2] = { };
   static_assert( std::ranges::begin(b) == (b + 0) );
 
-  struct Incomplete;
-  using A = Incomplete[]; // unbounded array of incomplete type
+  struct X { };
+  using A = X[]; // unbounded array
   extern A& f();
-  static_assert( same_as<decltype(std::ranges::begin(f())), Incomplete*> );
+  static_assert( same_as<decltype(std::ranges::begin(f())), X*> );
 }
 
 void
diff --git a/libstdc++-v3/testsuite/std/ranges/access/begin_neg.cc b/libstdc++-v3/testsuite/std/ranges/access/begin_neg.cc
new file mode 100644
index 00000000000..f31428526f3
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/access/begin_neg.cc
@@ -0,0 +1,39 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <ranges>
+
+auto
+test01()
+{
+  using A = int[2];
+  extern A&& f(); // rvalue of type that doesn't satisfy borrowed_range
+  return std::ranges::begin(f()); // { dg-error "no match" }
+}
+
+struct incomplete;
+extern incomplete array[2];
+
+auto
+test02()
+{
+  return std::ranges::begin(array); // { dg-error "here" }
+}
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/ranges/access/end_neg.cc b/libstdc++-v3/testsuite/std/ranges/access/end_neg.cc
index 3f690faa73d..e16f684443e 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/end_neg.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/end_neg.cc
@@ -25,9 +25,8 @@  extern int unbounded[];
 auto
 test01()
 {
-  return std::ranges::end(unbounded); // { dg-error "here" }
+  return std::ranges::end(unbounded); // { dg-error "no match" }
 }
-// { dg-error "static assertion failed" "" { target *-*-* } 0 }
 
 struct incomplete;
 extern incomplete array[2];
@@ -38,5 +37,3 @@  test02()
   return std::ranges::end(array); // { dg-error "here" }
 }
 // { dg-error "incomplete type" "" { target *-*-* } 0 }
-
-
diff --git a/libstdc++-v3/testsuite/std/ranges/access/size_neg.cc b/libstdc++-v3/testsuite/std/ranges/access/size_neg.cc
index 6ff8c1f892a..10d9b141fbf 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/size_neg.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/size_neg.cc
@@ -25,6 +25,5 @@  extern int unbounded[];
 auto
 test01()
 {
-  return std::ranges::size(unbounded); // { dg-error "here" }
+  return std::ranges::size(unbounded); // { dg-error "no match" }
 }
-// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/ranges/access/ssize.cc b/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
index 5aa05be8f20..6f5478e2bb1 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
@@ -36,11 +36,6 @@  test01()
   static_assert( std::same_as<decltype(std::ranges::ssize(a2)), ptrdiff_t> );
   VERIFY( std::ranges::ssize(a2) == 2);
   static_assert( noexcept(std::ranges::ssize(a2)) );
-
-  struct Incomplete;
-  using A = Incomplete[2]; // bounded array of incomplete type
-  extern A& f();
-  static_assert( std::same_as<decltype(std::ranges::ssize(f())), ptrdiff_t> );
 }
 
 void