https://github.com/Tsche updated 
https://github.com/llvm/llvm-project/pull/216462

>From c6ee0d5a900f11bcc7f0f81a13f867518928a4df Mon Sep 17 00:00:00 2001
From: Matthias Wippich <[email protected]>
Date: Sat, 15 Aug 2026 09:02:00 +0200
Subject: [PATCH 1/2] [clang] Implement the __builtin_type_order intrinsic for
 P2830R10 Constexpr Type Ordering

---
 clang/docs/LanguageExtensions.md              |  3 +
 clang/docs/ReleaseNotes.md                    |  3 +
 clang/include/clang/AST/ASTNodeTraverser.h    |  5 ++
 clang/include/clang/AST/ComputeDependence.h   |  2 +
 clang/include/clang/AST/ExprCXX.h             | 43 ++++++++++
 clang/include/clang/AST/RecursiveASTVisitor.h |  5 ++
 clang/include/clang/AST/StmtDataCollectors.td |  6 ++
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/include/clang/Basic/StmtNodes.td        |  1 +
 clang/include/clang/Basic/TokenKinds.def      |  1 +
 clang/include/clang/Parse/Parser.h            |  3 +
 clang/include/clang/Sema/Sema.h               |  9 ++
 .../include/clang/Serialization/ASTBitCodes.h |  1 +
 clang/lib/AST/ASTImporter.cpp                 | 19 ++++-
 clang/lib/AST/ASTStructuralEquivalence.cpp    |  8 ++
 clang/lib/AST/ComputeDependence.cpp           |  8 ++
 clang/lib/AST/Expr.cpp                        |  1 +
 clang/lib/AST/ExprClassification.cpp          |  1 +
 clang/lib/AST/ExprConstant.cpp                |  1 +
 clang/lib/AST/ItaniumMangle.cpp               |  1 +
 clang/lib/AST/StmtPrinter.cpp                 |  8 ++
 clang/lib/AST/StmtProfile.cpp                 |  6 ++
 clang/lib/Parse/ParseExpr.cpp                 |  4 +
 clang/lib/Parse/ParseExprCXX.cpp              | 33 ++++++++
 clang/lib/Sema/SemaExceptionSpec.cpp          |  1 +
 clang/lib/Sema/SemaTypeTraits.cpp             | 66 +++++++++++++++
 clang/lib/Sema/TreeTransform.h                | 35 +++++++-
 clang/lib/Serialization/ASTReaderStmt.cpp     | 13 +++
 clang/lib/Serialization/ASTWriter.cpp         |  1 +
 clang/lib/Serialization/ASTWriterStmt.cpp     |  8 ++
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |  1 +
 clang/test/AST/builtin-type-order.cpp         | 35 ++++++++
 clang/test/PCH/builtin-type-order.cpp         | 31 +++++++
 clang/test/Parser/builtin_type_order.cpp      | 14 ++++
 clang/test/SemaCXX/builtin-type-order.cpp     | 82 +++++++++++++++++++
 clang/tools/libclang/CIndex.cpp               |  6 ++
 clang/tools/libclang/CXCursor.cpp             |  1 +
 37 files changed, 464 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/AST/builtin-type-order.cpp
 create mode 100644 clang/test/PCH/builtin-type-order.cpp
 create mode 100644 clang/test/Parser/builtin_type_order.cpp
 create mode 100644 clang/test/SemaCXX/builtin-type-order.cpp

diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md
index 85586174e9190..6080f70ec8311 100644
--- a/clang/docs/LanguageExtensions.md
+++ b/clang/docs/LanguageExtensions.md
@@ -2058,6 +2058,9 @@ The following type trait primitives are supported by 
Clang. Those traits marked
 - `__builtin_lt_synthesizes_from_spaceship`, 
`__builtin_gt_synthesizes_from_spaceship`,
   `__builtin_le_synthesizes_from_spaceship`, 
`__builtin_ge_synthesizes_from_spaceship` (Clang):
   These builtins can be used to determine whether the corresponding operator 
is synthesized from a spaceship operator.
+- `__builtin_type_order` (C++): Returns `std::strong_ordering::less` if `T` 
precedes `U` in an
+  implementation-defined total ordering of all types, 
`std::strong_ordering::greater` if `U` precedes `T`, 
+  and `std::strong_ordering::equal` if they are the same type.
 
 In addition, the following expression traits are supported:
 
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 9a19bb2f2d5c7..6ac9e3678ade1 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -125,6 +125,9 @@ features cannot lower the translation-unit ABI level;
 
 #### C++2c Feature Support
 
+- Added `__builtin_type_order` for compatibility with GCC as part of the
+  implementation of 
[P2830R10](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html)
 (Constexpr Type Ordering).
+
 - Clang now supports 
[P3533R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3533r2.html)
 (constexpr virtual inheritance).
 
 #### C++23 Feature Support
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h 
b/clang/include/clang/AST/ASTNodeTraverser.h
index a8a73c5b72d33..14fcbf3656752 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -934,6 +934,11 @@ class ASTNodeTraverser
       Visit(A->getType());
   }
 
+  void VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *E) {
+    Visit(E->getLhsType());
+    Visit(E->getRhsType());
+  }
+
   void VisitLambdaExpr(const LambdaExpr *Node) {
     if (Traversal == TK_IgnoreUnlessSpelledInSource) {
       for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
diff --git a/clang/include/clang/AST/ComputeDependence.h 
b/clang/include/clang/AST/ComputeDependence.h
index 3a3c86842501a..c78cf273dc17e 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -83,6 +83,7 @@ class CXXDependentScopeMemberExpr;
 class MaterializeTemporaryExpr;
 class CXXFoldExpr;
 class CXXParenListInitExpr;
+class BuiltinTypeOrderExpr;
 class TypeTraitExpr;
 class ConceptSpecializationExpr;
 class SYCLUniqueStableNameExpr;
@@ -178,6 +179,7 @@ ExprDependence 
computeDependence(CXXDependentScopeMemberExpr *E);
 ExprDependence computeDependence(MaterializeTemporaryExpr *E);
 ExprDependence computeDependence(CXXFoldExpr *E);
 ExprDependence computeDependence(CXXParenListInitExpr *E);
+ExprDependence computeDependence(BuiltinTypeOrderExpr *E);
 ExprDependence computeDependence(TypeTraitExpr *E);
 ExprDependence computeDependence(ConceptSpecializationExpr *E,
                                  bool ValueDependent);
diff --git a/clang/include/clang/AST/ExprCXX.h 
b/clang/include/clang/AST/ExprCXX.h
index d3d3b9c6d6326..9b56fa5515f7f 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2886,6 +2886,49 @@ class CXXPseudoDestructorExpr : public Expr {
   }
 };
 
+/// Represents a C++26 __builtin_type_order(T, U) expression. Used to implement
+/// std::type_order.
+class BuiltinTypeOrderExpr final : public Expr {
+  friend class ASTStmtReader;
+
+  SourceLocation Loc;
+  SourceLocation RParenLoc;
+  TypeSourceInfo *Lhs;
+  TypeSourceInfo *Rhs;
+
+public:
+  BuiltinTypeOrderExpr(QualType T, SourceLocation Loc, TypeSourceInfo *LHS,
+                       TypeSourceInfo *RHS, SourceLocation RParenLoc)
+      : Expr(BuiltinTypeOrderExprClass, T, VK_PRValue, OK_Ordinary), Loc(Loc),
+        RParenLoc(RParenLoc), Lhs(LHS), Rhs(RHS) {
+    setDependence(computeDependence(this));
+  }
+
+  explicit BuiltinTypeOrderExpr(EmptyShell Empty)
+      : Expr(BuiltinTypeOrderExprClass, Empty) {}
+
+  TypeSourceInfo *getLhsTypeInfo() const { return Lhs; }
+  TypeSourceInfo *getRhsTypeInfo() const { return Rhs; }
+
+  QualType getLhsType() const { return getLhsTypeInfo()->getType(); }
+  QualType getRhsType() const { return getRhsTypeInfo()->getType(); }
+
+  SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
+  SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == BuiltinTypeOrderExprClass;
+  }
+
+  child_range children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+
+  const_child_range children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+};
+
 /// A type trait used in the implementation of various C++11 and
 /// Library TR1 trait templates.
 ///
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index 617990b82edca..2ee34d4675865 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2865,6 +2865,11 @@ DEF_TRAVERSE_STMT(TypeTraitExpr, {
     TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc()));
 })
 
+DEF_TRAVERSE_STMT(BuiltinTypeOrderExpr, {
+  TRY_TO(TraverseTypeLoc(S->getLhsTypeInfo()->getTypeLoc()));
+  TRY_TO(TraverseTypeLoc(S->getRhsTypeInfo()->getTypeLoc()));
+})
+
 DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
   TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
 })
diff --git a/clang/include/clang/AST/StmtDataCollectors.td 
b/clang/include/clang/AST/StmtDataCollectors.td
index abf4b5f34d349..8b8c9da988579 100644
--- a/clang/include/clang/AST/StmtDataCollectors.td
+++ b/clang/include/clang/AST/StmtDataCollectors.td
@@ -37,6 +37,12 @@ class TypeTraitExpr {
       addData(S->getArg(i)->getType());
   }];
 }
+class BuiltinTypeOrderExpr {
+  code Code = [{
+    addData(S->getLhsType());
+    addData(S->getRhsType());
+  }];
+}
 
 //--- Calls --------------------------------------------------------------//
 class CallExpr {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b314c17ad27bd..9356416eed302 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13354,7 +13354,7 @@ def warn_invalid_default_version_priority
 
 // three-way comparison operator diagnostics
 def err_implied_comparison_category_type_not_found : Error<
-  "cannot %select{use builtin operator '<=>'|default 'operator<=>'}1 "
+  "cannot %select{use builtin operator '<=>'|default 'operator<=>'|retrieve 
type order}1 "
   "because type '%0' was not found; include <compare>">;
 def err_spaceship_argument_narrowing : Error<
   "argument to 'operator<=>' "
diff --git a/clang/include/clang/Basic/StmtNodes.td 
b/clang/include/clang/Basic/StmtNodes.td
index 6df244d7a8c90..0c0f82f944ceb 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -150,6 +150,7 @@ def CXXStdInitializerListExpr : StmtNode<Expr>;
 def CXXNewExpr : StmtNode<Expr>;
 def CXXDeleteExpr : StmtNode<Expr>;
 def CXXPseudoDestructorExpr : StmtNode<Expr>;
+def BuiltinTypeOrderExpr : StmtNode<Expr>;
 def TypeTraitExpr : StmtNode<Expr>;
 def ArrayTypeTraitExpr : StmtNode<Expr>;
 def ExpressionTraitExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Basic/TokenKinds.def 
b/clang/include/clang/Basic/TokenKinds.def
index dc9c7d8109467..38995aca639a5 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -469,6 +469,7 @@ KEYWORD(__builtin_FUNCSIG           , KEYMS)
 KEYWORD(__builtin_LINE              , KEYALL)
 KEYWORD(__builtin_COLUMN            , KEYALL)
 KEYWORD(__builtin_source_location   , KEYCXX)
+KEYWORD(__builtin_type_order        , KEYCXX)
 
 KEYWORD(__builtin_va_arg            , KEYALL)
 KEYWORD(__extension__               , KEYALL)
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 163aa483a84e3..feb39ecb5ca55 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -5195,6 +5195,9 @@ class Parser : public CodeCompletionHandler {
   ///
   ExprResult ParseTypeTrait();
 
+  /// Parse __builtin_type_order(T, U), used to implement C++26 
std::type_order.
+  ExprResult ParseBuiltinTypeOrder();
+
   
//===--------------------------------------------------------------------===//
   // Embarcadero: Arary and Expression Traits
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d931e70cb2342..ecccc1d985924 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5335,6 +5335,8 @@ class Sema final : public SemaBase {
     /// typically only applies to 'std::strong_ordering', due to the implicit
     /// fallback return value.
     DefaultedOperator,
+    /// The '__builtin_type_order' builtin needed 'std::strong_ordering'.
+    BuiltinTypeOrder,
   };
 
   /// Lookup the specified comparison category types in the standard
@@ -8723,6 +8725,13 @@ class Sema final : public SemaBase {
 
   bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N);
 
+  ExprResult ActOnBuiltinTypeOrder(SourceLocation KWLoc, ParsedType LhsTy,
+                                   ParsedType RhsTy, SourceLocation RParenLoc);
+  ExprResult BuildBuiltinTypeOrderExpr(SourceLocation KWLoc,
+                                       TypeSourceInfo *LhsT,
+                                       TypeSourceInfo *RhsT,
+                                       SourceLocation RParenLoc);
+
   /// Parsed one of the type trait support pseudo-functions.
   ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
                             ArrayRef<ParsedType> Args,
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h 
b/clang/include/clang/Serialization/ASTBitCodes.h
index b582cbdadc070..191918df5e5e7 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1938,6 +1938,7 @@ enum StmtCode {
 
   EXPR_OPAQUE_VALUE,                // OpaqueValueExpr
   EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
+  EXPR_BUILTIN_TYPE_ORDER,          // BuiltinTypeOrderExpr
   EXPR_TYPE_TRAIT,                  // TypeTraitExpr
   EXPR_ARRAY_TYPE_TRAIT,            // ArrayTypeTraitIntExpr
 
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 5be9ce780aec5..a8c03b1eb768c 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -696,7 +696,9 @@ namespace clang {
     ExpectedStmt VisitArrayInitIndexExpr(ArrayInitIndexExpr *E);
     ExpectedStmt VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E);
     ExpectedStmt VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
-    ExpectedStmt 
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
+    ExpectedStmt
+    VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
+    ExpectedStmt VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E);
     ExpectedStmt VisitTypeTraitExpr(TypeTraitExpr *E);
     ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E);
     ExpectedStmt VisitCXXFoldExpr(CXXFoldExpr *E);
