public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r10-9591] libstdc++: Implement LWG 3530 for concept-constrained comparisons
@ 2021-03-29 20:03 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2021-03-29 20:03 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:913312de92522e9e6696331fc3018e1020845c26

commit r10-9591-g913312de92522e9e6696331fc3018e1020845c26
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Mar 10 15:27:06 2021 +0000

    libstdc++: Implement LWG 3530 for concept-constrained comparisons
    
    The proposed resolution for this library issue simplifies the
    constraints for compare_three_way, ranges::equal_to, ranges::less etc.
    so that they do not work with types which are convertible to pointers
    but which fail to meet the usual syntactic requirements for the
    comparisons.
    
    This affects the example in PR libstdc++/93628 but doesn't fix the
    problem described in that report.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/range_cmp.h (__eq_builtin_ptr_cmp): Remove.
            (ranges::equal_to, ranges::not_equal_to): Do not constrain
            with __eq_builtin_ptr_cmp.
            (ranges::less, ranges::greater, ranges::less_equal)
            (ranges::greater_equal): Do not constrain with
            __less_builtin_ptr_cmp.
            * libsupc++/compare (compare_three_way): Do not constrain with
            __3way_builtin_ptr_cmp.
            * testsuite/18_support/comparisons/object/builtin-ptr-three-way.cc: Moved to...
            * testsuite/18_support/comparisons/object/lwg3530.cc: ...here.
            * testsuite/20_util/function_objects/range.cmp/lwg3530.cc: New test.
    
    (cherry picked from commit dddd011113b6ceede733d7ae33eca695c06b181b)

Diff:
---
 libstdc++-v3/include/bits/range_cmp.h              | 23 +++--------
 libstdc++-v3/libsupc++/compare                     |  7 +++-
 .../{builtin-ptr-three-way.cc => lwg3530.cc}       | 13 ++++--
 .../20_util/function_objects/range.cmp/lwg3530.cc  | 47 ++++++++++++++++++++++
 4 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/libstdc++-v3/include/bits/range_cmp.h b/libstdc++-v3/include/bits/range_cmp.h
