Skip to content

[libc++][concepts] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with#99420

Merged
frederick-vs-ja merged 21 commits intollvm:mainfrom
randomnetcat:p2404
Dec 19, 2025
Merged

[libc++][concepts] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with#99420
frederick-vs-ja merged 21 commits intollvm:mainfrom
randomnetcat:p2404

Conversation

@randomnetcat
Copy link
Contributor

@randomnetcat randomnetcat commented Jul 18, 2024

This implements all of P2404R3's concept changes.

Fixes #105210.

@randomnetcat randomnetcat requested a review from a team as a code owner July 18, 2024 02:54
@github-actions
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jul 18, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2024

@llvm/pr-subscribers-libcxx

Author: Janet Cobb (randomnetcat)

Changes

This should implement all of P2404R3's concept changes.

This would be my first contribution, so I apologize if I've done anything wrong here.


Full diff: https://github.com/llvm/llvm-project/pull/99420.diff

11 Files Affected:

  • (modified) libcxx/docs/ReleaseNotes/19.rst (+1)
  • (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1)
  • (modified) libcxx/docs/Status/SpaceshipPapers.csv (+1-1)
  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (modified) libcxx/include/__compare/three_way_comparable.h (+17)
  • (added) libcxx/include/__concepts/comparison_common_type.h (+39)
  • (modified) libcxx/include/__concepts/equality_comparable.h (+19)
  • (modified) libcxx/include/module.modulemap (+23-22)
  • (modified) libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp (+10)
  • (modified) libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp (+28)
  • (modified) libcxx/test/support/compare_types.h (+23)
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index e6d8acb74aeb2..1699c97652488 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -55,6 +55,7 @@ Implemented Papers
 - P2231R1 - Missing ``constexpr`` in ``std::optional`` and ``std::variant``
 - P0019R8 - ``std::atomic_ref``
 - P2389R2 - Alias template ``dims`` for the ``extents`` of ``mdspan``
+- P2404R3 - Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 4f589cd938d7c..bc13e4d9ebfd3 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -67,7 +67,7 @@
 "`P2302R4 <https://wg21.link/P2302R4>`__","LWG","``std::ranges::contains``","July 2022","|Complete|","19.0","|ranges|"
 "`P2322R6 <https://wg21.link/P2322R6>`__","LWG","``ranges::fold``","July 2022","","","|ranges|"
 "`P2374R4 <https://wg21.link/P2374R4>`__","LWG","``views::cartesian_product``","July 2022","","","|ranges|"
-"`P2404R3 <https://wg21.link/P2404R3>`__","LWG","Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``","July 2022","",""
+"`P2404R3 <https://wg21.link/P2404R3>`__","LWG","Move-only types for ``equality_comparable_with``, ``totally_ordered_with``, and ``three_way_comparable_with``","July 2022","|Complete|","19.0"
 "`P2408R5 <https://wg21.link/P2408R5>`__","LWG","Ranges iterators as inputs to non-Ranges algorithms","July 2022","","","|ranges|"
 "`P2417R2 <https://wg21.link/P2417R2>`__","LWG","A more ``constexpr`` ``bitset``","July 2022","|Complete|","16.0"
 "`P2419R2 <https://wg21.link/P2419R2>`__","LWG","Clarify handling of encodings in localized formatting of chrono types","July 2022","",""
diff --git a/libcxx/docs/Status/SpaceshipPapers.csv b/libcxx/docs/Status/SpaceshipPapers.csv
index 39e1f968c1754..5fbf6a53b6db7 100644
--- a/libcxx/docs/Status/SpaceshipPapers.csv
+++ b/libcxx/docs/Status/SpaceshipPapers.csv
@@ -1,6 +1,6 @@
 "Number","Name","Status","First released version"
 `P1614R2 <https://wg21.link/P1614R2>`_,The Mothership has Landed,|In Progress|,
