Skip to content

Conversation

philnik777
Copy link
Contributor

This set of builtins makes it possible to detect whether a comparison operation is synthesised from a spaceship operator. This makes it possible to avoid calling the comparison multiple times if you care about the three-way relation. This is especially interesting for the associative containers from the STL, since a lot of functions call the comparator twice to establish the relation. With this builtin these functions can call the comparator just once and use the result of the three way comparison directly.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 27, 2025

@llvm/pr-subscribers-clang

Author: Nikolas Klauser (philnik777)

Changes

This set of builtins makes it possible to detect whether a comparison operation is synthesised from a spaceship operator. This makes it possible to avoid calling the comparison multiple times if you care about the three-way relation. This is especially interesting for the associative containers from the STL, since a lot of functions call the comparator twice to establish the relation. With this builtin these functions can call the comparator just once and use the result of the three way comparison directly.


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

5 Files Affected:

  • (modified) clang/include/clang/Basic/TokenKinds.def (+4)
  • (modified) clang/lib/Sema/SemaTypeTraits.cpp (+45)
  • (modified) clang/test/SemaCXX/type-trait-common-type.cpp (+8-8)
  • (added) clang/test/SemaCXX/type-trait-synthesises-from-spaceship.cpp (+212)
  • (modified) clang/test/SemaCXX/type-traits.cpp (+13-13)
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..8aabc0ccd2a04 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);
+
+    auto 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-common-type.cpp b/clang/test/SemaCXX/type-trait-common-type.cpp
index 8f2b97ba784c3..1606c675ee249 100644
--- a/clang/test/SemaCXX/type-trait-common-type.cpp
+++ b/clang/test/SemaCXX/type-trait-common-type.cpp
@@ -79,16 +79,16 @@ static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], int [
 static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], long [[clang::address_space(1)]]>, type_identity<long [[clang::address_space(1)]]>));
 static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], long [[clang::address_space(2)]]>, type_identity<long>));
 
-struct S {};
-struct T : S {};
+struct DefaultSpaceship {};
+struct T : DefaultSpaceship {};
 
-static_assert(__is_same(common_type_base<int S::*, int S::*>, type_identity<int S::*>));
-static_assert(__is_same(common_type_base<int S::*, int T::*>, type_identity<int T::*>));
-static_assert(__is_same(common_type_base<int S::*, long S::*>, empty_type));
+static_assert(__is_same(common_type_base<int DefaultSpaceship::*, int DefaultSpaceship::*>, type_identity<int DefaultSpaceship::*>));
+static_assert(__is_same(common_type_base<int DefaultSpaceship::*, int T::*>, type_identity<int T::*>));
+static_assert(__is_same(common_type_base<int DefaultSpaceship::*, long DefaultSpaceship::*>, empty_type));
 
-static_assert(__is_same(common_type_base<int (S::*)(), int (S::*)()>, type_identity<int (S::*)()>));
-static_assert(__is_same(common_type_base<int (S::*)(), int (T::*)()>, type_identity<int (T::*)()>));
-static_assert(__is_same(common_type_base<int (S::*)(), long (S::*)()>, empty_type));
+static_assert(__is_same(common_type_base<int (DefaultSpaceship::*)(), int (DefaultSpaceship::*)()>, type_identity<int (DefaultSpaceship::*)()>));
+static_assert(__is_same(common_type_base<int (DefaultSpaceship::*)(), int (T::*)()>, type_identity<int (T::*)()>));
+static_assert(__is_same(common_type_base<int (DefaultSpaceship::*)(), long (DefaultSpaceship::*)()>, empty_type));
 
 struct NoCommonType {};
 
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));
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 3f0124755c674..0372c871bb6c0 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -4199,7 +4199,7 @@ class Template {};
 static_assert(!__is_trivially_equality_comparable(Template<Template<int>>));
 
 
-struct S operator==(S, S);
+struct DefaultSpaceship operator==(S, S);
 
 template <class> struct basic_string_view {};
 
@@ -4778,7 +4778,7 @@ void check_decay() {
 
 template <class T> struct CheckAbominableFunction {};
 template <class M>
-struct CheckAbominableFunction<M S::*> {
+struct CheckAbominableFunction<M DefaultSpaceship::*> {
   static void checks() {
     static_assert(__is_same(add_lvalue_reference_t<M>, M));
     static_assert(__is_same(add_pointer_t<M>, M));
@@ -4794,17 +4794,17 @@ struct CheckAbominableFunction<M S::*> {
 };
 
 void check_abominable_function() {
-  { CheckAbominableFunction<int (S::*)() &> x; }
-  { CheckAbominableFunction<int (S::*)() &&> x; }
-  { CheckAbominableFunction<int (S::*)() const> x; }
-  { CheckAbominableFunction<int (S::*)() const &> x; }
-  { CheckAbominableFunction<int (S::*)() const &&> x; }
-  { CheckAbominableFunction<int (S::*)() volatile> x; }
-  { CheckAbominableFunction<int (S::*)() volatile &> x; }
-  { CheckAbominableFunction<int (S::*)() volatile &&> x; }
-  { CheckAbominableFunction<int (S::*)() const volatile> x; }
-  { CheckAbominableFunction<int (S::*)() const volatile &> x; }
-  { CheckAbominableFunction<int (S::*)() const volatile &&> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() &> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() &&> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() const> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() const &> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() const &&> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() volatile> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() volatile &> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() volatile &&> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() const volatile> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() const volatile &> x; }
+  { CheckAbominableFunction<int (DefaultSpaceship::*)() const volatile &&> x; }
 }
 
 template <class T> using make_signed_t = __make_signed(T);

@philnik777 philnik777 force-pushed the builtin_synthesises_from_spaceship branch from c9fd3da to 949db87 Compare August 27, 2025 12:32
@philnik777 philnik777 force-pushed the builtin_synthesises_from_spaceship branch from 949db87 to e96ef97 Compare August 27, 2025 12:33
@ldionne
Copy link
Member

ldionne commented Aug 27, 2025

This is clever: that way we know it's a pure optimization to call spaceship instead of less-than twice. IIUC you'd plan to use this from libc++ to optimize eg __find_equal even on user-defined types?

@philnik777
Copy link
Contributor Author

This is clever: that way we know it's a pure optimization to call spaceship instead of less-than twice. IIUC you'd plan to use this from libc++ to optimize eg __find_equal even on user-defined types?

Yes, exactly.

@shafik shafik requested a review from erichkeane August 28, 2025 00:35
Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

1 nit, else lgtm.

MIGHT be worth having a release note as well though, while this is just a builtin, I'm hopeful putting it here will mean that libstdc++ will see/use it too.

UnresolvedSet<16> Functions;
Self.LookupBinOp(Self.TUScope, KeyLoc, OpKind, Functions);

auto Result =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not a spot we can use 'auto'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants