2019-10-17 Jonathan Wakely <jwakely@redhat.com>
+ * include/Makefile.am: Add new header.
+ * include/Makefile.in: Regenerate.
+ * include/bits/range_cmp.h: New header for C++20 function objects.
+ * include/std/functional: Include new header.
+ * testsuite/20_util/function_objects/identity/1.cc: New test.
+ * testsuite/20_util/function_objects/range.cmp/equal_to.cc: New test.
+ * testsuite/20_util/function_objects/range.cmp/greater.cc: New test.
+ * testsuite/20_util/function_objects/range.cmp/greater_equal.cc: New
+ test.
+ * testsuite/20_util/function_objects/range.cmp/less.cc: New test.
+ * testsuite/20_util/function_objects/range.cmp/less_equal.cc: New test.
+ * testsuite/20_util/function_objects/range.cmp/not_equal_to.cc: New
+ test.
+
PR libstdc++/92124
* include/bits/forward_list.h
(_M_move_assign(forward_list&&, false_type)): Do not use
${bits_srcdir}/random.h \
${bits_srcdir}/random.tcc \
${bits_srcdir}/range_access.h \
+ ${bits_srcdir}/range_cmp.h \
${bits_srcdir}/refwrap.h \
${bits_srcdir}/regex.h \
${bits_srcdir}/regex.tcc \
${bits_srcdir}/random.h \
${bits_srcdir}/random.tcc \
${bits_srcdir}/range_access.h \
+ ${bits_srcdir}/range_cmp.h \
${bits_srcdir}/refwrap.h \
${bits_srcdir}/regex.h \
${bits_srcdir}/regex.tcc \
--- /dev/null
+// Concept-constrained comparison implementations -*- C++ -*-
+
+// Copyright (C) 2019 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/ranges_function.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _RANGE_CMP_H
+#define _RANGE_CMP_H 1
+
+#if __cplusplus > 201703L
+# include <bits/move.h>
+# include <concepts>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ struct __is_transparent; // not defined
+
+ // Define std::identity here so that <iterator> and <ranges>
+ // don't need to include <bits/stl_function.h> to get it.
+
+ /// [func.identity] The identity function.
+ struct identity
+ {
+ template<typename _Tp>
+ constexpr _Tp&&
+ operator()(_Tp&& __t) const noexcept
+ { return std::forward<_Tp>(__t); }
+
+ using is_transparent = __is_transparent;
+ };
+
+namespace ranges
+{
+ namespace __detail
+ {
+ // BUILTIN-PTR-CMP(T, ==, U)
+ template<typename _Tp, typename _Up>
+ concept __eq_builtin_ptr_cmp
+ = 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)
+ template<typename _Tp, typename _Up>
+ concept __less_builtin_ptr_cmp
+ = 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)); });
+ } // namespace __detail
+
+ // [range.cmp] Concept-constrained comparisons
+
+ /// 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>()))
+ { return std::forward<_Tp>(__t) == std::forward<_Up>(__u); }
+
+ using is_transparent = __is_transparent;
+ };
+
+ /// ranges::not_equal_to function object type.
+ struct not_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<_Up>() == std::declval<_Tp>()))
+ { return !equal_to{}(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
+
+ using is_transparent = __is_transparent;
+ };
+
+ /// ranges::less function object type.
+ struct less
+ {
+ 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>()))
+ {
+ if constexpr (__detail::__less_builtin_ptr_cmp<_Tp, _Up>)
+ return std::less<const volatile void*>{}(
+ static_cast<const volatile void*>(std::forward<_Tp>(__t)),
+ static_cast<const volatile void*>(std::forward<_Up>(__u)));
+ return std::forward<_Tp>(__t) < std::forward<_Up>(__u);
+ }
+
+ using is_transparent = __is_transparent;
+ };
+
+ /// ranges::greater function object type.
+ struct greater
+ {
+ 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>()))
+ { return less{}(std::forward<_Up>(__u), std::forward<_Tp>(__t)); }
+
+ using is_transparent = __is_transparent;
+ };
+
+ /// ranges::greater_equal function object type.
+ struct greater_equal
+ {
+ 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>()))
+ { return !less{}(std::forward<_Tp>(__t), std::forward<_Up>(__u)); }
+
+ using is_transparent = __is_transparent;
+ };
+
+ /// ranges::less_equal function object type.
+ struct less_equal
+ {
+ 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>()))
+ { return !less{}(std::forward<_Up>(__u), std::forward<_Tp>(__t)); }
+
+ using is_transparent = __is_transparent;
+ };
+
+} // namespace ranges
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+#endif // _RANGE_CMP_H
# include <utility>
# include <bits/stl_algo.h>
#endif
+#if __cplusplus > 201703L
+# include <bits/range_cmp.h>
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
--- /dev/null
+// Copyright (C) 2019 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 <functional>
+
+// C++20 [func.identity]
+static_assert( std::is_default_constructible_v<std::identity> );
+static_assert( std::is_copy_constructible_v<std::identity> );
+static_assert( std::is_move_constructible_v<std::identity> );
+static_assert( std::is_copy_assignable_v<std::identity> );
+static_assert( std::is_move_assignable_v<std::identity> );
+
+static_assert( !std::is_invocable_v<std::identity> );
+static_assert( !std::is_invocable_v<std::identity, int&, int&> );
+static_assert( std::is_nothrow_invocable_r_v<int&, std::identity&, int&> );
+static_assert( std::is_nothrow_invocable_r_v<const long&, std::identity, const long&> );
+static_assert( std::is_nothrow_invocable_r_v<short&&, const std::identity&, short> );
+static_assert( std::is_nothrow_invocable_r_v<const char&&, const std::identity, const char> );
+
+int i;
+static_assert( std::addressof(std::identity{}(i)) == std::addressof(i) );
+
+using T = std::identity::is_transparent; // required typedef
--- /dev/null
+// Copyright (C) 2019 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 run { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// C++20 [range.cmp]
+
+using F = std::ranges::equal_to;
+static_assert( std::is_default_constructible_v<F> );
+static_assert( std::is_copy_constructible_v<F> );
+static_assert( std::is_move_constructible_v<F> );
+static_assert( std::is_copy_assignable_v<F> );
+static_assert( std::is_move_assignable_v<F> );
+
+static_assert( ! std::is_invocable_v<F> );
+static_assert( ! std::is_invocable_v<F, int&> );
+static_assert( ! std::is_invocable_v<F, int, void> );
+static_assert( ! std::is_invocable_v<F, int, void*> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, int&, int> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F, const long&, char> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F&, short, int&> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F, const char, char> );
+
+using T = F::is_transparent; // required typedef
+
+static_assert( std::ranges::equal_to{}(99, 99.0) );
+static_assert( ! std::ranges::equal_to{}(99, 99.01) );
+static_assert( ! std::ranges::equal_to{}(99, 140L) );
+
+void
+test01()
+{
+ F f;
+ int a[2]{};
+ VERIFY( f(&a, (void*)&a[0]) );
+ VERIFY( ! f(&a, (void*)&a[1]) );
+ VERIFY( f(&a + 1, (void*)(a + 2)) );
+}
+
+struct X { };
+int operator==(X, X) noexcept { return 2; }
+int operator!=(X, X) { return 0; }
+
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, X, X> );
+
+void
+test02()
+{
+ X x;
+ F f;
+ VERIFY( f(x, x) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
--- /dev/null
+// Copyright (C) 2019 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 run { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// C++20 [range.cmp]
+
+using F = std::ranges::greater;
+static_assert( std::is_default_constructible_v<F> );
+static_assert( std::is_copy_constructible_v<F> );
+static_assert( std::is_move_constructible_v<F> );
+static_assert( std::is_copy_assignable_v<F> );
+static_assert( std::is_move_assignable_v<F> );
+
+static_assert( ! std::is_invocable_v<F> );
+static_assert( ! std::is_invocable_v<F, int&> );
+static_assert( ! std::is_invocable_v<F, int, void> );
+static_assert( ! std::is_invocable_v<F, int, void*> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, int&, int> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F, const long&, char> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F&, short, int&> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F, const char, char> );
+
+using T = F::is_transparent; // required typedef
+
+static_assert( ! std::ranges::greater{}(99, 99.0) );
+static_assert( std::ranges::greater{}(99.01, 99) );
+static_assert( std::ranges::greater{}(990, 140L) );
+
+void
+test01()
+{
+ F f;
+ int a[2]{};
+ VERIFY( ! f(&a, (void*)&a[0]) );
+ VERIFY( f((void*)&a[1], &a) );
+ VERIFY( f(&a + 1, (void*)(a + 1)) );
+ VERIFY( ! f(&a, (void*)(a + 1)) );
+}
+
+struct X { };
+int operator==(X, X) { return 2; }
+int operator!=(X, X) { return 0; }
+int operator<(X, X) noexcept { return 0; }
+int operator>(X, X) { return 0; }
+int operator<=(X, X) { return 3; }
+int operator>=(X, X) { return 4; }
+
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, X, X> );
+
+void
+test02()
+{
+ X x;
+ F f;
+ VERIFY( ! f(x, x) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
--- /dev/null
+// Copyright (C) 2019 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 run { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// C++20 [range.cmp]
+
+using F = std::ranges::greater_equal;
+static_assert( std::is_default_constructible_v<F> );
+static_assert( std::is_copy_constructible_v<F> );
+static_assert( std::is_move_constructible_v<F> );
+static_assert( std::is_copy_assignable_v<F> );
+static_assert( std::is_move_assignable_v<F> );
+
+static_assert( ! std::is_invocable_v<F> );
+static_assert( ! std::is_invocable_v<F, int&> );
+static_assert( ! std::is_invocable_v<F, int, void> );
+static_assert( ! std::is_invocable_v<F, int, void*> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, int&, int> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F, const long&, char> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F&, short, int&> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F, const char, char> );
+
+using T = F::is_transparent; // required typedef
+
+static_assert( std::ranges::greater_equal{}(99, 99.0) );
+static_assert( std::ranges::greater_equal{}(99.01, 99) );
+static_assert( ! std::ranges::greater_equal{}(99, 140L) );
+
+void
+test01()
+{
+ F f;
+ int a[2]{};
+ VERIFY( f(&a, (void*)&a[0]) );
+ VERIFY( f((void*)&a[1], &a) );
+ VERIFY( f(&a + 1, (void*)(a + 1)) );
+ VERIFY( ! f(&a, (void*)(a + 1)) );
+}
+
+struct X { };
+int operator==(X, X) { return 2; }
+int operator!=(X, X) { return 0; }
+int operator<(X, X) noexcept { return 0; }
+int operator>(X, X) { return 0; }
+int operator<=(X, X) { return 3; }
+int operator>=(X, X) { return 4; }
+
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, X, X> );
+
+void
+test02()
+{
+ X x;
+ F f;
+ VERIFY( f(x, x) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
--- /dev/null
+// Copyright (C) 2019 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 run { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// C++20 [range.cmp]
+
+using F = std::ranges::less;
+static_assert( std::is_default_constructible_v<F> );
+static_assert( std::is_copy_constructible_v<F> );
+static_assert( std::is_move_constructible_v<F> );
+static_assert( std::is_copy_assignable_v<F> );
+static_assert( std::is_move_assignable_v<F> );
+
+static_assert( ! std::is_invocable_v<F> );
+static_assert( ! std::is_invocable_v<F, int&> );
+static_assert( ! std::is_invocable_v<F, int, void> );
+static_assert( ! std::is_invocable_v<F, int, void*> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, int&, int> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F, const long&, char> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F&, short, int&> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F, const char, char> );
+
+using T = F::is_transparent; // required typedef
+
+static_assert( ! std::ranges::less{}(99, 99.0) );
+static_assert( std::ranges::less{}(99, 99.01) );
+static_assert( std::ranges::less{}(99, 140L) );
+
+void
+test01()
+{
+ F f;
+ int a[2]{};
+ VERIFY( ! f(&a, (void*)&a[0]) );
+ VERIFY( f(&a, (void*)&a[1]) );
+ VERIFY( ! f(&a + 1, (void*)(a + 2)) );
+ VERIFY( f(&a, (void*)(a + 1)) );
+}
+
+struct X { };
+int operator==(X, X) { return 2; }
+int operator!=(X, X) { return 0; }
+int operator<(X, X) noexcept { return 0; }
+int operator>(X, X) { return 0; }
+int operator<=(X, X) { return 3; }
+int operator>=(X, X) { return 4; }
+
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, X, X> );
+
+void
+test02()
+{
+ X x;
+ F f;
+ VERIFY( ! f(x, x) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
--- /dev/null
+// Copyright (C) 2019 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 run { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// C++20 [range.cmp]
+
+using F = std::ranges::less_equal;
+static_assert( std::is_default_constructible_v<F> );
+static_assert( std::is_copy_constructible_v<F> );
+static_assert( std::is_move_constructible_v<F> );
+static_assert( std::is_copy_assignable_v<F> );
+static_assert( std::is_move_assignable_v<F> );
+
+static_assert( ! std::is_invocable_v<F> );
+static_assert( ! std::is_invocable_v<F, int&> );
+static_assert( ! std::is_invocable_v<F, int, void> );
+static_assert( ! std::is_invocable_v<F, int, void*> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, int&, int> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F, const long&, char> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F&, short, int&> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F, const char, char> );
+
+using T = F::is_transparent; // required typedef
+
+static_assert( std::ranges::less_equal{}(99, 99.0) );
+static_assert( ! std::ranges::less_equal{}(99.01, 99) );
+static_assert( std::ranges::less_equal{}(99, 140L) );
+
+void
+test01()
+{
+ F f;
+ int a[2]{};
+ VERIFY( f(&a, (void*)&a[0]) );
+ VERIFY( ! f((void*)&a[1], &a) );
+ VERIFY( ! f(&a + 1, (void*)(a + 1)) );
+ VERIFY( f(&a, (void*)(a + 1)) );
+}
+
+struct X { };
+int operator==(X, X) { return 2; }
+int operator!=(X, X) { return 0; }
+int operator<(X, X) noexcept { return 0; }
+int operator>(X, X) { return 0; }
+int operator<=(X, X) { return 3; }
+int operator>=(X, X) { return 4; }
+
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, X, X> );
+
+void
+test02()
+{
+ X x;
+ F f;
+ VERIFY( f(x, x) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
--- /dev/null
+// Copyright (C) 2019 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 run { target c++2a } }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+// C++20 [range.cmp]
+
+using F = std::ranges::not_equal_to;
+static_assert( std::is_default_constructible_v<F> );
+static_assert( std::is_copy_constructible_v<F> );
+static_assert( std::is_move_constructible_v<F> );
+static_assert( std::is_copy_assignable_v<F> );
+static_assert( std::is_move_assignable_v<F> );
+
+static_assert( ! std::is_invocable_v<F> );
+static_assert( ! std::is_invocable_v<F, int&> );
+static_assert( ! std::is_invocable_v<F, int, void> );
+static_assert( ! std::is_invocable_v<F, int, void*> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, int&, int> );
+static_assert( std::is_nothrow_invocable_r_v<bool, F, const long&, char> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F&, short, int&> );
+static_assert( std::is_nothrow_invocable_r_v<bool, const F, const char, char> );
+
+using T = F::is_transparent; // required typedef
+
+static_assert( ! std::ranges::not_equal_to{}(99, 99.0) );
+static_assert( std::ranges::not_equal_to{}(99, 99.01) );
+static_assert( std::ranges::not_equal_to{}(99, 140L) );
+
+void
+test01()
+{
+ F f;
+ int a[2]{};
+ VERIFY( ! f(&a, (void*)&a[0]) );
+ VERIFY( f(&a, (void*)&a[1]) );
+ VERIFY( ! f(&a + 1, (void*)(a + 2)) );
+}
+
+struct X { };
+int operator==(X, X) noexcept { return 2; }
+int operator!=(X, X) { return 0; }
+
+static_assert( std::is_nothrow_invocable_r_v<bool, F&, X, X> );
+
+void
+test02()
+{
+ X x;
+ F f;
+ VERIFY( ! f(x, x) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}