[libcxx-commits] [libcxx] WIP - [libc++][functional] P2944R3 (partial): Comparisons for ``reference_wrapper`` (``reference_wrapper`` operators only) (PR #88384)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Apr 29 22:54:27 PDT 2024
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/88384
>From d4023142fb3ee65b8e3325a965ddd3270c35eb51 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 11 Apr 2024 10:20:05 +0300
Subject: [PATCH 01/15] [libc++][functional] P2944R3 (partial): Comparisons for
``reference_wrapper`` (``reference_wrapper`` operators only)
Implements parially https://wg21.link/P2944R3
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
libcxx/docs/ReleaseNotes/19.rst | 1 +
libcxx/docs/Status/Cxx2c.rst | 1 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
.../include/__functional/reference_wrapper.h | 52 +++++++++++++++++++
libcxx/include/functional | 9 ++++
libcxx/include/version | 2 +-
.../functional.version.compile.pass.cpp | 16 ++----
.../version.version.compile.pass.cpp | 16 ++----
.../compare.three_way.pass.cpp | 33 ++++++++++++
.../refwrap.comparissons/equal.pass.cpp | 48 +++++++++++++++++
.../generate_feature_test_macro_components.py | 1 -
12 files changed, 157 insertions(+), 26 deletions(-)
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 3197d2cd1b271c..83d8213ec29f9e 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -444,7 +444,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_rcu`` *unimplemented*
---------------------------------------------------------- -----------------
- ``__cpp_lib_reference_wrapper`` *unimplemented*
+ ``__cpp_lib_reference_wrapper`` ``202403L``
---------------------------------------------------------- -----------------
``__cpp_lib_saturation_arithmetic`` ``202311L``
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 53cc7a77d1af48..513852d8c71531 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -46,6 +46,7 @@ Implemented Papers
- P2869R4 - Remove Deprecated ``shared_ptr`` Atomic Access APIs from C++26
- P2872R3 - Remove ``wstring_convert`` From C++26
- P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
+- P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only)
- P2302R4 - ``std::ranges::contains``
- P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
- P3029R1 - Better ``mdspan``'s CTAD
diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst
index a7ebc4662f517c..b6f1714a182a6c 100644
--- a/libcxx/docs/Status/Cxx2c.rst
+++ b/libcxx/docs/Status/Cxx2c.rst
@@ -40,6 +40,7 @@ Paper Status
.. note::
.. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
+ .. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only.
.. _issues-status-cxx2c:
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 1b00a05ad3d6fd..31314a209dfe8d 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -59,7 +59,7 @@
"`P2248R8 <https://wg21.link/P2248R8>`__","LWG","Enabling list-initialization for algorithms","Tokyo March 2024","","",""
"`P2810R4 <https://wg21.link/P2810R4>`__","LWG","``is_debugger_present`` ``is_replaceable``","Tokyo March 2024","","",""
"`P1068R11 <https://wg21.link/P1068R11>`__","LWG","Vector API for random number generation","Tokyo March 2024","","",""
-"`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","","",""
+"`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","|Partial|","19.0",""
"`P2642R6 <https://wg21.link/P2642R6>`__","LWG","Padded ``mdspan`` layouts","Tokyo March 2024","","",""
"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0",""
"","","","","","",""
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index 94b39e3bc78616..8c7ba9e36da094 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -10,11 +10,14 @@
#ifndef _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
#define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
+#include <__compare/synth_three_way.h>
#include <__config>
#include <__functional/invoke.h>
#include <__functional/weak_result_type.h>
#include <__memory/addressof.h>
#include <__type_traits/enable_if.h>
+#include <__type_traits/is_const.h>
+#include <__type_traits/is_convertible.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
@@ -64,6 +67,55 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
{
return std::__invoke(get(), std::forward<_ArgTypes>(__args)...);
}
+
+#if _LIBCPP_STD_VER >= 26
+
+ // [refwrap.comparisons], comparisons
+
+ friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) {
+ // Mandates: The expression x.get() == y.get() is well-formed and its result is convertible to bool.
+ static_assert(is_convertible_v<decltype(__x.get() == __y.get()), bool>);
+
+ return __x.get() == __y.get();
+ }
+
+ friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y) {
+ // Mandates: The expression x.get() == y is well-formed and its result is convertible to bool.
+ static_assert(is_convertible_v<decltype(__x.get() == __y), bool>);
+
+ return __x.get() == __y;
+ }
+
+ friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
+ requires(!is_const_v<_Tp>)
+ {
+ // Constraints: is_const_v<T> is false.
+ // Mandates: The expression x.get() == y.get() is well-formed and its result is convertible to bool.
+ static_assert(is_convertible_v<decltype(__x.get() == __y.get()), bool>);
+
+ return __x.get() == __y.get();
+ }
+
+ friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, reference_wrapper __y) {
+ // return __synth_three_way_result(x.get(), y.get());
+ return std::__synth_three_way(__x.get(), __y.get());
+ }
+
+ friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, const _Tp& __y) {
+ // return __synth_three_way_result(__x.get(), __y);
+ return std::__synth_three_way(__x.get(), __y.get());
+ }
+
+ friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
+ requires(!is_const_v<_Tp>)
+ {
+ // Constraints: is_const_v<T> is false.
+
+ // return __synth_three_way_result(__x.get(), __y.get());
+ return std::__synth_three_way(__x.get(), __y.get());
+ }
+
+#endif // _LIBCPP_STD_VER >= 26
};
#if _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/functional b/libcxx/include/functional
index a2476c93ad1b43..1da953f82241b5 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -77,6 +77,15 @@ template <class T> struct unwrap_ref_decay : unwrap_reference<decay_t<T>> { };
template <class T> using unwrap_reference_t = typename unwrap_reference<T>::type; // since C++20
template <class T> using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type; // since C++20
+// [refwrap.comparisons], comparisons
+friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
+friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
+friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
+
+friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper); // Since C++26
+friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, const T&); // Since C++26
+friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
+
template <class T> // <class T=void> in C++14
struct plus {
T operator()(const T& x, const T& y) const;
diff --git a/libcxx/include/version b/libcxx/include/version
index 0ed77345baa71d..0ce262462eb3ee 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -524,7 +524,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
// # define __cpp_lib_ranges_concat 202403L
# define __cpp_lib_ratio 202306L
// # define __cpp_lib_rcu 202306L
-// # define __cpp_lib_reference_wrapper 202403L
+# define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_saturation_arithmetic 202311L
// # define __cpp_lib_smart_ptr_owner_equality 202306L
# define __cpp_lib_span_at 202311L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index aeb09a30b42591..27e76e5b2b05a3 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -535,17 +535,11 @@
# error "__cpp_lib_ranges should have the value 202207L in c++26"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_reference_wrapper
-# error "__cpp_lib_reference_wrapper should be defined in c++26"
-# endif
-# if __cpp_lib_reference_wrapper != 202403L
-# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_reference_wrapper
-# error "__cpp_lib_reference_wrapper should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_reference_wrapper
+# error "__cpp_lib_reference_wrapper should be defined in c++26"
+# endif
+# if __cpp_lib_reference_wrapper != 202403L
+# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif
# ifndef __cpp_lib_result_of_sfinae
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 3ec548f56cea1d..54fb538680ebad 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -7433,17 +7433,11 @@
# endif
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_reference_wrapper
-# error "__cpp_lib_reference_wrapper should be defined in c++26"
-# endif
-# if __cpp_lib_reference_wrapper != 202403L
-# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_reference_wrapper
-# error "__cpp_lib_reference_wrapper should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_reference_wrapper
+# error "__cpp_lib_reference_wrapper should be defined in c++26"
+# endif
+# if __cpp_lib_reference_wrapper != 202403L
+# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif
# ifndef __cpp_lib_remove_cvref
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
new file mode 100644
index 00000000000000..cbf5d8830200b5
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+
+// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper); // Since C++26
+// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, const T&); // Since C++26
+// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
+
+#include <cassert>
+#include <functional>
+
+#include "test_macros.h"
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
new file mode 100644
index 00000000000000..fb5c122b41d79c
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+// friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
+// friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
+// friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
+
+#include <cassert>
+#include <functional>
+
+#include "test_macros.h"
+
+constexpr bool test() {
+ {
+ int i = 92;
+ std::reference_wrapper<int> lhs{i};
+ std::reference_wrapper<int> rhs = lhs;
+ assert(lhs == rhs);
+ }
+ {
+ int i = 92;
+ std::reference_wrapper<int> lhs{i};
+ int j = 84;
+ std::reference_wrapper<int> rhs{j};
+ assert(lhs != rhs);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index f2b8d55c0e11b0..5f127bd1213c14 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1040,7 +1040,6 @@ def add_version_header(tc):
"name": "__cpp_lib_reference_wrapper",
"values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
"headers": ["functional"],
- "unimplemented": True,
},
{
"name": "__cpp_lib_remove_cvref",
>From 1f22a3347694d06163b4d7ec3bbad1496b5e2bb4 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Thu, 11 Apr 2024 15:31:18 +0300
Subject: [PATCH 02/15] Tests: operator== WIP
---
.../include/__functional/reference_wrapper.h | 11 +---
.../refwrap.comparissons/equal.pass.cpp | 51 +++++++++++++++----
2 files changed, 43 insertions(+), 19 deletions(-)
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index 8c7ba9e36da094..738d57e32efe38 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -73,14 +73,12 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
// [refwrap.comparisons], comparisons
friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) {
- // Mandates: The expression x.get() == y.get() is well-formed and its result is convertible to bool.
static_assert(is_convertible_v<decltype(__x.get() == __y.get()), bool>);
return __x.get() == __y.get();
}
friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y) {
- // Mandates: The expression x.get() == y is well-formed and its result is convertible to bool.
static_assert(is_convertible_v<decltype(__x.get() == __y), bool>);
return __x.get() == __y;
@@ -89,29 +87,22 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
requires(!is_const_v<_Tp>)
{
- // Constraints: is_const_v<T> is false.
- // Mandates: The expression x.get() == y.get() is well-formed and its result is convertible to bool.
static_assert(is_convertible_v<decltype(__x.get() == __y.get()), bool>);
return __x.get() == __y.get();
}
friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, reference_wrapper __y) {
- // return __synth_three_way_result(x.get(), y.get());
return std::__synth_three_way(__x.get(), __y.get());
}
friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, const _Tp& __y) {
- // return __synth_three_way_result(__x.get(), __y);
- return std::__synth_three_way(__x.get(), __y.get());
+ return std::__synth_three_way(__x.get(), __y);
}
friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
requires(!is_const_v<_Tp>)
{
- // Constraints: is_const_v<T> is false.
-
- // return __synth_three_way_result(__x.get(), __y.get());
return std::__synth_three_way(__x.get(), __y.get());
}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index fb5c122b41d79c..9f0d4b7adb5a1a 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -23,18 +23,51 @@
#include "test_macros.h"
constexpr bool test() {
+ int i = 92;
+ int j = 84;
+
+ // ==
+ {
+ // refwrap, refwrap
+ std::reference_wrapper<int> rw1{i};
+ std::reference_wrapper<int> rw2 = rw1;
+ assert(rw1 == rw2);
+ assert(rw2 == rw1);
+ }
+ {
+ // refwrap, const&
+ std::reference_wrapper<int> rw{i};
+ assert(rw == i);
+ assert(i == rw);
+ }
+ {
+ // refwrap, refwrap<const>
+ std::reference_wrapper<int> rw1{i};
+ std::reference_wrapper<const int> rw2 = rw1;
+ assert(rw1 == rw2);
+ assert(rw2 == rw1);
+ }
+
+ // !=
+ {
+ // refwrap, refwrap
+ std::reference_wrapper<int> rw1{i};
+ std::reference_wrapper<int> rw2{j};
+ assert(rw1 != rw2);
+ assert(rw2 != rw1);
+ }
{
- int i = 92;
- std::reference_wrapper<int> lhs{i};
- std::reference_wrapper<int> rhs = lhs;
- assert(lhs == rhs);
+ // refwrap, const&
+ std::reference_wrapper<int> rw{i};
+ assert(rw != j);
+ assert(j != rw);
}
{
- int i = 92;
- std::reference_wrapper<int> lhs{i};
- int j = 84;
- std::reference_wrapper<int> rhs{j};
- assert(lhs != rhs);
+ // refwrap, refwrap<const>
+ std::reference_wrapper<int> rw1{i};
+ std::reference_wrapper<const int> rw2{j};
+ assert(rw1 != rw2);
+ assert(rw2 != rw1);
}
return true;
>From ca199a8cbaa2aa7df76f87120143258bb4a56c2e Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 17 Apr 2024 21:47:54 +0300
Subject: [PATCH 03/15] =?UTF-8?q?Test:=20operator<=3D=3F>=20WIP?=
---
.../compare.three_way.pass.cpp | 36 ++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
index cbf5d8830200b5..bc158c74f3738e 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
@@ -21,9 +21,43 @@
#include <cassert>
#include <functional>
+#include "test_comparisons.h"
#include "test_macros.h"
-constexpr bool test() { return true; }
+template <typename Order>
+constexpr void test() {
+ int integer = 47;
+
+ int bigger = 94;
+ int smaller = 82;
+
+ // Identical contents
+ {
+ std::reference_wrapper<int> rw1{integer};
+ std::reference_wrapper<int> rw2{integer};
+ assert(testOrder(rw1, rw2, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<int> rw1{smaller};
+ std::reference_wrapper<int> rw2{bigger};
+ assert(testOrder(rw1, rw2, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<int> rw1{bigger};
+ std::reference_wrapper<int> rw2{smaller};
+ assert(testOrder(rw1, rw2, Order::greater));
+ }
+}
+
+constexpr bool test() {
+ test<std::strong_ordering>();
+ test<std::weak_ordering>();
+ test<std::partial_ordering>();
+
+ return true;
+}
int main(int, char**) {
test();
>From 24dc20b487405f0ee5e1d5fa616e4be80e232518 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 09:56:14 +0300
Subject: [PATCH 04/15] Implemented https://wg21.link/LWG4071
---
.../include/__functional/reference_wrapper.h | 42 +++++++++++++------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index 738d57e32efe38..04e6fe0c90d968 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -72,36 +72,52 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
// [refwrap.comparisons], comparisons
- friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) {
- static_assert(is_convertible_v<decltype(__x.get() == __y.get()), bool>);
-
+ friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y)
+ requires requires {
+ { __x.get() == __y.get() } -> __boolean_testable;
+ }
+ {
return __x.get() == __y.get();
}
- friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y) {
- static_assert(is_convertible_v<decltype(__x.get() == __y), bool>);
-
+ friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y)
+ requires requires {
+ { __x.get() == __y } -> __boolean_testable;
+ }
+ {
return __x.get() == __y;
}
friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
- requires(!is_const_v<_Tp>)
+ requires(!is_const_v<_Tp>) && requires {
+ { __x.get() == __y.get() } -> __boolean_testable;
+ }
{
- static_assert(is_convertible_v<decltype(__x.get() == __y.get()), bool>);
-
return __x.get() == __y.get();
}
- friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, reference_wrapper __y) {
+ // `operator<=>`: Checks the constraints of `synth-three-way` as per https://wg21.link/LWG4071 directly
+
+ friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper __y)
+ requires requires(const _Tp t) {
+ { t < t } -> __boolean_testable;
+ }
+ {
return std::__synth_three_way(__x.get(), __y.get());
}
- friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, const _Tp& __y) {
+ friend constexpr auto operator<=>(reference_wrapper __x, const _Tp& __y)
+ requires requires(const _Tp t) {
+ { t < t } -> __boolean_testable;
+ }
+ {
return std::__synth_three_way(__x.get(), __y);
}
- friend constexpr __synth_three_way_result<_Tp> operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
- requires(!is_const_v<_Tp>)
+ friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
+ requires(!is_const_v<_Tp>) && requires(const _Tp t) {
+ { t < t } -> __boolean_testable;
+ }
{
return std::__synth_three_way(__x.get(), __y.get());
}
>From f100fa25f95f7f56c9c3fd6c0ff55b6cd0876d47 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 10:34:16 +0300
Subject: [PATCH 05/15] Fixed includes
---
libcxx/include/__functional/reference_wrapper.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index 04e6fe0c90d968..c5e8b88f3fcd0a 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -11,13 +11,13 @@
#define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
#include <__compare/synth_three_way.h>
+#include <__concepts/boolean_testable.h>
#include <__config>
#include <__functional/invoke.h>
#include <__functional/weak_result_type.h>
#include <__memory/addressof.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_const.h>
-#include <__type_traits/is_convertible.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
>From 62541657e553efb46cd5863236e2045c08c8698c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 14:09:43 +0300
Subject: [PATCH 06/15] Tests: WIP SFINAE `operator==`
---
libcxx/docs/Status/Cxx2cIssues.csv | 1 +
.../refwrap.comparissons/equal.pass.cpp | 70 +++++++++++++++----
2 files changed, 58 insertions(+), 13 deletions(-)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 008f7418ab9c05..97257ca48c0b33 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -64,4 +64,5 @@
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
"XXXX","","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0"
+"`4071 <https://wg21.link/LWG4071>`__","","``reference_wrapper`` comparisons are not SFINAE-friendly","Not Yet Adopted","|Complete|","19.0"
"","","","","",""
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 9f0d4b7adb5a1a..1a4516c52f731e 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -18,32 +18,71 @@
// friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
#include <cassert>
+#include <concepts>
#include <functional>
+#include "test_comparisons.h"
#include "test_macros.h"
-constexpr bool test() {
- int i = 92;
- int j = 84;
+// Test SFINAE
+
+struct EqualityComparable {
+ constexpr EqualityComparable(int value) : value_{value} {};
+
+ friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
+
+ int value_;
+};
+
+static_assert(std::equality_comparable<EqualityComparable>);
+static_assert(EqualityComparable{94} == EqualityComparable{94});
+static_assert(EqualityComparable{94} != EqualityComparable{82});
+
+// struct EqualityComparableWith {
+// constexpr EqualityComparableWith(int value) : value_{value} {};
+
+// friend constexpr bool operator==(const EqualityComparableWith&, const EqualityComparableWith&) noexcept = default;
+// friend constexpr bool operator==(const EqualityComparableWith& x, const int& y) noexcept { return x.value_ == y; };
+
+// int value_;
+// };
+
+struct NonComparable {};
+
+static_assert(!std::equality_comparable<NonComparable>);
+
+// struct NonComparableWith {
+// constexpr NonComparableWith(int value);
+// };
+
+static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
+// static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparableWith>, int>);
+static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
+// static_assert(!std::equality_comparable_with<std::reference_wrapper<NonComparableWith>, int>);
+
+template <typename T>
+constexpr void test() {
+ T i{92};
+ T j{84};
// ==
{
// refwrap, refwrap
- std::reference_wrapper<int> rw1{i};
- std::reference_wrapper<int> rw2 = rw1;
+ std::reference_wrapper<T> rw1{i};
+ std::reference_wrapper<T> rw2 = rw1;
assert(rw1 == rw2);
assert(rw2 == rw1);
}
{
// refwrap, const&
- std::reference_wrapper<int> rw{i};
+ std::reference_wrapper<T> rw{i};
assert(rw == i);
assert(i == rw);
}
{
// refwrap, refwrap<const>
- std::reference_wrapper<int> rw1{i};
- std::reference_wrapper<const int> rw2 = rw1;
+ std::reference_wrapper<T> rw1{i};
+ std::reference_wrapper<const T> rw2 = rw1;
assert(rw1 == rw2);
assert(rw2 == rw1);
}
@@ -51,24 +90,29 @@ constexpr bool test() {
// !=
{
// refwrap, refwrap
- std::reference_wrapper<int> rw1{i};
- std::reference_wrapper<int> rw2{j};
+ std::reference_wrapper<T> rw1{i};
+ std::reference_wrapper<T> rw2{j};
assert(rw1 != rw2);
assert(rw2 != rw1);
}
{
// refwrap, const&
- std::reference_wrapper<int> rw{i};
+ std::reference_wrapper<T> rw{i};
assert(rw != j);
assert(j != rw);
}
{
// refwrap, refwrap<const>
- std::reference_wrapper<int> rw1{i};
- std::reference_wrapper<const int> rw2{j};
+ std::reference_wrapper<T> rw1{i};
+ std::reference_wrapper<const T> rw2{j};
assert(rw1 != rw2);
assert(rw2 != rw1);
}
+}
+
+constexpr bool test() {
+ test<int>();
+ test<EqualityComparable>();
return true;
}
>From fc106043db78b710314d6dc1fdc53c630bb7812c Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 14:26:02 +0300
Subject: [PATCH 07/15] Tests: WIP SFINAE `operator<=>`
---
.../compare.three_way.pass.cpp | 44 +++++++++++++------
.../refwrap.comparissons/equal.pass.cpp | 19 ++------
2 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
index bc158c74f3738e..3b14ab8944899c 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
@@ -19,42 +19,60 @@
// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
#include <cassert>
+#include <concepts>
#include <functional>
#include "test_comparisons.h"
#include "test_macros.h"
-template <typename Order>
+struct NonComparable {};
+
+static_assert(!std::three_way_comparable<NonComparable>);
+
+// Test SFINAE.
+
+static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
+static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
+static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);
+
+static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);
+
+// Test comparisons.
+
+template <typename T, typename Order>
constexpr void test() {
- int integer = 47;
+ T t{47};
- int bigger = 94;
- int smaller = 82;
+ T bigger{94};
+ T smaller{82};
// Identical contents
{
- std::reference_wrapper<int> rw1{integer};
- std::reference_wrapper<int> rw2{integer};
+ std::reference_wrapper<T> rw1{t};
+ std::reference_wrapper<T> rw2{t};
assert(testOrder(rw1, rw2, Order::equivalent));
}
// Less
{
- std::reference_wrapper<int> rw1{smaller};
- std::reference_wrapper<int> rw2{bigger};
+ std::reference_wrapper<T> rw1{smaller};
+ std::reference_wrapper<T> rw2{bigger};
assert(testOrder(rw1, rw2, Order::less));
}
// Greater
{
- std::reference_wrapper<int> rw1{bigger};
- std::reference_wrapper<int> rw2{smaller};
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<T> rw2{smaller};
assert(testOrder(rw1, rw2, Order::greater));
}
}
constexpr bool test() {
- test<std::strong_ordering>();
- test<std::weak_ordering>();
- test<std::partial_ordering>();
+ test<int, std::strong_ordering>();
+ test<StrongOrder, std::strong_ordering>();
+ test<int, std::weak_ordering>();
+ test<WeakOrder, std::weak_ordering>();
+ test<int, std::partial_ordering>();
+ test<PartialOrder, std::partial_ordering>();
return true;
}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 1a4516c52f731e..2cd96c7cc9aef2 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -24,7 +24,6 @@
#include "test_comparisons.h"
#include "test_macros.h"
-// Test SFINAE
struct EqualityComparable {
constexpr EqualityComparable(int value) : value_{value} {};
@@ -38,27 +37,17 @@ static_assert(std::equality_comparable<EqualityComparable>);
static_assert(EqualityComparable{94} == EqualityComparable{94});
static_assert(EqualityComparable{94} != EqualityComparable{82});
-// struct EqualityComparableWith {
-// constexpr EqualityComparableWith(int value) : value_{value} {};
-
-// friend constexpr bool operator==(const EqualityComparableWith&, const EqualityComparableWith&) noexcept = default;
-// friend constexpr bool operator==(const EqualityComparableWith& x, const int& y) noexcept { return x.value_ == y; };
-
-// int value_;
-// };
-
struct NonComparable {};
static_assert(!std::equality_comparable<NonComparable>);
-// struct NonComparableWith {
-// constexpr NonComparableWith(int value);
-// };
+// Test SFINAE.
static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
-// static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparableWith>, int>);
+
static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
-// static_assert(!std::equality_comparable_with<std::reference_wrapper<NonComparableWith>, int>);
+
+// Test equality.
template <typename T>
constexpr void test() {
>From 288bbc0d74f00cbf896004b38abb1cdfb3c2f39f Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 14:35:22 +0300
Subject: [PATCH 08/15] Fixed formatting
---
.../function.objects/refwrap/refwrap.comparissons/equal.pass.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 2cd96c7cc9aef2..3681a767e76997 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -24,7 +24,6 @@
#include "test_comparisons.h"
#include "test_macros.h"
-
struct EqualityComparable {
constexpr EqualityComparable(int value) : value_{value} {};
>From a76111bf24c172bcb2456c05381d631d623ac06a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 15:42:04 +0300
Subject: [PATCH 09/15] Tests: WIP `operator<=>`
---
.../compare.three_way.pass.cpp | 68 +++++++++++++++----
.../refwrap.comparissons/equal.pass.cpp | 35 +++++++++-
2 files changed, 89 insertions(+), 14 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
index 3b14ab8944899c..6ea51924b9d7a1 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
@@ -46,23 +46,67 @@ constexpr void test() {
T bigger{94};
T smaller{82};
- // Identical contents
+ // operator<=>(reference_wrapper, reference_wrapper)
{
- std::reference_wrapper<T> rw1{t};
- std::reference_wrapper<T> rw2{t};
- assert(testOrder(rw1, rw2, Order::equivalent));
+ // Identical contents
+ {
+ std::reference_wrapper<T> rw1{t};
+ std::reference_wrapper<T> rw2{t};
+ assert(testOrder(rw1, rw2, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<T> rw1{smaller};
+ std::reference_wrapper<T> rw2{bigger};
+ assert(testOrder(rw1, rw2, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<T> rw2{smaller};
+ assert(testOrder(rw1, rw2, Order::greater));
+ }
}
- // Less
+
+ // operator<=>(reference_wrapper, const T&)
{
- std::reference_wrapper<T> rw1{smaller};
- std::reference_wrapper<T> rw2{bigger};
- assert(testOrder(rw1, rw2, Order::less));
+ // Identical contents
+ {
+ std::reference_wrapper<T> rw1{t};
+ assert(testOrder(rw1, t, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<T> rw1{smaller};
+ assert(testOrder(rw1, bigger, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<T> rw1{bigger};
+ assert(testOrder(rw1, smaller, Order::greater));
+ }
}
- // Greater
+
+ // operator<=>(reference_wrapper, reference_wrapper<const T>)
{
- std::reference_wrapper<T> rw1{bigger};
- std::reference_wrapper<T> rw2{smaller};
- assert(testOrder(rw1, rw2, Order::greater));
+ // Identical contents
+ {
+ std::reference_wrapper<T> rw1{t};
+ std::reference_wrapper<const T> rw2{t};
+ assert(testOrder(rw1, rw2, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<T> rw1{smaller};
+ std::reference_wrapper<const T> rw2{bigger};
+ assert(testOrder(rw1, rw2, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<const T> rw2{smaller};
+ assert(testOrder(rw1, rw2, Order::greater));
+ }
}
}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 3681a767e76997..69ac847ba3e2ff 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -46,6 +46,18 @@ static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable
static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
+// // refwrap, refwrap
+// static_assert(AssertEqualityAreNoexcept<std::reference_wrapper<EqualityComparable>>());
+// static_assert(AssertEqualityReturnBool<std::reference_wrapper<EqualityComparable>>());
+// // refwrap, const&
+// static_assert(AssertEqualityAreNoexcept<std::reference_wrapper<EqualityComparable>, int>());
+// static_assert(AssertEqualityReturnBool<std::reference_wrapper<EqualityComparable>, int>());
+// // refwrap, refwrap<const>
+// static_assert(AssertEqualityAreNoexcept<std::reference_wrapper<EqualityComparable>,
+// std::reference_wrapper<const EqualityComparable>>());
+// static_assert(AssertEqualityReturnBool<std::reference_wrapper<EqualityComparable>,
+// std::reference_wrapper<const EqualityComparable>>());
+
// Test equality.
template <typename T>
@@ -53,29 +65,48 @@ constexpr void test() {
T i{92};
T j{84};
- // ==
+ // `operator==`
{
// refwrap, refwrap
std::reference_wrapper<T> rw1{i};
std::reference_wrapper<T> rw2 = rw1;
+ // std::reference_wrapper<T> rw3{j};
+ // static_assert(AssertEqualityAreNoexcept<decltype(rw1), decltype(rw1)>);
+ // static_assert(AssertEqualityReturnBool<decltype(rw1), decltype(rw1)>);
+ std::same_as<bool> decltype(auto) _ = rw1 == rw1;
+ assert(rw1 == rw1);
+ // static_assert(AssertEqualityAreNoexcept<decltype(rw1), decltype(rw2)>);
+ // static_assert(AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>);
+ std::same_as<bool> decltype(auto) _ = rw1 == rw2;
assert(rw1 == rw2);
+ // static_assert(AssertEqualityAreNoexcept<decltype(rw2), decltype(rw1)>);
+ // static_assert(AssertEqualityReturnBool<decltype(rw2), decltype(rw1)>);
+ std::same_as<bool> decltype(auto) _ = rw2 == rw1;
assert(rw2 == rw1);
}
{
// refwrap, const&
std::reference_wrapper<T> rw{i};
+ // static_assert(AssertEqualityAreNoexcept<decltype(rw), decltype(i)>);
+ // static_assert(AssertEqualityReturnBool<decltype(rw), decltype(i)>);
assert(rw == i);
+ // static_assert(AssertEqualityAreNoexcept<decltype(i), decltype(rw)>);
+ // static_assert(AssertEqualityReturnBool<decltype(i), decltype(rw)>);
assert(i == rw);
}
{
// refwrap, refwrap<const>
std::reference_wrapper<T> rw1{i};
std::reference_wrapper<const T> rw2 = rw1;
+ // static_assert(AssertEqualityAreNoexcept<decltype(rw1), decltype(rw2)>);
+ // static_assert(AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>);
assert(rw1 == rw2);
+ // static_assert(AssertEqualityAreNoexcept<decltype(rw2), decltype(rw1)>);
+ // static_assert(AssertEqualityReturnBool<decltype(rw2), decltype(rw1)>);
assert(rw2 == rw1);
}
- // !=
+ // `operator!=`
{
// refwrap, refwrap
std::reference_wrapper<T> rw1{i};
>From 6ced2a048657f63e9582fb2a981786bf0b26a16f Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 15:46:57 +0300
Subject: [PATCH 10/15] Tests: WIP `operator<=>`
---
.../refwrap.comparissons/equal.pass.cpp | 50 +++++++++----------
1 file changed, 23 insertions(+), 27 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 69ac847ba3e2ff..7b94045925a132 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -46,18 +46,6 @@ static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable
static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
-// // refwrap, refwrap
-// static_assert(AssertEqualityAreNoexcept<std::reference_wrapper<EqualityComparable>>());
-// static_assert(AssertEqualityReturnBool<std::reference_wrapper<EqualityComparable>>());
-// // refwrap, const&
-// static_assert(AssertEqualityAreNoexcept<std::reference_wrapper<EqualityComparable>, int>());
-// static_assert(AssertEqualityReturnBool<std::reference_wrapper<EqualityComparable>, int>());
-// // refwrap, refwrap<const>
-// static_assert(AssertEqualityAreNoexcept<std::reference_wrapper<EqualityComparable>,
-// std::reference_wrapper<const EqualityComparable>>());
-// static_assert(AssertEqualityReturnBool<std::reference_wrapper<EqualityComparable>,
-// std::reference_wrapper<const EqualityComparable>>());
-
// Test equality.
template <typename T>
@@ -70,39 +58,35 @@ constexpr void test() {
// refwrap, refwrap
std::reference_wrapper<T> rw1{i};
std::reference_wrapper<T> rw2 = rw1;
- // std::reference_wrapper<T> rw3{j};
- // static_assert(AssertEqualityAreNoexcept<decltype(rw1), decltype(rw1)>);
- // static_assert(AssertEqualityReturnBool<decltype(rw1), decltype(rw1)>);
+
std::same_as<bool> decltype(auto) _ = rw1 == rw1;
assert(rw1 == rw1);
- // static_assert(AssertEqualityAreNoexcept<decltype(rw1), decltype(rw2)>);
- // static_assert(AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>);
+
std::same_as<bool> decltype(auto) _ = rw1 == rw2;
assert(rw1 == rw2);
- // static_assert(AssertEqualityAreNoexcept<decltype(rw2), decltype(rw1)>);
- // static_assert(AssertEqualityReturnBool<decltype(rw2), decltype(rw1)>);
+
std::same_as<bool> decltype(auto) _ = rw2 == rw1;
assert(rw2 == rw1);
}
{
// refwrap, const&
std::reference_wrapper<T> rw{i};
- // static_assert(AssertEqualityAreNoexcept<decltype(rw), decltype(i)>);
- // static_assert(AssertEqualityReturnBool<decltype(rw), decltype(i)>);
+
+ std::same_as<bool> decltype(auto) _ = rw == i;
assert(rw == i);
- // static_assert(AssertEqualityAreNoexcept<decltype(i), decltype(rw)>);
- // static_assert(AssertEqualityReturnBool<decltype(i), decltype(rw)>);
+
+ std::same_as<bool> decltype(auto) _ = i == rw;
assert(i == rw);
}
{
// refwrap, refwrap<const>
std::reference_wrapper<T> rw1{i};
std::reference_wrapper<const T> rw2 = rw1;
- // static_assert(AssertEqualityAreNoexcept<decltype(rw1), decltype(rw2)>);
- // static_assert(AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>);
+
+ std::same_as<bool> decltype(auto) _ = rw1 == rw2;
assert(rw1 == rw2);
- // static_assert(AssertEqualityAreNoexcept<decltype(rw2), decltype(rw1)>);
- // static_assert(AssertEqualityReturnBool<decltype(rw2), decltype(rw1)>);
+
+ std::same_as<bool> decltype(auto) _ = rw2 == rw1;
assert(rw2 == rw1);
}
@@ -111,20 +95,32 @@ constexpr void test() {
// refwrap, refwrap
std::reference_wrapper<T> rw1{i};
std::reference_wrapper<T> rw2{j};
+
+ std::same_as<bool> decltype(auto) _ = rw1 != rw2;
assert(rw1 != rw2);
+
+ std::same_as<bool> decltype(auto) _ = rw2 != rw1;
assert(rw2 != rw1);
}
{
// refwrap, const&
std::reference_wrapper<T> rw{i};
+
+ std::same_as<bool> decltype(auto) _ = rw != j;
assert(rw != j);
+
+ std::same_as<bool> decltype(auto) _ = j != rw;
assert(j != rw);
}
{
// refwrap, refwrap<const>
std::reference_wrapper<T> rw1{i};
std::reference_wrapper<const T> rw2{j};
+
+ std::same_as<bool> decltype(auto) _ = rw1 != rw2;
assert(rw1 != rw2);
+
+ std::same_as<bool> decltype(auto) _ = rw2 != rw1;
assert(rw2 != rw1);
}
}
>From a61120516306774cf2e24a0694d40a13d0928824 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 16:06:12 +0300
Subject: [PATCH 11/15] Tests: `operator==`
---
.../refwrap.comparissons/equal.pass.cpp | 90 +++++--------------
1 file changed, 20 insertions(+), 70 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 7b94045925a132..28297d7f659a8c 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -53,76 +53,26 @@ constexpr void test() {
T i{92};
T j{84};
- // `operator==`
- {
- // refwrap, refwrap
- std::reference_wrapper<T> rw1{i};
- std::reference_wrapper<T> rw2 = rw1;
-
- std::same_as<bool> decltype(auto) _ = rw1 == rw1;
- assert(rw1 == rw1);
-
- std::same_as<bool> decltype(auto) _ = rw1 == rw2;
- assert(rw1 == rw2);
-
- std::same_as<bool> decltype(auto) _ = rw2 == rw1;
- assert(rw2 == rw1);
- }
- {
- // refwrap, const&
- std::reference_wrapper<T> rw{i};
-
- std::same_as<bool> decltype(auto) _ = rw == i;
- assert(rw == i);
-
- std::same_as<bool> decltype(auto) _ = i == rw;
- assert(i == rw);
- }
- {
- // refwrap, refwrap<const>
- std::reference_wrapper<T> rw1{i};
- std::reference_wrapper<const T> rw2 = rw1;
-
- std::same_as<bool> decltype(auto) _ = rw1 == rw2;
- assert(rw1 == rw2);
-
- std::same_as<bool> decltype(auto) _ = rw2 == rw1;
- assert(rw2 == rw1);
- }
-
- // `operator!=`
- {
- // refwrap, refwrap
- std::reference_wrapper<T> rw1{i};
- std::reference_wrapper<T> rw2{j};
-
- std::same_as<bool> decltype(auto) _ = rw1 != rw2;
- assert(rw1 != rw2);
-
- std::same_as<bool> decltype(auto) _ = rw2 != rw1;
- assert(rw2 != rw1);
- }
- {
- // refwrap, const&
- std::reference_wrapper<T> rw{i};
-
- std::same_as<bool> decltype(auto) _ = rw != j;
- assert(rw != j);
-
- std::same_as<bool> decltype(auto) _ = j != rw;
- assert(j != rw);
- }
- {
- // refwrap, refwrap<const>
- std::reference_wrapper<T> rw1{i};
- std::reference_wrapper<const T> rw2{j};
-
- std::same_as<bool> decltype(auto) _ = rw1 != rw2;
- assert(rw1 != rw2);
-
- std::same_as<bool> decltype(auto) _ = rw2 != rw1;
- assert(rw2 != rw1);
- }
+ std::reference_wrapper<T> rw1{i};
+ std::reference_wrapper<T> rw2 = rw1;
+ std::reference_wrapper<T> rw3{j};
+ std::reference_wrapper<const T> crw1{i};
+ std::reference_wrapper<const T> crw3{j};
+
+ /// refwrap, refwrap
+ AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>();
+ assert(testEquality(rw1, rw2, true));
+ assert(testEquality(rw1, rw3, false));
+
+ // refwrap, const&
+ AssertEqualityReturnBool<decltype(rw1), decltype(i)>();
+ assert(testEquality(rw1, i, true));
+ assert(testEquality(rw1, j, false));
+
+ // refwrap, refwrap<const>
+ AssertEqualityReturnBool<decltype(rw1), decltype(crw1)>();
+ assert(testEquality(rw1, crw1, true));
+ assert(testEquality(rw1, crw3, false));
}
constexpr bool test() {
>From 60a463119490ae35cdb00869a78a72c4e7143838 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 16:19:41 +0300
Subject: [PATCH 12/15] Tests: SFINAE `operator==`
---
.../refwrap/refwrap.comparissons/equal.pass.cpp | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 28297d7f659a8c..9490e7cdf3f7f1 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -42,9 +42,20 @@ static_assert(!std::equality_comparable<NonComparable>);
// Test SFINAE.
+template <typename T>
+concept HasEqualityOperatorWithInt = requires(T t, int i) {
+ { t.get() == i } -> std::convertible_to<bool>;
+};
+
static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
+static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<EqualityComparable>>);
+static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
+ std::reference_wrapper<const EqualityComparable>>);
static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
+static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
+static_assert(!std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
+ std::reference_wrapper<const NonComparable>>);
// Test equality.
>From eb0e7a9e82e38d7db9c48ccea7e1eccd9f3184fd Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Apr 2024 17:34:18 +0300
Subject: [PATCH 13/15] Tests: `operator<=>`
---
.../compare.three_way.pass.cpp | 54 ++++++++++++++++++-
.../refwrap.comparissons/equal.pass.cpp | 6 +++
2 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
index 6ea51924b9d7a1..14fb0efbb2b8dc 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
@@ -31,11 +31,41 @@ static_assert(!std::three_way_comparable<NonComparable>);
// Test SFINAE.
+template <class _Tp>
+concept BooleanTestableImpl = std::convertible_to<_Tp, bool>;
+
+template <class _Tp>
+concept BooleanTestable = BooleanTestableImpl<_Tp> && requires(_Tp&& __t) {
+ { !std::forward<_Tp>(__t) } -> BooleanTestableImpl;
+};
+
+template <typename T>
+concept HasEqualityOperatorWithInt = requires(T t, int i) {
+ { t < i } -> BooleanTestable;
+ { i < t } -> BooleanTestable;
+};
+
+// refwrap, refwrap
static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);
-
+// refwrap, const&
+static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<StrongOrder>>);
+static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<WeakOrder>>);
+static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<PartialOrder>>);
+// refwrap, refwrap<const>
+static_assert(std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const StrongOrder>);
+static_assert(std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const WeakOrder>);
+static_assert(std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const PartialOrder>);
+
+// refwrap, refwrap
static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);
+// refwrap, const&
+static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
+// refwrap, refwrap<const>
+static_assert(!std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const NonComparable>);
+static_assert(!std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const NonComparable>);
+static_assert(!std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const NonComparable>);
// Test comparisons.
@@ -46,6 +76,8 @@ constexpr void test() {
T bigger{94};
T smaller{82};
+ T unordered{std::numeric_limits<int>::min()};
+
// operator<=>(reference_wrapper, reference_wrapper)
{
// Identical contents
@@ -66,6 +98,12 @@ constexpr void test() {
std::reference_wrapper<T> rw2{smaller};
assert(testOrder(rw1, rw2, Order::greater));
}
+ // Unordered
+ if constexpr (std::same_as<T, PartialOrder>) {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<T> rw2{unordered};
+ assert(testOrder(rw1, rw2, Order::unordered));
+ }
}
// operator<=>(reference_wrapper, const T&)
@@ -85,6 +123,11 @@ constexpr void test() {
std::reference_wrapper<T> rw1{bigger};
assert(testOrder(rw1, smaller, Order::greater));
}
+ // Unordered
+ if constexpr (std::same_as<T, PartialOrder>) {
+ std::reference_wrapper<T> rw1{bigger};
+ assert(testOrder(rw1, unordered, Order::unordered));
+ }
}
// operator<=>(reference_wrapper, reference_wrapper<const T>)
@@ -107,6 +150,12 @@ constexpr void test() {
std::reference_wrapper<const T> rw2{smaller};
assert(testOrder(rw1, rw2, Order::greater));
}
+ // Unordered
+ if constexpr (std::same_as<T, PartialOrder>) {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<const T> rw2{unordered};
+ assert(testOrder(rw1, rw2, Order::unordered));
+ }
}
}
@@ -118,6 +167,9 @@ constexpr bool test() {
test<int, std::partial_ordering>();
test<PartialOrder, std::partial_ordering>();
+ // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
+ test<LessAndEqComp, std::weak_ordering>();
+
return true;
}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
index 9490e7cdf3f7f1..117073345813af 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
@@ -47,13 +47,19 @@ concept HasEqualityOperatorWithInt = requires(T t, int i) {
{ t.get() == i } -> std::convertible_to<bool>;
};
+// refwrap, refwrap
static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
+// refwrap, const&
static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<EqualityComparable>>);
+// refwrap, refwrap<const>
static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
std::reference_wrapper<const EqualityComparable>>);
+// refwrap, refwrap
static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
+// refwrap, const&
static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
+// refwrap, refwrap<const>
static_assert(!std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
std::reference_wrapper<const NonComparable>>);
>From 13c345dc2e3484645fb897eba517f4fdbba017ed Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Fri, 26 Apr 2024 21:56:26 +0300
Subject: [PATCH 14/15] Addressed some review comments
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
.../include/__functional/reference_wrapper.h | 24 ++++++++---------
libcxx/include/functional | 12 ++++-----
libcxx/include/version | 2 +-
.../functional.version.compile.pass.cpp | 16 ++++++++----
.../version.version.compile.pass.cpp | 16 ++++++++----
.../compare.three_way.pass.cpp | 26 +++++++++----------
.../generate_feature_test_macro_components.py | 1 +
9 files changed, 57 insertions(+), 44 deletions(-)
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 83d8213ec29f9e..3197d2cd1b271c 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -444,7 +444,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_rcu`` *unimplemented*
---------------------------------------------------------- -----------------
- ``__cpp_lib_reference_wrapper`` ``202403L``
+ ``__cpp_lib_reference_wrapper`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_saturation_arithmetic`` ``202311L``
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 31314a209dfe8d..c6dd0cae5b09af 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -59,7 +59,7 @@
"`P2248R8 <https://wg21.link/P2248R8>`__","LWG","Enabling list-initialization for algorithms","Tokyo March 2024","","",""
"`P2810R4 <https://wg21.link/P2810R4>`__","LWG","``is_debugger_present`` ``is_replaceable``","Tokyo March 2024","","",""
"`P1068R11 <https://wg21.link/P1068R11>`__","LWG","Vector API for random number generation","Tokyo March 2024","","",""
-"`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","|Partial|","19.0",""
+"`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","|Partial| [#note-P2944R3]_","19.0",""
"`P2642R6 <https://wg21.link/P2642R6>`__","LWG","Padded ``mdspan`` layouts","Tokyo March 2024","","",""
"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0",""
"","","","","","",""
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index c5e8b88f3fcd0a..0d05a4f883970b 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -72,7 +72,7 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
// [refwrap.comparisons], comparisons
- friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y)
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y)
requires requires {
{ __x.get() == __y.get() } -> __boolean_testable;
}
@@ -80,7 +80,7 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
return __x.get() == __y.get();
}
- friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y)
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y)
requires requires {
{ __x.get() == __y } -> __boolean_testable;
}
@@ -88,7 +88,7 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
return __x.get() == __y;
}
- friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
requires(!is_const_v<_Tp>) && requires {
{ __x.get() == __y.get() } -> __boolean_testable;
}
@@ -98,25 +98,25 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
// `operator<=>`: Checks the constraints of `synth-three-way` as per https://wg21.link/LWG4071 directly
- friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper __y)
- requires requires(const _Tp t) {
- { t < t } -> __boolean_testable;
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper __y)
+ requires requires(const _Tp __t) {
+ { __t < __t } -> __boolean_testable;
}
{
return std::__synth_three_way(__x.get(), __y.get());
}
- friend constexpr auto operator<=>(reference_wrapper __x, const _Tp& __y)
- requires requires(const _Tp t) {
- { t < t } -> __boolean_testable;
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, const _Tp& __y)
+ requires requires(const _Tp __t) {
+ { __t < __t } -> __boolean_testable;
}
{
return std::__synth_three_way(__x.get(), __y);
}
- friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
- requires(!is_const_v<_Tp>) && requires(const _Tp t) {
- { t < t } -> __boolean_testable;
+ _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
+ requires(!is_const_v<_Tp>) && requires(const _Tp __t) {
+ { __t < __t } -> __boolean_testable;
}
{
return std::__synth_three_way(__x.get(), __y.get());
diff --git a/libcxx/include/functional b/libcxx/include/functional
index 1da953f82241b5..27cf21e1a4c8bd 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -78,13 +78,13 @@ template <class T> using unwrap_reference_t = typename unwrap_reference<T>::type
template <class T> using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type; // since C++20
// [refwrap.comparisons], comparisons
-friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
-friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
-friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
+friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
+friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
+friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
-friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper); // Since C++26
-friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, const T&); // Since C++26
-friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
+friend constexpr auto operator<=>(reference_wrapper, reference_wrapper); // Since C++26
+friend constexpr auto operator<=>(reference_wrapper, const T&); // Since C++26
+friend constexpr auto operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
template <class T> // <class T=void> in C++14
struct plus {
diff --git a/libcxx/include/version b/libcxx/include/version
index 0ce262462eb3ee..0ed77345baa71d 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -524,7 +524,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
// # define __cpp_lib_ranges_concat 202403L
# define __cpp_lib_ratio 202306L
// # define __cpp_lib_rcu 202306L
-# define __cpp_lib_reference_wrapper 202403L
+// # define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_saturation_arithmetic 202311L
// # define __cpp_lib_smart_ptr_owner_equality 202306L
# define __cpp_lib_span_at 202311L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index 27e76e5b2b05a3..aeb09a30b42591 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -535,11 +535,17 @@
# error "__cpp_lib_ranges should have the value 202207L in c++26"
# endif
-# ifndef __cpp_lib_reference_wrapper
-# error "__cpp_lib_reference_wrapper should be defined in c++26"
-# endif
-# if __cpp_lib_reference_wrapper != 202403L
-# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
+# if !defined(_LIBCPP_VERSION)
+# ifndef __cpp_lib_reference_wrapper
+# error "__cpp_lib_reference_wrapper should be defined in c++26"
+# endif
+# if __cpp_lib_reference_wrapper != 202403L
+# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
+# endif
+# else // _LIBCPP_VERSION
+# ifdef __cpp_lib_reference_wrapper
+# error "__cpp_lib_reference_wrapper should not be defined because it is unimplemented in libc++!"
+# endif
# endif
# ifndef __cpp_lib_result_of_sfinae
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 54fb538680ebad..3ec548f56cea1d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -7433,11 +7433,17 @@
# endif
# endif
-# ifndef __cpp_lib_reference_wrapper
-# error "__cpp_lib_reference_wrapper should be defined in c++26"
-# endif
-# if __cpp_lib_reference_wrapper != 202403L
-# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
+# if !defined(_LIBCPP_VERSION)
+# ifndef __cpp_lib_reference_wrapper
+# error "__cpp_lib_reference_wrapper should be defined in c++26"
+# endif
+# if __cpp_lib_reference_wrapper != 202403L
+# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
+# endif
+# else // _LIBCPP_VERSION
+# ifdef __cpp_lib_reference_wrapper
+# error "__cpp_lib_reference_wrapper should not be defined because it is unimplemented in libc++!"
+# endif
# endif
# ifndef __cpp_lib_remove_cvref
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
index 14fb0efbb2b8dc..b2c6428872f5b0 100644
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
@@ -14,9 +14,9 @@
// // [refwrap.comparisons], comparisons
-// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper); // Since C++26
-// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, const T&); // Since C++26
-// friend constexpr synth-three-way-result<T> operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
+// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper); // Since C++26
+// friend constexpr auto operator<=>(reference_wrapper, const T&); // Since C++26
+// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
#include <cassert>
#include <concepts>
@@ -31,16 +31,16 @@ static_assert(!std::three_way_comparable<NonComparable>);
// Test SFINAE.
-template <class _Tp>
-concept BooleanTestableImpl = std::convertible_to<_Tp, bool>;
+template <class T>
+concept BooleanTestableImpl = std::convertible_to<T, bool>;
-template <class _Tp>
-concept BooleanTestable = BooleanTestableImpl<_Tp> && requires(_Tp&& __t) {
- { !std::forward<_Tp>(__t) } -> BooleanTestableImpl;
+template <class T>
+concept BooleanTestable = BooleanTestableImpl<T> && requires(T&& t) {
+ { !std::forward<T>(t) } -> BooleanTestableImpl;
};
template <typename T>
-concept HasEqualityOperatorWithInt = requires(T t, int i) {
+concept HasSpaceshipOperatorWithInt = requires(T t, int i) {
{ t < i } -> BooleanTestable;
{ i < t } -> BooleanTestable;
};
@@ -50,9 +50,9 @@ static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);
// refwrap, const&
-static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<StrongOrder>>);
-static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<WeakOrder>>);
-static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<PartialOrder>>);
+static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<StrongOrder>>);
+static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<WeakOrder>>);
+static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<PartialOrder>>);
// refwrap, refwrap<const>
static_assert(std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const StrongOrder>);
static_assert(std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const WeakOrder>);
@@ -61,7 +61,7 @@ static_assert(std::three_way_comparable_with<std::reference_wrapper<PartialOrder
// refwrap, refwrap
static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);
// refwrap, const&
-static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
+static_assert(!HasSpaceshipOperatorWithInt<std::reference_wrapper<NonComparable>>);
// refwrap, refwrap<const>
static_assert(!std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const NonComparable>);
static_assert(!std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const NonComparable>);
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 5f127bd1213c14..f2b8d55c0e11b0 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1040,6 +1040,7 @@ def add_version_header(tc):
"name": "__cpp_lib_reference_wrapper",
"values": {"c++26": 202403}, # P2944R3: Comparisons for reference_wrapper
"headers": ["functional"],
+ "unimplemented": True,
},
{
"name": "__cpp_lib_remove_cvref",
>From 532c6d659892bb9a23be3dd7d614bf981aa9d5f2 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Tue, 30 Apr 2024 08:49:23 +0300
Subject: [PATCH 15/15] Split tests: one test per overload
---
.../compare.three_way.pass.cpp | 181 ------------------
...mpare.three_way.refwrap.const_ref.pass.cpp | 89 +++++++++
...compare.three_way.refwrap.refwrap.pass.cpp | 93 +++++++++
...e.three_way.refwrap.refwrap_const.pass.cpp | 95 +++++++++
.../refwrap.comparissons/equal.pass.cpp | 107 -----------
.../equal.refwrap.const_ref.pass.cpp | 62 ++++++
.../equal.refwrap.refwrap.pass.cpp | 64 +++++++
.../equal.refwrap.refwrap_const.pass.cpp | 67 +++++++
.../refwrap.comparissons/helper_concepts.h | 38 ++++
.../refwrap.comparissons/helper_types.h | 30 +++
10 files changed, 538 insertions(+), 288 deletions(-)
delete mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp
delete mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h
create mode 100644 libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
deleted file mode 100644
index b2c6428872f5b0..00000000000000
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.pass.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
-
-// <functional>
-
-// class reference_wrapper
-
-// // [refwrap.comparisons], comparisons
-
-// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper); // Since C++26
-// friend constexpr auto operator<=>(reference_wrapper, const T&); // Since C++26
-// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
-
-#include <cassert>
-#include <concepts>
-#include <functional>
-
-#include "test_comparisons.h"
-#include "test_macros.h"
-
-struct NonComparable {};
-
-static_assert(!std::three_way_comparable<NonComparable>);
-
-// Test SFINAE.
-
-template <class T>
-concept BooleanTestableImpl = std::convertible_to<T, bool>;
-
-template <class T>
-concept BooleanTestable = BooleanTestableImpl<T> && requires(T&& t) {
- { !std::forward<T>(t) } -> BooleanTestableImpl;
-};
-
-template <typename T>
-concept HasSpaceshipOperatorWithInt = requires(T t, int i) {
- { t < i } -> BooleanTestable;
- { i < t } -> BooleanTestable;
-};
-
-// refwrap, refwrap
-static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
-static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
-static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);
-// refwrap, const&
-static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<StrongOrder>>);
-static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<WeakOrder>>);
-static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<PartialOrder>>);
-// refwrap, refwrap<const>
-static_assert(std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const StrongOrder>);
-static_assert(std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const WeakOrder>);
-static_assert(std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const PartialOrder>);
-
-// refwrap, refwrap
-static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);
-// refwrap, const&
-static_assert(!HasSpaceshipOperatorWithInt<std::reference_wrapper<NonComparable>>);
-// refwrap, refwrap<const>
-static_assert(!std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const NonComparable>);
-static_assert(!std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const NonComparable>);
-static_assert(!std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const NonComparable>);
-
-// Test comparisons.
-
-template <typename T, typename Order>
-constexpr void test() {
- T t{47};
-
- T bigger{94};
- T smaller{82};
-
- T unordered{std::numeric_limits<int>::min()};
-
- // operator<=>(reference_wrapper, reference_wrapper)
- {
- // Identical contents
- {
- std::reference_wrapper<T> rw1{t};
- std::reference_wrapper<T> rw2{t};
- assert(testOrder(rw1, rw2, Order::equivalent));
- }
- // Less
- {
- std::reference_wrapper<T> rw1{smaller};
- std::reference_wrapper<T> rw2{bigger};
- assert(testOrder(rw1, rw2, Order::less));
- }
- // Greater
- {
- std::reference_wrapper<T> rw1{bigger};
- std::reference_wrapper<T> rw2{smaller};
- assert(testOrder(rw1, rw2, Order::greater));
- }
- // Unordered
- if constexpr (std::same_as<T, PartialOrder>) {
- std::reference_wrapper<T> rw1{bigger};
- std::reference_wrapper<T> rw2{unordered};
- assert(testOrder(rw1, rw2, Order::unordered));
- }
- }
-
- // operator<=>(reference_wrapper, const T&)
- {
- // Identical contents
- {
- std::reference_wrapper<T> rw1{t};
- assert(testOrder(rw1, t, Order::equivalent));
- }
- // Less
- {
- std::reference_wrapper<T> rw1{smaller};
- assert(testOrder(rw1, bigger, Order::less));
- }
- // Greater
- {
- std::reference_wrapper<T> rw1{bigger};
- assert(testOrder(rw1, smaller, Order::greater));
- }
- // Unordered
- if constexpr (std::same_as<T, PartialOrder>) {
- std::reference_wrapper<T> rw1{bigger};
- assert(testOrder(rw1, unordered, Order::unordered));
- }
- }
-
- // operator<=>(reference_wrapper, reference_wrapper<const T>)
- {
- // Identical contents
- {
- std::reference_wrapper<T> rw1{t};
- std::reference_wrapper<const T> rw2{t};
- assert(testOrder(rw1, rw2, Order::equivalent));
- }
- // Less
- {
- std::reference_wrapper<T> rw1{smaller};
- std::reference_wrapper<const T> rw2{bigger};
- assert(testOrder(rw1, rw2, Order::less));
- }
- // Greater
- {
- std::reference_wrapper<T> rw1{bigger};
- std::reference_wrapper<const T> rw2{smaller};
- assert(testOrder(rw1, rw2, Order::greater));
- }
- // Unordered
- if constexpr (std::same_as<T, PartialOrder>) {
- std::reference_wrapper<T> rw1{bigger};
- std::reference_wrapper<const T> rw2{unordered};
- assert(testOrder(rw1, rw2, Order::unordered));
- }
- }
-}
-
-constexpr bool test() {
- test<int, std::strong_ordering>();
- test<StrongOrder, std::strong_ordering>();
- test<int, std::weak_ordering>();
- test<WeakOrder, std::weak_ordering>();
- test<int, std::partial_ordering>();
- test<PartialOrder, std::partial_ordering>();
-
- // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
- test<LessAndEqComp, std::weak_ordering>();
-
- return true;
-}
-
-int main(int, char**) {
- test();
- static_assert(test());
-
- return 0;
-}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp
new file mode 100644
index 00000000000000..cbfff337adec95
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.const_ref.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+
+// friend constexpr auto operator<=>(reference_wrapper, const T&); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+#include "helper_concepts.h"
+#include "helper_types.h"
+
+// Test SFINAE.
+
+static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<StrongOrder>>);
+static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<WeakOrder>>);
+static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<PartialOrder>>);
+
+static_assert(!HasSpaceshipOperatorWithInt<std::reference_wrapper<NonComparable>>);
+
+// Test comparisons.
+
+template <typename T, typename Order>
+constexpr void test() {
+ T t{47};
+
+ T bigger{94};
+ T smaller{82};
+
+ T unordered{std::numeric_limits<int>::min()};
+
+ // Identical contents
+ {
+ std::reference_wrapper<T> rw1{t};
+ assert(testOrder(rw1, t, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<T> rw1{smaller};
+ assert(testOrder(rw1, bigger, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<T> rw1{bigger};
+ assert(testOrder(rw1, smaller, Order::greater));
+ }
+ // Unordered
+ if constexpr (std::same_as<T, PartialOrder>) {
+ std::reference_wrapper<T> rw1{bigger};
+ assert(testOrder(rw1, unordered, Order::unordered));
+ }
+}
+
+constexpr bool test() {
+ test<int, std::strong_ordering>();
+ test<StrongOrder, std::strong_ordering>();
+ test<int, std::weak_ordering>();
+ test<WeakOrder, std::weak_ordering>();
+ test<int, std::partial_ordering>();
+ test<PartialOrder, std::partial_ordering>();
+
+ // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
+ test<LessAndEqComp, std::weak_ordering>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp
new file mode 100644
index 00000000000000..bb9974494a1a28
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap.pass.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+
+// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+#include "helper_concepts.h"
+#include "helper_types.h"
+
+// Test SFINAE.
+
+static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
+static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
+static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);
+
+static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);
+
+// Test comparisons.
+
+template <typename T, typename Order>
+constexpr void test() {
+ T t{47};
+
+ T bigger{94};
+ T smaller{82};
+
+ T unordered{std::numeric_limits<int>::min()};
+
+ // Identical contents
+ {
+ std::reference_wrapper<T> rw1{t};
+ std::reference_wrapper<T> rw2{t};
+ assert(testOrder(rw1, rw2, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<T> rw1{smaller};
+ std::reference_wrapper<T> rw2{bigger};
+ assert(testOrder(rw1, rw2, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<T> rw2{smaller};
+ assert(testOrder(rw1, rw2, Order::greater));
+ }
+ // Unordered
+ if constexpr (std::same_as<T, PartialOrder>) {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<T> rw2{unordered};
+ assert(testOrder(rw1, rw2, Order::unordered));
+ }
+}
+
+constexpr bool test() {
+ test<int, std::strong_ordering>();
+ test<StrongOrder, std::strong_ordering>();
+ test<int, std::weak_ordering>();
+ test<WeakOrder, std::weak_ordering>();
+ test<int, std::partial_ordering>();
+ test<PartialOrder, std::partial_ordering>();
+
+ // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
+ test<LessAndEqComp, std::weak_ordering>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp
new file mode 100644
index 00000000000000..1f2c6477868204
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/compare.three_way.refwrap.refwrap_const.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+
+// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+#include "helper_concepts.h"
+#include "helper_types.h"
+
+// Test SFINAE.
+
+static_assert(std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const StrongOrder>);
+static_assert(std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const WeakOrder>);
+static_assert(std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const PartialOrder>);
+
+static_assert(!std::three_way_comparable_with<std::reference_wrapper<StrongOrder>, const NonComparable>);
+static_assert(!std::three_way_comparable_with<std::reference_wrapper<WeakOrder>, const NonComparable>);
+static_assert(!std::three_way_comparable_with<std::reference_wrapper<PartialOrder>, const NonComparable>);
+
+// Test comparisons.
+
+template <typename T, typename Order>
+constexpr void test() {
+ T t{47};
+
+ T bigger{94};
+ T smaller{82};
+
+ T unordered{std::numeric_limits<int>::min()};
+
+ // Identical contents
+ {
+ std::reference_wrapper<T> rw1{t};
+ std::reference_wrapper<const T> rw2{t};
+ assert(testOrder(rw1, rw2, Order::equivalent));
+ }
+ // Less
+ {
+ std::reference_wrapper<T> rw1{smaller};
+ std::reference_wrapper<const T> rw2{bigger};
+ assert(testOrder(rw1, rw2, Order::less));
+ }
+ // Greater
+ {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<const T> rw2{smaller};
+ assert(testOrder(rw1, rw2, Order::greater));
+ }
+ // Unordered
+ if constexpr (std::same_as<T, PartialOrder>) {
+ std::reference_wrapper<T> rw1{bigger};
+ std::reference_wrapper<const T> rw2{unordered};
+ assert(testOrder(rw1, rw2, Order::unordered));
+ }
+}
+
+constexpr bool test() {
+ test<int, std::strong_ordering>();
+ test<StrongOrder, std::strong_ordering>();
+ test<int, std::weak_ordering>();
+ test<WeakOrder, std::weak_ordering>();
+ test<int, std::partial_ordering>();
+ test<PartialOrder, std::partial_ordering>();
+
+ // `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
+ test<LessAndEqComp, std::weak_ordering>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
deleted file mode 100644
index 117073345813af..00000000000000
--- a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.pass.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
-
-// <functional>
-
-// class reference_wrapper
-
-// // [refwrap.comparisons], comparisons
-// friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
-// friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
-// friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
-
-#include <cassert>
-#include <concepts>
-#include <functional>
-
-#include "test_comparisons.h"
-#include "test_macros.h"
-
-struct EqualityComparable {
- constexpr EqualityComparable(int value) : value_{value} {};
-
- friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
-
- int value_;
-};
-
-static_assert(std::equality_comparable<EqualityComparable>);
-static_assert(EqualityComparable{94} == EqualityComparable{94});
-static_assert(EqualityComparable{94} != EqualityComparable{82});
-
-struct NonComparable {};
-
-static_assert(!std::equality_comparable<NonComparable>);
-
-// Test SFINAE.
-
-template <typename T>
-concept HasEqualityOperatorWithInt = requires(T t, int i) {
- { t.get() == i } -> std::convertible_to<bool>;
-};
-
-// refwrap, refwrap
-static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
-// refwrap, const&
-static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<EqualityComparable>>);
-// refwrap, refwrap<const>
-static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
- std::reference_wrapper<const EqualityComparable>>);
-
-// refwrap, refwrap
-static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
-// refwrap, const&
-static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
-// refwrap, refwrap<const>
-static_assert(!std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
- std::reference_wrapper<const NonComparable>>);
-
-// Test equality.
-
-template <typename T>
-constexpr void test() {
- T i{92};
- T j{84};
-
- std::reference_wrapper<T> rw1{i};
- std::reference_wrapper<T> rw2 = rw1;
- std::reference_wrapper<T> rw3{j};
- std::reference_wrapper<const T> crw1{i};
- std::reference_wrapper<const T> crw3{j};
-
- /// refwrap, refwrap
- AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>();
- assert(testEquality(rw1, rw2, true));
- assert(testEquality(rw1, rw3, false));
-
- // refwrap, const&
- AssertEqualityReturnBool<decltype(rw1), decltype(i)>();
- assert(testEquality(rw1, i, true));
- assert(testEquality(rw1, j, false));
-
- // refwrap, refwrap<const>
- AssertEqualityReturnBool<decltype(rw1), decltype(crw1)>();
- assert(testEquality(rw1, crw1, true));
- assert(testEquality(rw1, crw3, false));
-}
-
-constexpr bool test() {
- test<int>();
- test<EqualityComparable>();
-
- return true;
-}
-
-int main(int, char**) {
- test();
- static_assert(test());
-
- return 0;
-}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp
new file mode 100644
index 00000000000000..97dfb8de0a3c4b
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.const_ref.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+
+// friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+#include "helper_concepts.h"
+#include "helper_types.h"
+
+// Test SFINAE.
+
+static_assert(HasEqualityOperatorWithInt<std::reference_wrapper<EqualityComparable>>);
+
+static_assert(!HasEqualityOperatorWithInt<std::reference_wrapper<NonComparable>>);
+
+// Test equality.
+
+template <typename T>
+constexpr void test() {
+ T i{92};
+ T j{84};
+
+ std::reference_wrapper<T> rw1{i};
+
+ // refwrap, const&
+ AssertEqualityReturnBool<decltype(rw1), decltype(i)>();
+ assert(testEquality(rw1, i, true));
+ assert(testEquality(rw1, j, false));
+}
+
+constexpr bool test() {
+ test<int>();
+ test<EqualityComparable>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp
new file mode 100644
index 00000000000000..913ff66e629422
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+// friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+#include "helper_concepts.h"
+#include "helper_types.h"
+
+// Test SFINAE.
+
+static_assert(std::equality_comparable<std::reference_wrapper<EqualityComparable>>);
+
+static_assert(!std::equality_comparable<std::reference_wrapper<NonComparable>>);
+
+// Test equality.
+
+template <typename T>
+constexpr void test() {
+ T i{92};
+ T j{84};
+
+ std::reference_wrapper<T> rw1{i};
+ std::reference_wrapper<T> rw2 = rw1;
+ std::reference_wrapper<T> rw3{j};
+ std::reference_wrapper<const T> crw1{i};
+ std::reference_wrapper<const T> crw3{j};
+
+ AssertEqualityReturnBool<decltype(rw1), decltype(rw2)>();
+ assert(testEquality(rw1, rw2, true));
+ assert(testEquality(rw1, rw3, false));
+}
+
+constexpr bool test() {
+ test<int>();
+ test<EqualityComparable>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp
new file mode 100644
index 00000000000000..90650b487497a0
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/equal.refwrap.refwrap_const.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <functional>
+
+// class reference_wrapper
+
+// // [refwrap.comparisons], comparisons
+
+// friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+#include "helper_concepts.h"
+#include "helper_types.h"
+
+// Test SFINAE.
+
+static_assert(std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
+ std::reference_wrapper<const EqualityComparable>>);
+
+static_assert(!std::equality_comparable_with<std::reference_wrapper<EqualityComparable>,
+ std::reference_wrapper<const NonComparable>>);
+
+// Test equality.
+
+template <typename T>
+constexpr void test() {
+ T i{92};
+ T j{84};
+
+ std::reference_wrapper<T> rw1{i};
+
+ std::reference_wrapper<T> rw3{j};
+ std::reference_wrapper<const T> crw1{i};
+ std::reference_wrapper<const T> crw3{j};
+
+ AssertEqualityReturnBool<decltype(rw1), decltype(crw1)>();
+ assert(testEquality(rw1, crw1, true));
+ assert(testEquality(rw1, crw3, false));
+}
+
+constexpr bool test() {
+ test<int>();
+ test<EqualityComparable>();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h
new file mode 100644
index 00000000000000..2dbb304f8af638
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_concepts.h
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H
+#define TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H
+
+#include <concepts>
+#include <utility>
+
+// Equality
+
+template <typename T>
+concept HasEqualityOperatorWithInt = requires(T t, int i) {
+ { t.get() == i } -> std::convertible_to<bool>;
+};
+
+// Spaceship
+
+template <class T>
+concept BooleanTestableImpl = std::convertible_to<T, bool>;
+
+template <class T>
+concept BooleanTestable = BooleanTestableImpl<T> && requires(T&& t) {
+ { !std::forward<T>(t) } -> BooleanTestableImpl;
+};
+
+template <typename T>
+concept HasSpaceshipOperatorWithInt = requires(T t, int i) {
+ { t < i } -> BooleanTestable;
+ { i < t } -> BooleanTestable;
+};
+
+#endif // TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_CONCEPTS_H
diff --git a/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h
new file mode 100644
index 00000000000000..cf5e568dbf9360
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/refwrap/refwrap.comparissons/helper_types.h
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H
+#define TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H
+
+#include <concepts>
+
+struct EqualityComparable {
+ constexpr EqualityComparable(int value) : value_{value} {};
+
+ friend constexpr bool operator==(const EqualityComparable&, const EqualityComparable&) noexcept = default;
+
+ int value_;
+};
+
+static_assert(std::equality_comparable<EqualityComparable>);
+static_assert(EqualityComparable{94} == EqualityComparable{94});
+static_assert(EqualityComparable{94} != EqualityComparable{82});
+
+struct NonComparable {};
+
+static_assert(!std::three_way_comparable<NonComparable>);
+
+#endif // TEST_STD_FUNCTIONOBJECTS_REFWRAP_HELPER_TYPES_H
More information about the libcxx-commits
mailing list