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 
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 
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.
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.
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) {
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 
81  const NamespaceDecl *StdNS,
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 
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 
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 
141  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
142  assert(Info && "info for comparison category not found");
143  return *Info;
144 }
145 
147  assert(Record);
148  return QualType(Record->getTypeForDecl(), 0);
149 }
150 
152  using CCKT = ComparisonCategoryType;
153  switch (Kind) {
154  case CCKT::WeakEquality:
155  return "weak_equality";
157  return "strong_equality";
159  return "partial_ordering";
160  case CCKT::WeakOrdering:
161  return "weak_ordering";
163  return "strong_ordering";
164  }
165  llvm_unreachable("unhandled cases in switch");
166 }
167 
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>
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 }
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
A (possibly-)qualified type.
Definition: Type.h:638
static CXXRecordDecl * lookupCXXRecordDecl(const ASTContext &Ctx, const NamespaceDecl *StdNS, ComparisonCategoryType Kind)
C Language Family Type Representation.
const Type * getTypeForDecl() const
Definition: Decl.h:2898
The base class of the type hierarchy.
Definition: Type.h:1407
Represent a C++ namespace.
Definition: Decl.h:515
float __ovld __cnfn distance(float p0, float p1)
Returns the distance between p0 and p1.
reference back() const
Definition: DeclBase.h:1235
static std::vector< ComparisonCategoryResult > getPossibleResultsForType(ComparisonCategoryType Type)
Return the list of results which are valid for the specified comparison category type.
reference front() const
Definition: DeclBase.h:1234
static StringRef getResultString(ComparisonCategoryResult Kind)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:155
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1187
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
IdentifierTable & Idents
Definition: ASTContext.h:566
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:728
field_iterator field_begin() const
Definition: Decl.cpp:4145
const ComparisonCategoryInfo & getInfoForType(QualType Ty) const
Return the comparison category information as specified by getCategoryForType(Ty).
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1595
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1613
static StringRef getCategoryString(ComparisonCategoryType Kind)
SourceLocation End
llvm::APSInt getIntValue() const
Get the constant integer value used by this variable to represent the comparison category result type...
field_iterator field_end() const
Definition: Decl.h:3787
APValue & getStructField(unsigned i)
Definition: APValue.h:365
APValue * evaluateValue() const
Attempt to evaluate the value of the initializer attached to this declaration, and produce notes expl...
Definition: Decl.cpp:2258
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:703
bool hasValidIntValue() const
True iff we&#39;ve successfully evaluated the variable as a constant expression and extracted its integer...
Kind
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
const ComparisonCategoryInfo * lookupInfo(ComparisonCategoryType Kind) const
Return the cached comparison category information for the specified &#39;Kind&#39;.
Dataflow Directional Tag Classes.
static const NamespaceDecl * lookupStdNamespace(const ASTContext &Ctx, NamespaceDecl *&StdNS)
CXXRecordDecl * Record
The declaration for the comparison category type from the standard library.
bool checkInitIsICE() const
Determine whether the value of the initializer attached to this declaration is an integral constant e...
Definition: Decl.cpp:2330
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1009
Represents a C++ struct/union/class.
Definition: DeclCXX.h:300
QualType getType() const
Definition: Decl.h:648
APSInt & getInt()
Definition: APValue.h:252
ComparisonCategoryType
An enumeration representing the different comparison categories types.