clang  10.0.0git
ComparisonCategories.cpp
Go to the documentation of this file.
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 
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 
24  using CCT = ComparisonCategoryType;
25 
27  return CCT::StrongOrdering;
28 
29  if (T->isRealFloatingType())
30  return CCT::PartialOrdering;
31 
32  // C++2a [expr.spaceship]p8: If the composite pointer type is an object
33  // pointer type, p <=> q is of type std::strong_ordering.
34  // Note: this assumes neither operand is a null pointer constant.
35  if (T->isObjectPointerType())
36  return CCT::StrongOrdering;
37 
38  // TODO: Extend support for operator<=> to ObjC types.
39  return llvm::None;
40 }
41 
43  assert(VD && "must have var decl");
44  if (!VD->checkInitIsICE())
45  return false;
46 
47  // Before we attempt to get the value of the first field, ensure that we
48  // actually have one (and only one) field.
49  auto *Record = VD->getType()->getAsCXXRecordDecl();
50  if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
51  !Record->field_begin()->getType()->isIntegralOrEnumerationType())
52  return false;
53 
54  return true;
55 }
56 
57 /// Attempt to determine the integer value used to represent the comparison
58 /// category result by evaluating the initializer for the specified VarDecl as
59 /// a constant expression and retreiving the value of the class's first
60 /// (and only) field.
61 ///
62 /// Note: The STL types are expected to have the form:
63 /// struct X { T value; };
64 /// where T is an integral or enumeration type.
66  assert(hasValidIntValue() && "must have a valid value");
67  return VD->evaluateValue()->getStructField(0).getInt();
68 }
69 
70 ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
71  ComparisonCategoryResult ValueKind) const {
72  // Check if we already have a cache entry for this value.
73  auto It = llvm::find_if(
74  Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
75  if (It != Objects.end())
76  return &(*It);
77 
78  // We don't have a cached result. Lookup the variable declaration and create
79  // a new entry representing it.
81  &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
82  if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
83  return nullptr;
84  Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
85  return &Objects.back();
86 }
87 
88 static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
89  NamespaceDecl *&StdNS) {
90  if (!StdNS) {
92  Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
93  if (!Lookup.empty())
94  StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
95  }
96  return StdNS;
97 }
98 
100  const NamespaceDecl *StdNS,
102  StringRef Name = ComparisonCategories::getCategoryString(Kind);
103  DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
104  if (!Lookup.empty())
105  if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
106  return RD;
107  return nullptr;
108 }
109 
112  auto It = Data.find(static_cast<char>(Kind));
113  if (It != Data.end())
114  return &It->second;
115 
116  if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
117  if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
118  return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
119 
120  return nullptr;
121 }
122 
125  assert(!Ty.isNull() && "type must be non-null");
126  using CCT = ComparisonCategoryType;
127  auto *RD = Ty->getAsCXXRecordDecl();
128  if (!RD)
129  return nullptr;
130 
131  // Check to see if we have information for the specified type cached.
132  const auto *CanonRD = RD->getCanonicalDecl();
133  for (auto &KV : Data) {
134  const ComparisonCategoryInfo &Info = KV.second;
135  if (CanonRD == Info.Record->getCanonicalDecl())
136  return &Info;
137  }
138 
139  if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
140  return nullptr;
141 
142  // If not, check to see if the decl names a type in namespace std with a name
143  // matching one of the comparison category types.
144  for (unsigned I = static_cast<unsigned>(CCT::First),
145  End = static_cast<unsigned>(CCT::Last);
146  I <= End; ++I) {
147  CCT Kind = static_cast<CCT>(I);
148 
149  // We've found the comparison category type. Build a new cache entry for
150  // it.
151  if (getCategoryString(Kind) == RD->getName())
152  return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
153  }
154 
155  // We've found nothing. This isn't a comparison category type.
156  return nullptr;
157 }
158 
160  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
161  assert(Info && "info for comparison category not found");
162  return *Info;
163 }
164 
166  assert(Record);
167  return QualType(Record->getTypeForDecl(), 0);
168 }
169 
171  using CCKT = ComparisonCategoryType;
172  switch (Kind) {
174  return "partial_ordering";
175  case CCKT::WeakOrdering:
176  return "weak_ordering";
178  return "strong_ordering";
179  }
180  llvm_unreachable("unhandled cases in switch");
181 }
182 
184  using CCVT = ComparisonCategoryResult;
185  switch (Kind) {
186  case CCVT::Equal:
187  return "equal";
188  case CCVT::Equivalent:
189  return "equivalent";
190  case CCVT::Less:
191  return "less";
192  case CCVT::Greater:
193  return "greater";
194  case CCVT::Unordered:
195  return "unordered";
196  }
197  llvm_unreachable("unhandled case in switch");
198 }
199 
200 std::vector<ComparisonCategoryResult>
202  using CCT = ComparisonCategoryType;
203  using CCR = ComparisonCategoryResult;
204  std::vector<CCR> Values;
205  Values.reserve(4);
206  bool IsStrong = Type == CCT::StrongOrdering;
207  Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
208  Values.push_back(CCR::Less);
209  Values.push_back(CCR::Greater);
210  if (Type == CCT::PartialOrdering)
211  Values.push_back(CCR::Unordered);
212  return Values;
213 }
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
A (possibly-)qualified type.
Definition: Type.h:654
static CXXRecordDecl * lookupCXXRecordDecl(const ASTContext &Ctx, const NamespaceDecl *StdNS, ComparisonCategoryType Kind)
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2021
C Language Family Type Representation.
const Type * getTypeForDecl() const
Definition: Decl.h:3053
The base class of the type hierarchy.
Definition: Type.h:1450
Represent a C++ namespace.
Definition: Decl.h:497
float __ovld __cnfn distance(float p0, float p1)
Returns the distance between p0 and p1.
reference back() const
Definition: DeclBase.h:1243
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:1242
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:168
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1195
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:6881
IdentifierTable & Idents
Definition: ASTContext.h:580
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:492
field_iterator field_begin() const
Definition: Decl.cpp:4425
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:1612
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1690
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:3966
APValue & getStructField(unsigned i)
Definition: APValue.h:507
APValue * evaluateValue() const
Attempt to evaluate the value of the initializer attached to this declaration, and produce notes expl...
Definition: Decl.cpp:2356
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:719
bool hasValidIntValue() const
True iff we&#39;ve successfully evaluated the variable as a constant expression and extracted its integer...
bool isObjectPointerType() const
Definition: Type.h:6528
Kind
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
llvm::APSInt APSInt
const ComparisonCategoryInfo * lookupInfoForType(QualType Ty) const
Optional< ComparisonCategoryType > getComparisonCategoryForBuiltinCmp(QualType T)
Get the comparison category that should be used when comparing values of type T.
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:2428
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:253
QualType getType() const
Definition: Decl.h:630
APSInt & getInt()
Definition: APValue.h:380
ComparisonCategoryType
An enumeration representing the different comparison categories types.