clang  14.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/ASTContext.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 
25  using CCT = ComparisonCategoryType;
26 
28  return CCT::StrongOrdering;
29 
30  if (T->isRealFloatingType())
31  return CCT::PartialOrdering;
32 
33  // C++2a [expr.spaceship]p8: If the composite pointer type is an object
34  // pointer type, p <=> q is of type std::strong_ordering.
35  // Note: this assumes neither operand is a null pointer constant.
36  if (T->isObjectPointerType())
37  return CCT::StrongOrdering;
38 
39  // TODO: Extend support for operator<=> to ObjC types.
40  return llvm::None;
41 }
42 
44  assert(VD && "must have var decl");
46  return false;
47 
48  // Before we attempt to get the value of the first field, ensure that we
49  // actually have one (and only one) field.
50  auto *Record = VD->getType()->getAsCXXRecordDecl();
51  if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
52  !Record->field_begin()->getType()->isIntegralOrEnumerationType())
53  return false;
54 
55  return true;
56 }
57 
58 /// Attempt to determine the integer value used to represent the comparison
59 /// category result by evaluating the initializer for the specified VarDecl as
60 /// a constant expression and retrieving the value of the class's first
61 /// (and only) field.
62 ///
63 /// Note: The STL types are expected to have the form:
64 /// struct X { T value; };
65 /// where T is an integral or enumeration type.
67  assert(hasValidIntValue() && "must have a valid value");
68  return VD->evaluateValue()->getStructField(0).getInt();
69 }
70 
71 ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
72  ComparisonCategoryResult ValueKind) const {
73  // Check if we already have a cache entry for this value.
74  auto It = llvm::find_if(
75  Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
76  if (It != Objects.end())
77  return &(*It);
78 
79  // We don't have a cached result. Lookup the variable declaration and create
80  // a new entry representing it.
83  if (Lookup.empty() || !isa<VarDecl>(Lookup.front()))
84  return nullptr;
85  Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
86  return &Objects.back();
87 }
88 
89 static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
90  NamespaceDecl *&StdNS) {
91  if (!StdNS) {
93  Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
94  if (!Lookup.empty())
95  StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
96  }
97  return StdNS;
98 }
99 
101  const NamespaceDecl *StdNS,
104  DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
105  if (!Lookup.empty())
106  if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
107  return RD;
108  return nullptr;
109 }
110 
113  auto It = Data.find(static_cast<char>(Kind));
114  if (It != Data.end())
115  return &It->second;
116 
117  if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
118  if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
119  return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
120 
121  return nullptr;
122 }
123 
126  assert(!Ty.isNull() && "type must be non-null");
127  using CCT = ComparisonCategoryType;
128  auto *RD = Ty->getAsCXXRecordDecl();
129  if (!RD)
130  return nullptr;
131 
132  // Check to see if we have information for the specified type cached.
133  const auto *CanonRD = RD->getCanonicalDecl();
134  for (auto &KV : Data) {
135  const ComparisonCategoryInfo &Info = KV.second;
136  if (CanonRD == Info.Record->getCanonicalDecl())
137  return &Info;
138  }
139 
140  if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
141  return nullptr;
142 
143  // If not, check to see if the decl names a type in namespace std with a name
144  // matching one of the comparison category types.
145  for (unsigned I = static_cast<unsigned>(CCT::First),
146  End = static_cast<unsigned>(CCT::Last);
147  I <= End; ++I) {
148  CCT Kind = static_cast<CCT>(I);
149 
150  // We've found the comparison category type. Build a new cache entry for
151  // it.
152  if (getCategoryString(Kind) == RD->getName())
153  return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
154  }
155 
156  // We've found nothing. This isn't a comparison category type.
157  return nullptr;
158 }
159 
161  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
162  assert(Info && "info for comparison category not found");
163  return *Info;
164 }
165 
167  assert(Record);
168  return QualType(Record->getTypeForDecl(), 0);
169 }
170 
172  using CCKT = ComparisonCategoryType;
173  switch (Kind) {
174  case CCKT::PartialOrdering:
175  return "partial_ordering";
176  case CCKT::WeakOrdering:
177  return "weak_ordering";
178  case CCKT::StrongOrdering:
179  return "strong_ordering";
180  }
181  llvm_unreachable("unhandled cases in switch");
182 }
183 
185  using CCVT = ComparisonCategoryResult;
186  switch (Kind) {
187  case CCVT::Equal:
188  return "equal";
189  case CCVT::Equivalent:
190  return "equivalent";
191  case CCVT::Less:
192  return "less";
193  case CCVT::Greater:
194  return "greater";
195  case CCVT::Unordered:
196  return "unordered";
197  }
198  llvm_unreachable("unhandled case in switch");
199 }
200 
201 std::vector<ComparisonCategoryResult>
203  using CCT = ComparisonCategoryType;
204  using CCR = ComparisonCategoryResult;
205  std::vector<CCR> Values;
206  Values.reserve(4);
207  bool IsStrong = Type == CCT::StrongOrdering;
208  Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent);
209  Values.push_back(CCR::Less);
210  Values.push_back(CCR::Greater);
211  if (Type == CCT::PartialOrdering)
212  Values.push_back(CCR::Unordered);
213  return Values;
214 }
clang::getComparisonCategoryForBuiltinCmp
Optional< ComparisonCategoryType > getComparisonCategoryForBuiltinCmp(QualType T)
Get the comparison category that should be used when comparing values of type T.
Definition: ComparisonCategories.cpp:24
clang::Decl::getASTContext
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:414
clang::RecordDecl::field_begin
field_iterator field_begin() const
Definition: Decl.cpp:4605
clang::ComparisonCategoryInfo::ValueInfo::hasValidIntValue
bool hasValidIntValue() const
True iff we've successfully evaluated the variable as a constant expression and extracted its integer...
Definition: ComparisonCategories.cpp:43
clang::IdentifierTable::get
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Definition: IdentifierTable.h:592
clang::ComparisonCategoryInfo::ValueInfo::VD
VarDecl * VD
Definition: ComparisonCategories.h:86
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
clang::TypeDecl::getTypeForDecl
const Type * getTypeForDecl() const
Definition: Decl.h:3162
clang::ComparisonCategories::getInfoForType
const ComparisonCategoryInfo & getInfoForType(QualType Ty) const
Return the comparison category information as specified by getCategoryForType(Ty).
Definition: ComparisonCategories.cpp:160
clang::Type::isObjectPointerType
bool isObjectPointerType() const
Definition: Type.h:6697
DeclCXX.h
clang::Type::isRealFloatingType
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2113
distance
float __ovld __cnfn distance(float p0, float p1)
Returns the distance between p0 and p1.
llvm::Optional
Definition: LLVM.h:40
clang::ComparisonCategoryInfo::ValueInfo::getIntValue
llvm::APSInt getIntValue() const
Get the constant integer value used by this variable to represent the comparison category result type...
Definition: ComparisonCategories.cpp:66
End
SourceLocation End
Definition: USRLocFinder.cpp:167
clang::ASTContext::getTranslationUnitDecl
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1057
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1490
Decl.h
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:19
clang::ComparisonCategoryInfo::Record
const CXXRecordDecl * Record
The declaration for the comparison category type from the standard library.
Definition: ComparisonCategories.h:118
clang::ComparisonCategories::getPossibleResultsForType
static std::vector< ComparisonCategoryResult > getPossibleResultsForType(ComparisonCategoryType Type)
Return the list of results which are valid for the specified comparison category type.
Definition: ComparisonCategories.cpp:202
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:212
clang::DeclContextLookupResult::front
reference front() const
Definition: DeclBase.h:1315
lookupStdNamespace
static const NamespaceDecl * lookupStdNamespace(const ASTContext &Ctx, NamespaceDecl *&StdNS)
Definition: ComparisonCategories.cpp:89
clang::ComparisonCategoryType
ComparisonCategoryType
An enumeration representing the different comparison categories types.
Definition: ComparisonCategories.h:44
clang::ComparisonCategories::lookupInfoForType
const ComparisonCategoryInfo * lookupInfoForType(QualType Ty) const
Definition: ComparisonCategories.cpp:125
Type.h
ASTContext.h
clang::Type::getAsCXXRecordDecl
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1753
clang::ComparisonCategories::lookupInfo
const ComparisonCategoryInfo * lookupInfo(ComparisonCategoryType Kind) const
Return the cached comparison category information for the specified 'Kind'.
Definition: ComparisonCategories.cpp:112
clang::ComparisonCategoryInfo
Definition: ComparisonCategories.h:75
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:255
clang::ComparisonCategoryInfo::ValueInfo::Kind
ComparisonCategoryResult Kind
Definition: ComparisonCategories.h:85
clang::ASTContext::Idents
IdentifierTable & Idents
Definition: ASTContext.h:648
clang::QualType::isNull
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:738
clang::ComparisonCategories::getCategoryString
static StringRef getCategoryString(ComparisonCategoryType Kind)
Definition: ComparisonCategories.cpp:171
clang::RecordDecl::field_end
field_iterator field_end() const
Definition: Decl.h:4082
clang::ComparisonCategoryInfo::getType
QualType getType() const
Definition: ComparisonCategories.cpp:166
clang::VarDecl::isUsableInConstantExpressions
bool isUsableInConstantExpressions(const ASTContext &C) const
Determine whether this variable's value can be used in a constant expression, according to the releva...
Definition: Decl.cpp:2384
ComparisonCategories.h
clang
Definition: CalledOnceCheck.h:17
clang::DeclContext::lookup
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Definition: DeclBase.cpp:1645
clang::ComparisonCategoryResult
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
Definition: ComparisonCategories.h:66
clang::CXXRecordDecl::getCanonicalDecl
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:494
clang::ComparisonCategoryInfo::Kind
ComparisonCategoryType Kind
The Kind of the comparison category type.
Definition: ComparisonCategories.h:121
lookupCXXRecordDecl
static CXXRecordDecl * lookupCXXRecordDecl(const ASTContext &Ctx, const NamespaceDecl *StdNS, ComparisonCategoryType Kind)
Definition: ComparisonCategories.cpp:100
clang::DeclContextLookupResult
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1292
clang::ComparisonCategoryInfo::ValueInfo
Definition: ComparisonCategories.h:84
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:687
clang::ComparisonCategories::getResultString
static StringRef getResultString(ComparisonCategoryResult Kind)
Definition: ComparisonCategories.cpp:184
clang::NamespaceDecl
Represent a C++ namespace.
Definition: Decl.h:542
clang::DeclContextLookupResult::empty
bool empty() const
Definition: DeclBase.h:1313
clang::Type::isIntegralOrEnumerationType
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Definition: Type.h:7059