Coverage Report

Created: 2020-09-22 08:39

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/ComparisonCategories.cpp
Line
Count
Source (jump to first uncovered line)
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/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
23
Optional<ComparisonCategoryType>
24
374
clang::getComparisonCategoryForBuiltinCmp(QualType T) {
25
374
  using CCT = ComparisonCategoryType;
26
27
374
  if (T->isIntegralOrEnumerationType())
28
314
    return CCT::StrongOrdering;
29
30
60
  if (T->isRealFloatingType())
31
25
    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
35
  if (T->isObjectPointerType())
37
17
    return CCT::StrongOrdering;
38
39
  // TODO: Extend support for operator<=> to ObjC types.
40
18
  return llvm::None;
41
18
}
42
43
418
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
44
418
  assert(VD && "must have var decl");
45
418
  if (!VD->checkInitIsICE())
46
0
    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
418
  auto *Record = VD->getType()->getAsCXXRecordDecl();
51
418
  if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
52
418
      !Record->field_begin()->getType()->isIntegralOrEnumerationType())
53
0
    return false;
54
55
418
  return true;
56
418
}
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 retreiving 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.
66
40
llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const {
67
40
  assert(hasValidIntValue() && "must have a valid value");
68
40
  return VD->evaluateValue()->getStructField(0).getInt();
69
40
}
70
71
ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo(
72
436
    ComparisonCategoryResult ValueKind) const {
73
  // Check if we already have a cache entry for this value.
74
436
  auto It = llvm::find_if(
75
641
      Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
76
436
  if (It != Objects.end())
77
332
    return &(*It);
78
79
  // We don't have a cached result. Lookup the variable declaration and create
80
  // a new entry representing it.
81
104
  DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
82
104
      &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
83
104
  if (Lookup.empty() || 
!isa<VarDecl>(Lookup.front())103
)
84
1
    return nullptr;
85
103
  Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
86
103
  return &Objects.back();
87
103
}
88
89
static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
90
32
                                               NamespaceDecl *&StdNS) {
91
32
  if (!StdNS) {
92
25
    DeclContextLookupResult Lookup =
93
25
        Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
94
25
    if (!Lookup.empty())
95
19
      StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
96
25
  }
97
32
  return StdNS;
98
32
}
99
100
static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
101
                                          const NamespaceDecl *StdNS,
102
26
                                          ComparisonCategoryType Kind) {
103
26
  StringRef Name = ComparisonCategories::getCategoryString(Kind);
104
26
  DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
105
26
  if (!Lookup.empty())
106
26
    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
107
26
      return RD;
108
0
  return nullptr;
109
0
}
110
111
const ComparisonCategoryInfo *
112
401
ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
113
401
  auto It = Data.find(static_cast<char>(Kind));
114
401
  if (It != Data.end())
115
369
    return &It->second;
116
117
32
  if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
118
26
    if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
119
26
      return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
120
121
6
  return nullptr;
122
6
}
123
124
const ComparisonCategoryInfo *
125
339
ComparisonCategories::lookupInfoForType(QualType Ty) const {
126
339
  assert(!Ty.isNull() && "type must be non-null");
127
339
  using CCT = ComparisonCategoryType;
128
339
  auto *RD = Ty->getAsCXXRecordDecl();
129
339
  if (!RD)
130
2
    return nullptr;
131
132
  // Check to see if we have information for the specified type cached.
133
337
  const auto *CanonRD = RD->getCanonicalDecl();
134
397
  for (auto &KV : Data) {
135
397
    const ComparisonCategoryInfo &Info = KV.second;
136
397
    if (CanonRD == Info.Record->getCanonicalDecl())
137
325
      return &Info;
138
397
  }
139
140
12
  if (!RD->getEnclosingNamespaceContext()->isStdNamespace())
141
3
    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
9
  for (unsigned I = static_cast<unsigned>(CCT::First),
146
9
                End = static_cast<unsigned>(CCT::Last);
147
23
       I <= End; 
++I14
) {
148
23
    CCT Kind = static_cast<CCT>(I);
149
150
    // We've found the comparison category type. Build a new cache entry for
151
    // it.
152
23
    if (getCategoryString(Kind) == RD->getName())
153
9
      return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
154
23
  }
155
156
  // We've found nothing. This isn't a comparison category type.
157
0
  return nullptr;
158
9
}
159
160
261
const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
161
261
  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
162
261
  assert(Info && "info for comparison category not found");
163
261
  return *Info;
164
261
}
165
166
817
QualType ComparisonCategoryInfo::getType() const {
167
817
  assert(Record);
168
817
  return QualType(Record->getTypeForDecl(), 0);
169
817
}
170
171
55
StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
172
55
  using CCKT = ComparisonCategoryType;
173
55
  switch (Kind) {
174
17
  case CCKT::PartialOrdering:
175
17
    return "partial_ordering";
176
8
  case CCKT::WeakOrdering:
177
8
    return "weak_ordering";
178
30
  case CCKT::StrongOrdering:
179
30
    return "strong_ordering";
180
0
  }
181
0
  llvm_unreachable("unhandled cases in switch");
182
0
}
183
184
196
StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
185
196
  using CCVT = ComparisonCategoryResult;
186
196
  switch (Kind) {
187
46
  case CCVT::Equal:
188
46
    return "equal";
189
18
  case CCVT::Equivalent:
190
18
    return "equivalent";
191
60
  case CCVT::Less:
192
60
    return "less";
193
59
  case CCVT::Greater:
194
59
    return "greater";
195
13
  case CCVT::Unordered:
196
13
    return "unordered";
197
0
  }
198
0
  llvm_unreachable("unhandled case in switch");
199
0
}
200
201
std::vector<ComparisonCategoryResult>
202
30
ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
203
30
  using CCT = ComparisonCategoryType;
204
30
  using CCR = ComparisonCategoryResult;
205
30
  std::vector<CCR> Values;
206
30
  Values.reserve(4);
207
30
  bool IsStrong = Type == CCT::StrongOrdering;
208
22
  Values.push_back(IsStrong ? CCR::Equal : 
CCR::Equivalent8
);
209
30
  Values.push_back(CCR::Less);
210
30
  Values.push_back(CCR::Greater);
211
30
  if (Type == CCT::PartialOrdering)
212
7
    Values.push_back(CCR::Unordered);
213
30
  return Values;
214
30
}