[committed] libstdc++: Make ranges CPOs final and not addressable

Message ID YMjxP4uzHl48WSr5@redhat.com
State New
Headers show
Series
  • [committed] libstdc++: Make ranges CPOs final and not addressable
Related show

Commit Message

Martin Sebor via Gcc-patches June 15, 2021, 6:28 p.m.
This restricts the API of the CPOs and other function objects so they
cannot be misused by deriving from them or taking their addresses.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>


libstdc++-v3/ChangeLog:

	* include/bits/ranges_base.h (ranges::begin, ranges::end)
	(ranges::cbegin, ranges::cend, ranges::rbeing, ranges::rend)
	(ranges::crbegin, ranges::crend, ranges::size, ranges::ssize)
	(ranges::empty, ranges::data, ranges::cdata): Make types final.
	Add deleted operator& overloads.
	(ranges::advance, ranges::distance, ranges::next, ranges::prev):
	Likewise.
	* testsuite/std/ranges/headers/ranges/synopsis.cc: Replace
	ill-formed & expressions with using-declarations. Add checks for
	other function objects.

Tested powerpc64le-linux. Committed to trunk.
commit 8b93548778a487f31f21e0c6afe7e0bde9711fc4
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jun 15 17:54:53 2021

    libstdc++: Make ranges CPOs final and not addressable
    
    This restricts the API of the CPOs and other function objects so they
    cannot be misused by deriving from them or taking their addresses.
    
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

    
    libstdc++-v3/ChangeLog:
    
            * include/bits/ranges_base.h (ranges::begin, ranges::end)
            (ranges::cbegin, ranges::cend, ranges::rbeing, ranges::rend)
            (ranges::crbegin, ranges::crend, ranges::size, ranges::ssize)
            (ranges::empty, ranges::data, ranges::cdata): Make types final.
            Add deleted operator& overloads.
            (ranges::advance, ranges::distance, ranges::next, ranges::prev):
            Likewise.
            * testsuite/std/ranges/headers/ranges/synopsis.cc: Replace
            ill-formed & expressions with using-declarations. Add checks for
            other function objects.

Comments

Martin Sebor via Gcc-patches June 15, 2021, 8:32 p.m. | #1
CPOs are specified as actual semiregular function objects that can be
copied and constructed freely, so it seems a bit hostile to make them
final/non-addressable? (It's debatable whether the type of a CPO is a
type "specified in the C++ standard library" for which [derivation]/4
would apply.)


On Tue, Jun 15, 2021 at 1:34 PM Jonathan Wakely via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>

> This restricts the API of the CPOs and other function objects so they

> cannot be misused by deriving from them or taking their addresses.

>

> Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

>

> libstdc++-v3/ChangeLog:

>

>         * include/bits/ranges_base.h (ranges::begin, ranges::end)

>         (ranges::cbegin, ranges::cend, ranges::rbeing, ranges::rend)

>         (ranges::crbegin, ranges::crend, ranges::size, ranges::ssize)

>         (ranges::empty, ranges::data, ranges::cdata): Make types final.

>         Add deleted operator& overloads.

>         (ranges::advance, ranges::distance, ranges::next, ranges::prev):

>         Likewise.

>         * testsuite/std/ranges/headers/ranges/synopsis.cc: Replace

>         ill-formed & expressions with using-declarations. Add checks for

>         other function objects.

>

> Tested powerpc64le-linux. Committed to trunk.

>
Martin Sebor via Gcc-patches June 15, 2021, 9:33 p.m. | #2
On Tue, 15 Jun 2021 at 21:32, Tim Song wrote:
>

> CPOs are specified as actual semiregular function objects that can be

> copied and constructed freely, so it seems a bit hostile to make them

> final/non-addressable? (It's debatable whether the type of a CPO is a

> type "specified in the C++ standard library" for which [derivation]/4

> would apply.)


I noticed that libstdc++ was failing some libc++ tests, but that was
only for ranges::advance etc and not the CPOs. I guess I got a bit
carried away, and it shouldn't apply to the CPOs, only the
[range.iter.ops] "function templates" (which are not really function
templates).
Martin Sebor via Gcc-patches June 16, 2021, 1:37 p.m. | #3
On Tue, 15 Jun 2021 at 22:33, Jonathan Wakely wrote:
>

> On Tue, 15 Jun 2021 at 21:32, Tim Song wrote:

