1 // Copyright (C) 2019-2021 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library.  This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3.  If not see
16 // <http://www.gnu.org/licenses/>.
17 
18 // { dg-options "-std=gnu++2a" }
19 // { dg-do run { target c++2a } }
20 
21 #include <ranges>
22 #include <testsuite_hooks.h>
23 using std::same_as;
24 
25 void
test01()26 test01()
27 {
28   int a[2] = {};
29 
30   static_assert(same_as<decltype(std::ranges::cbegin(a)), const int*>);
31   static_assert(noexcept(std::ranges::cbegin(a)));
32   VERIFY( std::ranges::cbegin(a) == (a + 0) );
33 
34   constexpr long b[2] = {};
35   static_assert( std::ranges::cbegin(b) == (b + 0) );
36 }
37 
38 struct R
39 {
40   int a[4] = { 0, 1, 2, 3 };
41 
begin(R & r)42   friend int* begin(R& r) { return r.a + 0; }
43   friend int* begin(R&&); // this function is not defined
begin(const R & r)44   friend const int* begin(const R& r) noexcept { return r.a + 2; }
45   friend const int* begin(const R&&); // this function is not defined
46 };
47 
48 struct RV // view on an R
49 {
50   R& r;
51 
52   friend int* begin(RV&); // this function is not defined
begin(const RV & rv)53   friend const int* begin(const RV& rv) noexcept { return begin(std::as_const(rv.r)); }
54 };
55 
56 // Allow ranges::begin to work with RV&&
57 template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
58 
59 void
test03()60 test03()
61 {
62   R r;
63   const R& c = r;
64   VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c));
65   VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c));
66 
67   RV v{r};
68   VERIFY(std::ranges::cbegin(std::move(v)) == std::ranges::begin(c));
69   const RV cv{r};
70   VERIFY(std::ranges::cbegin(std::move(cv)) == std::ranges::begin(c));
71 }
72 
73 struct RR
74 {
75   short s = 0;
76   long l = 0;
77   int a[4] = { 0, 1, 2, 3 };
78 
beginRR79   short* begin() noexcept { return &s; }
beginRR80   const long* begin() const { return &l; }
81 
begin(RR & r)82   friend int* begin(RR& r) { return r.a + 0; }
begin(RR && r)83   friend int* begin(RR&& r) { return r.a + 1; }
begin(const RR & r)84   friend const int* begin(const RR& r) { return r.a + 2; }
begin(const RR && r)85   friend const int* begin(const RR&& r) noexcept { return r.a + 3; }
86 };
87 
88 // N.B. this is a lie, cbegin on an RR rvalue will return a dangling pointer.
89 template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
90 
91 void
test04()92 test04()
93 {
94   RR r;
95   const RR& c = r;
96   VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c));
97   VERIFY(std::ranges::cbegin(std::move(r)) == std::ranges::begin(c));
98   VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c));
99   VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(c));
100 }
101 
102 int
main()103 main()
104 {
105   test01();
106   test03();
107   test04();
108 }
109