@@ -9157,6 +9159,21 @@ ExpectedStmt 
ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
       ToParamType, E->getIndex(), E->getPackIndex(), E->getFinal());
 }
 
+ExpectedStmt
+ASTNodeImporter::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
+  Error Err = Error::success();
+  auto ToType = importChecked(Err, E->getType());
+  auto ToBeginLoc = importChecked(Err, E->getBeginLoc());
+  auto ToEndLoc = importChecked(Err, E->getEndLoc());
+  auto *ToLhs = importChecked(Err, E->getLhsTypeInfo());
+  auto *ToRhs = importChecked(Err, E->getRhsTypeInfo());
+  if (Err)
+    return std::move(Err);
+
+  return new (Importer.getToContext())
+      BuiltinTypeOrderExpr(ToType, ToBeginLoc, ToLhs, ToRhs, ToEndLoc);
+}
+
 ExpectedStmt ASTNodeImporter::VisitTypeTraitExpr(TypeTraitExpr *E) {
   Error Err = Error::success();
   auto ToType = importChecked(Err, E->getType());
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp 
b/clang/lib/AST/ASTStructuralEquivalence.cpp
index d8bbfbe5dac72..7cbcdc1bf8495 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -351,6 +351,14 @@ class StmtComparer {
     return true;
   }
 
+  bool IsStmtEquivalent(const BuiltinTypeOrderExpr *E1,
+                        const BuiltinTypeOrderExpr *E2) {
+    return IsStructurallyEquivalent(Context, E1->getLhsType(),
+                                    E2->getLhsType()) &&
+           IsStructurallyEquivalent(Context, E1->getRhsType(),
+                                    E2->getRhsType());
+  }
+
   bool IsStmtEquivalent(const CXXDependentScopeMemberExpr *E1,
                         const CXXDependentScopeMemberExpr *E2) {
     if (!IsStructurallyEquivalent(Context, E1->getMember(), E2->getMember())) {
diff --git a/clang/lib/AST/ComputeDependence.cpp 
b/clang/lib/AST/ComputeDependence.cpp
index 7e6bd69711c5b..40ab05f7f8ebc 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -931,6 +931,14 @@ ExprDependence clang::computeDependence(TypeTraitExpr *E) {
   return D;
 }
 
+ExprDependence clang::computeDependence(BuiltinTypeOrderExpr *E) {
+  ExprDependence D = ExprDependence::None;
+  for (TypeSourceInfo *Arg : {E->getLhsTypeInfo(), E->getRhsTypeInfo()})
+    D |= toExprDependenceAsWritten(Arg->getType()->getDependence()) &
+         ~ExprDependence::Type;
+  return D;
+}
+
 ExprDependence clang::computeDependence(ConceptSpecializationExpr *E,
                                         bool ValueDependent) {
   auto TA = TemplateArgumentDependence::None;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 5d7ee4710481c..55a5d8214e5da 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3747,6 +3747,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
   case CXXNullPtrLiteralExprClass:
   case CXXThisExprClass:
   case CXXScalarValueInitExprClass:
+  case BuiltinTypeOrderExprClass:
   case TypeTraitExprClass:
   case ArrayTypeTraitExprClass:
   case ExpressionTraitExprClass:
diff --git a/clang/lib/AST/ExprClassification.cpp 
b/clang/lib/AST/ExprClassification.cpp
index ef071cdef66b6..37d799e329df0 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -192,6 +192,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const 
Expr *E) {
   case Expr::FloatingLiteralClass:
   case Expr::CXXNoexceptExprClass:
   case Expr::CXXScalarValueInitExprClass:
+  case Expr::BuiltinTypeOrderExprClass:
   case Expr::TypeTraitExprClass:
   case Expr::ArrayTypeTraitExprClass:
   case Expr::ExpressionTraitExprClass:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 480d5119a5363..47df253ddfef4 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -22441,6 +22441,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext 
&Ctx) {
   case Expr::ObjCBoolLiteralExprClass:
   case Expr::CXXBoolLiteralExprClass:
   case Expr::CXXScalarValueInitExprClass:
+  case Expr::BuiltinTypeOrderExprClass:
   case Expr::TypeTraitExprClass:
   case Expr::ConceptSpecializationExprClass:
   case Expr::RequiresExprClass:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index f6c4ca1ae6ba8..126c1b67452c5 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5056,6 +5056,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::StmtExprClass:
   case Expr::ArrayTypeTraitExprClass:
   case Expr::ExpressionTraitExprClass:
+  case Expr::BuiltinTypeOrderExprClass:
   case Expr::VAArgExprClass:
   case Expr::CUDAKernelCallExprClass:
   case Expr::AsTypeExprClass:
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index eeb377c794e05..5f220b26936b1 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2708,6 +2708,14 @@ void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
   OS << ")";
 }
 
+void StmtPrinter::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
+  OS << "__builtin_type_order(";
+  E->getLhsType().print(OS, Policy);
+  OS << ", ";
+  E->getRhsType().print(OS, Policy);
+  OS << ')';
+}
+
 void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
   OS << getTraitSpelling(E->getTrait()) << '(';
   E->getQueriedType().print(OS, Policy);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 45c962aa27553..7baf7443b02f6 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2320,6 +2320,12 @@ void StmtProfiler::VisitTypeTraitExpr(const 
TypeTraitExpr *S) {
     VisitType(S->getArg(I)->getType());
 }
 
+void StmtProfiler::VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *S) {
+  VisitExpr(S);
+  VisitType(S->getLhsType());
+  VisitType(S->getRhsType());
+}
+
 void StmtProfiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *S) {
   VisitExpr(S);
   ID.AddInteger(S->getTrait());
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 87cd7a01451cf..a84de3a72170c 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1523,6 +1523,10 @@ Parser::ParseCastExpression(CastParseKind ParseKind, 
bool isAddressOfOperand,
     break;
   }
 
+  case tok::kw___builtin_type_order:
+    Res = ParseBuiltinTypeOrder();
+    break;
+
 #define TYPE_TRAIT(N,Spelling,K) \
   case tok::kw_##Spelling:
 #include "clang/Basic/TokenKinds.def"
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index f9a0dcc7d53af..57e4f2096a9d9 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -3490,6 +3490,39 @@ static ExpressionTrait 
ExpressionTraitFromTokKind(tok::TokenKind kind) {
   }
 }
 