> >

> > CPOs are specified as actual semiregular function objects that can be

> > copied and constructed freely, so it seems a bit hostile to make them

> > final/non-addressable? (It's debatable whether the type of a CPO is a

> > type "specified in the C++ standard library" for which [derivation]/4

> > would apply.)

>

> I noticed that libstdc++ was failing some libc++ tests, but that was

> only for ranges::advance etc and not the CPOs. I guess I got a bit

> carried away, and it shouldn't apply to the CPOs, only the

> [range.iter.ops] "function templates" (which are not really function

> templates).


This reverts the changes to the [range.access] CPOs, and improves some
tests slightly.

Tested powerpc64le-linux. Pushed to trunk.
commit b9e35ee6d64bc9f82b8fe641aa8ac12a9e259fe8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 16 12:34:52 2021

    libstdc++: Revert final/non-addressable changes to ranges CPOs
    
    In r12-1489-g8b93548778a487f31f21e0c6afe7e0bde9711fc4 I made the
    [range.access] CPO types final and non-addressable. Tim Song pointed out
    this is wrong. Only the [range.iter.ops] functions should be final and
    non-addressable. Revert the changes to the [range.access] objects.
    
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/ranges_base.h (ranges::begin, ranges::end)
            (ranges::cbegin, ranges::cend, ranges::rbeing, ranges::rend)
            (ranges::crbegin, ranges::crend, ranges::size, ranges::ssize)
            (ranges::empty, ranges::data, ranges::cdata): Remove final
            keywords and deleted operator& overloads.
            * testsuite/24_iterators/customization_points/iter_move.cc: Use
            new is_customization_point_object function.
            * testsuite/24_iterators/customization_points/iter_swap.cc:
            Likewise.
            * testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc:
            Likewise.
            * testsuite/std/ranges/access/begin.cc: Likewise.
            * testsuite/std/ranges/access/cbegin.cc: Likewise.
            * testsuite/std/ranges/access/cdata.cc: Likewise.
            * testsuite/std/ranges/access/cend.cc: Likewise.
            * testsuite/std/ranges/access/crbegin.cc: Likewise.
            * testsuite/std/ranges/access/crend.cc: Likewise.
            * testsuite/std/ranges/access/data.cc: Likewise.
            * testsuite/std/ranges/access/empty.cc: Likewise.
            * testsuite/std/ranges/access/end.cc: Likewise.
            * testsuite/std/ranges/access/rbegin.cc: Likewise.
            * testsuite/std/ranges/access/rend.cc: Likewise.
            * testsuite/std/ranges/access/size.cc: Likewise.
            * testsuite/std/ranges/access/ssize.cc: Likewise.
            * testsuite/util/testsuite_iterators.h
            (is_customization_point_object): New function.

diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index e392c370fcd..25af4b742a6 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -91,7 +91,7 @@ namespace ranges
     using std::ranges::__detail::__maybe_borrowed_range;
     using std::__detail::__range_iter_t;
 
-    struct _Begin final
+    struct _Begin
     {
     private:
       template<typename _Tp>
@@ -106,8 +106,6 @@ namespace ranges
 	    return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
 	}
 
-      void operator&() const = delete;
-
     public:
       template<__maybe_borrowed_range _Tp>
 	requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
@@ -144,7 +142,7 @@ namespace ranges
 	  { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
 	};
 
-    struct _End final
+    struct _End
     {
     private:
       template<typename _Tp>
@@ -159,8 +157,6 @@ namespace ranges
 	    return noexcept(__decay_copy(end(std::declval<_Tp&>())));
 	}
 
-      void operator&() const = delete;
-
     public:
       template<__maybe_borrowed_range _Tp>
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
@@ -193,7 +189,7 @@ namespace ranges
 	  return static_cast<const _Tp&&>(__t);
       }
 
-    struct _CBegin final
+    struct _CBegin
     {
       template<typename _Tp>
 	constexpr auto
@@ -203,8 +199,6 @@ namespace ranges
 	{
 	  return _Begin{}(__cust_access::__as_const<_Tp>(__e));
 	}
-
-      void operator&() const = delete;
     };
 
     struct _CEnd final
@@ -217,8 +211,6 @@ namespace ranges
 	{
 	  return _End{}(__cust_access::__as_const<_Tp>(__e));
 	}
-
-      void operator&() const = delete;
     };
 
     template<typename _Tp>