-`P2404R3 <https://wg21.link/P2404R3>`_,"Relaxing ``equality_comparable_with``'s, ``totally_ordered_with``'s, and ``three_way_comparable_with``'s common reference requirements to support move-only types",,
+`P2404R3 <https://wg21.link/P2404R3>`_,"Relaxing ``equality_comparable_with``'s, ``totally_ordered_with``'s, and ``three_way_comparable_with``'s common reference requirements to support move-only types","|Complete|","19.0"
 `LWG3330 <https://wg21.link/LWG3330>`_,Include ``<compare>`` from most library headers,"|Complete|","13.0"
 `LWG3347 <https://wg21.link/LWG3347>`_,"``std::pair<T, U>`` now requires ``T`` and ``U`` to be *less-than-comparable*",|Nothing To Do|,
 `LWG3350 <https://wg21.link/LWG3350>`_,Simplify return type of ``lexicographical_compare_three_way``,|Nothing To Do|,
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index cd64fe91449c2..e618847b1e27c 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -296,6 +296,7 @@ set(files
   __concepts/class_or_enum.h
   __concepts/common_reference_with.h
   __concepts/common_with.h
+  __concepts/comparison_common_type.h
   __concepts/constructible.h
   __concepts/convertible_to.h
   __concepts/copyable.h
diff --git a/libcxx/include/__compare/three_way_comparable.h b/libcxx/include/__compare/three_way_comparable.h
index 7a44ea9158a6f..3b14725be3309 100644
--- a/libcxx/include/__compare/three_way_comparable.h
+++ b/libcxx/include/__compare/three_way_comparable.h
@@ -12,6 +12,7 @@
 #include <__compare/common_comparison_category.h>
 #include <__compare/ordering.h>
 #include <__concepts/common_reference_with.h>
+#include <__concepts/comparison_common_type.h>
 #include <__concepts/equality_comparable.h>
 #include <__concepts/same_as.h>
 #include <__concepts/totally_ordered.h>
@@ -37,6 +38,20 @@ concept three_way_comparable =
       { __a <=> __b } -> __compares_as<_Cat>;
     };
 
+#  if _LIBCPP_STD_VER >= 23
+
+template <class _Tp, class _Up, class _cat = partial_ordering>
+concept three_way_comparable_with =
+    three_way_comparable<_Tp, _cat> && three_way_comparable<_Up, _cat> && __comparison_common_type_with<_Tp, _Up> &&
+    three_way_comparable<common_reference_t<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>>, _cat> &&
+    __weakly_equality_comparable_with<_Tp, _Up> && __partially_ordered_with<_Tp, _Up> &&
+    requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) {
+      { __t <=> __u } -> __compares_as<_cat>;
+      { __u <=> __t } -> __compares_as<_cat>;
+    };
+
+#  else
+
 template <class _Tp, class _Up, class _Cat = partial_ordering>
 concept three_way_comparable_with =
     three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> &&
@@ -48,6 +63,8 @@ concept three_way_comparable_with =
       { __u <=> __t } -> __compares_as<_Cat>;
     };
 
+#  endif // _LIBCPP_STD_VER >= 23
+
 #endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__concepts/comparison_common_type.h b/libcxx/include/__concepts/comparison_common_type.h
new file mode 100644
index 0000000000000..a1f246d2a6dca
--- /dev/null
+++ b/libcxx/include/__concepts/comparison_common_type.h
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
+#define _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
+
+#include "__concepts/convertible_to.h"
+#include "__concepts/same_as.h"
+#include "__config"
+#include "__type_traits/common_reference.h"
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+template <class _Tp, class _Up, class _C = common_reference_t<const _Tp&, const _Up&>>
+concept __comparison_common_type_with_impl =
+    same_as<common_reference_t<const _Tp&, const _Up&>, common_reference_t<const _Up&, const _Tp&>> && requires {
+      requires convertible_to<const _Tp&, const _C&> || convertible_to<_Tp, const _C&>;
+      requires convertible_to<const _Up&, const _C&> || convertible_to<_Up, const _C&>;
+    };
+
+template <class _Tp, class _Up>
+concept __comparison_common_type_with = __comparison_common_type_with_impl<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H
diff --git a/libcxx/include/__concepts/equality_comparable.h b/libcxx/include/__concepts/equality_comparable.h
index 278fc76409289..1904b2e451a8d 100644
--- a/libcxx/include/__concepts/equality_comparable.h
+++ b/libcxx/include/__concepts/equality_comparable.h
@@ -11,6 +11,7 @@
 
 #include <__concepts/boolean_testable.h>
 #include <__concepts/common_reference_with.h>
+#include <__concepts/comparison_common_type.h>
 #include <__config>
 #include <__type_traits/common_reference.h>
 #include <__type_traits/make_const_lvalue_ref.h>