index 0587c599c4b..81bee0801dc 100644
--- a/libstdc++-v3/include/bits/range_cmp.h
+++ b/libstdc++-v3/include/bits/range_cmp.h
@@ -62,19 +62,9 @@ namespace ranges
 {
   namespace __detail
   {
-    // BUILTIN-PTR-CMP(T, ==, U)
-    template<typename _Tp, typename _Up>
-      concept __eq_builtin_ptr_cmp
-	= requires (_Tp&& __t, _Up&& __u) { { __t == __u } -> same_as<bool>; }
-	  && convertible_to<_Tp, const volatile void*>
-	  && convertible_to<_Up, const volatile void*>
-	  && (! requires(_Tp&& __t, _Up&& __u)
-	      { operator==(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
-	      &&
-	      ! requires(_Tp&& __t, _Up&& __u)
-	      { std::forward<_Tp>(__t).operator==(std::forward<_Up>(__u)); });
-
     // BUILTIN-PTR-CMP(T, <, U)
+    // This determines whether t < u results in a call to a built-in operator<
+    // comparing pointers. It doesn't work for function pointers (PR 93628).
     template<typename _Tp, typename _Up>
       concept __less_builtin_ptr_cmp
 	= requires (_Tp&& __t, _Up&& __u) { { __t < __u } -> same_as<bool>; }
@@ -88,12 +78,14 @@ namespace ranges
 
   // [range.cmp] Concept-constrained comparisons
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks
+
   /// ranges::equal_to function object type.
   struct equal_to
   {
     template<typename _Tp, typename _Up>
       requires equality_comparable_with<_Tp, _Up>
-	|| __detail::__eq_builtin_ptr_cmp<_Tp, _Up>
       constexpr bool
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Tp>() == std::declval<_Up>()))
@@ -107,7 +99,6 @@ namespace ranges
   {
     template<typename _Tp, typename _Up>
       requires equality_comparable_with<_Tp, _Up>
-	|| __detail::__eq_builtin_ptr_cmp<_Tp, _Up>
       constexpr bool
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Up>() == std::declval<_Tp>()))
@@ -121,7 +112,6 @@ namespace ranges
   {
     template<typename _Tp, typename _Up>
       requires totally_ordered_with<_Tp, _Up>
-	|| __detail::__less_builtin_ptr_cmp<_Tp, _Up>
       constexpr bool
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Tp>() < std::declval<_Up>()))
@@ -150,7 +140,6 @@ namespace ranges
   {
     template<typename _Tp, typename _Up>
       requires totally_ordered_with<_Tp, _Up>
-	|| __detail::__less_builtin_ptr_cmp<_Up, _Tp>
       constexpr bool
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Up>() < std::declval<_Tp>()))
@@ -164,7 +153,6 @@ namespace ranges
   {
     template<typename _Tp, typename _Up>
       requires totally_ordered_with<_Tp, _Up>
-	|| __detail::__less_builtin_ptr_cmp<_Tp, _Up>
       constexpr bool
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Tp>() < std::declval<_Up>()))
@@ -178,7 +166,6 @@ namespace ranges
   {
     template<typename _Tp, typename _Up>
       requires totally_ordered_with<_Tp, _Up>
-	|| __detail::__less_builtin_ptr_cmp<_Up, _Tp>
       constexpr bool
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Up>() < std::declval<_Tp>()))
diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare
index 28dfe843ee7..bd9c3b2352b 100644
--- a/libstdc++-v3/libsupc++/compare
+++ b/libstdc++-v3/libsupc++/compare
@@ -479,6 +479,9 @@ namespace std
   namespace __detail
   {
     // BUILTIN-PTR-THREE-WAY(T, U)
+    // This determines whether t <=> u results in a call to a built-in
+    // operator<=> comparing pointers. It doesn't work for function pointers
+    // (PR 93628).
     template<typename _Tp, typename _Up>
       concept __3way_builtin_ptr_cmp
 	= requires(_Tp&& __t, _Up&& __u)
@@ -491,12 +494,14 @@ namespace std
 	  { static_cast<_Tp&&>(__t).operator<=>(static_cast<_Up&&>(__u)); };
   } // namespace __detail
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 3530 BUILTIN-PTR-MEOW should not opt the type out of syntactic checks
+
   // [cmp.object], typename compare_three_way
   struct compare_three_way
   {
     template<typename _Tp, typename _Up>
       requires three_way_comparable_with<_Tp, _Up>
-      || __detail::__3way_builtin_ptr_cmp<_Tp, _Up>
       constexpr auto
       operator()(_Tp&& __t, _Up&& __u) const
       noexcept(noexcept(std::declval<_Tp>() <=> std::declval<_Up>()))
diff --git a/libstdc++-v3/testsuite/18_support/comparisons/object/builtin-ptr-three-way.cc b/libstdc++-v3/testsuite/18_support/comparisons/object/lwg3530.cc
similarity index 79%
rename from libstdc++-v3/testsuite/18_support/comparisons/object/builtin-ptr-three-way.cc
rename to libstdc++-v3/testsuite/18_support/comparisons/object/lwg3530.cc
index 38b3c6e3211..39250680932 100644
--- a/libstdc++-v3/testsuite/18_support/comparisons/object/builtin-ptr-three-way.cc
+++ b/libstdc++-v3/testsuite/18_support/comparisons/object/lwg3530.cc
@@ -20,6 +20,11 @@
 
 #include <compare>
 
+template<typename C, typename T, typename U>
+  concept comparable = requires (const C& cmp, const T& t, const U& u) {
+    cmp(t, u);
+  };
+
 void
 test01()
 {
@@ -39,7 +44,9 @@ test01()
 
   long l;
   // But <=> is valid and resolves to a builtin operator comparing pointers:
-  auto c = &l <=> x;
-  // So std::compare_three_way should be usable:
-  auto c2 = std::compare_three_way()(&l, x);
+  [[maybe_unused]] auto c = &l <=> x;
+
+  // But LWG 3530 says std::compare_three_way should not be usable:
+  static_assert( ! comparable<std::compare_three_way, long*, X> );
+  static_assert( ! comparable<std::compare_three_way, X, long*> );
 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/range.cmp/lwg3530.cc b/libstdc++-v3/testsuite/20_util/function_objects/range.cmp/lwg3530.cc
new file mode 100644
index 00000000000..cd9664678cf
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/range.cmp/lwg3530.cc
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 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++20" }
+// { dg-do compile { target c++20 } }
+
+#include <functional>
+
+struct S {
+  constexpr operator int*() const { return nullptr; }
+};
+
+void operator!=(S const&, S const&) {}
+void operator>=(S const&, S const&) {}
+
+// S can be compared via conversion to int*
+static_assert(S{} == S{});
+static_assert(S{} <= S{});
+// But concept not satisfied because operator!= returns void
+static_assert(!std::equality_comparable_with<S,S>);
+// But concept not satisfied because operator>= returns void
+static_assert(!std::totally_ordered<S>);
+
+template<typename C, typename T>
+  concept comparable = requires (const C& cmp, const T& t) { cmp(t, t); };
+
+// LWG 3530 says [range.cmp] comparisons should not work for S
+static_assert( ! comparable<std::ranges::equal_to,      S> );
+static_assert( ! comparable<std::ranges::not_equal_to,  S> );
+static_assert( ! comparable<std::ranges::greater,       S> );
+static_assert( ! comparable<std::ranges::less,          S> );
+static_assert( ! comparable<std::ranges::greater_equal, S> );
+static_assert( ! comparable<std::ranges::less_equal,    S> );


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

only message in thread, other threads:[~2021-03-29 20:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-29 20:03 [gcc r10-9591] libstdc++: Implement LWG 3530 for concept-constrained comparisons 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).