+ExprResult Parser::ParseBuiltinTypeOrder() {
+  SourceLocation Loc = ConsumeToken();
+
+  BalancedDelimiterTracker Parens(*this, tok::l_paren);
+  if (Parens.expectAndConsume())
+    return ExprError();
+
+  TypeResult LHS = ParseTypeName(/*SourceRange=*/nullptr,
+                                 DeclaratorContext::TemplateTypeArg);
+  if (LHS.isInvalid()) {
+    Parens.skipToEnd();
+    return ExprError();
+  }
+
+  if (ExpectAndConsume(tok::comma)) {
+    Parens.skipToEnd();
+    return ExprError();
+  }
+
+  TypeResult RHS = ParseTypeName(/*SourceRange=*/nullptr,
+                                 DeclaratorContext::TemplateTypeArg);
+  if (RHS.isInvalid()) {
+    Parens.skipToEnd();
+    return ExprError();
+  }
+
+  if (Parens.consumeClose())
+    return ExprError();
+
+  return Actions.ActOnBuiltinTypeOrder(Loc, LHS.get(), RHS.get(),
+                                       Parens.getCloseLocation());
+}
+
 ExprResult Parser::ParseTypeTrait() {
   tok::TokenKind Kind = Tok.getKind();
 
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp 
b/clang/lib/Sema/SemaExceptionSpec.cpp
index d41137ddc85d5..213aa6701fdb0 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1390,6 +1390,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Expr::AddrLabelExprClass:
   case Expr::ArrayTypeTraitExprClass:
   case Expr::AtomicExprClass:
+  case Expr::BuiltinTypeOrderExprClass:
   case Expr::TypeTraitExprClass:
   case Expr::CXXBoolLiteralExprClass:
   case Expr::CXXNoexceptExprClass:
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 53ab235f3654a..78e6d8d76b114 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -10,7 +10,9 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "clang/AST/ComparisonCategories.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/Mangle.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/BuiltinTraits.h"
@@ -25,6 +27,9 @@
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaHLSL.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
 
 using namespace clang;
 
@@ -1463,6 +1468,67 @@ bool Sema::CheckTypeTraitArity(unsigned Arity, 
SourceLocation Loc, size_t N) {
   return true;
 }
 
+static ComparisonCategoryResult EvaluateTypeOrder(Sema &S, QualType LHS,
+                                                  QualType RHS) {
+  if (S.Context.hasSameType(LHS, RHS))
+    return ComparisonCategoryResult::Equal;
+
+  std::unique_ptr<MangleContext> MC(S.Context.createMangleContext());
+  SmallString<64> LhsName, RhsName;
+  {
+    llvm::raw_svector_ostream LhsOut(LhsName), RhsOut(RhsName);
+    MC->mangleCanonicalTypeName(LHS, LhsOut);
+    MC->mangleCanonicalTypeName(RHS, RhsOut);
+  }
+
+  int Result = LhsName.compare(RhsName);
+  return Result == 0  ? ComparisonCategoryResult::Equal
+         : Result > 0 ? ComparisonCategoryResult::Greater
+                      : ComparisonCategoryResult::Less;
+}
+
+ExprResult Sema::ActOnBuiltinTypeOrder(SourceLocation KWLoc, ParsedType LhsTy,
+                                       ParsedType RhsTy,
+                                       SourceLocation RParenLoc) {
+  SmallVector<TypeSourceInfo *, 2> Args;
+  for (auto ArgT : {LhsTy, RhsTy}) {
+    TypeSourceInfo *TInfo;
+    QualType T = GetTypeFromParser(ArgT, &TInfo);
+    if (!TInfo)
+      TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc);
+
+    Args.push_back(TInfo);
+  }
+  return BuildBuiltinTypeOrderExpr(KWLoc, Args[0], Args[1], RParenLoc);
+}
+
+ExprResult Sema::BuildBuiltinTypeOrderExpr(SourceLocation KWLoc,
+                                           TypeSourceInfo *LhsT,
+                                           TypeSourceInfo *RhsT,
+                                           SourceLocation RParenLoc) {
+  QualType StrongOrdering =
+      CheckComparisonCategoryType(ComparisonCategoryType::StrongOrdering, 
KWLoc,
+                                  ComparisonCategoryUsage::BuiltinTypeOrder);
+  if (StrongOrdering.isNull())
+    return ExprError();
+
+  QualType LHS = LhsT->getType();
+  QualType RHS = RhsT->getType();
+  if (LHS->isDependentType() || RHS->isDependentType())
+    return new (Context)
+        BuiltinTypeOrderExpr(StrongOrdering, KWLoc, LhsT, RhsT, RParenLoc);
+
+  ComparisonCategoryResult Result = EvaluateTypeOrder(*this, LHS, RHS);
+  VarDecl *ResultVD = Context.CompCategories.getInfoForType(StrongOrdering)
+                          .getValueInfo(Result)
+                          ->VD;
+  Expr *ResultExpr =
+      BuildDeclRefExpr(ResultVD, ResultVD->getType(), VK_LValue, KWLoc);
+  return PerformCopyInitialization(
+      InitializedEntity::InitializeTemporary(StrongOrdering), KWLoc,
+      ResultExpr);
+}
+
 enum class TypeTraitReturnType {
   Bool,
   SizeT,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index e6abb3ad577c6..035a76c1612de 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3567,6 +3567,17 @@ class TreeTransform {
                                     Operand);
   }
 