@@ -244,7 +236,7 @@ namespace ranges
 	  { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
 	};
 
-    struct _RBegin final
+    struct _RBegin
     {
     private:
       template<typename _Tp>
@@ -268,8 +260,6 @@ namespace ranges
 	    }
 	}
 
-      void operator&() const = delete;
-
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
@@ -304,7 +294,7 @@ namespace ranges
 	    -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
 	};
 
-    struct _REnd final
+    struct _REnd
     {
     private:
       template<typename _Tp>
@@ -328,8 +318,6 @@ namespace ranges
 	    }
 	}
 
-      void operator&() const = delete;
-
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
@@ -346,7 +334,7 @@ namespace ranges
 	}
     };
 
-    struct _CRBegin final
+    struct _CRBegin
     {
       template<typename _Tp>
 	constexpr auto
@@ -356,11 +344,9 @@ namespace ranges
 	{
 	  return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
 	}
-
-      void operator&() const = delete;
     };
 
-    struct _CREnd final
+    struct _CREnd
     {
       template<typename _Tp>
 	constexpr auto
@@ -370,8 +356,6 @@ namespace ranges
 	{
 	  return _REnd{}(__cust_access::__as_const<_Tp>(__e));
 	}
-
-      void operator&() const = delete;
     };
 
     template<typename _Tp>
@@ -402,7 +386,7 @@ namespace ranges
 	  __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
 	};
 
-    struct _Size final
+    struct _Size
     {
     private:
       template<typename _Tp>
@@ -420,8 +404,6 @@ namespace ranges
 			    - _Begin{}(std::declval<_Tp&>()));
 	}
 
-      void operator&() const = delete;
-
     public:
       template<typename _Tp>
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
@@ -440,7 +422,7 @@ namespace ranges
 	}
     };
 
-    struct _SSize final
+    struct _SSize
     {
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
@@ -469,8 +451,6 @@ namespace ranges
 	  else // Must be one of __max_diff_type or __max_size_type.
 	    return __detail::__max_diff_type(__size);
 	}
-
-      void operator&() const = delete;
     };
 
     template<typename _Tp>
@@ -487,7 +467,7 @@ namespace ranges
 	  bool(_Begin{}(__t) == _End{}(__t));
 	};
 
-    struct _Empty final
+    struct _Empty
     {
     private:
       template<typename _Tp>
@@ -503,8 +483,6 @@ namespace ranges
 		== _End{}(std::declval<_Tp&>())));
 	}
 
-      void operator&() const = delete;
-
     public:
       template<typename _Tp>
 	requires __member_empty<_Tp> || __size0_empty<_Tp>
@@ -534,7 +512,7 @@ namespace ranges
     template<typename _Tp>
       concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
 
-    struct _Data final
+    struct _Data
     {
     private:
       template<typename _Tp>
@@ -547,8 +525,6 @@ namespace ranges
 	    return noexcept(_Begin{}(std::declval<_Tp&>()));
 	}
 
-      void operator&() const = delete;
-
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_data<_Tp> || __begin_data<_Tp>
@@ -562,7 +538,7 @@ namespace ranges
 	}
     };
 
-    struct _CData final
+    struct _CData
     {
       template<typename _Tp>
 	constexpr auto
@@ -572,8 +548,6 @@ namespace ranges
 	{
 	  return _Data{}(__cust_access::__as_const<_Tp>(__e));
 	}
-
-      void operator&() const = delete;
     };
 
   } // namespace __cust_access
