https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/155612

>From d5086ee9311f6667839fbb88f4ef4f99413c11bf Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <[email protected]>
Date: Wed, 27 Aug 2025 14:28:22 +0200
Subject: [PATCH] [Clang] Introduce __builtin_meow_synthesises_from_spaceship

---
 clang/docs/LanguageExtensions.rst             |   3 +
 clang/docs/ReleaseNotes.rst                   |   5 +
 clang/include/clang/Basic/TokenKinds.def      |   4 +
 clang/lib/Sema/SemaTypeTraits.cpp             |  45 ++++
 .../type-trait-synthesises-from-spaceship.cpp | 212 ++++++++++++++++++
 5 files changed, 269 insertions(+)
 create mode 100644 clang/test/SemaCXX/type-trait-synthesises-from-spaceship.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index a42a546555716..53b84fee110d8 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1903,6 +1903,9 @@ The following type trait primitives are supported by 
Clang. Those traits marked
     Returns true if a reference ``T`` can be copy-initialized from a temporary 
of type
     a non-cv-qualified ``U``.
 * ``__underlying_type`` (C++, GNU, Microsoft)
+* ``__builtin_lt_synthesises_from_spaceship``, 
``__builtin_gt_synthesises_from_spaceship``,
+  ``__builtin_le_synthesises_from_spaceship``, 
``__builtin_ge_synthesises_from_spaceship`` (Clang):
+  These builtins can be used to determine whether the corresponding operator 
is synthesised from a spaceship operator.
 
 In addition, the following expression traits are supported:
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9a94c4bcd9980..8c2f7468c4609 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -124,6 +124,11 @@ C++ Language Changes
   Diagnostics that would have resulted from the instantiation of these 
template candidates are no longer
   produced. This aligns Clang closer to the behavior of GCC, and fixes 
(#GH62096), (#GH74581), and (#GH74581).
 
+- A new family of builtins ``__builtin_*_synthesises_from_spaceship`` has been 
added. These can be queried to know
+  whether the ``<`` (``lt``), ``>`` (``gt``), ``<=`` (``le``), or ``>=`` 
(``ge``) operators are synthesised from a
+  ``<=>``. This makes it possible to optimize certain facilities by using the 
``<=>`` operation directly instead of
+  doing multiple comparisons.
+
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index 94e72fea56a68..9d1a23d1af218 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -552,6 +552,10 @@ TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
 TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
 TYPE_TRAIT_2(__reference_constructs_from_temporary, 
ReferenceConstructsFromTemporary, KEYCXX)
 TYPE_TRAIT_2(__reference_converts_from_temporary, 
ReferenceConvertsFromTemporary, KEYCXX)
+TYPE_TRAIT_2(__builtin_lt_synthesises_from_spaceship, 
LtSynthesisesFromSpaceship, KEYCXX)
+TYPE_TRAIT_2(__builtin_le_synthesises_from_spaceship, 
LeSynthesisesFromSpaceship, KEYCXX)
+TYPE_TRAIT_2(__builtin_gt_synthesises_from_spaceship, 
GtSynthesisesFromSpaceship, KEYCXX)
+TYPE_TRAIT_2(__builtin_ge_synthesises_from_spaceship, 
GeSynthesisesFromSpaceship, KEYCXX)
 // IsDeducible is only used internally by clang for CTAD implementation and
 // is not exposed to users.
 TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX)
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index c2f0600295e9e..0646405fc8adb 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1824,6 +1824,51 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, 
TypeTrait BTT,
 
     return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
   }
+  case BTT_LtSynthesisesFromSpaceship:
+  case BTT_LeSynthesisesFromSpaceship:
+  case BTT_GtSynthesisesFromSpaceship:
+  case BTT_GeSynthesisesFromSpaceship: {
+    EnterExpressionEvaluationContext UnevaluatedContext(
+        Self, Sema::ExpressionEvaluationContext::Unevaluated);
+    Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true);
+    Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
+
+    OpaqueValueExpr LHS(KeyLoc, LhsT.getNonReferenceType(),
+                        LhsT->isLValueReferenceType() ? 
ExprValueKind::VK_LValue
+                        : LhsT->isRValueReferenceType()
+                            ? ExprValueKind::VK_XValue
+                            : ExprValueKind::VK_PRValue);
+    OpaqueValueExpr RHS(KeyLoc, RhsT.getNonReferenceType(),
+                        RhsT->isLValueReferenceType() ? 
ExprValueKind::VK_LValue
+                        : RhsT->isRValueReferenceType()
+                            ? ExprValueKind::VK_XValue
+                            : ExprValueKind::VK_PRValue);
+
+    auto OpKind = [&] {
+      switch (BTT) {
+      case BTT_LtSynthesisesFromSpaceship:
+        return BinaryOperatorKind::BO_LT;
+      case BTT_LeSynthesisesFromSpaceship:
+        return BinaryOperatorKind::BO_LE;
+      case BTT_GtSynthesisesFromSpaceship:
+        return BinaryOperatorKind::BO_GT;
+      case BTT_GeSynthesisesFromSpaceship:
+        return BinaryOperatorKind::BO_GE;
+      default:
+        llvm_unreachable("Trying to Synthesize non-comparison operator?");
+      }
+    }();
+
+    UnresolvedSet<16> Functions;
+    Self.LookupBinOp(Self.TUScope, KeyLoc, OpKind, Functions);
+
+    ExprResult Result =
+        Self.CreateOverloadedBinOp(KeyLoc, OpKind, Functions, &LHS, &RHS);
+    if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+      return false;
+
+    return isa<CXXRewrittenBinaryOperator>(Result.get());
+  }
   default:
     llvm_unreachable("not a BTT");
   }