+  /// Build a new type ordering expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildBuiltinTypeOrderExpr(SourceLocation StartLoc,
+                                         TypeSourceInfo *LhsT,
+                                         TypeSourceInfo *RhsT,
+                                         SourceLocation RParenLoc) {
+    return getSema().BuildBuiltinTypeOrderExpr(StartLoc, LhsT, RhsT, 
RParenLoc);
+  }
+
   /// Build a new type trait expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -15485,9 +15496,29 @@ 
TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
                                             Old->requiresADL(), &TransArgs);
 }
 
-template<typename Derived>
+template <typename Derived>
 ExprResult
-TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
+TreeTransform<Derived>::TransformBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) 
{
+  SmallVector<TypeSourceInfo *, 2> Args;
+  bool ArgChanged = false;
+  for (TypeSourceInfo *From : {E->getLhsTypeInfo(), E->getRhsTypeInfo()}) {
+    TypeSourceInfo *To = getDerived().TransformType(From);
+    if (!To)
+      return ExprError();
+
+    Args.push_back(To);
+    ArgChanged |= To != From;
+  }
+
+  if (!getDerived().AlwaysRebuild() && !ArgChanged)
+    return E;
+
+  return getDerived().RebuildBuiltinTypeOrderExpr(E->getBeginLoc(), Args[0],
+                                                  Args[1], E->getEndLoc());
+}
+
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
   bool ArgChanged = false;
   SmallVector<TypeSourceInfo *, 4> Args;
   for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 1afde95b05290..2b53f447a29af 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2225,6 +2225,15 @@ void 
ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
   E->NamingClass = readDeclAs<CXXRecordDecl>();
 }
 
+void ASTStmtReader::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
+  VisitExpr(E);
+  SourceRange Range = readSourceRange();
+  E->Loc = Range.getBegin();
+  E->RParenLoc = Range.getEnd();
+  E->Lhs = readTypeSourceInfo();
+  E->Rhs = readTypeSourceInfo();
+}
+
 void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
   VisitExpr(E);
   E->TypeTraitExprBits.IsBooleanTypeTrait = Record.readInt();
@@ -4452,6 +4461,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       break;
     }
 
+    case EXPR_BUILTIN_TYPE_ORDER:
+      S = new (Context) BuiltinTypeOrderExpr(Empty);
+      break;
+
     case EXPR_TYPE_TRAIT:
       S = TypeTraitExpr::CreateDeserialized(
           Context, Record[ASTStmtReader::NumExprFields],
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index f34b2ff182bc8..1c7df49705658 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -866,6 +866,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
   RECORD(EXPR_CXX_NOEXCEPT);
   RECORD(EXPR_OPAQUE_VALUE);
   RECORD(EXPR_BINARY_CONDITIONAL_OPERATOR);
+  RECORD(EXPR_BUILTIN_TYPE_ORDER);
   RECORD(EXPR_TYPE_TRAIT);
   RECORD(EXPR_ARRAY_TYPE_TRAIT);
   RECORD(EXPR_PACK_EXPANSION);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index 3854eabd62a46..780359f58ed34 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2244,6 +2244,14 @@ void 
ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
   }
 }
 
