[clang] [clang] Implement the __builtin_type_order intrinsic for P2830R10 Constexpr Type Ordering (PR #216462)
Matthias Wippich via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 18 20:08:57 PDT 2026
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 <mfwippich at gmail.com>
Date: Sat, 15 Aug 2026 09:02:00 +0200
Subject: [PATCH 1/8] [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 at -1 {{expected ')'}} \
+ // expected-note at -1 {{to match this '('}}
+ (void)__builtin_type_order(int, T...);
+ // expected-error at -1 {{expected ')'}} \
+ // expected-note at -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 at -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 <mfwippich at gmail.com>
Date: Mon, 17 Aug 2026 02:12:07 +0200
Subject: [PATCH 2/8] 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) {
>From f9a0d890ad3f1a471f88d9977c91adedc69f6d95 Mon Sep 17 00:00:00 2001
From: Matthias Wippich <mfwippich at gmail.com>
Date: Wed, 19 Aug 2026 04:06:04 +0200
Subject: [PATCH 3/8] reimplement in terms of TypeTraitExpr
---
clang/include/clang/AST/ExprCXX.h | 11 ++-
clang/include/clang/Basic/BuiltinTraits.td | 5 ++
clang/include/clang/Sema/Sema.h | 4 +-
clang/lib/AST/ByteCode/Compiler.cpp | 16 ++++
clang/lib/AST/ExprCXX.cpp | 30 ++++++--
clang/lib/AST/ExprConstant.cpp | 43 ++++++++---
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 43 ++++++++---
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 1 +
clang/lib/CodeGen/CGExprAgg.cpp | 43 ++++++++---
clang/lib/CodeGen/CGExprScalar.cpp | 1 +
clang/lib/Sema/SemaTypeTraits.cpp | 74 +++++++++++++------
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 2 +
clang/test/AST/ast-dump-traits.cpp | 57 +++++++++++---
clang/test/CIR/CodeGen/cxx-traits.cpp | 61 +++++++++++++++
clang/test/PCH/cxx-traits.cpp | 4 +
clang/test/PCH/cxx-traits.h | 23 ++++++
16 files changed, 343 insertions(+), 75 deletions(-)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index a8ad7065e60bb..2704df16acb87 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_AST_EXPRCXX_H
#include "clang/AST/ASTConcept.h"
+#include "clang/AST/ComparisonCategories.h"
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
@@ -2948,7 +2949,7 @@ class TypeTraitExpr final
TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc,
- std::variant<bool, APValue> Value);
+ std::variant<bool, APValue, ComparisonCategoryResult> Value);
TypeTraitExpr(EmptyShell Empty, bool IsStoredAsBool);
@@ -2977,6 +2978,12 @@ class TypeTraitExpr final
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc, APValue Value);
+ static TypeTraitExpr *Create(const ASTContext &C, QualType T,
+ SourceLocation Loc, TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc,
+ ComparisonCategoryResult Value);
+
static TypeTraitExpr *CreateDeserialized(const ASTContext &C,
bool IsStoredAsBool,
unsigned NumArgs);
@@ -2996,7 +3003,7 @@ class TypeTraitExpr final
}
const APValue &getAPValue() const {
- assert(!isValueDependent() && !TypeTraitExprBits.IsBooleanTypeTrait);
+ assert(!TypeTraitExprBits.IsBooleanTypeTrait);
return *getTrailingObjects<APValue>();
}
diff --git a/clang/include/clang/Basic/BuiltinTraits.td b/clang/include/clang/Basic/BuiltinTraits.td
index f5546acdb17c4..17a8b4a4623d1 100644
--- a/clang/include/clang/Basic/BuiltinTraits.td
+++ b/clang/include/clang/Basic/BuiltinTraits.td
@@ -126,6 +126,11 @@ def TypeCompatible : BinaryTrait {
let KeyFlags = [KEYNOCXX];
}
+def TypeOrder : BinaryTrait {
+ let Spelling = "__builtin_type_order2";
+ let KeyFlags = [KEYCXX];
+}
+
// MS Extensions
def IsInterfaceClass : UnaryTrait {
let Spelling = "__is_interface_class";
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ecccc1d985924..4b41f3acdfb6e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5335,8 +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,
+ /// A builtin needed 'std::strong_ordering' (eg. '__builtin_type_order').
+ Builtin,
};
/// Lookup the specified comparison category types in the standard
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index bfb5df69b0e3a..02dcb68026571 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3681,6 +3681,22 @@ bool Compiler<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
return this->emitConstBool(E->getBoolValue(), E);
return this->emitConst(E->getBoolValue(), E);
}
+ if (!E->getType()->isIntegerType()) {
+ const ComparisonCategoryInfo &CmpInfo =
+ Ctx.getASTContext().CompCategories.getInfoForType(E->getType());
+ const auto Result =
+ ComparisonCategoryResult(E->getAPValue().getInt().getZExtValue());
+ const Record *R = getRecord(E->getType());
+ if (!R || R->getNumFields() == 0)
+ return false;
+ const Record::Field *Field = R->getField(0U);
+ PrimType FieldT = classifyPrim(Field->Decl->getType());
+ if (!this->emitConst(CmpInfo.getValueInfo(Result)->getIntValue(), FieldT,
+ E))
+ return false;
+ return this->emitInitField(FieldT, Field->Offset, E);
+ }
+
PrimType T = classifyPrim(E->getType());
return this->visitAPValue(E->getAPValue(), T, E);
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 6c1cde6540d85..13db61573bd7f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
+#include "clang/AST/ComparisonCategories.h"
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclAccessPair.h"
@@ -1864,10 +1865,10 @@ bool MaterializeTemporaryExpr::isUsableInConstantExpressions(
VD->isUsableInConstantExpressions(Context);
}
-TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
- ArrayRef<TypeSourceInfo *> Args,
- SourceLocation RParenLoc,
- std::variant<bool, APValue> Value)
+TypeTraitExpr::TypeTraitExpr(
+ QualType T, SourceLocation Loc, TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc,
+ std::variant<bool, APValue, ComparisonCategoryResult> Value)
: Expr(TypeTraitExprClass, T, VK_PRValue, OK_Ordinary), Loc(Loc),
RParenLoc(RParenLoc) {
assert(Kind <= TT_Last && "invalid enum value!");
@@ -1879,9 +1880,14 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
TypeTraitExprBits.IsBooleanTypeTrait = std::holds_alternative<bool>(Value);
if (TypeTraitExprBits.IsBooleanTypeTrait)
TypeTraitExprBits.Value = std::get<bool>(Value);
- else
- ::new (getTrailingObjects<APValue>())
- APValue(std::get<APValue>(std::move(Value)));
+ else {
+ if (auto *CCR = std::get_if<ComparisonCategoryResult>(&Value)) {
+ llvm::APSInt EncodedValue = llvm::APSInt::get(llvm::to_underlying(*CCR));
+ ::new (getTrailingObjects<APValue>()) APValue(std::move(EncodedValue));
+ } else
+ ::new (getTrailingObjects<APValue>())
+ APValue(std::get<APValue>(std::move(Value)));
+ }
TypeTraitExprBits.NumArgs = Args.size();
assert(Args.size() == TypeTraitExprBits.NumArgs &&
@@ -1923,6 +1929,16 @@ TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T,
return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
}
+TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T,
+ SourceLocation Loc, TypeTrait Kind,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc,
+ ComparisonCategoryResult Value) {
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<APValue, TypeSourceInfo *>(1, Args.size()));
+ return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
+}
+
TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
bool IsStoredAsBool,
unsigned NumArgs) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 47df253ddfef4..2053ae3beb1ec 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -42,6 +42,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/ComparisonCategories.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
#include "clang/AST/Expr.h"
#include "clang/AST/InferAlloc.h"
@@ -11357,6 +11358,7 @@ namespace {
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
bool VisitBinCmp(const BinaryOperator *E);
+ bool VisitTypeTraitExpr(const TypeTraitExpr *E);
bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
ArrayRef<Expr *> Args);
@@ -19443,6 +19445,22 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return DoAfter();
}
+static bool EvaluateComparisonResult(EvalInfo &Info, const Expr *E,
+ ComparisonCategoryResult CCR,
+ APValue &Result) {
+ const ComparisonCategoryInfo &CmpInfo =
+ Info.Ctx.CompCategories.getInfoForType(E->getType());
+ const VarDecl *VD = CmpInfo.getValueInfo(CmpInfo.makeWeakResult(CCR))->VD;
+
+ // Check and evaluate the result as a constant expression.
+ LValue LV;
+ LV.set(VD);
+ if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ return false;
+ return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
+ ConstantExprKind::Normal);
+}
+
bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
if (!CheckLiteralType(Info, E))
return false;
@@ -19465,24 +19483,25 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
CCR = ComparisonCategoryResult::Unordered;
break;
}
- // Evaluation succeeded. Lookup the information for the comparison category
- // type and fetch the VarDecl for the result.
- const ComparisonCategoryInfo &CmpInfo =
- Info.Ctx.CompCategories.getInfoForType(E->getType());
- const VarDecl *VD = CmpInfo.getValueInfo(CmpInfo.makeWeakResult(CCR))->VD;
- // Check and evaluate the result as a constant expression.
- LValue LV;
- LV.set(VD);
- if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
- return false;
- return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
- ConstantExprKind::Normal);
+ return EvaluateComparisonResult(Info, E, CCR, Result);
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
return ExprEvaluatorBaseTy::VisitBinCmp(E);
});
}
+bool RecordExprEvaluator::VisitTypeTraitExpr(const TypeTraitExpr *E) {
+ if (!CheckLiteralType(Info, E))
+ return false;
+
+ assert(!E->isStoredAsBoolean() && E->getAPValue().isInt() &&
+ "expected a non-boolean type trait with a stored value");
+
+ ComparisonCategoryResult CCR = static_cast<ComparisonCategoryResult>(
+ E->getAPValue().getInt().getZExtValue());
+ return EvaluateComparisonResult(Info, E, CCR, Result);
+}
+
bool RecordExprEvaluator::VisitCXXParenListInitExpr(
const CXXParenListInitExpr *E) {
return VisitCXXParenListOrInitListExpr(E, E->getInitExprs());
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 6f57551c3ce24..dbc9eee8c5e6e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -147,6 +147,10 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
void emitNullInitializationToLValue(mlir::Location loc, LValue lv);
+ void emitComparisonResult(const Expr *e, mlir::Location loc,
+ const ComparisonCategoryInfo &cmpInfo,
+ mlir::Value resultValue);
+
void Visit(Expr *e) { StmtVisitor<AggExprEmitter>::Visit(e); }
void VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
@@ -423,18 +427,22 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
}
}
- // Create the return value in the destination slot.
- ensureDest(loc, e->getType());
- LValue destLVal = cgf.makeAddrLValue(dest.getAddress(), e->getType());
+ emitComparisonResult(e, loc, cmpInfo, resultScalar);
+ }
+
+ void VisitTypeTraitExpr(const TypeTraitExpr *e) {
+ assert(!e->isStoredAsBoolean() && !e->getType()->isIntegerType() &&
+ "expected a non-boolean type trait with a stored value");
- // Emit the address of the first (and only) field in the comparison category
- // type, and initialize it from the constant integer value produced above.
- const FieldDecl *resultField = *cmpInfo.Record->field_begin();
- LValue fieldLVal = cgf.emitLValueForFieldInitialization(
- destLVal, resultField, resultField->getName());
- cgf.emitStoreThroughLValue(RValue::get(resultScalar), fieldLVal);
+ const ComparisonCategoryInfo &cmpInfo =
+ cgf.getContext().CompCategories.getInfoForType(e->getType());
+ const auto result =
+ ComparisonCategoryResult(e->getAPValue().getInt().getZExtValue());
+ mlir::Location loc = cgf.getLoc(e->getSourceRange());
+ mlir::Value resultValue = cgf.getBuilder().getConstInt(
+ loc, cmpInfo.getValueInfo(result)->getIntValue());
- // All done! The result is in the dest slot.
+ emitComparisonResult(e, loc, cmpInfo, resultValue);
}
void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *e) {
@@ -999,6 +1007,21 @@ void AggExprEmitter::emitNullInitializationToLValue(mlir::Location loc,
cgf.emitNullInitialization(loc, lv.getAddress(), lv.getType());
}
+void AggExprEmitter::emitComparisonResult(const Expr *e, mlir::Location loc,
+ const ComparisonCategoryInfo &cmpInfo,
+ mlir::Value resultValue) {
+ // Create the return value in the destination slot.
+ ensureDest(loc, e->getType());
+ LValue destLVal = cgf.makeAddrLValue(dest.getAddress(), e->getType());
+
+ // Emit the address of the first (and only) field in the comparison category
+ // type, and initialize it from the constant integer value produced above.
+ const FieldDecl *resultField = *cmpInfo.Record->field_begin();
+ LValue fieldLVal = cgf.emitLValueForFieldInitialization(
+ destLVal, resultField, resultField->getName());
+ cgf.emitStoreThroughLValue(RValue::get(resultValue), fieldLVal);
+}
+
void AggExprEmitter::VisitLambdaExpr(LambdaExpr *e) {
CIRGenFunction::SourceLocRAIIObject loc{cgf, cgf.getLoc(e->getSourceRange())};
AggValueSlot slot = ensureSlot(cgf.getLoc(e->getSourceRange()), e->getType());
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 8d660a0a2c721..d08fee1f55be2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -901,6 +901,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
return builder.getConstInt(loc, cgf.convertType(e->getType()),
(uint64_t)e->getBoolValue());
}
+ assert(e->getType()->isIntegerType() && "not a scalar type trait");
return builder.getConstInt(loc, e->getAPValue().getInt());
}
mlir::Value
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index bc35ffdaad2bd..bc89f3fa37fd3 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -95,6 +95,10 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
Expr *ExprToVisit, ArrayRef<Expr *> Args,
Expr *ArrayFiller);
+ void EmitComparisonResult(const Expr *E,
+ const ComparisonCategoryInfo &CmpInfo,
+ llvm::Value *ResultValue);
+
AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
return AggValueSlot::NeedsGCBarriers;
@@ -164,6 +168,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
void VisitBinAssign(const BinaryOperator *E);
void VisitBinComma(const BinaryOperator *E);
void VisitBinCmp(const BinaryOperator *E);
+ void VisitTypeTraitExpr(const TypeTraitExpr *E);
void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
Visit(E->getSemanticForm());
}
@@ -1204,6 +1209,21 @@ static llvm::Value *EmitCompare(CGBuilderTy &Builder, CodeGenFunction &CGF,
"already been handled");
}
+void AggExprEmitter::EmitComparisonResult(const Expr *E,
+ const ComparisonCategoryInfo &CmpInfo,
+ llvm::Value *ResultValue) {
+ // Create the return value in the destination slot.
+ EnsureDest(E->getType());
+ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
+
+ // Emit the address of the first (and only) field in the comparison category
+ // type, and initialize it from the constant integer value selected above.
+ LValue FieldLV = CGF.EmitLValueForFieldInitialization(
+ DestLV, *CmpInfo.Record->field_begin());
+ CGF.EmitStoreThroughLValue(RValue::get(ResultValue), FieldLV,
+ /*IsInit=*/true);
+}
+
void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
using llvm::BasicBlock;
using llvm::PHINode;
@@ -1271,17 +1291,22 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
Select = Builder.CreateSelect(
EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()), SelectGT, "sel.lt");
}
- // Create the return value in the destination slot.
- EnsureDest(E->getType());
- LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
- // Emit the address of the first (and only) field in the comparison category
- // type, and initialize it from the constant integer value selected above.
- LValue FieldLV = CGF.EmitLValueForFieldInitialization(
- DestLV, *CmpInfo.Record->field_begin());
- CGF.EmitStoreThroughLValue(RValue::get(Select), FieldLV, /*IsInit*/ true);
+ EmitComparisonResult(E, CmpInfo, Select);
+}
+
+void AggExprEmitter::VisitTypeTraitExpr(const TypeTraitExpr *E) {
+ assert(!E->isStoredAsBoolean() && E->getAPValue().isInt() &&
+ "expected a non-boolean type trait with a stored value");
+
+ const ComparisonCategoryInfo &CmpInfo =
+ CGF.getContext().CompCategories.getInfoForType(E->getType());
+ const auto Result =
+ ComparisonCategoryResult(E->getAPValue().getInt().getZExtValue());
+ llvm::Value *ResultValue =
+ Builder.getInt(CmpInfo.getValueInfo(Result)->getIntValue());
- // All done! The result is in the Dest slot.
+ EmitComparisonResult(E, CmpInfo, ResultValue);
}
void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 67014904ffb37..d15892f8dc23d 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -786,6 +786,7 @@ class ScalarExprEmitter
if (E->isStoredAsBoolean())
return llvm::ConstantInt::get(ConvertType(E->getType()),
E->getBoolValue());
+ assert(E->getType()->isIntegerType() && "not a scalar type trait");
assert(E->getAPValue().isInt() && "APValue type not supported");
return llvm::ConstantInt::get(ConvertType(E->getType()),
E->getAPValue().getInt());
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 898e7ce71a311..8a3d4aa31787c 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -636,6 +636,26 @@ static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) {
}
}
+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);
+ if (Result == 0)
+ return ComparisonCategoryResult::Equal;
+ return Result > 0 ? ComparisonCategoryResult::Greater
+ : ComparisonCategoryResult::Less;
+}
+
static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
SourceLocation KeyLoc,
TypeSourceInfo *TInfo) {
@@ -1413,6 +1433,32 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
return false;
}
+static ExprResult
+EvaluateStrongOrderingTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<TypeSourceInfo *> Args,
+ SourceLocation RParenLoc, bool IsDependent) {
+ QualType StrongOrdering = S.CheckComparisonCategoryType(
+ ComparisonCategoryType::StrongOrdering, KWLoc,
+ Sema::ComparisonCategoryUsage::Builtin);
+ if (StrongOrdering.isNull())
+ return ExprError();
+
+ if (IsDependent)
+ return TypeTraitExpr::Create(S.Context, StrongOrdering, KWLoc, Kind, Args,
+ RParenLoc, APValue());
+
+ switch (Kind) {
+ case clang::BTT_TypeOrder: {
+ ComparisonCategoryResult Result =
+ EvaluateTypeOrder(S, Args[0]->getType(), Args[1]->getType());
+ return TypeTraitExpr::Create(S.Context, StrongOrdering, KWLoc, Kind, Args,
+ RParenLoc, Result);
+ }
+ default:
+ llvm_unreachable("not a strong_ordering type trait");
+ }
+}
+
namespace {
void DiagnoseBuiltinDeprecation(Sema &S, TypeTrait Kind, SourceLocation KWLoc) {
TypeTrait Replacement;
@@ -1468,26 +1514,6 @@ 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);
- if (Result == 0)
- return ComparisonCategoryResult::Equal;
- return Result > 0 ? ComparisonCategoryResult::Greater
- : ComparisonCategoryResult::Less;
-}
-
ExprResult Sema::ActOnBuiltinTypeOrder(SourceLocation KWLoc, ParsedType LhsTy,
ParsedType RhsTy,
SourceLocation RParenLoc) {
@@ -1509,7 +1535,7 @@ ExprResult Sema::BuildBuiltinTypeOrderExpr(SourceLocation KWLoc,
SourceLocation RParenLoc) {
QualType StrongOrdering =
CheckComparisonCategoryType(ComparisonCategoryType::StrongOrdering, KWLoc,
- ComparisonCategoryUsage::BuiltinTypeOrder);
+ ComparisonCategoryUsage::Builtin);
if (StrongOrdering.isNull())
return ExprError();
@@ -1533,11 +1559,14 @@ ExprResult Sema::BuildBuiltinTypeOrderExpr(SourceLocation KWLoc,
enum class TypeTraitReturnType {
Bool,
SizeT,
+ StrongOrdering,
};
static TypeTraitReturnType GetReturnType(TypeTrait Kind) {
if (Kind == TypeTrait::UTT_StructuredBindingSize)
return TypeTraitReturnType::SizeT;
+ if (Kind == TypeTrait::BTT_TypeOrder)
+ return TypeTraitReturnType::StrongOrdering;
return TypeTraitReturnType::Bool;
}
@@ -1574,6 +1603,9 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
return TypeTraitExpr::Create(Context, Context.getSizeType(), KWLoc, Kind,
Args, RParenLoc, Result);
}
+ case TypeTraitReturnType::StrongOrdering:
+ return EvaluateStrongOrderingTypeTrait(*this, Kind, KWLoc, Args, RParenLoc,
+ Dependent);
}
llvm_unreachable("unhandled type trait return type");
}
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 57c97b2852445..d48836d0c391b 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -368,6 +368,8 @@ std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
const auto *TE = cast<TypeTraitExpr>(E);
if (TE->isStoredAsBoolean())
return makeTruthVal(TE->getBoolValue(), TE->getType());
+ if (!TE->getType()->isIntegerType())
+ return UnknownVal();
assert(TE->getAPValue().isInt() && "APValue type not supported");
return makeIntVal(TE->getAPValue().getInt());
}
diff --git a/clang/test/AST/ast-dump-traits.cpp b/clang/test/AST/ast-dump-traits.cpp
index b844fd6bcc49c..cbd8d19445357 100644
--- a/clang/test/AST/ast-dump-traits.cpp
+++ b/clang/test/AST/ast-dump-traits.cpp
@@ -33,6 +33,28 @@ void test_unary_expr_or_type_trait() {
(void) alignof(int);
(void) __alignof(int);
}
+
+namespace std {
+struct strong_ordering {
+ signed char value;
+
+ constexpr explicit strong_ordering(signed char 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{-1};
+inline constexpr strong_ordering strong_ordering::equal{0};
+inline constexpr strong_ordering strong_ordering::greater{1};
+} // namespace std
+
+template <class T, class U>
+constexpr std::strong_ordering test_strong_ordering_type_trait() {
+ return __builtin_type_order(T, U);
+}
+
// CHECK: TranslationUnitDecl {{.*}} <<invalid sloc>> <invalid sloc>{{( <undeserialized declarations>)?}}
// CHECK: |-FunctionDecl {{.*}} <{{.*}}ast-dump-traits.cpp:10:1, line:18:1> line:10:6{{( imported)?}} test_type_trait 'void ()'
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:24, line:18:1>
@@ -48,10 +70,10 @@ void test_unary_expr_or_type_trait() {
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'float'
// CHECK-NEXT: | `-CStyleCastExpr {{.*}} <line:17:3, col:47> 'void' <ToVoid>
// CHECK-NEXT: | `-TypeTraitExpr {{.*}} <col:10, col:47> 'bool' __is_constructible
-// CHECK-NEXT: |-BuiltinType {{.*}} 'int'
-// CHECK-NEXT: |-BuiltinType {{.*}} 'int'
-// CHECK-NEXT: |-BuiltinType {{.*}} 'int'
-// CHECK-NEXT: `-BuiltinType {{.*}} 'int'
+// CHECK-NEXT: | |-BuiltinType {{.*}} 'int'
+// CHECK-NEXT: | |-BuiltinType {{.*}} 'int'
+// CHECK-NEXT: | |-BuiltinType {{.*}} 'int'
+// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-FunctionDecl {{.*}} <line:20:1, line:23:1> line:20:6{{( imported)?}} test_array_type_trait 'void ()'
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:30, line:23:1>
// CHECK-NEXT: | `-CStyleCastExpr {{.*}} <line:22:3, col:34> 'void' <ToVoid>
@@ -60,11 +82,22 @@ void test_unary_expr_or_type_trait() {
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:30, line:28:1>
// CHECK-NEXT: | `-CStyleCastExpr {{.*}} <line:27:3, col:28> 'void' <ToVoid>
// CHECK-NEXT: | `-ExpressionTraitExpr {{.*}} <col:10, col:28> 'bool' __is_lvalue_expr
-// CHECK-NEXT: `-FunctionDecl {{.*}} <line:30:1, line:35:1> line:30:6{{( imported)?}} test_unary_expr_or_type_trait 'void ()'
-// CHECK-NEXT: `-CompoundStmt {{.*}} <col:38, line:35:1>
-// CHECK-NEXT: |-CStyleCastExpr {{.*}} <line:32:3, col:20> 'void' <ToVoid>
-// CHECK-NEXT: | `-UnaryExprOrTypeTraitExpr {{.*}} <col:10, col:20> '__size_t':'unsigned long' sizeof 'int'
-// CHECK-NEXT: |-CStyleCastExpr {{.*}} <line:33:3, col:21> 'void' <ToVoid>
-// CHECK-NEXT: | `-UnaryExprOrTypeTraitExpr {{.*}} <col:10, col:21> '__size_t':'unsigned long' alignof 'int'
-// CHECK-NEXT: `-CStyleCastExpr {{.*}} <line:34:3, col:23> 'void' <ToVoid>
-// CHECK-NEXT: `-UnaryExprOrTypeTraitExpr {{.*}} <col:10, col:23> '__size_t':'unsigned long' __alignof 'int'
+// CHECK-NEXT: |-FunctionDecl {{.*}} <line:30:1, line:35:1> line:30:6{{( imported)?}} test_unary_expr_or_type_trait 'void ()'
+// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:38, line:35:1>
+// CHECK-NEXT: | |-CStyleCastExpr {{.*}} <line:32:3, col:20> 'void' <ToVoid>
+// CHECK-NEXT: | | `-UnaryExprOrTypeTraitExpr {{.*}} <col:10, col:20> '__size_t':'unsigned long' sizeof 'int'
+// CHECK-NEXT: | |-CStyleCastExpr {{.*}} <line:33:3, col:21> 'void' <ToVoid>
+// CHECK-NEXT: | | `-UnaryExprOrTypeTraitExpr {{.*}} <col:10, col:21> '__size_t':'unsigned long' alignof 'int'
+// CHECK-NEXT: | `-CStyleCastExpr {{.*}} <line:34:3, col:23> 'void' <ToVoid>
+// CHECK-NEXT: | `-UnaryExprOrTypeTraitExpr {{.*}} <col:10, col:23> '__size_t':'unsigned long' __alignof 'int'
+// CHECK: `-FunctionTemplateDecl {{.*}} <line:53:1, line:56:1> line:54:32{{( imported)?}} test_strong_ordering_type_trait
+// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} <line:53:11, col:17> col:17{{( imported)?}} referenced class depth 0 index 0 T
+// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} <col:20, col:26> col:26{{( imported)?}} referenced class depth 0 index 1 U
+// CHECK-NEXT: `-FunctionDecl {{.*}} <line:54:1, line:56:1> line:54:32{{( imported)?}} constexpr test_strong_ordering_type_trait 'std::strong_ordering ()'
+// CHECK-NEXT: `-CompoundStmt {{.*}} <col:66, line:56:1>
+// CHECK-NEXT: `-ReturnStmt {{.*}} <line:55:3, col:36>
+// CHECK-NEXT: `-TypeTraitExpr {{.*}} <col:10, col:36> 'std::strong_ordering' __builtin_type_order2
+// CHECK-NEXT: |-TemplateTypeParmType {{.*}} 'T' dependent{{( imported)?}} depth 0 index 0
+// CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'T'
+// CHECK-NEXT: `-TemplateTypeParmType {{.*}} 'U' dependent{{( imported)?}} depth 0 index 1
+// CHECK-NEXT: `-TemplateTypeParm {{.*}} 'U'
diff --git a/clang/test/CIR/CodeGen/cxx-traits.cpp b/clang/test/CIR/CodeGen/cxx-traits.cpp
index e078b8a178d2b..1a27e2c3a80cb 100644
--- a/clang/test/CIR/CodeGen/cxx-traits.cpp
+++ b/clang/test/CIR/CodeGen/cxx-traits.cpp
@@ -5,6 +5,25 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+namespace std {
+struct strong_ordering {
+ signed char value;
+
+ constexpr explicit strong_ordering(signed char 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(-1);
+inline constexpr strong_ordering strong_ordering::equal(0);
+inline constexpr strong_ordering strong_ordering::greater(1);
+} // namespace std
+
+struct A {};
+struct B {};
+
void expression_trait_expr() {
bool a = __is_lvalue_expr(0);
}
@@ -79,3 +98,45 @@ void array_type_trait_expr() {
// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8
// OGCG: store i64 2, ptr %[[A_ADDR]], align 8
// OGCG: store i64 20, ptr %[[B_ADDR]], align 8
+
+std::strong_ordering strong_ordering_type_trait_equal() {
+ return __builtin_type_order(int, int);
+}
+
+std::strong_ordering strong_ordering_type_trait_less() {
+ return __builtin_type_order(A, B);
+}
+
+std::strong_ordering strong_ordering_type_trait_greater() {
+ return __builtin_type_order(B, A);
+}
+
+// CIR-LABEL: cir.func {{.*}}@_Z32strong_ordering_type_trait_equalv
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s8i
+// CIR: cir.store {{.*}} %[[ZERO]], {{.*}} : !s8i, !cir.ptr<!s8i>
+
+// CIR-LABEL: cir.func {{.*}}@_Z31strong_ordering_type_trait_lessv
+// CIR: %[[MINUS_ONE:.*]] = cir.const #cir.int<-1> : !s8i
+// CIR: cir.store {{.*}} %[[MINUS_ONE]], {{.*}} : !s8i, !cir.ptr<!s8i>
+
+// CIR-LABEL: cir.func {{.*}}@_Z34strong_ordering_type_trait_greaterv
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s8i
+// CIR: cir.store {{.*}} %[[ONE]], {{.*}} : !s8i, !cir.ptr<!s8i>
+
+// LLVM-LABEL: define{{.*}} i8 @_Z32strong_ordering_type_trait_equalv()
+// LLVM: store i8 0
+
+// LLVM-LABEL: define{{.*}} i8 @_Z31strong_ordering_type_trait_lessv()
+// LLVM: store i8 -1
+
+// LLVM-LABEL: define{{.*}} i8 @_Z34strong_ordering_type_trait_greaterv()
+// LLVM: store i8 1
+
+// OGCG-LABEL: define{{.*}} i8 @_Z32strong_ordering_type_trait_equalv()
+// OGCG: store i8 0
+
+// OGCG-LABEL: define{{.*}} i8 @_Z31strong_ordering_type_trait_lessv()
+// OGCG: store i8 -1
+
+// OGCG-LABEL: define{{.*}} i8 @_Z34strong_ordering_type_trait_greaterv()
+// OGCG: store i8 1
diff --git a/clang/test/PCH/cxx-traits.cpp b/clang/test/PCH/cxx-traits.cpp
index 01b9e9302d790..b801aaec56009 100644
--- a/clang/test/PCH/cxx-traits.cpp
+++ b/clang/test/PCH/cxx-traits.cpp
@@ -3,6 +3,7 @@
// RUN: %clang_cc1 -fms-extensions -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
// RUN: %clang_cc1 -fms-extensions -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
#ifdef PCH
// expected-no-diagnostics
@@ -14,6 +15,9 @@ bool _Is_empty_check = n::__is_empty<int>::__value;
bool default_construct_int = n::is_trivially_constructible<int>::value;
bool copy_construct_int = n::is_trivially_constructible<int, const int&>::value;
+static_assert(type_order<int, int>().value == std::__order::equal, "");
+static_assert(type_order<int, long>().value != std::__order::equal, "");
+
// The built-ins should still work too:
bool _is_abstract_result = __is_abstract(int);
bool _is_aggregate_result = __is_aggregate(int);
diff --git a/clang/test/PCH/cxx-traits.h b/clang/test/PCH/cxx-traits.h
index 0a4bd09c363e9..1385018e4caa9 100644
--- a/clang/test/PCH/cxx-traits.h
+++ b/clang/test/PCH/cxx-traits.h
@@ -69,3 +69,26 @@ struct __is_volatile {}; // expected-warning {{made available}}
}
+
+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;
+};
+
+constexpr strong_ordering strong_ordering::less(__order::less);
+constexpr strong_ordering strong_ordering::equal(__order::equal);
+constexpr strong_ordering strong_ordering::greater(__order::greater);
+} // namespace std
+
+template <class T, class U>
+constexpr std::strong_ordering type_order() {
+ return __builtin_type_order(T, U);
+}
>From 6a4cfe8a7e40e2d189574bfc6f90d26187ee5022 Mon Sep 17 00:00:00 2001
From: Matthias Wippich <mfwippich at gmail.com>
Date: Wed, 19 Aug 2026 04:23:44 +0200
Subject: [PATCH 4/8] revert node-based implementation
---
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/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 | 7 ---
.../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 | 42 ------------------
clang/lib/Sema/TreeTransform.h | 34 +--------------
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/tools/libclang/CIndex.cpp | 6 ---
clang/tools/libclang/CXCursor.cpp | 1 -
33 files changed, 2 insertions(+), 349 deletions(-)
delete mode 100644 clang/test/AST/builtin-type-order.cpp
delete mode 100644 clang/test/PCH/builtin-type-order.cpp
delete mode 100644 clang/test/Parser/builtin_type_order.cpp
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index e7c02bdae2d74..a8a73c5b72d33 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -934,11 +934,6 @@ 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 c78cf273dc17e..3a3c86842501a 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -83,7 +83,6 @@ class CXXDependentScopeMemberExpr;
class MaterializeTemporaryExpr;
class CXXFoldExpr;
class CXXParenListInitExpr;
-class BuiltinTypeOrderExpr;
class TypeTraitExpr;
class ConceptSpecializationExpr;
class SYCLUniqueStableNameExpr;
@@ -179,7 +178,6 @@ 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 2704df16acb87..56ce2c9dfe987 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2887,49 +2887,6 @@ 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 e204da9ca3899..617990b82edca 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2865,11 +2865,6 @@ 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 7863cca48d079..abf4b5f34d349 100644
--- a/clang/include/clang/AST/StmtDataCollectors.td
+++ b/clang/include/clang/AST/StmtDataCollectors.td
@@ -37,12 +37,6 @@ 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/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index 0c0f82f944ceb..6df244d7a8c90 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -150,7 +150,6 @@ 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 38995aca639a5..dc9c7d8109467 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -469,7 +469,6 @@ 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 feb39ecb5ca55..163aa483a84e3 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -5195,9 +5195,6 @@ 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 4b41f3acdfb6e..63988e110168c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8725,13 +8725,6 @@ 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 191918df5e5e7..b582cbdadc070 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1938,7 +1938,6 @@ 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 e85f0c49e8807..5be9ce780aec5 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -696,9 +696,7 @@ namespace clang {
ExpectedStmt VisitArrayInitIndexExpr(ArrayInitIndexExpr *E);
ExpectedStmt VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E);
ExpectedStmt VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
- ExpectedStmt
- VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
- ExpectedStmt VisitBuiltinTypeOrderExpr(BuiltinTypeOrderExpr *E);
+ ExpectedStmt VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
ExpectedStmt VisitTypeTraitExpr(TypeTraitExpr *E);
ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E);
ExpectedStmt VisitCXXFoldExpr(CXXFoldExpr *E);
@@ -9159,21 +9157,6 @@ 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 e9292792bc823..d8bbfbe5dac72 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -351,14 +351,6 @@ 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 8e14387641030..7e6bd69711c5b 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -931,14 +931,6 @@ 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 55a5d8214e5da..5d7ee4710481c 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3747,7 +3747,6 @@ 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 37d799e329df0..ef071cdef66b6 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -192,7 +192,6 @@ 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 2053ae3beb1ec..d6c4a5d21b46e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -22460,7 +22460,6 @@ 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 126c1b67452c5..f6c4ca1ae6ba8 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5056,7 +5056,6 @@ 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 44acfc28113c4..eeb377c794e05 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2708,14 +2708,6 @@ 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 d2ff5f6742321..45c962aa27553 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2320,12 +2320,6 @@ 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 a84de3a72170c..87cd7a01451cf 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1523,10 +1523,6 @@ 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 57e4f2096a9d9..f9a0dcc7d53af 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -3490,39 +3490,6 @@ 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 213aa6701fdb0..d41137ddc85d5 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1390,7 +1390,6 @@ 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 8a3d4aa31787c..557fc7b4fb33a 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1514,48 +1514,6 @@ bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
return true;
}
-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::Builtin);
- 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 aa630a55fa965..454e497c385fe 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3567,17 +3567,6 @@ 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.
@@ -15496,28 +15485,7 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
Old->requiresADL(), &TransArgs);
}
-template <typename Derived>
-ExprResult
-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>
+template<typename Derived>
ExprResult TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
bool ArgChanged = false;
SmallVector<TypeSourceInfo *, 4> Args;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 09572ffef827b..1afde95b05290 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2225,15 +2225,6 @@ 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();
@@ -4461,10 +4452,6 @@ 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 1c7df49705658..f34b2ff182bc8 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -866,7 +866,6 @@ 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 1983e7fef73a9..3854eabd62a46 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2244,14 +2244,6 @@ 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 64ff7766ba9a4..328ed5b23dd83 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1699,7 +1699,6 @@ 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
deleted file mode 100644
index 7b2447e647273..0000000000000
--- a/clang/test/AST/builtin-type-order.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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
deleted file mode 100644
index f948028bb494f..0000000000000
--- a/clang/test/PCH/builtin-type-order.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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
deleted file mode 100644
index 293a6b930681b..0000000000000
--- a/clang/test/Parser/builtin_type_order.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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 at -1 {{expected ')'}} \
- // expected-note at -1 {{to match this '('}}
- (void)__builtin_type_order(int, T...);
- // expected-error at -1 {{expected ')'}} \
- // expected-note at -1 {{to match this '('}}
-}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index e424bf412adc8..e485e6e2e5547 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2128,7 +2128,6 @@ 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);
@@ -3272,11 +3271,6 @@ 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 421630c764ebc..e27964d0ad6e1 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -304,7 +304,6 @@ 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 c68a55b918e2ca8f7b5012d4f76413d4933003b8 Mon Sep 17 00:00:00 2001
From: Matthias Wippich <mfwippich at gmail.com>
Date: Wed, 19 Aug 2026 04:24:12 +0200
Subject: [PATCH 5/8] rename new trait
---
clang/include/clang/Basic/BuiltinTraits.td | 2 +-
clang/test/AST/ast-dump-traits.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/BuiltinTraits.td b/clang/include/clang/Basic/BuiltinTraits.td
index 17a8b4a4623d1..b4a0c7379d373 100644
--- a/clang/include/clang/Basic/BuiltinTraits.td
+++ b/clang/include/clang/Basic/BuiltinTraits.td
@@ -127,7 +127,7 @@ def TypeCompatible : BinaryTrait {
}
def TypeOrder : BinaryTrait {
- let Spelling = "__builtin_type_order2";
+ let Spelling = "__builtin_type_order";
let KeyFlags = [KEYCXX];
}
diff --git a/clang/test/AST/ast-dump-traits.cpp b/clang/test/AST/ast-dump-traits.cpp
index cbd8d19445357..1826268272545 100644
--- a/clang/test/AST/ast-dump-traits.cpp
+++ b/clang/test/AST/ast-dump-traits.cpp
@@ -96,7 +96,7 @@ constexpr std::strong_ordering test_strong_ordering_type_trait() {
// CHECK-NEXT: `-FunctionDecl {{.*}} <line:54:1, line:56:1> line:54:32{{( imported)?}} constexpr test_strong_ordering_type_trait 'std::strong_ordering ()'
// CHECK-NEXT: `-CompoundStmt {{.*}} <col:66, line:56:1>
// CHECK-NEXT: `-ReturnStmt {{.*}} <line:55:3, col:36>
-// CHECK-NEXT: `-TypeTraitExpr {{.*}} <col:10, col:36> 'std::strong_ordering' __builtin_type_order2
+// CHECK-NEXT: `-TypeTraitExpr {{.*}} <col:10, col:36> 'std::strong_ordering' __builtin_type_order
// CHECK-NEXT: |-TemplateTypeParmType {{.*}} 'T' dependent{{( imported)?}} depth 0 index 0
// CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'T'
// CHECK-NEXT: `-TemplateTypeParmType {{.*}} 'U' dependent{{( imported)?}} depth 0 index 1
>From a0121bd4fb59521f33537c69be603d403f51dc26 Mon Sep 17 00:00:00 2001
From: Matthias Wippich <mfwippich at gmail.com>
Date: Wed, 19 Aug 2026 04:45:29 +0200
Subject: [PATCH 6/8] massage the diagnostic
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/test/SemaCXX/builtin-type-order.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9356416eed302..d70e640d084f1 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<=>'|retrieve type order}1 "
+ "cannot %select{use builtin operator '<=>'|default 'operator<=>'|compute order}1 "
"because type '%0' was not found; include <compare>">;
def err_spaceship_argument_narrowing : Error<
"argument to 'operator<=>' "
diff --git a/clang/test/SemaCXX/builtin-type-order.cpp b/clang/test/SemaCXX/builtin-type-order.cpp
index 2de69008b9e23..42c8c16bfbace 100644
--- a/clang/test/SemaCXX/builtin-type-order.cpp
+++ b/clang/test/SemaCXX/builtin-type-order.cpp
@@ -4,7 +4,7 @@
// 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 at -1 {{cannot retrieve type order because type 'std::strong_ordering' was not found; include <compare>}}
+// expected-error at -1 {{cannot compute order because type 'std::strong_ordering' was not found; include <compare>}}
namespace std {
struct strong_ordering {
>From 0ad10cee7da901dc53779620ea16ca6bbcd0af1f Mon Sep 17 00:00:00 2001
From: Matthias Wippich <mfwippich at gmail.com>
Date: Wed, 19 Aug 2026 05:05:25 +0200
Subject: [PATCH 7/8] fix column mismatch
---
clang/test/AST/ast-dump-traits.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/AST/ast-dump-traits.cpp b/clang/test/AST/ast-dump-traits.cpp
index 1826268272545..8fdb1eedcde39 100644
--- a/clang/test/AST/ast-dump-traits.cpp
+++ b/clang/test/AST/ast-dump-traits.cpp
@@ -95,8 +95,8 @@ constexpr std::strong_ordering test_strong_ordering_type_trait() {
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} <col:20, col:26> col:26{{( imported)?}} referenced class depth 0 index 1 U
// CHECK-NEXT: `-FunctionDecl {{.*}} <line:54:1, line:56:1> line:54:32{{( imported)?}} constexpr test_strong_ordering_type_trait 'std::strong_ordering ()'
// CHECK-NEXT: `-CompoundStmt {{.*}} <col:66, line:56:1>
-// CHECK-NEXT: `-ReturnStmt {{.*}} <line:55:3, col:36>
-// CHECK-NEXT: `-TypeTraitExpr {{.*}} <col:10, col:36> 'std::strong_ordering' __builtin_type_order
+// CHECK-NEXT: `-ReturnStmt {{.*}} <line:55:3, col:35>
+// CHECK-NEXT: `-TypeTraitExpr {{.*}} <col:10, col:35> 'std::strong_ordering' __builtin_type_order
// CHECK-NEXT: |-TemplateTypeParmType {{.*}} 'T' dependent{{( imported)?}} depth 0 index 0
// CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'T'
// CHECK-NEXT: `-TemplateTypeParmType {{.*}} 'U' dependent{{( imported)?}} depth 0 index 1
>From 9d56f6f9841d39751ec2e235454bb056b8a914f6 Mon Sep 17 00:00:00 2001
From: Matthias Wippich <mfwippich at gmail.com>
Date: Wed, 19 Aug 2026 05:08:38 +0200
Subject: [PATCH 8/8] revert accidental formatting change
---
clang/lib/Sema/TreeTransform.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 454e497c385fe..e6abb3ad577c6 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15486,7 +15486,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
}
template<typename Derived>
-ExprResult TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
+ExprResult
+TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
bool ArgChanged = false;
SmallVector<TypeSourceInfo *, 4> Args;
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
More information about the cfe-commits
mailing list