diff --git a/clang/test/SemaCXX/type-trait-synthesises-from-spaceship.cpp 
b/clang/test/SemaCXX/type-trait-synthesises-from-spaceship.cpp
new file mode 100644
index 0000000000000..ba581475bb4c7
--- /dev/null
+++ b/clang/test/SemaCXX/type-trait-synthesises-from-spaceship.cpp
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
+
+static_assert(!__builtin_lt_synthesises_from_spaceship()); // expected-error 
{{expected a type}}
+static_assert(!__builtin_lt_synthesises_from_spaceship(int)); // 
expected-error {{type trait requires 2 arguments; have 1 argument}}
+static_assert(!__builtin_lt_synthesises_from_spaceship(int, int, int)); // 
expected-error {{type trait requires 2 arguments; have 3 argument}}
+static_assert(!__builtin_lt_synthesises_from_spaceship(int, 0)); // 
expected-error {{expected a type}}
+
+static_assert(!__builtin_le_synthesises_from_spaceship()); // expected-error 
{{expected a type}}
+static_assert(!__builtin_le_synthesises_from_spaceship(int)); // 
expected-error {{type trait requires 2 arguments; have 1 argument}}
+static_assert(!__builtin_le_synthesises_from_spaceship(int, int, int)); // 
expected-error {{type trait requires 2 arguments; have 3 argument}}
+static_assert(!__builtin_le_synthesises_from_spaceship(int, 0)); // 
expected-error {{expected a type}}
+
+static_assert(!__builtin_gt_synthesises_from_spaceship()); // expected-error 
{{expected a type}}
+static_assert(!__builtin_gt_synthesises_from_spaceship(int)); // 
expected-error {{type trait requires 2 arguments; have 1 argument}}
+static_assert(!__builtin_gt_synthesises_from_spaceship(int, int, int)); // 
expected-error {{type trait requires 2 arguments; have 3 argument}}
+static_assert(!__builtin_gt_synthesises_from_spaceship(int, 0)); // 
expected-error {{expected a type}}
+
+static_assert(!__builtin_ge_synthesises_from_spaceship()); // expected-error 
{{expected a type}}
+static_assert(!__builtin_ge_synthesises_from_spaceship(int)); // 
expected-error {{type trait requires 2 arguments; have 1 argument}}
+static_assert(!__builtin_ge_synthesises_from_spaceship(int, int, int)); // 
expected-error {{type trait requires 2 arguments; have 3 argument}}
+static_assert(!__builtin_ge_synthesises_from_spaceship(int, 0)); // 
expected-error {{expected a type}}
+
+namespace std {
+  struct strong_ordering {
+    int n;
+    constexpr operator int() const { return n; }
+    static const strong_ordering less, equal, greater;
+  };
+  constexpr strong_ordering strong_ordering::less = {-1};
+  constexpr strong_ordering strong_ordering::equal = {0};
+  constexpr strong_ordering strong_ordering::greater = {1};
+}
+
+struct DefaultSpaceship {
+  friend auto operator<=>(DefaultSpaceship, DefaultSpaceship) = default;
+};
+
+static_assert(__builtin_lt_synthesises_from_spaceship(const DefaultSpaceship&, 
const DefaultSpaceship&));
+static_assert(__builtin_le_synthesises_from_spaceship(const DefaultSpaceship&, 
const DefaultSpaceship&));
+static_assert(__builtin_gt_synthesises_from_spaceship(const DefaultSpaceship&, 
const DefaultSpaceship&));
+static_assert(__builtin_ge_synthesises_from_spaceship(const DefaultSpaceship&, 
const DefaultSpaceship&));
+
+struct CustomSpaceship {
+  int i;
+
+  friend auto operator<=>(CustomSpaceship lhs, CustomSpaceship rhs) {
+    return rhs.i <=> lhs.i;
+  }
+};
+
+static_assert(__builtin_lt_synthesises_from_spaceship(const CustomSpaceship&, 
const CustomSpaceship&));
+static_assert(__builtin_le_synthesises_from_spaceship(const CustomSpaceship&, 
const CustomSpaceship&));
+static_assert(__builtin_gt_synthesises_from_spaceship(const CustomSpaceship&, 
const CustomSpaceship&));
+static_assert(__builtin_ge_synthesises_from_spaceship(const CustomSpaceship&, 
const CustomSpaceship&));
+
+struct CustomLT {
+  int i;
+
+  friend auto operator<(CustomLT lhs, CustomLT rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomLT&, const 
CustomLT&));
+static_assert(!__builtin_le_synthesises_from_spaceship(const CustomLT&, const 
CustomLT&));
+static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomLT&, const 
CustomLT&));
+static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomLT&, const 
CustomLT&));
+
+struct CustomLE {
+  int i;
+
+  friend auto operator<=(CustomLE lhs, CustomLE rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomLE&, const 
CustomLE&));
+static_assert(!__builtin_le_synthesises_from_spaceship(const CustomLE&, const 
CustomLE&));
+static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomLE&, const 
CustomLE&));
+static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomLE&, const 
CustomLE&));
+
+struct CustomGT {
+  int i;
+
+  friend auto operator>(CustomGT lhs, CustomGT rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomGT&, const 
CustomGT&));
+static_assert(!__builtin_le_synthesises_from_spaceship(const CustomGT&, const 
CustomGT&));
+static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomGT&, const 
CustomGT&));
+static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomGT&, const 
CustomGT&));
+
+struct CustomGE {
+  int i;
+
+  friend auto operator>=(CustomGE lhs, CustomGE rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(!__builtin_lt_synthesises_from_spaceship(const CustomGE&, const 
CustomGE&));
+static_assert(!__builtin_le_synthesises_from_spaceship(const CustomGE&, const 
CustomGE&));
+static_assert(!__builtin_gt_synthesises_from_spaceship(const CustomGE&, const 
CustomGE&));
+static_assert(!__builtin_ge_synthesises_from_spaceship(const CustomGE&, const 
CustomGE&));
+
+struct CustomLTAndSpaceship {
+  int i;
+
+  friend auto operator<=>(CustomLTAndSpaceship lhs, CustomLTAndSpaceship rhs) {
+    return rhs.i <=> lhs.i;
+  }
+
+  friend auto operator<(CustomLTAndSpaceship lhs, CustomLTAndSpaceship rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(!__builtin_lt_synthesises_from_spaceship(const 
CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
+static_assert(__builtin_le_synthesises_from_spaceship(const 
CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
+static_assert(__builtin_gt_synthesises_from_spaceship(const 
CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
+static_assert(__builtin_ge_synthesises_from_spaceship(const 
CustomLTAndSpaceship&, const CustomLTAndSpaceship&));
+
+struct CustomLEAndSpaceship {
+  int i;
+
+  friend auto operator<=>(CustomLEAndSpaceship lhs, CustomLEAndSpaceship rhs) {
+    return rhs.i <=> lhs.i;
+  }
+
+  friend auto operator<=(CustomLEAndSpaceship lhs, CustomLEAndSpaceship rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(__builtin_lt_synthesises_from_spaceship(const 
CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
+static_assert(!__builtin_le_synthesises_from_spaceship(const 
CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
+static_assert(__builtin_gt_synthesises_from_spaceship(const 
CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
+static_assert(__builtin_ge_synthesises_from_spaceship(const 
CustomLEAndSpaceship&, const CustomLEAndSpaceship&));
+
+struct CustomGTAndSpaceship {
+  int i;
+
+  friend auto operator<=>(CustomGTAndSpaceship lhs, CustomGTAndSpaceship rhs) {
+    return rhs.i <=> lhs.i;
+  }
+
+  friend auto operator>(CustomGTAndSpaceship lhs, CustomGTAndSpaceship rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(__builtin_lt_synthesises_from_spaceship(const 
CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
+static_assert(__builtin_le_synthesises_from_spaceship(const 
CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
+static_assert(!__builtin_gt_synthesises_from_spaceship(const 
CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
+static_assert(__builtin_ge_synthesises_from_spaceship(const 
CustomGTAndSpaceship&, const CustomGTAndSpaceship&));
+
+struct CustomGEAndSpaceship {
+  int i;
+
+  friend auto operator<=>(CustomGEAndSpaceship lhs, CustomGEAndSpaceship rhs) {
+    return rhs.i <=> lhs.i;
+  }
+
+  friend auto operator>=(CustomGEAndSpaceship lhs, CustomGEAndSpaceship rhs) {
+    return rhs.i < lhs.i;
+  }
+};
+
+static_assert(__builtin_lt_synthesises_from_spaceship(const 
CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
+static_assert(__builtin_le_synthesises_from_spaceship(const 
CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
+static_assert(__builtin_gt_synthesises_from_spaceship(const 
CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
+static_assert(!__builtin_ge_synthesises_from_spaceship(const 
CustomGEAndSpaceship&, const CustomGEAndSpaceship&));
+
+struct DefaultedCmpAndSpaceship {
+  int i;
+
+  friend auto operator<=>(DefaultedCmpAndSpaceship lhs, 
DefaultedCmpAndSpaceship rhs) {
+    return rhs.i <=> lhs.i;
+  }
+
+  friend bool operator<(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship 
rhs) = default;
+  friend bool operator<=(DefaultedCmpAndSpaceship lhs, 
DefaultedCmpAndSpaceship rhs) = default;
+  friend bool operator>(DefaultedCmpAndSpaceship lhs, DefaultedCmpAndSpaceship 
rhs) = default;
+  friend bool operator>=(DefaultedCmpAndSpaceship lhs, 
DefaultedCmpAndSpaceship rhs) = default;
+};
+
+// TODO: This should probably return true
+static_assert(!__builtin_lt_synthesises_from_spaceship(const 
DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
+static_assert(!__builtin_le_synthesises_from_spaceship(const 
DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
+static_assert(!__builtin_gt_synthesises_from_spaceship(const 
DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
+static_assert(!__builtin_ge_synthesises_from_spaceship(const 
DefaultedCmpAndSpaceship&, const DefaultedCmpAndSpaceship&));
+
+struct DifferentTypes {
+  int i;
+
+  friend auto operator<=>(DifferentTypes lhs, int rhs) {
+    return rhs <=> lhs.i;
+  }
+};
+
+static_assert(__builtin_lt_synthesises_from_spaceship(const DifferentTypes&, 
const int&));
+static_assert(__builtin_le_synthesises_from_spaceship(const DifferentTypes&, 
const int&));
+static_assert(__builtin_gt_synthesises_from_spaceship(const DifferentTypes&, 
const int&));
+static_assert(__builtin_ge_synthesises_from_spaceship(const DifferentTypes&, 
const int&));
+
+// TODO: Should this return true? It's technically not synthesized from 
spaceship, but it behaves exactly as-if it was
+static_assert(!__builtin_lt_synthesises_from_spaceship(int, int));
+static_assert(!__builtin_le_synthesises_from_spaceship(int, int));
+static_assert(!__builtin_gt_synthesises_from_spaceship(int, int));
+static_assert(!__builtin_ge_synthesises_from_spaceship(int, int));

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to