+void ASTStmtWriter::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
+  VisitExpr(E);
+  Record.AddSourceRange(E->getSourceRange());
+  Record.AddTypeSourceInfo(E->getLhsTypeInfo());
+  Record.AddTypeSourceInfo(E->getRhsTypeInfo());
+  Code = serialization::EXPR_BUILTIN_TYPE_ORDER;
+}
+
 void ASTStmtWriter::VisitTypeTraitExpr(TypeTraitExpr *E) {
   VisitExpr(E);
   Record.push_back(E->TypeTraitExprBits.IsBooleanTypeTrait);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 328ed5b23dd83..64ff7766ba9a4 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1699,6 +1699,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::DependentScopeDeclRefExprClass:
     case Stmt::ArrayTypeTraitExprClass:
     case Stmt::ExpressionTraitExprClass:
+    case Stmt::BuiltinTypeOrderExprClass:
     case Stmt::UnresolvedLookupExprClass:
     case Stmt::UnresolvedMemberExprClass:
     case Stmt::RecoveryExprClass:
diff --git a/clang/test/AST/builtin-type-order.cpp 
b/clang/test/AST/builtin-type-order.cpp
new file mode 100644
index 0000000000000..7b2447e647273
--- /dev/null
+++ b/clang/test/AST/builtin-type-order.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -ast-print %s | 
FileCheck %s --check-prefix=PRINT
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -ast-dump 
-ast-dump-filter=dependent_order %s | FileCheck %s --check-prefix=AST
+
+namespace std {
+enum class __order : signed char { less = -1, equal = 0, greater = 1 };
+
+struct strong_ordering {
+  __order value;
+
+  constexpr explicit strong_ordering(__order value) : value(value) {}
+
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+};
+
+inline constexpr strong_ordering strong_ordering::less(__order::less);
+inline constexpr strong_ordering strong_ordering::equal(__order::equal);
+inline constexpr strong_ordering strong_ordering::greater(__order::greater);
+} // namespace std
+
+template <class T, class U>
+constexpr std::strong_ordering dependent_order() {
+  return __builtin_type_order(T, U);
+}
+
+// PRINT: template <class T, class U> constexpr std::strong_ordering 
dependent_order()
+// PRINT: return __builtin_type_order(T, U);
+
+// AST-LABEL: FunctionTemplateDecl {{.*}} dependent_order
+// AST: BuiltinTypeOrderExpr {{.*}} 'std::strong_ordering'
+// AST-NEXT: |-TemplateTypeParmType {{.*}} 'T' dependent
+// AST-NEXT: | `-TemplateTypeParm {{.*}} 'T'
+// AST-NEXT: `-TemplateTypeParmType {{.*}} 'U' dependent
+// AST-NEXT:   `-TemplateTypeParm {{.*}} 'U'
diff --git a/clang/test/PCH/builtin-type-order.cpp 
b/clang/test/PCH/builtin-type-order.cpp
new file mode 100644
index 0000000000000..f948028bb494f
--- /dev/null
+++ b/clang/test/PCH/builtin-type-order.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++20 -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++20 -include-pch %t -DTEST %s -verify
+// RUN: %clang_cc1 -std=c++20 -include-pch %t -DTEST %s -verify 
-fexperimental-new-constant-interpreter
+
+#ifndef TEST
+namespace std {
+enum class __order : signed char { less = -1, equal = 0, greater = 1 };
+
+struct strong_ordering {
+  __order value;
+
+  constexpr explicit strong_ordering(__order value) : value(value) {}
+
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+};
+
+inline constexpr strong_ordering strong_ordering::less(__order::less);
+inline constexpr strong_ordering strong_ordering::equal(__order::equal);
+inline constexpr strong_ordering strong_ordering::greater(__order::greater);
+} // namespace std
+
+template <class T, class U>
+constexpr auto type_order = __builtin_type_order(T, U);
+#else
+static_assert(type_order<int, int>.value == std::__order::equal);
+static_assert(type_order<int, long>.value != std::__order::equal);
+
+// expected-no-diagnostics
+#endif
diff --git a/clang/test/Parser/builtin_type_order.cpp 
b/clang/test/Parser/builtin_type_order.cpp
new file mode 100644
index 0000000000000..293a6b930681b
--- /dev/null
+++ b/clang/test/Parser/builtin_type_order.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template <typename... T>
+void syntax_errors() {
+  (void)__builtin_type_order(int); // expected-error {{expected ','}}
+  (void)__builtin_type_order(T...); // expected-error {{expected ','}}
+
+  (void)__builtin_type_order(int, long, char); 
+  // expected-error@-1 {{expected ')'}} \
+  //   expected-note@-1 {{to match this '('}}
+  (void)__builtin_type_order(int, T...);
+  // expected-error@-1 {{expected ')'}} \
+  //   expected-note@-1 {{to match this '('}}
+}
diff --git a/clang/test/SemaCXX/builtin-type-order.cpp 
b/clang/test/SemaCXX/builtin-type-order.cpp
new file mode 100644
index 0000000000000..2de69008b9e23
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-type-order.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fsyntax-only 
-verify -DITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fsyntax-only 
-verify -DITANIUM -fexperimental-new-constant-interpreter %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++20 -fsyntax-only 
-verify -DMICROSOFT %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++20 -fsyntax-only 
-verify -DMICROSOFT -fexperimental-new-constant-interpreter %s
+
+constexpr auto missing = __builtin_type_order(int, long);
+// expected-error@-1 {{cannot retrieve type order because type 
'std::strong_ordering' was not found; include <compare>}}
+
+namespace std {
+  struct strong_ordering {
+  enum __order { LT = -1, EQ = 0, GT = 1 };
+  __order value;
+
+  constexpr explicit strong_ordering(__order value) : value(value) {}
+  constexpr bool operator==(strong_ordering const& other) const {
+    return value == other.value;
+  }
+  static const strong_ordering less;
+  static const strong_ordering equal;
+  static const strong_ordering greater;
+};
+
+inline constexpr strong_ordering strong_ordering::less(__order::LT);
+inline constexpr strong_ordering strong_ordering::equal(__order::EQ);
+inline constexpr strong_ordering strong_ordering::greater(__order::GT);
+} // namespace std
+
+static_assert(__is_same(decltype(__builtin_type_order(int, long)),
+                        std::strong_ordering));
+
+static_assert(__builtin_type_order(int, int) == std::strong_ordering::equal);
+static_assert(__builtin_type_order(int, int const) != 
std::strong_ordering::equal);
+static_assert(__builtin_type_order(void(*)(int), void(*)(int)) == 
std::strong_ordering::equal);
+
+static_assert(__builtin_type_order(void*, void const volatile*) != 
std::strong_ordering::equal);
+static_assert(__builtin_type_order(int, long) != std::strong_ordering::equal);
+static_assert(__builtin_type_order(int, long).value ==
+              -__builtin_type_order(long, int).value);
+
+using int_alias = int;
+static_assert(__builtin_type_order(int, int_alias) ==
+              std::strong_ordering::equal);
+
+struct incomplete;
+static_assert(__builtin_type_order(incomplete, incomplete) ==
+              std::strong_ordering::equal);
+static_assert(__builtin_type_order(int incomplete::*, char incomplete::*) != 
std::strong_ordering::equal);
+static_assert(__builtin_type_order(void (incomplete::*)(), void 
(incomplete::*)() const) != std::strong_ordering::equal);
+
+struct A {};
+struct B {};
+static_assert(__builtin_type_order(A, B) == std::strong_ordering::less);
+static_assert(__builtin_type_order(B, A) == std::strong_ordering::greater);
+static_assert(__builtin_type_order(void(*)(A), void(*)(B)) == 
std::strong_ordering::less);
+static_assert(__builtin_type_order(A[1], B[1]) == std::strong_ordering::less);
+
+#ifdef ITANIUM
+static_assert(__builtin_type_order(A, int) == std::strong_ordering::less);
+#endif
+#ifdef MICROSOFT
+static_assert(__builtin_type_order(A, int) == std::strong_ordering::greater);
+#endif
+
+template <class T> struct C;
+static_assert(__builtin_type_order(C<A>, C<B>) == std::strong_ordering::less);
+static_assert(__builtin_type_order(C<B>, C<A>) == 
std::strong_ordering::greater);
+
+
+template <class T, class U>
+constexpr std::strong_ordering dependent_order() {
+  return __builtin_type_order(T, U);
+}
+static_assert(dependent_order<int, int>() == std::strong_ordering::equal);
+static_assert(dependent_order<const int, const int>() ==
+              std::strong_ordering::equal);
+
+template <class T>
+constexpr bool dependent_constant_expression() {
+  static_assert(__builtin_type_order(T, T) == std::strong_ordering::equal);
+  return true;
+}
+static_assert(dependent_constant_expression<int>());
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index e485e6e2e5547..e798e691374b1 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2128,6 +2128,7 @@ class EnqueueVisitor : public 
ConstStmtVisitor<EnqueueVisitor, void>,
   void VisitStmt(const Stmt *S);
   void VisitSwitchStmt(const SwitchStmt *S);
   void VisitWhileStmt(const WhileStmt *W);