diff --git a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc
index 22030eca9a7..a43448581f3 100644
--- a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc
+++ b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc
@@ -20,6 +20,9 @@
 
 #include <iterator>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+static_assert(__gnu_test::is_customization_point_object(std::ranges::iter_move));
 
 struct X
 {
diff --git a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc
index 35802723d60..f170e177d30 100644
--- a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc
+++ b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_swap.cc
@@ -20,6 +20,9 @@
 
 #include <iterator>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+static_assert(__gnu_test::is_customization_point_object(std::ranges::iter_swap));
 
 struct X
 {
diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc
index 4479c26f30b..ea469e953b2 100644
--- a/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc
+++ b/libstdc++-v3/testsuite/std/concepts/concepts.lang/concept.swappable/swap.cc
@@ -19,6 +19,10 @@
 // { dg-do compile { target c++2a } }
 
 #include <concepts>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+static_assert(__gnu_test::is_customization_point_object(std::ranges::swap));
 
 namespace nu
 {
diff --git a/libstdc++-v3/testsuite/std/ranges/access/begin.cc b/libstdc++-v3/testsuite/std/ranges/access/begin.cc
index 6ef44ee631c..a08ad37fd34 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/begin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/begin.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::begin));
+
 using std::same_as;
 
 void
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
index dc06695139e..ed80af589cf 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
@@ -20,6 +20,10 @@
 
 #include <ranges>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+static_assert(__gnu_test::is_customization_point_object(std::ranges::cbegin));
+
 using std::same_as;
 
 void
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
index 2dfb6830789..d51ff1d32eb 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
@@ -20,6 +20,9 @@
 
 #include <ranges>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+static_assert(__gnu_test::is_customization_point_object(std::ranges::cdata));
 
 template<typename T>
   concept has_cdata
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
index fcb80f28d3a..3e685ae9ce2 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
@@ -20,6 +20,9 @@
 
 #include <ranges>
 #include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+static_assert(__gnu_test::is_customization_point_object(std::ranges::cend));
 
 using std::same_as;
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
index a41234b2dd4..6b02b478a15 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::crbegin));
+
 struct R1
 {
   int i = 0;
diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc b/libstdc++-v3/testsuite/std/ranges/access/crend.cc
index 8f8b08abd3f..eb010d9d477 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/crend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::crend));
+
 struct R1
 {
   int i = 0;
diff --git a/libstdc++-v3/testsuite/std/ranges/access/data.cc b/libstdc++-v3/testsuite/std/ranges/access/data.cc
index 4f16f447f9f..b2083d1890e 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/data.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/data.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::data));
+
 template<typename T>
   concept has_data
     = requires (T&& t) { std::ranges::data(std::forward<T>(t)); };
diff --git a/libstdc++-v3/testsuite/std/ranges/access/empty.cc b/libstdc++-v3/testsuite/std/ranges/access/empty.cc
index b2d8b105325..3cad4740124 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/empty.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/empty.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::empty));
+
 using std::same_as;
 
 void
diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc
index 7bf0dd44bb3..25f21c75afc 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/end.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::end));
+
 using std::same_as;
 
 void
diff --git a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
index a166ad74348..0006f89d4c5 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::rbegin));
+
 struct R1
 {
   int i = 0;
diff --git a/libstdc++-v3/testsuite/std/ranges/access/rend.cc b/libstdc++-v3/testsuite/std/ranges/access/rend.cc
index 4ba5447c74a..0ac86bc8d4b 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/rend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/rend.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::rend));
+
 struct R1
 {
   int i = 0;
diff --git a/libstdc++-v3/testsuite/std/ranges/access/size.cc b/libstdc++-v3/testsuite/std/ranges/access/size.cc
index f25a1cb9ddb..c7e4f78f96a 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/size.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/size.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::size));
+
 void
 test01()
 {
diff --git a/libstdc++-v3/testsuite/std/ranges/access/ssize.cc b/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
index fdbf245d036..7337f626a25 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/ssize.cc
@@ -22,6 +22,8 @@
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+static_assert(__gnu_test::is_customization_point_object(std::ranges::ssize));
+
 using std::ptrdiff_t;
 
 void
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index 4e668d648f2..6b835ac475e 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -894,6 +894,22 @@ namespace __gnu_test
 // This is also true for test_container, although only when it has forward
 // iterators (because output_iterator_wrapper and input_iterator_wrapper are
 // not default constructible so do not model std::input_or_output_iterator).
+
+
+  // Test for basic properties of C++20 16.3.3.6 [customization.point.object].
+  template<typename T>
+    constexpr bool
+    is_customization_point_object(T& obj) noexcept
+    {
+      // A [CPO] is a function object with a literal class type.
+      static_assert( std::is_class_v<T> || std::is_union_v<T> );
+      static_assert( __is_literal_type(T) );
+      // The type of a [CPO], ignoring cv-qualifiers, shall model semiregular.
+      static_assert( std::semiregular<std::remove_cv_t<T>> );
+
+      return true;
+    }
+
 #endif // C++20
 } // namespace __gnu_test
 #endif // _TESTSUITE_ITERATORS

Patch

diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index a63ef8eb7f4..e392c370fcd 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -91,7 +91,7 @@  namespace ranges
     using std::ranges::__detail::__maybe_borrowed_range;
     using std::__detail::__range_iter_t;
 
-    struct _Begin
+    struct _Begin final
     {
     private:
       template<typename _Tp>
@@ -106,6 +106,8 @@  namespace ranges
 	    return noexcept(__decay_copy(begin(std::declval<_Tp&>())));
 	}
 
+      void operator&() const = delete;
+
     public:
       template<__maybe_borrowed_range _Tp>
 	requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
@@ -142,7 +144,7 @@  namespace ranges
 	  { __decay_copy(end(__t)) } -> sentinel_for<__range_iter_t<_Tp>>;
 	};
 
-    struct _End
+    struct _End final
     {
     private:
       template<typename _Tp>
@@ -157,6 +159,8 @@  namespace ranges
 	    return noexcept(__decay_copy(end(std::declval<_Tp&>())));
 	}
 
+      void operator&() const = delete;
+
     public:
       template<__maybe_borrowed_range _Tp>
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
@@ -189,7 +193,7 @@  namespace ranges
 	  return static_cast<const _Tp&&>(__t);
       }
 
-    struct _CBegin
+    struct _CBegin final
     {
       template<typename _Tp>
 	constexpr auto
@@ -199,9 +203,11 @@  namespace ranges
 	{
 	  return _Begin{}(__cust_access::__as_const<_Tp>(__e));
 	}
+
+      void operator&() const = delete;
     };
 
-    struct _CEnd
+    struct _CEnd final
     {
       template<typename _Tp>
 	constexpr auto
@@ -211,6 +217,8 @@  namespace ranges
 	{
 	  return _End{}(__cust_access::__as_const<_Tp>(__e));
 	}
+
+      void operator&() const = delete;
     };
 
     template<typename _Tp>
@@ -236,7 +244,7 @@  namespace ranges
 	  { _End{}(__t) } -> same_as<decltype(_Begin{}(__t))>;
 	};
 
-    struct _RBegin
+    struct _RBegin final
     {
     private:
       template<typename _Tp>
@@ -260,6 +268,8 @@  namespace ranges
 	    }
 	}
 
+      void operator&() const = delete;
+
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
@@ -294,7 +304,7 @@  namespace ranges
 	    -> sentinel_for<decltype(_RBegin{}(std::forward<_Tp>(__t)))>;
 	};
 
-    struct _REnd
+    struct _REnd final
     {
     private:
       template<typename _Tp>
@@ -318,6 +328,8 @@  namespace ranges
 	    }
 	}
 
+      void operator&() const = delete;
+
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
@@ -334,7 +346,7 @@  namespace ranges
 	}
     };
 
-    struct _CRBegin
+    struct _CRBegin final
     {
       template<typename _Tp>
 	constexpr auto
@@ -344,9 +356,11 @@  namespace ranges
 	{
 	  return _RBegin{}(__cust_access::__as_const<_Tp>(__e));
 	}
+
+      void operator&() const = delete;
     };
 
-    struct _CREnd
+    struct _CREnd final
     {
       template<typename _Tp>
 	constexpr auto
@@ -356,6 +370,8 @@  namespace ranges
 	{
 	  return _REnd{}(__cust_access::__as_const<_Tp>(__e));
 	}
+
+      void operator&() const = delete;
     };
 
     template<typename _Tp>
@@ -386,7 +402,7 @@  namespace ranges
 	  __detail::__to_unsigned_like(_End{}(__t) - _Begin{}(__t));
 	};
 
-    struct _Size
+    struct _Size final
     {
     private:
       template<typename _Tp>
@@ -404,6 +420,8 @@  namespace ranges
 			    - _Begin{}(std::declval<_Tp&>()));
 	}
 
+      void operator&() const = delete;
+
     public:
       template<typename _Tp>
 	requires is_bounded_array_v<remove_reference_t<_Tp>>
@@ -422,7 +440,7 @@  namespace ranges
 	}
     };
 
-    struct _SSize
+    struct _SSize final
     {
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 3403. Domain of ranges::ssize(E) doesn't match ranges::size(E)
@@ -451,6 +469,8 @@  namespace ranges
 	  else // Must be one of __max_diff_type or __max_size_type.
 	    return __detail::__max_diff_type(__size);
 	}
+
+      void operator&() const = delete;
     };
 
     template<typename _Tp>
