clang 10.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
14 #include "clang/AST/ComparisonCategories.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/Type.h"
18 #include "llvm/ADT/SmallVector.h"
19
20 using namespace clang;
21
22 Optional<ComparisonCategoryType>
23 clang::getComparisonCategoryForBuiltinCmp(QualType T) {
24 using CCT = ComparisonCategoryType;
25
26 if (T->isIntegralOrEnumerationType())
27 return CCT::StrongOrdering;
28
29 if (T->isRealFloatingType())
30 return CCT::PartialOrdering;
31
32 // C++2a [expr.spaceship]p8: If the composite pointer type is an object
33 // pointer type, p <=> q is of type std::strong_ordering.
34 // Note: this assumes neither operand is a null pointer constant.
35 if (T->isObjectPointerType())
36 return CCT::StrongOrdering;
37
38 // TODO: Extend support for operator<=> to ObjC types.
39 return llvm::None;
40 }
41
42 bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
43 assert(VD && "must have var decl");
44 if (!VD->checkInitIsICE())
45 return false;
46
47 // Before we attempt to get the value of the first field, ensure that we
48 // actually have one (and only one) field.
49 auto *Record = VD->getType()->getAsCXXRecordDecl();
50 if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
51 !Record->field_begin()->getType()->isIntegralOrEnumerationType())
52 return false;
53
54 return true;
55 }
56
57 /// Attempt to determine the integer value used to represent the comparison
58 /// category result by evaluating the initializer for the specified VarDecl as
59 /// a constant expression and retreiving the value of the class's first
60 /// (and only) field.
61 ///
62 /// Note: The STL types are expected to have the form:
63 /// struct X { T value; };
64 /// where T is an integral or enumeration type.
65 llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
66 assert(hasValidIntValue() && "must have a valid value");
67 return VD->evaluateValue()->getStructField(0).getInt();
68 }
69
70 ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
71 ComparisonCategoryResult ValueKind) const {
72 // Check if we already have a cache entry for this value.
73 auto It = llvm::find_if(
74 Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
75 if (It != Objects.end())
76 return &(*It);
77
78 // We don't have a cached result. Lookup the variable declaration and create
79 // a new entry representing it.
80 DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
81 &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
82 if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
83 return nullptr;
84 Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
85 return &Objects.back();
86 }
87
88 static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
89 NamespaceDecl *&StdNS) {
90 if (!StdNS) {
91 DeclContextLookupResult Lookup =
92 Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
93 if (!Lookup.empty())
94 StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
95 }
96 return StdNS;
97 }
98
99 static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
100 const NamespaceDecl *StdNS,
101 ComparisonCategoryType Kind) {
102 StringRef Name = ComparisonCategories::getCategoryString(Kind);
103 DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
104 if (!Lookup.empty())
105 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
106 return RD;
107 return nullptr;
108 }
109
110 const ComparisonCategoryInfo *
111 ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
112 auto It = Data.find(static_cast<char>(Kind));
113 if (It != Data.end())
114 return &It->second;
115
116 if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
117 if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
118 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
119
120 return nullptr;
121 }
122
123 const ComparisonCategoryInfo *
124 ComparisonCategories::lookupInfoForType(QualType Ty) const {
125 assert(!Ty.isNull() && "type must be non-null");
126 using CCT = ComparisonCategoryType;
127 auto *RD = Ty->getAsCXXRecordDecl();
128 if (!RD)
129 return nullptr;
130
131 // Check to see if we have information for the specified type cached.
132 const auto *CanonRD = RD->getCanonicalDecl();
133 for (auto &KV : Data) {
134 const ComparisonCategoryInfo &Info = KV.second;
135 if (CanonRD == Info.Record->getCanonicalDecl())
136 return &Info;
137 }
138
139 if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
140 return nullptr;
141
142 // If not, check to see if the decl names a type in namespace std with a name
143 // matching one of the comparison category types.
144 for (unsigned I = static_cast<unsigned>(CCT::First),
145 End = static_cast<unsigned>(CCT::Last);
146 I <= End; ++I) {
147 CCT Kind = static_cast<CCT>(I);
148
149 // We've found the comparison category type. Build a new cache entry for
150 // it.
151 if (getCategoryString(Kind) == RD->getName())
152 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
153 }
154
155 // We've found nothing. This isn't a comparison category type.
156 return nullptr;
157 }
158
159 const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
160 const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
161 assert(Info && "info for comparison category not found");
162 return *Info;
163 }
164
165 QualType ComparisonCategoryInfo::getType() const {
166 assert(Record);
167 return QualType(Record->getTypeForDecl(), 0);
168 }
169
170 StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
171 using CCKT = ComparisonCategoryType;
172 switch (Kind) {
173 case CCKT::PartialOrdering:
174 return "partial_ordering";
175 case CCKT::WeakOrdering:
176 return "weak_ordering";
177 case CCKT::StrongOrdering:
178 return "strong_ordering";
179 }
180 llvm_unreachable("unhandled cases in switch");
181 }
182
183 StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
184 using CCVT = ComparisonCategoryResult;
185 switch (Kind) {
186 case CCVT::Equal:
187 return "equal";
188 case CCVT::Equivalent:
189 return "equivalent";
190 case CCVT::Less:
191 return "less";
192 case CCVT::Greater:
193 return "greater";
194 case CCVT::Unordered:
195 return "unordered";
196 }
197 llvm_unreachable("unhandled case in switch");
198 }
199
200 std::vector<ComparisonCategoryResult>
201 ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
202 using CCT = ComparisonCategoryType;
203 using CCR = ComparisonCategoryResult;
204 std::vector<CCR> Values;
205 Values.reserve(4);
206 bool IsStrong = Type == CCT::StrongOrdering;
207 Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
208 Values.push_back(CCR::Less);
209 Values.push_back(CCR::Greater);
210 if (Type == CCT::PartialOrdering)
211 Values.push_back(CCR::Unordered);
212 return Values;
213 }
clang::ComparisonCategoryInfo
Definition: ComparisonCategories.h:74
clang::if
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
Definition: RecursiveASTVisitor.h:1045
clang::ComparisonCategoryInfo::ValueInfo
Definition: ComparisonCategories.h:83
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:654
lookupCXXRecordDecl
static CXXRecordDecl * lookupCXXRecordDecl(const ASTContext &Ctx, const NamespaceDecl *StdNS, ComparisonCategoryType Kind)
Definition: ComparisonCategories.cpp:99
clang::ComparisonCategoryResult::Equal
clang::ComparisonCategoryResult::Greater
clang::Type::isRealFloatingType
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2021
Type.h
C Language Family Type Representation.
clang::TypeDecl::getTypeForDecl
const Type * getTypeForDecl() const
Definition: Decl.h:3053
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1450
clang::NamespaceDecl
Represent a C++ namespace.
Definition: Decl.h:497
distance
float __ovld __cnfn distance(float p0, float p1)
Returns the distance between p0 and p1.
clang::DeclContextLookupResult::back
reference back() const
Definition: DeclBase.h:1243
clang::ComparisonCategories::getPossibleResultsForType
static std::vector< ComparisonCategoryResult > getPossibleResultsForType(ComparisonCategoryType Type)
Return the list of results which are valid for the specified comparison category type.
Definition: ComparisonCategories.cpp:201
clang::ComparisonCategoryResult::Equivalent
clang::DeclContextLookupResult::front
reference front() const
Definition: DeclBase.h:1242
clang::ComparisonCategories::getResultString
static StringRef getResultString(ComparisonCategoryResult Kind)
Definition: ComparisonCategories.cpp:183
clang::ComparisonCategoryType::PartialOrdering
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:168
llvm::Optional
Definition: LLVM.h:37
clang::DeclContextLookupResult
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1195
clang::ComparisonCategoryInfo::ValueInfo::VD
VarDecl * VD
Definition: ComparisonCategories.h:85
clang::ComparisonCategoryResult
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
Definition: ComparisonCategories.h:65
clang::Type::isIntegralOrEnumerationType
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:6881
clang::ASTContext::Idents
IdentifierTable & Idents
Definition: ASTContext.h:580
clang::ComparisonCategoryType::First
clang::ComparisonCategoryResult::Less
clang::CXXRecordDecl::getCanonicalDecl
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:492
clang::RecordDecl::field_begin
field_iterator field_begin() const
Definition: Decl.cpp:4425
clang::ComparisonCategories::getInfoForType
const ComparisonCategoryInfo & getInfoForType(QualType Ty) const
Return the comparison category information as specified by getCategoryForType(Ty).
Definition: ComparisonCategories.cpp:159
clang::DeclContext::lookup
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1612
clang::ComparisonCategoryType::StrongOrdering
clang::Type::getAsCXXRecordDecl
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1690
clang::ComparisonCategories::getCategoryString
static StringRef getCategoryString(ComparisonCategoryType Kind)
Definition: ComparisonCategories.cpp:170
End
SourceLocation End
Definition: USRLocFinder.cpp:166
clang::ComparisonCategoryInfo::ValueInfo::getIntValue
llvm::APSInt getIntValue() const
Get the constant integer value used by this variable to represent the comparison category result type...
Definition: ComparisonCategories.cpp:65
clang::RecordDecl::field_end
field_iterator field_end() const
Definition: Decl.h:3966
clang::APValue::getStructField
APValue & getStructField(unsigned i)
Definition: APValue.h:507
clang::VarDecl::evaluateValue
APValue * evaluateValue() const
Attempt to evaluate the value of the initializer attached to this declaration, and produce notes expl...
Definition: Decl.cpp:2356
clang::ComparisonCategoryType::Last
clang::ComparisonCategoryType::WeakOrdering
clang::QualType::isNull
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:719
clang::ComparisonCategoryInfo::ValueInfo::hasValidIntValue
bool hasValidIntValue() const
True iff we&#39;ve successfully evaluated the variable as a constant expression and extracted its integer...
Definition: ComparisonCategories.cpp:42
clang::Type::isObjectPointerType
bool isObjectPointerType() const
Definition: Type.h:6528
Kind
Kind
Definition: ChrootChecker.cpp:29
clang::IdentifierTable::get
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Definition: IdentifierTable.h:529
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:18
clang::ComparisonCategories::lookupInfoForType
const ComparisonCategoryInfo * lookupInfoForType(QualType Ty) const
Definition: ComparisonCategories.cpp:124
clang::getComparisonCategoryForBuiltinCmp
Optional< ComparisonCategoryType > getComparisonCategoryForBuiltinCmp(QualType T)
Get the comparison category that should be used when comparing values of type T.
Definition: ComparisonCategories.cpp:23
clang::MultiVersionKind::None
clang::ComparisonCategories::lookupInfo
const ComparisonCategoryInfo * lookupInfo(ComparisonCategoryType Kind) const
Return the cached comparison category information for the specified &#39;Kind&#39;.
Definition: ComparisonCategories.cpp:111
Decl.h
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
lookupStdNamespace
static const NamespaceDecl * lookupStdNamespace(const ASTContext &Ctx, NamespaceDecl *&StdNS)
Definition: ComparisonCategories.cpp:88
clang::ComparisonCategoryInfo::Record
CXXRecordDecl * Record
The declaration for the comparison category type from the standard library.
Definition: ComparisonCategories.h:118
clang::VarDecl::checkInitIsICE
bool checkInitIsICE() const
Determine whether the value of the initializer attached to this declaration is an integral constant e...
Definition: Decl.cpp:2428
DeclCXX.h
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
clang::ASTContext::getTranslationUnitDecl
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1009
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:253
clang::ComparisonCategoryResult::Unordered
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:630
clang::ComparisonCategoryInfo::getType
QualType getType() const
Definition: ComparisonCategories.cpp:165
clang::APValue::getInt
APSInt & getInt()
Definition: APValue.h:380
ComparisonCategories.h
clang::ComparisonCategoryType
ComparisonCategoryType
An enumeration representing the different comparison categories types.
Definition: ComparisonCategories.h:43
clang::DeclContextLookupResult::empty
bool empty() const
Definition: DeclBase.h:1239
clang::ComparisonCategoryInfo::ValueInfo::Kind
ComparisonCategoryResult Kind
Definition: ComparisonCategories.h:84