clang 22.0.0git
ComparisonCategories.cpp
Go to the documentation of this file.
1//===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the Comparison Category enum and data types, which
10// store the types and expressions needed to support operator<=>
11//
12//===----------------------------------------------------------------------===//
13
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Type.h"
19#include "llvm/ADT/SmallVector.h"
20#include <optional>
21
22using namespace clang;
23
24std::optional<ComparisonCategoryType>
26 using CCT = ComparisonCategoryType;
27
28 if (T->isIntegralOrEnumerationType())
29 return CCT::StrongOrdering;
30
31 if (T->isRealFloatingType())
32 return CCT::PartialOrdering;
33
34 // C++2a [expr.spaceship]p8: If the composite pointer type is an object
35 // pointer type, p <=> q is of type std::strong_ordering.
36 // Note: this assumes neither operand is a null pointer constant.
37 if (T->isObjectPointerType())
38 return CCT::StrongOrdering;
39
40 // TODO: Extend support for operator<=> to ObjC types.
41 return std::nullopt;
42}
43
45 assert(VD && "must have var decl");
46 if (!VD->isUsableInConstantExpressions(VD->getASTContext()))
47 return false;
48
49 // Before we attempt to get the value of the first field, ensure that we
50 // actually have one (and only one) field.
51 const auto *Record = VD->getType()->getAsCXXRecordDecl();
52 if (!Record || Record->getNumFields() != 1 ||
53 !Record->field_begin()->getType()->isIntegralOrEnumerationType())
54 return false;
55
56 return true;
57}
58
59/// Attempt to determine the integer value used to represent the comparison
60/// category result by evaluating the initializer for the specified VarDecl as
61/// a constant expression and retrieving the value of the class's first
62/// (and only) field.
63///
64/// Note: The STL types are expected to have the form:
65/// struct X { T value; };
66/// where T is an integral or enumeration type.
68 assert(hasValidIntValue() && "must have a valid value");
69 return VD->evaluateValue()->getStructField(0).getInt();
70}
71
72ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
73 ComparisonCategoryResult ValueKind) const {
74 // Check if we already have a cache entry for this value.
75 auto It = llvm::find_if(
76 Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
77 if (It != Objects.end())
78 return &(*It);
79
80 // We don't have a cached result. Lookup the variable declaration and create
81 // a new entry representing it.
82 DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
84 if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
85 return nullptr;
86 // The static member must have the same type as the comparison category class
87 // itself (e.g., std::partial_ordering::less must be of type
88 // partial_ordering).
89 VarDecl *VD = cast<VarDecl>(Lookup.front());
90 const CXXRecordDecl *VDRecord = VD->getType()->getAsCXXRecordDecl();
91 if (!VDRecord || VDRecord->getCanonicalDecl() != Record->getCanonicalDecl())
92 return nullptr;
93
94 Objects.emplace_back(ValueKind, VD);
95 return &Objects.back();
96}
97
99 NamespaceDecl *&StdNS) {
100 if (!StdNS) {
102 Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
103 if (!Lookup.empty())
104 StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
105 }
106 return StdNS;
107}
108
110 const NamespaceDecl *StdNS,
112 StringRef Name = ComparisonCategories::getCategoryString(Kind);
113 DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
114 if (!Lookup.empty())
115 if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
116 return RD;
117 return nullptr;
118}
119
122 auto It = Data.find(static_cast<char>(Kind));
123 if (It != Data.end())
124 return &It->second;
125
126 if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
127 if (const CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
128 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
129
130 return nullptr;
131}
132
135 assert(!Ty.isNull() && "type must be non-null");
136 using CCT = ComparisonCategoryType;
137 const auto *RD = Ty->getAsCXXRecordDecl();
138 if (!RD)
139 return nullptr;
140
141 // Check to see if we have information for the specified type cached.
142 const auto *CanonRD = RD->getCanonicalDecl();
143 for (const auto &KV : Data) {
144 const ComparisonCategoryInfo &Info = KV.second;
145 if (CanonRD == Info.Record->getCanonicalDecl())
146 return &Info;
147 }
148
149 if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
150 return nullptr;
151
152 // If not, check to see if the decl names a type in namespace std with a name
153 // matching one of the comparison category types.
154 for (unsigned I = static_cast<unsigned>(CCT::First),
155 End = static_cast<unsigned>(CCT::Last);
156 I <= End; ++I) {
157 CCT Kind = static_cast<CCT>(I);
158
159 // We've found the comparison category type. Build a new cache entry for
160 // it.
161 if (getCategoryString(Kind) == RD->getName())
162 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
163 }
164
165 // We've found nothing. This isn't a comparison category type.
166 return nullptr;
167}
168
171 assert(Info && "info for comparison category not found");
172 return *Info;
173}
174
176 assert(Record);
177 return Record->getASTContext().getCanonicalTagType(Record);
178}
179
181 using CCKT = ComparisonCategoryType;
182 switch (Kind) {
183 case CCKT::PartialOrdering:
184 return "partial_ordering";
185 case CCKT::WeakOrdering:
186 return "weak_ordering";
187 case CCKT::StrongOrdering:
188 return "strong_ordering";
189 }
190 llvm_unreachable("unhandled cases in switch");
191}
192
194 using CCVT = ComparisonCategoryResult;
195 switch (Kind) {
196 case CCVT::Equal:
197 return "equal";
198 case CCVT::Equivalent:
199 return "equivalent";
200 case CCVT::Less:
201 return "less";
202 case CCVT::Greater:
203 return "greater";
204 case CCVT::Unordered:
205 return "unordered";
206 }
207 llvm_unreachable("unhandled case in switch");
208}
209
210std::vector<ComparisonCategoryResult>
212 using CCT = ComparisonCategoryType;
213 using CCR = ComparisonCategoryResult;
214 std::vector<CCR> Values;
215 Values.reserve(4);
216 bool IsStrong = Type == CCT::StrongOrdering;
217 Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
218 Values.push_back(CCR::Less);
219 Values.push_back(CCR::Greater);
220 if (Type == CCT::PartialOrdering)
221 Values.push_back(CCR::Unordered);
222 return Values;
223}
Defines the clang::ASTContext interface.
static const NamespaceDecl * lookupStdNamespace(const ASTContext &Ctx, NamespaceDecl *&StdNS)
static const CXXRecordDecl * lookupCXXRecordDecl(const ASTContext &Ctx, const NamespaceDecl *StdNS, ComparisonCategoryType Kind)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::MachO::Record Record
Definition MachO.h:31
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
TranslationUnitDecl * getTranslationUnitDecl() const
IdentifierTable & Idents
Definition ASTContext.h:790
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition DeclCXX.h:522
const ComparisonCategoryInfo * lookupInfoForType(QualType Ty) const
const ComparisonCategoryInfo & getInfoForType(QualType Ty) const
Return the comparison category information as specified by getCategoryForType(Ty).
const ComparisonCategoryInfo * lookupInfo(ComparisonCategoryType Kind) const
Return the cached comparison category information for the specified 'Kind'.
static StringRef getCategoryString(ComparisonCategoryType Kind)
static StringRef getResultString(ComparisonCategoryResult Kind)
static std::vector< ComparisonCategoryResult > getPossibleResultsForType(ComparisonCategoryType Type)
Return the list of results which are valid for the specified comparison category type.
const CXXRecordDecl * Record
The declaration for the comparison category type from the standard library.
ComparisonCategoryInfo(const ASTContext &Ctx, const CXXRecordDecl *RD, ComparisonCategoryType Kind)
The results of name lookup within a DeclContext.
Definition DeclBase.h:1382
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Represent a C++ namespace.
Definition Decl.h:592
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
The base class of the type hierarchy.
Definition TypeBase.h:1833
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
std::optional< ComparisonCategoryType > getComparisonCategoryForBuiltinCmp(QualType T)
Get the comparison category that should be used when comparing values of type T.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
const FunctionProtoType * T
ComparisonCategoryType
An enumeration representing the different comparison categories types.
U cast(CodeGen::Address addr)
Definition Address.h:327
bool hasValidIntValue() const
True iff we've successfully evaluated the variable as a constant expression and extracted its integer...
llvm::APSInt getIntValue() const
Get the constant integer value used by this variable to represent the comparison category result type...