+  void VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *E);
   void VisitTypeTraitExpr(const TypeTraitExpr *E);
   void VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
   void VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
@@ -3271,6 +3272,11 @@ void EnqueueVisitor::VisitTypeTraitExpr(const 
TypeTraitExpr *E) {
     AddTypeLoc(E->getArg(I - 1));
 }
 
+void EnqueueVisitor::VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *E) {
+  AddTypeLoc(E->getRhsTypeInfo());
+  AddTypeLoc(E->getLhsTypeInfo());
+}
+
 void EnqueueVisitor::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
   AddTypeLoc(E->getQueriedTypeSourceInfo());
 }
diff --git a/clang/tools/libclang/CXCursor.cpp 
b/clang/tools/libclang/CXCursor.cpp
index e27964d0ad6e1..421630c764ebc 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -304,6 +304,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl 
*Parent,
   case Stmt::AsTypeExprClass:
   case Stmt::AtomicExprClass:
   case Stmt::BinaryConditionalOperatorClass:
+  case Stmt::BuiltinTypeOrderExprClass:
   case Stmt::TypeTraitExprClass:
   case Stmt::CoawaitExprClass:
   case Stmt::DependentCoawaitExprClass:

>From 6272eb44e77795475dee3225c95728f3c0597f7e Mon Sep 17 00:00:00 2001
From: Matthias Wippich <[email protected]>
Date: Mon, 17 Aug 2026 02:12:07 +0200
Subject: [PATCH 2/2] rename Lhs/Rhs to LHS/RHS, break up nested conditional
 expression

---
 clang/include/clang/AST/ASTNodeTraverser.h    |  4 ++--
 clang/include/clang/AST/ExprCXX.h             | 14 +++++++-------
 clang/include/clang/AST/RecursiveASTVisitor.h |  4 ++--
 clang/include/clang/AST/StmtDataCollectors.td |  4 ++--
 clang/lib/AST/ASTImporter.cpp                 |  4 ++--
 clang/lib/AST/ASTStructuralEquivalence.cpp    |  8 ++++----
 clang/lib/AST/ComputeDependence.cpp           |  2 +-
 clang/lib/AST/StmtPrinter.cpp                 |  4 ++--
 clang/lib/AST/StmtProfile.cpp                 |  4 ++--
 clang/lib/Sema/SemaTypeTraits.cpp             |  7 ++++---
 clang/lib/Sema/TreeTransform.h                |  2 +-
 clang/lib/Serialization/ASTReaderStmt.cpp     |  4 ++--
 clang/lib/Serialization/ASTWriterStmt.cpp     |  4 ++--
 clang/tools/libclang/CIndex.cpp               |  4 ++--
 14 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/clang/include/clang/AST/ASTNodeTraverser.h 