@@ -37,6 +38,22 @@ concept __weakly_equality_comparable_with =
 template <class _Tp>
 concept equality_comparable = __weakly_equality_comparable_with<_Tp, _Tp>;
 
+#  if _LIBCPP_STD_VER >= 23
+
+// clang-format off
+template <class _Tp, class _Up>
+concept equality_comparable_with =
+    equality_comparable<_Tp> && equality_comparable<_Up> &&
+    __comparison_common_type_with<_Tp, _Up> &&
+    equality_comparable<
+        common_reference_t<
+            __make_const_lvalue_ref<_Tp>,
+            __make_const_lvalue_ref<_Up>>> &&
+    __weakly_equality_comparable_with<_Tp, _Up>;
+// clang-format on
+
+#  else
+
 // clang-format off
 template <class _Tp, class _Up>
 concept equality_comparable_with =
@@ -49,6 +66,8 @@ concept equality_comparable_with =
     __weakly_equality_comparable_with<_Tp, _Up>;
 // clang-format on
 
+#  endif // _LIBCPP_STD_VER >= 23
+
 #endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index f4aaa14c1c2ee..eabb32daf2c96 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1173,43 +1173,44 @@ module std_private_compare_weak_order                     [system] { header "__c
 
 module std_private_complex_complex_fwd            [system] { header "__fwd/complex.h" }
 
