Clang Project

clang_source_code/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
20using namespace clang;
21
22bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
23   (0) . __assert_fail ("VD && \"must have var decl\"", "/home/seafit/code_projects/clang_source/clang/lib/AST/ComparisonCategories.cpp", 23, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">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.
45llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
46   (0) . __assert_fail ("hasValidIntValue() && \"must have a valid value\"", "/home/seafit/code_projects/clang_source/clang/lib/AST/ComparisonCategories.cpp", 46, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(hasValidIntValue() && "must have a valid value");
47  return VD->evaluateValue()->getStructField(0).getInt();
48}
49
50ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
51    ComparisonCategoryResult ValueKindconst {
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
68static 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
79static 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
90const ComparisonCategoryInfo *
91ComparisonCategories::lookupInfo(ComparisonCategoryType Kindconst {
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
103const ComparisonCategoryInfo *
104ComparisonCategories::lookupInfoForType(QualType Tyconst {
105   (0) . __assert_fail ("!Ty.isNull() && \"type must be non-null\"", "/home/seafit/code_projects/clang_source/clang/lib/AST/ComparisonCategories.cpp", 105, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">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
139const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Tyconst {
140  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
141   (0) . __assert_fail ("Info && \"info for comparison category not found\"", "/home/seafit/code_projects/clang_source/clang/lib/AST/ComparisonCategories.cpp", 141, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Info && "info for comparison category not found");
142  return *Info;
143}
144
145QualType ComparisonCategoryInfo::getType() const {
146  assert(Record);
147  return QualType(Record->getTypeForDecl(), 0);
148}
149
150StringRef 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
167StringRef 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
188std::vector<ComparisonCategoryResult>
189ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
190  using CCT = ComparisonCategoryType;
191  using CCR = ComparisonCategoryResult;
192  std::vector<CCRValues;
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}
211
clang::ComparisonCategoryInfo::ValueInfo::hasValidIntValue
clang::ComparisonCategoryInfo::ValueInfo::getIntValue
clang::ComparisonCategoryInfo::lookupValueInfo
clang::ComparisonCategories::lookupInfo
clang::ComparisonCategories::lookupInfoForType
clang::ComparisonCategories::getInfoForType
clang::ComparisonCategoryInfo::getType
clang::ComparisonCategories::getCategoryString
clang::ComparisonCategories::getResultString
clang::ComparisonCategories::getPossibleResultsForType