@@ -467,7 +487,7 @@  namespace ranges
 	  bool(_Begin{}(__t) == _End{}(__t));
 	};
 
-    struct _Empty
+    struct _Empty final
     {
     private:
       template<typename _Tp>
@@ -483,6 +503,8 @@  namespace ranges
 		== _End{}(std::declval<_Tp&>())));
 	}
 
+      void operator&() const = delete;
+
     public:
       template<typename _Tp>
 	requires __member_empty<_Tp> || __size0_empty<_Tp>
@@ -512,7 +534,7 @@  namespace ranges
     template<typename _Tp>
       concept __begin_data = contiguous_iterator<__range_iter_t<_Tp>>;
 
-    struct _Data
+    struct _Data final
     {
     private:
       template<typename _Tp>
@@ -525,6 +547,8 @@  namespace ranges
 	    return noexcept(_Begin{}(std::declval<_Tp&>()));
 	}
 
+      void operator&() const = delete;
+
     public:
       template<__maybe_borrowed_range _Tp>
 	requires __member_data<_Tp> || __begin_data<_Tp>
@@ -538,7 +562,7 @@  namespace ranges
 	}
     };
 
-    struct _CData
+    struct _CData final
     {
       template<typename _Tp>
 	constexpr auto
@@ -548,6 +572,8 @@  namespace ranges
 	{
 	  return _Data{}(__cust_access::__as_const<_Tp>(__e));
 	}
+
+      void operator&() const = delete;
     };
 
   } // namespace __cust_access
@@ -669,7 +695,7 @@  namespace ranges
 
   // [range.iter.ops] range iterator operations
 
-  struct __advance_fn
+  struct __advance_fn final
   {
     template<input_or_output_iterator _It>
       constexpr void
@@ -774,11 +800,13 @@  namespace ranges
 	    return __n;
 	  }
       }
+
+    void operator&() const = delete;
   };
 
   inline constexpr __advance_fn advance{};
 
-  struct __distance_fn
+  struct __distance_fn final
   {
     template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
       constexpr iter_difference_t<_It>
@@ -807,11 +835,13 @@  namespace ranges
 	else
 	  return (*this)(ranges::begin(__r), ranges::end(__r));
       }
+
+    void operator&() const = delete;
   };
 
   inline constexpr __distance_fn distance{};
 
-  struct __next_fn
+  struct __next_fn final
   {
     template<input_or_output_iterator _It>
       constexpr _It
@@ -844,11 +874,13 @@  namespace ranges
 	ranges::advance(__x, __n, __bound);
 	return __x;
       }
+
+    void operator&() const = delete;
   };
 
   inline constexpr __next_fn next{};
 
-  struct __prev_fn
+  struct __prev_fn final
   {
     template<bidirectional_iterator _It>
       constexpr _It
@@ -873,6 +905,8 @@  namespace ranges
 	ranges::advance(__x, -__n, __bound);
 	return __x;
       }
+
+    void operator&() const = delete;
   };
 
   inline constexpr __prev_fn prev{};
diff --git a/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc b/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc
index 115b157fd6c..ea26b505678 100644
--- a/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc
+++ b/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc
@@ -33,12 +33,22 @@  namespace __gnu_test
 {
   constexpr const bool* disable_sized_range
     = &std::ranges::disable_sized_range<void>;
-  constexpr auto* begin = &std::ranges::begin;
-  constexpr auto* end = &std::ranges::end;
-  constexpr auto* cbegin = &std::ranges::cbegin;
-  constexpr auto* cend = &std::ranges::cend;
-  constexpr auto* rbegin = &std::ranges::rbegin;
-  constexpr auto* rend = &std::ranges::rend;
-  constexpr auto* crbegin = &std::ranges::crbegin;
-  constexpr auto* crend = &std::ranges::crend;
+  using std::ranges::begin;
+  using std::ranges::end;
+  using std::ranges::cbegin;
+  using std::ranges::cend;
+  using std::ranges::rbegin;
+  using std::ranges::rend;
+  using std::ranges::crbegin;
+  using std::ranges::crend;
+  using std::ranges::size;
+  using std::ranges::ssize;
+  using std::ranges::empty;
+  using std::ranges::data;
+  using std::ranges::cdata;
+
+  using std::ranges::advance;
+  using std::ranges::distance;
+  using std::ranges::next;
+  using std::ranges::prev;
 }