-module std_private_concepts_arithmetic            [system] { header "__concepts/arithmetic.h" }
-module std_private_concepts_assignable            [system] { header "__concepts/assignable.h" }
-module std_private_concepts_boolean_testable      [system] { header "__concepts/boolean_testable.h" }
-module std_private_concepts_class_or_enum         [system] { header "__concepts/class_or_enum.h" }
-module std_private_concepts_common_reference_with [system] { header "__concepts/common_reference_with.h" }
-module std_private_concepts_common_with           [system] { header "__concepts/common_with.h" }
-module std_private_concepts_constructible         [system] {
+module std_private_concepts_arithmetic              [system] { header "__concepts/arithmetic.h" }
+module std_private_concepts_assignable              [system] { header "__concepts/assignable.h" }
+module std_private_concepts_boolean_testable        [system] { header "__concepts/boolean_testable.h" }
+module std_private_concepts_class_or_enum           [system] { header "__concepts/class_or_enum.h" }
+module std_private_concepts_common_reference_with   [system] { header "__concepts/common_reference_with.h" }
+module std_private_concepts_common_with             [system] { header "__concepts/common_with.h" }
+module std_private_cooncepts_comparison_common_type [system] { header "__concepts/comparison_common_type.h" }
+module std_private_concepts_constructible           [system] {
   header "__concepts/constructible.h"
   export std_private_concepts_destructible
 }
-module std_private_concepts_convertible_to        [system] { header "__concepts/convertible_to.h" }
-module std_private_concepts_copyable              [system] { header "__concepts/copyable.h" }
-module std_private_concepts_derived_from          [system] { header "__concepts/derived_from.h" }
-module std_private_concepts_destructible          [system] {
+module std_private_concepts_convertible_to          [system] { header "__concepts/convertible_to.h" }
+module std_private_concepts_copyable                [system] { header "__concepts/copyable.h" }
+module std_private_concepts_derived_from            [system] { header "__concepts/derived_from.h" }
+module std_private_concepts_destructible            [system] {
   header "__concepts/destructible.h"
   export std_private_type_traits_is_nothrow_destructible
 }
-module std_private_concepts_different_from        [system] { header "__concepts/different_from.h" }
-module std_private_concepts_equality_comparable   [system] {
+module std_private_concepts_different_from          [system] { header "__concepts/different_from.h" }
+module std_private_concepts_equality_comparable     [system] {
   header "__concepts/equality_comparable.h"
   export std_private_type_traits_common_reference
 }
-module std_private_concepts_invocable             [system] { header "__concepts/invocable.h" }
-module std_private_concepts_movable               [system] {
+module std_private_concepts_invocable               [system] { header "__concepts/invocable.h" }
+module std_private_concepts_movable                 [system] {
   header "__concepts/movable.h"
   export std_private_type_traits_is_object
 }
-module std_private_concepts_predicate             [system] { header "__concepts/predicate.h" }
-module std_private_concepts_regular               [system] { header "__concepts/regular.h" }
-module std_private_concepts_relation              [system] { header "__concepts/relation.h" }
-module std_private_concepts_same_as               [system] {
+module std_private_concepts_predicate               [system] { header "__concepts/predicate.h" }
+module std_private_concepts_regular                 [system] { header "__concepts/regular.h" }
+module std_private_concepts_relation                [system] { header "__concepts/relation.h" }
+module std_private_concepts_same_as                 [system] {
   header "__concepts/same_as.h"
   export std_private_type_traits_is_same
 }
-module std_private_concepts_semiregular           [system] { header "__concepts/semiregular.h" }
-module std_private_concepts_swappable             [system] { header "__concepts/swappable.h" }
-module std_private_concepts_totally_ordered       [system] { header "__concepts/totally_ordered.h" }
+module std_private_concepts_semiregular             [system] { header "__concepts/semiregular.h" }
+module std_private_concepts_swappable               [system] { header "__concepts/swappable.h" }
+module std_private_concepts_totally_ordered         [system] { header "__concepts/totally_ordered.h" }
 
 module std_private_condition_variable_condition_variable [system] {
   header "__condition_variable/condition_variable.h"
diff --git a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
index e0edd1f332f81..45e3e88a10d14 100644
--- a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
+++ b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp
@@ -1119,4 +1119,14 @@ static_assert(
     std::common_reference_with<one_way_ne const&, explicit_operators const&>);
 static_assert(
     !check_equality_comparable_with<one_way_ne, explicit_operators>());
+
+#if TEST_STD_VER >= 23
+static_assert(check_equality_comparable_with<move_only_equality_with_int, int>());
+static_assert(check_equality_comparable_with<std::unique_ptr<int>, std::nullptr_t>());
+#else
+static_assert(!check_equality_comparable_with<move_only_equality_with_int, int>());
+static_assert(!check_equality_comparable_with<std::unique_ptr<int>, std::nullptr_t>());
+#endif // TEST_STD_VER >= 23
+
+static_assert(!check_equality_comparable_with<immobile_comparable_with_int, int>());
 } // namespace types_fit_for_purpose
diff --git a/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
index 50d9722aa29c0..2920240dddf55 100644
--- a/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
+++ b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp
@@ -14,6 +14,7 @@
 #include <compare>
 
 #include "compare_types.h"
+#include "test_macros.h"
 
 template <class T, class U = T, typename Cat = std::partial_ordering>
 constexpr bool check_three_way_comparable_with() {
@@ -223,4 +224,31 @@ struct SpaceshipNonConstArgument {
 };
 
 static_assert(!check_three_way_comparable_with<SpaceshipNonConstArgument>());
+
+struct MoveOnlyIntComparable {
+  MoveOnlyIntComparable(int) {}
+
+  MoveOnlyIntComparable(MoveOnlyIntComparable&&)            = default;
+  MoveOnlyIntComparable& operator=(MoveOnlyIntComparable&&) = default;
+
+  friend auto operator<=>(MoveOnlyIntComparable const&, MoveOnlyIntComparable const&) = default;
+};
+
+#if TEST_STD_VER >= 23
+static_assert(check_three_way_comparable_with<MoveOnlyIntComparable, int>());
+#else
+static_assert(!check_three_way_comparable_with<MoveOnlyIntComparable, int>());
+#endif // TEST_STD_VER >= 23
+
+struct ImmobileIntComparable {
+  ImmobileIntComparable(int) {}
+
+  ImmobileIntComparable(ImmobileIntComparable&&)            = delete;
+  ImmobileIntComparable& operator=(ImmobileIntComparable&&) = delete;
+
+  friend auto operator<=>(ImmobileIntComparable const&, ImmobileIntComparable const&) = default;
+};
+
+static_assert(!check_three_way_comparable_with<ImmobileIntComparable, int>());
+
 } // namespace user_defined
diff --git a/libcxx/test/support/compare_types.h b/libcxx/test/support/compare_types.h
index 8155f6221540c..eea219d033ae9 100644
--- a/libcxx/test/support/compare_types.h
+++ b/libcxx/test/support/compare_types.h
@@ -529,4 +529,27 @@ struct ForwardingTestObject {
   constexpr bool operator>=(const ForwardingTestObject&) const& { return false; }
 };
 
+struct move_only_equality_with_int {
+  move_only_equality_with_int(int);
+
+  move_only_equality_with_int(move_only_equality_with_int&&)            = default;
+  move_only_equality_with_int& operator=(move_only_equality_with_int&&) = default;
+
+  move_only_equality_with_int(move_only_equality_with_int const&)            = delete;
+  move_only_equality_with_int& operator=(move_only_equality_with_int const&) = delete;
+
+  friend bool operator==(move_only_equality_with_int const&, move_only_equality_with_int const&) = default;
+  friend bool operator==(move_only_equality_with_int const&, int);
+};
+
+struct immobile_comparable_with_int {
+  immobile_comparable_with_int(int);
+
+  immobile_comparable_with_int(immobile_comparable_with_int&&)            = delete;
+  immobile_comparable_with_int& operator=(immobile_comparable_with_int&&) = delete;
+
+  friend bool operator==(immobile_comparable_with_int const&, immobile_comparable_with_int const&) = default;
+  friend bool operator==(immobile_comparable_with_int const&, int);
+};
+
 #endif // TEST_SUPPORT_COMPARE_TYPES_H

@Zingam
Copy link
Contributor

Zingam commented Jul 18, 2024

The link to the paper in the description of the PR doesn't seem to be a valid one.

@randomnetcat
Copy link
Contributor Author

Fixed, sorry.

@Zingam
Copy link
Contributor

Zingam commented Jul 18, 2024

@randomnetcat Since I am not an approver I only skimmed over this patch. I hope it gets into LLVM19 release. Please make sure to fix the CI errors. There seem to be some affected tests.

Copy link
Contributor

@cjdb cjdb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

I'm inclined to suggest that we treat this as if it were a defect report, and backport this to C++20, so that we have a canonical definition of these concepts across standards. I think that will, in the long term, be more beneficial to users than having the concept change between standards.

@randomnetcat randomnetcat changed the title [libc++][spaceship] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with [libc++][concepts] P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with Jul 18, 2024
@randomnetcat
Copy link
Contributor Author

I'm inclined to suggest that we treat this as if it were a defect report, and backport this to C++20, so that we have a canonical definition of these concepts across standards. I think that will, in the long term, be more beneficial to users than having the concept change between standards.

Addressed the review comments, but haven't done this. I'm not sure if you meant "please do this" or "this is something we could consider".

@cjdb
Copy link
Contributor

cjdb commented Jul 18, 2024

I'm inclined to suggest that we treat this as if it were a defect report, and backport this to C++20, so that we have a canonical definition of these concepts across standards. I think that will, in the long term, be more beneficial to users than having the concept change between standards.

I'm not sure if you meant "please do this" or "this is something we could consider".

Definitely the latter. We typically don't make unilateral decisions, and doing it for something like this would definitely be not okay.

@frederick-vs-ja
Copy link
Contributor

I'm inclined to suggest that we treat this as if it were a defect report, and backport this to C++20, so that we have a canonical definition of these concepts across standards. I think that will, in the long term, be more beneficial to users than having the concept change between standards.

Currently, only MSVC STL has implemented this paper and leaves it C++23-only. I'd like to ask what do implementors/maintainers of other implementations think "as usual". (I'm personally neutral.)

CC @JMazurkiewicz @StephanTLavavej @jwakely

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your first contribution! This looks pretty good, but I have a few comments.

In terms of applying this as a DR, I would be OK with doing that if the other implementers also do it.

@StephanTLavavej
Copy link
Member

I would be fine with changing MSVC's STL to align with making this a de facto DR, if libstdc++ is also on-board. This doesn't take any new publicly-visible names, and it seems like a highly compatible change (Annex C lists a theoretical break but you have to be looking pretty hard for it).

@randomnetcat
Copy link
Contributor Author

So... should I be looking at implementing this without the version check?

@ldionne
Copy link
Member

ldionne commented Jul 31, 2024

@jwakely Do you think it makes sense to apply P2404R3 as a DR or do you see this as a real feature?

libc++ and MSVC STL are fine with a DR.

@cjdb
Copy link
Contributor

cjdb commented Jul 31, 2024

So... should I be looking at implementing this without the version check?

Let's hold off until we get an answer from Jonathan, but assuming libstdc++ consents, yes please.

@ldionne
Copy link
Member

ldionne commented Nov 28, 2024

@randomnetcat Let's rebase this onto main and implement it as a DR (i.e. no version check). When you're ready, please ping me and I'll commit some time to it so we can get it across the finish line.

@randomnetcat randomnetcat force-pushed the p2404 branch 2 times, most recently from 5c6b58e to f67c4de Compare June 9, 2025 15:07
@github-actions
Copy link

github-actions bot commented Jun 9, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@randomnetcat
Copy link
Contributor Author

Well, I've (6 months later, oops) finally gotten around to implementing this as a DR instead. @ldionne, you requested a ping for this.

Sorry for the delay.

@Zingam
Copy link
Contributor

Zingam commented Sep 1, 2025

@randomnetcat Can you, please, rebase, resolve the conflicts, and update the PR... release notes, etc.

randomnetcat and others added 2 commits September 21, 2025 14:45
Co-authored-by: A. Jiang <de34@live.cn>
@ldionne
Copy link
Member

ldionne commented Dec 1, 2025

It looks like some of the CI was failing with legitimate failures, let's ensure we have a green build.

@jwakely
Copy link
Contributor

jwakely commented Dec 1, 2025

@jwakely Do you think it makes sense to apply P2404R3 as a DR or do you see this as a real feature?

libc++ and MSVC STL are fine with a DR.

I missed the emails for this one among hundreds of other mails, sorry. I have no objection to treating this as a DR, we can do the same for libstdc++. (gcc tracker bug)

@StephanTLavavej
Copy link
Member

FYI, the MSVC Build Tools 14.51 (shipping in a future update to VS 2026 18.x) have implemented this downlevel for C++20. Thanks everyone!

@jwakely
Copy link
Contributor

jwakely commented Dec 9, 2025

Likewise for GCC 16: gcc-mirror/gcc@03562c1

@frederick-vs-ja
Copy link
Contributor

It seems that Clang's __builtin_common_type is overly permissive. Reported #171438.

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with passing CI, @frederick-vs-ja do you see anything else that needs changing before this lands?

@frederick-vs-ja
Copy link
Contributor

I slightly tweaked PR description. Please double check. @randomnetcat @ldionne

@randomnetcat
Copy link
Contributor Author

Oh, yep! That looks good. I'm sorry that I've not had the bandwidth to work on this due to holidays and travel. Thank you both!

@frederick-vs-ja
Copy link
Contributor

Oops, I forgot adding the entry to the release note. I'll add it immediately. CI has been mostly fine on macOS already.
@ldionne I think we can merge this when CI becomes green.

@frederick-vs-ja frederick-vs-ja added pending-ci Merging the PR is only pending completion of CI and removed pending-ci Merging the PR is only pending completion of CI labels Dec 19, 2025
@frederick-vs-ja frederick-vs-ja merged commit ef19006 into llvm:main Dec 19, 2025
82 checks passed
@github-actions
Copy link

@randomnetcat Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Dec 19, 2025
…ith, totally_ordered_with, and three_way_comparable_with (llvm#99420)

This implements all of [P2404R3](https://wg21.link/p2404r3)'s concept
changes.

---------

Co-authored-by: A. Jiang <de34@live.cn>
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
@llvm-ci
Copy link

llvm-ci commented Dec 21, 2025

LLVM Buildbot has detected a new failure on builder sanitizer-ppc64le-linux running on ppc64le-sanitizer while building libcxx at step 2 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/72/builds/16737

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure) (timed out)
...
[2516/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++abi.a
[2517/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/elfnix_tls.ppc64.S.o
[2518/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/sysv_reenter.x86-64.S.o
[2519/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/liborc_rt.a
[2520/2523] Linking CXX static library compiler-rt/lib/orc/tests/libRTOrc.test.powerpc64le.a
[2521/2523] Creating library symlink /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.so.1 /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.so
[2522/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.a
[2523/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++experimental.a
[4343/4345] No install step for 'runtimes'
[4345/4345] Completed 'runtimes'
command timed out: 1800 seconds without output running [b'python', b'../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=4565.773878
Step 10 (build compiler-rt tsan_debug) failure: build compiler-rt tsan_debug (failure)
...
[2481/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/linux.cpp.o
[2482/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/mem_map.cpp.o
[2483/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/mem_map_fuchsia.cpp.o
[2484/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/mem_map_linux.cpp.o
[2485/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/release.cpp.o
[2486/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/report.cpp.o
[2487/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/report_linux.cpp.o
[2488/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/string_utils.cpp.o
[2489/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/timing.cpp.o
[2490/2523] Building CXX object compiler-rt/lib/scudo/standalone/CMakeFiles/clang_rt.scudo_standalone-powerpc64le.dir/wrappers_c.cpp.o
[2491/2523] Building CXX object libcxx/src/CMakeFiles/cxx_shared.dir/locale.cpp.o
[2492/2523] Building CXX object libcxx/src/CMakeFiles/cxx_experimental.dir/experimental/time_zone.cpp.o
[2493/2523] Building ASM object compiler-rt/lib/asan/CMakeFiles/RTAsan.powerpc64le.dir/asan_interceptors_vfork.S.o
[2494/2523] Building ASM object libunwind/src/CMakeFiles/unwind_static_objects.dir/UnwindRegistersRestore.S.o
[2495/2523] Building ASM object libunwind/src/CMakeFiles/unwind_static_objects.dir/UnwindRegistersSave.S.o
[2496/2523] Building ASM object compiler-rt/lib/tsan/rtl/CMakeFiles/clang_rt.tsan-powerpc64le.dir/tsan_rtl_ppc64.S.o
[2497/2523] Building ASM object compiler-rt/lib/xray/CMakeFiles/RTXray.powerpc64le.dir/xray_trampoline_powerpc64_asm.S.o
[2498/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/elfnix_tls.x86-64.S.o
[2499/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/elfnix_tls.aarch64.S.o
[2500/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/elfnix_tls.systemz.S.o
[2501/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/sysv_reenter.arm64.S.o
[2502/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/libclang_rt.scudo_standalone.a
[2503/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/libclang_rt.asan.a
[2504/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/libclang_rt.xray.a
[2505/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/libclang_rt.tsan.a
[2506/2523] Generating exported symbols for clang_rt.asan-powerpc64le
[2507/2523] Generating exported symbols for clang_rt.tsan-powerpc64le
[2508/2523] Generating version list for clang_rt.asan-dynamic-powerpc64le
[2509/2523] Building CXX object compiler-rt/lib/asan/CMakeFiles/RTAsan_dynamic_version_script_dummy.powerpc64le.dir/dummy.cpp.o
[2510/2523] Building ASM object compiler-rt/lib/asan/CMakeFiles/RTAsan_dynamic.powerpc64le.dir/asan_interceptors_vfork.S.o
[2511/2523] Linking CXX shared library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/libclang_rt.asan.so
[2512/2523] Linking C static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libunwind.a
[2513/2523] Linking CXX shared library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.so.1.0
[2514/2523] Building ASM object compiler-rt/lib/tsan/rtl/CMakeFiles/clang_rt.tsan-dynamic-powerpc64le.dir/tsan_rtl_ppc64.S.o
[2515/2523] Linking CXX shared library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/libclang_rt.tsan.so
[2516/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++abi.a
[2517/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/elfnix_tls.ppc64.S.o
[2518/2523] Building ASM object compiler-rt/lib/orc/CMakeFiles/RTOrc.powerpc64le.dir/sysv_reenter.x86-64.S.o
[2519/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/clang/22/lib/powerpc64le-unknown-linux-gnu/liborc_rt.a
[2520/2523] Linking CXX static library compiler-rt/lib/orc/tests/libRTOrc.test.powerpc64le.a
[2521/2523] Creating library symlink /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.so.1 /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.so
[2522/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++.a
[2523/2523] Linking CXX static library /home/buildbots/llvm-external-buildbots/workers/ppc64le-sanitizer/sanitizer-ppc64le/build/build_default/lib/powerpc64le-unknown-linux-gnu/libc++experimental.a
[4343/4345] No install step for 'runtimes'
[4345/4345] Completed 'runtimes'

command timed out: 1800 seconds without output running [b'python', b'../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=4565.773878

valadaptive pushed a commit to valadaptive/llvm-project that referenced this pull request Dec 24, 2025
…ith, totally_ordered_with, and three_way_comparable_with (llvm#99420)

This implements all of [P2404R3](https://wg21.link/p2404r3)'s concept
changes.

---------

Co-authored-by: A. Jiang <de34@live.cn>
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jan 6, 2026
…ith, totally_ordered_with, and three_way_comparable_with (llvm#99420)

This implements all of [P2404R3](https://wg21.link/p2404r3)'s concept
changes.

---------

Co-authored-by: A. Jiang <de34@live.cn>
Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P2404R3: Move-only types for equality_comparable_with, totally_ordered_with, and three_way_comparable_with

9 participants