b/clang/include/clang/AST/ASTNodeTraverser.h
index 14fcbf3656752..e7c02bdae2d74 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -935,8 +935,8 @@ class ASTNodeTraverser
   }
 
   void VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *E) {
-    Visit(E->getLhsType());
-    Visit(E->getRhsType());
+    Visit(E->getLHSType());
+    Visit(E->getRHSType());
   }
 
   void VisitLambdaExpr(const LambdaExpr *Node) {
diff --git a/clang/include/clang/AST/ExprCXX.h 
b/clang/include/clang/AST/ExprCXX.h
index 9b56fa5515f7f..a8ad7065e60bb 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2893,25 +2893,25 @@ class BuiltinTypeOrderExpr final : public Expr {
 
   SourceLocation Loc;
   SourceLocation RParenLoc;
-  TypeSourceInfo *Lhs;
-  TypeSourceInfo *Rhs;
+  TypeSourceInfo *LHS;
+  TypeSourceInfo *RHS;
 
 public:
   BuiltinTypeOrderExpr(QualType T, SourceLocation Loc, TypeSourceInfo *LHS,
                        TypeSourceInfo *RHS, SourceLocation RParenLoc)
       : Expr(BuiltinTypeOrderExprClass, T, VK_PRValue, OK_Ordinary), Loc(Loc),
-        RParenLoc(RParenLoc), Lhs(LHS), Rhs(RHS) {
+        RParenLoc(RParenLoc), LHS(LHS), RHS(RHS) {
     setDependence(computeDependence(this));
   }
 
   explicit BuiltinTypeOrderExpr(EmptyShell Empty)
       : Expr(BuiltinTypeOrderExprClass, Empty) {}
 
-  TypeSourceInfo *getLhsTypeInfo() const { return Lhs; }
-  TypeSourceInfo *getRhsTypeInfo() const { return Rhs; }
+  TypeSourceInfo *getLHSTypeInfo() const { return LHS; }
+  TypeSourceInfo *getRHSTypeInfo() const { return RHS; }
 
-  QualType getLhsType() const { return getLhsTypeInfo()->getType(); }
-  QualType getRhsType() const { return getRhsTypeInfo()->getType(); }
+  QualType getLHSType() const { return getLHSTypeInfo()->getType(); }
+  QualType getRHSType() const { return getRHSTypeInfo()->getType(); }
 
   SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; }
   SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index 2ee34d4675865..e204da9ca3899 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2866,8 +2866,8 @@ DEF_TRAVERSE_STMT(TypeTraitExpr, {
 })
 
 DEF_TRAVERSE_STMT(BuiltinTypeOrderExpr, {
-  TRY_TO(TraverseTypeLoc(S->getLhsTypeInfo()->getTypeLoc()));
-  TRY_TO(TraverseTypeLoc(S->getRhsTypeInfo()->getTypeLoc()));
+  TRY_TO(TraverseTypeLoc(S->getLHSTypeInfo()->getTypeLoc()));
+  TRY_TO(TraverseTypeLoc(S->getRHSTypeInfo()->getTypeLoc()));
 })
 
 DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, {
diff --git a/clang/include/clang/AST/StmtDataCollectors.td 
b/clang/include/clang/AST/StmtDataCollectors.td
index 8b8c9da988579..7863cca48d079 100644
--- a/clang/include/clang/AST/StmtDataCollectors.td
+++ b/clang/include/clang/AST/StmtDataCollectors.td
@@ -39,8 +39,8 @@ class TypeTraitExpr {
 }
 class BuiltinTypeOrderExpr {
   code Code = [{
-    addData(S->getLhsType());
-    addData(S->getRhsType());
+    addData(S->getLHSType());
+    addData(S->getRHSType());
   }];
 }
 
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index a8c03b1eb768c..e85f0c49e8807 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -9165,8 +9165,8 @@ 
ASTNodeImporter::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
   auto ToType = importChecked(Err, E->getType());
   auto ToBeginLoc = importChecked(Err, E->getBeginLoc());
   auto ToEndLoc = importChecked(Err, E->getEndLoc());
-  auto *ToLhs = importChecked(Err, E->getLhsTypeInfo());
-  auto *ToRhs = importChecked(Err, E->getRhsTypeInfo());
+  auto *ToLhs = importChecked(Err, E->getLHSTypeInfo());
+  auto *ToRhs = importChecked(Err, E->getRHSTypeInfo());
   if (Err)
     return std::move(Err);
 
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp 
b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 7cbcdc1bf8495..e9292792bc823 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -353,10 +353,10 @@ class StmtComparer {
 
   bool IsStmtEquivalent(const BuiltinTypeOrderExpr *E1,
                         const BuiltinTypeOrderExpr *E2) {
-    return IsStructurallyEquivalent(Context, E1->getLhsType(),
-                                    E2->getLhsType()) &&
-           IsStructurallyEquivalent(Context, E1->getRhsType(),
-                                    E2->getRhsType());
+    return IsStructurallyEquivalent(Context, E1->getLHSType(),
+                                    E2->getLHSType()) &&
+           IsStructurallyEquivalent(Context, E1->getRHSType(),
+                                    E2->getRHSType());
   }
 
   bool IsStmtEquivalent(const CXXDependentScopeMemberExpr *E1,
diff --git a/clang/lib/AST/ComputeDependence.cpp 
b/clang/lib/AST/ComputeDependence.cpp
index 40ab05f7f8ebc..8e14387641030 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -933,7 +933,7 @@ ExprDependence clang::computeDependence(TypeTraitExpr *E) {
 
 ExprDependence clang::computeDependence(BuiltinTypeOrderExpr *E) {
   ExprDependence D = ExprDependence::None;
-  for (TypeSourceInfo *Arg : {E->getLhsTypeInfo(), E->getRhsTypeInfo()})
+  for (TypeSourceInfo *Arg : {E->getLHSTypeInfo(), E->getRHSTypeInfo()})
     D |= toExprDependenceAsWritten(Arg->getType()->getDependence()) &
          ~ExprDependence::Type;
   return D;
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 5f220b26936b1..44acfc28113c4 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2710,9 +2710,9 @@ void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
 
 void StmtPrinter::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
   OS << "__builtin_type_order(";
-  E->getLhsType().print(OS, Policy);
+  E->getLHSType().print(OS, Policy);
   OS << ", ";
-  E->getRhsType().print(OS, Policy);
+  E->getRHSType().print(OS, Policy);
   OS << ')';
 }
 
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 7baf7443b02f6..d2ff5f6742321 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2322,8 +2322,8 @@ void StmtProfiler::VisitTypeTraitExpr(const TypeTraitExpr 
*S) {
 
 void StmtProfiler::VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *S) {
   VisitExpr(S);
-  VisitType(S->getLhsType());
-  VisitType(S->getRhsType());
+  VisitType(S->getLHSType());
+  VisitType(S->getRHSType());
 }
 
 void StmtProfiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *S) {
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 78e6d8d76b114..898e7ce71a311 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1482,9 +1482,10 @@ static ComparisonCategoryResult EvaluateTypeOrder(Sema 
&S, QualType LHS,
   }
 
   int Result = LhsName.compare(RhsName);
-  return Result == 0  ? ComparisonCategoryResult::Equal
-         : Result > 0 ? ComparisonCategoryResult::Greater
-                      : ComparisonCategoryResult::Less;
+  if (Result == 0)
+    return ComparisonCategoryResult::Equal;
+  return Result > 0 ? ComparisonCategoryResult::Greater
+                    : ComparisonCategoryResult::Less;
 }
 
 ExprResult Sema::ActOnBuiltinTypeOrder(SourceLocation KWLoc, ParsedType LhsTy,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 035a76c1612de..aa630a55fa965 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15501,7 +15501,7 @@ ExprResult
 TreeTransform<Derived>::TransformBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) 
{
   SmallVector<TypeSourceInfo *, 2> Args;
   bool ArgChanged = false;
-  for (TypeSourceInfo *From : {E->getLhsTypeInfo(), E->getRhsTypeInfo()}) {
+  for (TypeSourceInfo *From : {E->getLHSTypeInfo(), E->getRHSTypeInfo()}) {
     TypeSourceInfo *To = getDerived().TransformType(From);
     if (!To)
       return ExprError();
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 2b53f447a29af..09572ffef827b 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2230,8 +2230,8 @@ void 
ASTStmtReader::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
   SourceRange Range = readSourceRange();
   E->Loc = Range.getBegin();
   E->RParenLoc = Range.getEnd();
-  E->Lhs = readTypeSourceInfo();
-  E->Rhs = readTypeSourceInfo();
+  E->LHS = readTypeSourceInfo();
+  E->RHS = readTypeSourceInfo();
 }
 
 void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index 780359f58ed34..1983e7fef73a9 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2247,8 +2247,8 @@ void 
ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
 void ASTStmtWriter::VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E) {
   VisitExpr(E);
   Record.AddSourceRange(E->getSourceRange());
-  Record.AddTypeSourceInfo(E->getLhsTypeInfo());
-  Record.AddTypeSourceInfo(E->getRhsTypeInfo());
+  Record.AddTypeSourceInfo(E->getLHSTypeInfo());
+  Record.AddTypeSourceInfo(E->getRHSTypeInfo());
   Code = serialization::EXPR_BUILTIN_TYPE_ORDER;
 }
 
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index e798e691374b1..e424bf412adc8 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -3273,8 +3273,8 @@ void EnqueueVisitor::VisitTypeTraitExpr(const 
TypeTraitExpr *E) {
 }
 
 void EnqueueVisitor::VisitBuiltinTypeOrderExpr(const BuiltinTypeOrderExpr *E) {
-  AddTypeLoc(E->getRhsTypeInfo());
-  AddTypeLoc(E->getLhsTypeInfo());
+  AddTypeLoc(E->getRHSTypeInfo());
+  AddTypeLoc(E->getLHSTypeInfo());
 }
 
 void EnqueueVisitor::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {

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

Reply via email to