diff --git a/libstdc++-v3/include/bits/ranges_cmp.h b/libstdc++-v3/include/bits/ranges_cmp.h index d6880714966..3f71d31e5a6 100644 --- a/libstdc++-v3/include/bits/ranges_cmp.h +++ b/libstdc++-v3/include/bits/ranges_cmp.h @@ -62,19 +62,9 @@ namespace ranges { namespace __detail { - // BUILTIN-PTR-CMP(T, ==, U) - template - concept __eq_builtin_ptr_cmp - = requires (_Tp&& __t, _Up&& __u) { { __t == __u } -> same_as; } - && 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 concept __less_builtin_ptr_cmp = requires (_Tp&& __t, _Up&& __u) { { __t < __u } -> same_as; } @@ -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 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 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 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 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 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 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 7025f597db8..82d00889272 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 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 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 823aa1af9b5..103fe4c9130 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 +template + 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 ); + static_assert( ! comparable ); } 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 +// . + +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } + +#include + +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); +// But concept not satisfied because operator>= returns void +static_assert(!std::totally_ordered); + +template + 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 ); +static_assert( ! comparable ); +static_assert( ! comparable ); +static_assert( ! comparable ); +static_assert( ! comparable ); +static_assert( ! comparable );