]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/AST/ComparisonCategories.cpp
Fix a memory leak in if_delgroups() introduced in r334118.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / AST / ComparisonCategories.cpp
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 bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
23   assert(VD && "must have var decl");
24   if (!VD->checkInitIsICE())
25     return false;
26
27   // Before we attempt to get the value of the first field, ensure that we
28   // actually have one (and only one) field.
29   auto *Record = VD->getType()->getAsCXXRecordDecl();
30   if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
31       !Record->field_begin()->getType()->isIntegralOrEnumerationType())
32     return false;
33
34   return true;
35 }
36
37 /// Attempt to determine the integer value used to represent the comparison
38 /// category result by evaluating the initializer for the specified VarDecl as
39 /// a constant expression and retreiving the value of the class's first
40 /// (and only) field.
41 ///
42 /// Note: The STL types are expected to have the form:
43 ///    struct X { T value; };
44 /// where T is an integral or enumeration type.
45 llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
46   assert(hasValidIntValue() && "must have a valid value");
47   return VD->evaluateValue()->getStructField(0).getInt();
48 }
49
50 ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
51     ComparisonCategoryResult ValueKind) const {
52   // Check if we already have a cache entry for this value.
53   auto It = llvm::find_if(
54       Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
55   if (It != Objects.end())
56     return &(*It);
57
58   // We don't have a cached result. Lookup the variable declaration and create
59   // a new entry representing it.
60   DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
61       &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
62   if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front()))
63     return nullptr;
64   Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
65   return &Objects.back();
66 }
67
68 static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
69                                                NamespaceDecl *&StdNS) {
70   if (!StdNS) {
71     DeclContextLookupResult Lookup =
72         Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
73     if (Lookup.size() == 1)
74       StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
75   }
76   return StdNS;
77 }
78
79 static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
80                                           const NamespaceDecl *StdNS,
81                                           ComparisonCategoryType Kind) {
82   StringRef Name = ComparisonCategories::getCategoryString(Kind);
83   DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
84   if (Lookup.size() == 1)
85     if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
86       return RD;
87   return nullptr;
88 }
89
90 const ComparisonCategoryInfo *
91 ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
92   auto It = Data.find(static_cast<char>(Kind));
93   if (It != Data.end())
94     return &It->second;
95
96   if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
97     if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
98       return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
99
100   return nullptr;
101 }
102
103 const ComparisonCategoryInfo *
104 ComparisonCategories::lookupInfoForType(QualType Ty) const {
105   assert(!Ty.isNull() && "type must be non-null");
106   using CCT = ComparisonCategoryType;
107   auto *RD = Ty->getAsCXXRecordDecl();
108   if (!RD)
109     return nullptr;
110
111   // Check to see if we have information for the specified type cached.
112   const auto *CanonRD = RD->getCanonicalDecl();
113   for (auto &KV : Data) {
114     const ComparisonCategoryInfo &Info = KV.second;
115     if (CanonRD == Info.Record->getCanonicalDecl())
116       return &Info;
117   }
118
119   if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
120     return nullptr;
121
122   // If not, check to see if the decl names a type in namespace std with a name
123   // matching one of the comparison category types.
124   for (unsigned I = static_cast<unsigned>(CCT::First),
125                 End = static_cast<unsigned>(CCT::Last);
126        I <= End; ++I) {
127     CCT Kind = static_cast<CCT>(I);
128
129     // We've found the comparison category type. Build a new cache entry for
130     // it.
131     if (getCategoryString(Kind) == RD->getName())
132       return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
133   }
134
135   // We've found nothing. This isn't a comparison category type.
136   return nullptr;
137 }
138
139 const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
140   const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
141   assert(Info && "info for comparison category not found");
142   return *Info;
143 }
144
145 QualType ComparisonCategoryInfo::getType() const {
146   assert(Record);
147   return QualType(Record->getTypeForDecl(), 0);
148 }
149
150 StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
151   using CCKT = ComparisonCategoryType;
152   switch (Kind) {
153   case CCKT::WeakEquality:
154     return "weak_equality";
155   case CCKT::StrongEquality:
156     return "strong_equality";
157   case CCKT::PartialOrdering:
158     return "partial_ordering";
159   case CCKT::WeakOrdering:
160     return "weak_ordering";
161   case CCKT::StrongOrdering:
162     return "strong_ordering";
163   }
164   llvm_unreachable("unhandled cases in switch");
165 }
166
167 StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
168   using CCVT = ComparisonCategoryResult;
169   switch (Kind) {
170   case CCVT::Equal:
171     return "equal";
172   case CCVT::Nonequal:
173     return "nonequal";
174   case CCVT::Equivalent:
175     return "equivalent";
176   case CCVT::Nonequivalent:
177     return "nonequivalent";
178   case CCVT::Less:
179     return "less";
180   case CCVT::Greater:
181     return "greater";
182   case CCVT::Unordered:
183     return "unordered";
184   }
185   llvm_unreachable("unhandled case in switch");
186 }
187
188 std::vector<ComparisonCategoryResult>
189 ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
190   using CCT = ComparisonCategoryType;
191   using CCR = ComparisonCategoryResult;
192   std::vector<CCR> Values;
193   Values.reserve(6);
194   Values.push_back(CCR::Equivalent);
195   bool IsStrong = (Type == CCT::StrongEquality || Type == CCT::StrongOrdering);
196   if (IsStrong)
197     Values.push_back(CCR::Equal);
198   if (Type == CCT::StrongOrdering || Type == CCT::WeakOrdering ||
199       Type == CCT::PartialOrdering) {
200     Values.push_back(CCR::Less);
201     Values.push_back(CCR::Greater);
202   } else {
203     Values.push_back(CCR::Nonequivalent);
204     if (IsStrong)
205       Values.push_back(CCR::Nonequal);
206   }
207   if (Type == CCT::PartialOrdering)
208     Values.push_back(CCR::Unordered);
209   return Values;
210 }