annotate clang/lib/AST/ComparisonCategories.cpp @ 222:81f6424ef0e3 llvm-original

LLVM original branch
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sun, 18 Jul 2021 22:10:01 +0900
parents 79ff65ed7e25
children c4bab56944e8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file defines the Comparison Category enum and data types, which
anatofuz
parents:
diff changeset
10 // store the types and expressions needed to support operator<=>
anatofuz
parents:
diff changeset
11 //
anatofuz
parents:
diff changeset
12 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
13
anatofuz
parents:
diff changeset
14 #include "clang/AST/ComparisonCategories.h"
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
15 #include "clang/AST/ASTContext.h"
150
anatofuz
parents:
diff changeset
16 #include "clang/AST/Decl.h"
anatofuz
parents:
diff changeset
17 #include "clang/AST/DeclCXX.h"
anatofuz
parents:
diff changeset
18 #include "clang/AST/Type.h"
anatofuz
parents:
diff changeset
19 #include "llvm/ADT/SmallVector.h"
anatofuz
parents:
diff changeset
20
anatofuz
parents:
diff changeset
21 using namespace clang;
anatofuz
parents:
diff changeset
22
anatofuz
parents:
diff changeset
23 Optional<ComparisonCategoryType>
anatofuz
parents:
diff changeset
24 clang::getComparisonCategoryForBuiltinCmp(QualType T) {
anatofuz
parents:
diff changeset
25 using CCT = ComparisonCategoryType;
anatofuz
parents:
diff changeset
26
anatofuz
parents:
diff changeset
27 if (T->isIntegralOrEnumerationType())
anatofuz
parents:
diff changeset
28 return CCT::StrongOrdering;
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 if (T->isRealFloatingType())
anatofuz
parents:
diff changeset
31 return CCT::PartialOrdering;
anatofuz
parents:
diff changeset
32
anatofuz
parents:
diff changeset
33 // C++2a [expr.spaceship]p8: If the composite pointer type is an object
anatofuz
parents:
diff changeset
34 // pointer type, p <=> q is of type std::strong_ordering.
anatofuz
parents:
diff changeset
35 // Note: this assumes neither operand is a null pointer constant.
anatofuz
parents:
diff changeset
36 if (T->isObjectPointerType())
anatofuz
parents:
diff changeset
37 return CCT::StrongOrdering;
anatofuz
parents:
diff changeset
38
anatofuz
parents:
diff changeset
39 // TODO: Extend support for operator<=> to ObjC types.
anatofuz
parents:
diff changeset
40 return llvm::None;
anatofuz
parents:
diff changeset
41 }
anatofuz
parents:
diff changeset
42
anatofuz
parents:
diff changeset
43 bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
anatofuz
parents:
diff changeset
44 assert(VD && "must have var decl");
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 173
diff changeset
45 if (!VD->isUsableInConstantExpressions(VD->getASTContext()))
150
anatofuz
parents:
diff changeset
46 return false;
anatofuz
parents:
diff changeset
47
anatofuz
parents:
diff changeset
48 // Before we attempt to get the value of the first field, ensure that we
anatofuz
parents:
diff changeset
49 // actually have one (and only one) field.
anatofuz
parents:
diff changeset
50 auto *Record = VD->getType()->getAsCXXRecordDecl();
anatofuz
parents:
diff changeset
51 if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
anatofuz
parents:
diff changeset
52 !Record->field_begin()->getType()->isIntegralOrEnumerationType())
anatofuz
parents:
diff changeset
53 return false;
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 return true;
anatofuz
parents:
diff changeset
56 }
anatofuz
parents:
diff changeset
57
anatofuz
parents:
diff changeset
58 /// Attempt to determine the integer value used to represent the comparison
anatofuz
parents:
diff changeset
59 /// category result by evaluating the initializer for the specified VarDecl as
anatofuz
parents:
diff changeset
60 /// a constant expression and retreiving the value of the class's first
anatofuz
parents:
diff changeset
61 /// (and only) field.
anatofuz
parents:
diff changeset
62 ///
anatofuz
parents:
diff changeset
63 /// Note: The STL types are expected to have the form:
anatofuz
parents:
diff changeset
64 /// struct X { T value; };
anatofuz
parents:
diff changeset
65 /// where T is an integral or enumeration type.
anatofuz
parents:
diff changeset
66 llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
anatofuz
parents:
diff changeset
67 assert(hasValidIntValue() && "must have a valid value");
anatofuz
parents:
diff changeset
68 return VD->evaluateValue()->getStructField(0).getInt();
anatofuz
parents:
diff changeset
69 }
anatofuz
parents:
diff changeset
70
anatofuz
parents:
diff changeset
71 ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
anatofuz
parents:
diff changeset
72 ComparisonCategoryResult ValueKind) const {
anatofuz
parents:
diff changeset
73 // Check if we already have a cache entry for this value.
anatofuz
parents:
diff changeset
74 auto It = llvm::find_if(
anatofuz
parents:
diff changeset
75 Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
anatofuz
parents:
diff changeset
76 if (It != Objects.end())
anatofuz
parents:
diff changeset
77 return &(*It);
anatofuz
parents:
diff changeset
78
anatofuz
parents:
diff changeset
79 // We don't have a cached result. Lookup the variable declaration and create
anatofuz
parents:
diff changeset
80 // a new entry representing it.
anatofuz
parents:
diff changeset
81 DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
anatofuz
parents:
diff changeset
82 &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
anatofuz
parents:
diff changeset
83 if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
anatofuz
parents:
diff changeset
84 return nullptr;
anatofuz
parents:
diff changeset
85 Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
anatofuz
parents:
diff changeset
86 return &Objects.back();
anatofuz
parents:
diff changeset
87 }
anatofuz
parents:
diff changeset
88
anatofuz
parents:
diff changeset
89 static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
anatofuz
parents:
diff changeset
90 NamespaceDecl *&StdNS) {
anatofuz
parents:
diff changeset
91 if (!StdNS) {
anatofuz
parents:
diff changeset
92 DeclContextLookupResult Lookup =
anatofuz
parents:
diff changeset
93 Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
anatofuz
parents:
diff changeset
94 if (!Lookup.empty())
anatofuz
parents:
diff changeset
95 StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
anatofuz
parents:
diff changeset
96 }
anatofuz
parents:
diff changeset
97 return StdNS;
anatofuz
parents:
diff changeset
98 }
anatofuz
parents:
diff changeset
99
anatofuz
parents:
diff changeset
100 static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
anatofuz
parents:
diff changeset
101 const NamespaceDecl *StdNS,
anatofuz
parents:
diff changeset
102 ComparisonCategoryType Kind) {
anatofuz
parents:
diff changeset
103 StringRef Name = ComparisonCategories::getCategoryString(Kind);
anatofuz
parents:
diff changeset
104 DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
anatofuz
parents:
diff changeset
105 if (!Lookup.empty())
anatofuz
parents:
diff changeset
106 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
anatofuz
parents:
diff changeset
107 return RD;
anatofuz
parents:
diff changeset
108 return nullptr;
anatofuz
parents:
diff changeset
109 }
anatofuz
parents:
diff changeset
110
anatofuz
parents:
diff changeset
111 const ComparisonCategoryInfo *
anatofuz
parents:
diff changeset
112 ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
anatofuz
parents:
diff changeset
113 auto It = Data.find(static_cast<char>(Kind));
anatofuz
parents:
diff changeset
114 if (It != Data.end())
anatofuz
parents:
diff changeset
115 return &It->second;
anatofuz
parents:
diff changeset
116
anatofuz
parents:
diff changeset
117 if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
anatofuz
parents:
diff changeset
118 if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
anatofuz
parents:
diff changeset
119 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 return nullptr;
anatofuz
parents:
diff changeset
122 }
anatofuz
parents:
diff changeset
123
anatofuz
parents:
diff changeset
124 const ComparisonCategoryInfo *
anatofuz
parents:
diff changeset
125 ComparisonCategories::lookupInfoForType(QualType Ty) const {
anatofuz
parents:
diff changeset
126 assert(!Ty.isNull() && "type must be non-null");
anatofuz
parents:
diff changeset
127 using CCT = ComparisonCategoryType;
anatofuz
parents:
diff changeset
128 auto *RD = Ty->getAsCXXRecordDecl();
anatofuz
parents:
diff changeset
129 if (!RD)
anatofuz
parents:
diff changeset
130 return nullptr;
anatofuz
parents:
diff changeset
131
anatofuz
parents:
diff changeset
132 // Check to see if we have information for the specified type cached.
anatofuz
parents:
diff changeset
133 const auto *CanonRD = RD->getCanonicalDecl();
anatofuz
parents:
diff changeset
134 for (auto &KV : Data) {
anatofuz
parents:
diff changeset
135 const ComparisonCategoryInfo &Info = KV.second;
anatofuz
parents:
diff changeset
136 if (CanonRD == Info.Record->getCanonicalDecl())
anatofuz
parents:
diff changeset
137 return &Info;
anatofuz
parents:
diff changeset
138 }
anatofuz
parents:
diff changeset
139
anatofuz
parents:
diff changeset
140 if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
anatofuz
parents:
diff changeset
141 return nullptr;
anatofuz
parents:
diff changeset
142
anatofuz
parents:
diff changeset
143 // If not, check to see if the decl names a type in namespace std with a name
anatofuz
parents:
diff changeset
144 // matching one of the comparison category types.
anatofuz
parents:
diff changeset
145 for (unsigned I = static_cast<unsigned>(CCT::First),
anatofuz
parents:
diff changeset
146 End = static_cast<unsigned>(CCT::Last);
anatofuz
parents:
diff changeset
147 I <= End; ++I) {
anatofuz
parents:
diff changeset
148 CCT Kind = static_cast<CCT>(I);
anatofuz
parents:
diff changeset
149
anatofuz
parents:
diff changeset
150 // We've found the comparison category type. Build a new cache entry for
anatofuz
parents:
diff changeset
151 // it.
anatofuz
parents:
diff changeset
152 if (getCategoryString(Kind) == RD->getName())
anatofuz
parents:
diff changeset
153 return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
anatofuz
parents:
diff changeset
154 }
anatofuz
parents:
diff changeset
155
anatofuz
parents:
diff changeset
156 // We've found nothing. This isn't a comparison category type.
anatofuz
parents:
diff changeset
157 return nullptr;
anatofuz
parents:
diff changeset
158 }
anatofuz
parents:
diff changeset
159
anatofuz
parents:
diff changeset
160 const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
anatofuz
parents:
diff changeset
161 const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
anatofuz
parents:
diff changeset
162 assert(Info && "info for comparison category not found");
anatofuz
parents:
diff changeset
163 return *Info;
anatofuz
parents:
diff changeset
164 }
anatofuz
parents:
diff changeset
165
anatofuz
parents:
diff changeset
166 QualType ComparisonCategoryInfo::getType() const {
anatofuz
parents:
diff changeset
167 assert(Record);
anatofuz
parents:
diff changeset
168 return QualType(Record->getTypeForDecl(), 0);
anatofuz
parents:
diff changeset
169 }
anatofuz
parents:
diff changeset
170
anatofuz
parents:
diff changeset
171 StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
anatofuz
parents:
diff changeset
172 using CCKT = ComparisonCategoryType;
anatofuz
parents:
diff changeset
173 switch (Kind) {
anatofuz
parents:
diff changeset
174 case CCKT::PartialOrdering:
anatofuz
parents:
diff changeset
175 return "partial_ordering";
anatofuz
parents:
diff changeset
176 case CCKT::WeakOrdering:
anatofuz
parents:
diff changeset
177 return "weak_ordering";
anatofuz
parents:
diff changeset
178 case CCKT::StrongOrdering:
anatofuz
parents:
diff changeset
179 return "strong_ordering";
anatofuz
parents:
diff changeset
180 }
anatofuz
parents:
diff changeset
181 llvm_unreachable("unhandled cases in switch");
anatofuz
parents:
diff changeset
182 }
anatofuz
parents:
diff changeset
183
anatofuz
parents:
diff changeset
184 StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
anatofuz
parents:
diff changeset
185 using CCVT = ComparisonCategoryResult;
anatofuz
parents:
diff changeset
186 switch (Kind) {
anatofuz
parents:
diff changeset
187 case CCVT::Equal:
anatofuz
parents:
diff changeset
188 return "equal";
anatofuz
parents:
diff changeset
189 case CCVT::Equivalent:
anatofuz
parents:
diff changeset
190 return "equivalent";
anatofuz
parents:
diff changeset
191 case CCVT::Less:
anatofuz
parents:
diff changeset
192 return "less";
anatofuz
parents:
diff changeset
193 case CCVT::Greater:
anatofuz
parents:
diff changeset
194 return "greater";
anatofuz
parents:
diff changeset
195 case CCVT::Unordered:
anatofuz
parents:
diff changeset
196 return "unordered";
anatofuz
parents:
diff changeset
197 }
anatofuz
parents:
diff changeset
198 llvm_unreachable("unhandled case in switch");
anatofuz
parents:
diff changeset
199 }
anatofuz
parents:
diff changeset
200
anatofuz
parents:
diff changeset
201 std::vector<ComparisonCategoryResult>
anatofuz
parents:
diff changeset
202 ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
anatofuz
parents:
diff changeset
203 using CCT = ComparisonCategoryType;
anatofuz
parents:
diff changeset
204 using CCR = ComparisonCategoryResult;
anatofuz
parents:
diff changeset
205 std::vector<CCR> Values;
anatofuz
parents:
diff changeset
206 Values.reserve(4);
anatofuz
parents:
diff changeset
207 bool IsStrong = Type == CCT::StrongOrdering;
anatofuz
parents:
diff changeset
208 Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
anatofuz
parents:
diff changeset
209 Values.push_back(CCR::Less);
anatofuz
parents:
diff changeset
210 Values.push_back(CCR::Greater);
anatofuz
parents:
diff changeset
211 if (Type == CCT::PartialOrdering)
anatofuz
parents:
diff changeset
212 Values.push_back(CCR::Unordered);
anatofuz
parents:
diff changeset
213 return Values;
anatofuz
parents:
diff changeset
214 }