]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/AST/ComparisonCategories.cpp
Merge clang trunk r338150, and resolve conflicts.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / AST / ComparisonCategories.cpp
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 }