clang 8.0.0

ComparisonCategories.cpp
Go to the documentation of this file.
1 //===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the Comparison Category enum and data types, which
11 // store the types and expressions needed to support operator<=>
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "clang/AST/ComparisonCategories.h"
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
21 using namespace clang;
22
23 bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
24 assert(VD && "must have var decl");
25 if (!VD->checkInitIsICE())
26 return false;
27
28 // Before we attempt to get the value of the first field, ensure that we
29 // actually have one (and only one) field.
30 auto *Record = VD->getType()->getAsCXXRecordDecl();
31 if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
32 !Record->field_begin()->getType()->isIntegralOrEnumerationType())
33 return false;
34
35 return true;
36 }
37
38 /// Attempt to determine the integer value used to represent the comparison
39 /// category result by evaluating the initializer for the specified VarDecl as
40 /// a constant expression and retreiving the value of the class's first
41 /// (and only) field.
42 ///
43 /// Note: The STL types are expected to have the form:
44 /// struct X { T value; };
45 /// where T is an integral or enumeration type.
46 llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
47 assert(hasValidIntValue() && "must have a valid value");
48 return VD->evaluateValue()->getStructField(0).getInt();
49 }
50
51 ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
52 ComparisonCategoryResult ValueKind) const {
53 // Check if we already have a cache entry for this value.
54 auto It = llvm::find_if(
55 Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
56 if (It != Objects.end())
57 return &(*It);
58
59 // We don't have a cached result. Lookup the variable declaration and create
60 // a new entry representing it.
61 DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
62 &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
63 if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front()))
64 return nullptr;
65 Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
66 return &Objects.back();
67 }
68
69 static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
70 NamespaceDecl *&StdNS) {
71 if (!StdNS) {
72 DeclContextLookupResult Lookup =
73 Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
74 if (Lookup.size() == 1)
75 StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
76 }
77 return StdNS;
78 }
79
80 static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
81 const NamespaceDecl *StdNS,
82 ComparisonCategoryType Kind) {
83 StringRef Name = ComparisonCategories::getCategoryString(Kind);
84 DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
85 if (Lookup.size() == 1)
86 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
87 return RD;
88 return nullptr;
89 }
90
91 const ComparisonCategoryInfo *
92 ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
93 auto It = Data.find(static_cast<char>(Kind));
94 if (It != Data.end())
95 return &It->second;
96
97 if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
98 if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
99 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
100
101 return nullptr;
102 }
103
104 const ComparisonCategoryInfo *
105 ComparisonCategories::lookupInfoForType(QualType Ty) const {
106 assert(!Ty.isNull() && "type must be non-null");
107 using CCT = ComparisonCategoryType;
108 auto *RD = Ty->getAsCXXRecordDecl();
109 if (!RD)
110 return nullptr;
111
112 // Check to see if we have information for the specified type cached.
113 const auto *CanonRD = RD->getCanonicalDecl();
114 for (auto &KV : Data) {
115 const ComparisonCategoryInfo &Info = KV.second;
116 if (CanonRD == Info.Record->getCanonicalDecl())
117 return &Info;
118 }
119
120 if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
121 return nullptr;
122
123 // If not, check to see if the decl names a type in namespace std with a name
124 // matching one of the comparison category types.
125 for (unsigned I = static_cast<unsigned>(CCT::First),
126 End = static_cast<unsigned>(CCT::Last);
127 I <= End; ++I) {
128 CCT Kind = static_cast<CCT>(I);
129
130 // We've found the comparison category type. Build a new cache entry for
131 // it.
132 if (getCategoryString(Kind) == RD->getName())
133 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
134 }
135
136 // We've found nothing. This isn't a comparison category type.
137 return nullptr;
138 }
139
140 const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
141 const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
142 assert(Info && "info for comparison category not found");
143 return *Info;
144 }
145
146 QualType ComparisonCategoryInfo::getType() const {
147 assert(Record);
148 return QualType(Record->getTypeForDecl(), 0);
149 }
150
151 StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
152 using CCKT = ComparisonCategoryType;
153 switch (Kind) {
154 case CCKT::WeakEquality:
155 return "weak_equality";
156 case CCKT::StrongEquality:
157 return "strong_equality";
158 case CCKT::PartialOrdering:
159 return "partial_ordering";
160 case CCKT::WeakOrdering:
161 return "weak_ordering";
162 case CCKT::StrongOrdering:
163 return "strong_ordering";
164 }
165 llvm_unreachable("unhandled cases in switch");
166 }
167
168 StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
169 using CCVT = ComparisonCategoryResult;
170 switch (Kind) {
171 case CCVT::Equal:
172 return "equal";
173 case CCVT::Nonequal:
174 return "nonequal";
175 case CCVT::Equivalent:
176 return "equivalent";
177 case CCVT::Nonequivalent:
178 return "nonequivalent";
179 case CCVT::Less:
180 return "less";
181 case CCVT::Greater:
182 return "greater";
183 case CCVT::Unordered:
184 return "unordered";
185 }
186 llvm_unreachable("unhandled case in switch");
187 }
188
189 std::vector<ComparisonCategoryResult>
190 ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
191 using CCT = ComparisonCategoryType;
192 using CCR = ComparisonCategoryResult;
193 std::vector<CCR> Values;
194 Values.reserve(6);
195 Values.push_back(CCR::Equivalent);
196 bool IsStrong = (Type == CCT::StrongEquality || Type == CCT::StrongOrdering);
197 if (IsStrong)
198 Values.push_back(CCR::Equal);
199 if (Type == CCT::StrongOrdering || Type == CCT::WeakOrdering ||
200 Type == CCT::PartialOrdering) {
201 Values.push_back(CCR::Less);
202 Values.push_back(CCR::Greater);
203 } else {
204 Values.push_back(CCR::Nonequivalent);
205 if (IsStrong)
206 Values.push_back(CCR::Nonequal);
207 }
208 if (Type == CCT::PartialOrdering)
209 Values.push_back(CCR::Unordered);
210 return Values;
211 }
clang::ComparisonCategoryInfo
Definition: ComparisonCategories.h:68
clang::if
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
clang::ComparisonCategoryInfo::ValueInfo
Definition: ComparisonCategories.h:77
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:638
lookupCXXRecordDecl
static CXXRecordDecl * lookupCXXRecordDecl(const ASTContext &Ctx, const NamespaceDecl *StdNS, ComparisonCategoryType Kind)
Definition: ComparisonCategories.cpp:80
clang::ComparisonCategoryResult::Equal
clang::ComparisonCategoryResult::Greater
Type.h
C Language Family Type Representation.
clang::TypeDecl::getTypeForDecl
const Type * getTypeForDecl() const
Definition: Decl.h:2898
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1407
clang::NamespaceDecl
Represent a C++ namespace.
Definition: Decl.h:515
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:1235
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:190
clang::ComparisonCategoryResult::Equivalent
clang::DeclContextLookupResult::front
reference front() const
Definition: DeclBase.h:1234
clang::ComparisonCategories::getResultString
static StringRef getResultString(ComparisonCategoryResult Kind)
Definition: ComparisonCategories.cpp:168
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:155
clang::DeclContextLookupResult
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1187
clang::ComparisonCategoryInfo::ValueInfo::VD
VarDecl * VD
Definition: ComparisonCategories.h:79
clang::ComparisonCategoryResult::Nonequal
clang::ComparisonCategoryResult
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
Definition: ComparisonCategories.h:57
clang::ASTContext::Idents
IdentifierTable & Idents
Definition: ASTContext.h:566
clang::ComparisonCategoryType::First
clang::ComparisonCategoryResult::Less
clang::CXXRecordDecl::getCanonicalDecl
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:728
clang::RecordDecl::field_begin
field_iterator field_begin() const
Definition: Decl.cpp:4145
clang::ComparisonCategories::getInfoForType
const ComparisonCategoryInfo & getInfoForType(QualType Ty) const
Return the comparison category information as specified by getCategoryForType(Ty).
Definition: ComparisonCategories.cpp:140
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:1595
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:1613
clang::ComparisonCategories::getCategoryString
static StringRef getCategoryString(ComparisonCategoryType Kind)
Definition: ComparisonCategories.cpp:151
End
SourceLocation End
Definition: USRLocFinder.cpp:167
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:46
clang::DeclContextLookupResult::size
size_t size() const
Definition: DeclBase.h:1233
clang::RecordDecl::field_end
field_iterator field_end() const
Definition: Decl.h:3787
clang::APValue::getStructField
APValue & getStructField(unsigned i)
Definition: APValue.h:365
clang::ComparisonCategoryType::WeakEquality
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:2258
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:703
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:23
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:519
clang::ComparisonCategoryType::StrongEquality
clang::ComparisonCategories::lookupInfo
const ComparisonCategoryInfo * lookupInfo(ComparisonCategoryType Kind) const
Return the cached comparison category information for the specified &#39;Kind&#39;.
Definition: ComparisonCategories.cpp:92
Decl.h
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:22
lookupStdNamespace
static const NamespaceDecl * lookupStdNamespace(const ASTContext &Ctx, NamespaceDecl *&StdNS)
Definition: ComparisonCategories.cpp:69
clang::ComparisonCategoryInfo::Record
CXXRecordDecl * Record
The declaration for the comparison category type from the standard library.
Definition: ComparisonCategories.h:112
clang::ComparisonCategoryResult::Nonequivalent
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:2330
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:300
clang::ComparisonCategoryResult::Unordered
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:648
clang::ComparisonCategoryInfo::getType
QualType getType() const
Definition: ComparisonCategories.cpp:146
clang::APValue::getInt
APSInt & getInt()
Definition: APValue.h:252
ComparisonCategories.h
clang::ComparisonCategoryType
ComparisonCategoryType
An enumeration representing the different comparison categories types.
Definition: ComparisonCategories.h:44
clang::ComparisonCategoryInfo::ValueInfo::Kind
ComparisonCategoryResult Kind
Definition: ComparisonCategories.h:78