Coverage Report

Created: 2021-01-23 06:44

/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
438
clang::getComparisonCategoryForBuiltinCmp(QualType T) {
25
438
  using CCT = ComparisonCategoryType;
26
27
438
  if (T->isIntegralOrEnumerationType())
28
378
    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
558
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
44
558
  assert(VD && "must have var decl");
45
558
  if (!VD->isUsableInConstantExpressions(VD->getASTContext()))
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
558
  auto *Record = VD->getType()->getAsCXXRecordDecl();
51
558
  if (std::distance(Record->field_begin(), Record->field_end()) != 1 ||
52
558
      !Record->field_begin()->getType()->isIntegralOrEnumerationType())
53
0
    return false;
54
55
558
  return true;
56
558
}
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
576
    ComparisonCategoryResult ValueKind) const {
73
  // Check if we already have a cache entry for this value.
74
576
  auto It = llvm::find_if(
75
781
      Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; });
76
576
  if (It != Objects.end())
77
361
    return &(*It);
78
79
  // We don't have a cached result. Lookup the variable declaration and create
80
  // a new entry representing it.
81
215
  DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup(
82
215
      &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind)));
83
215
  if (Lookup.empty() || 
!isa<VarDecl>(Lookup.front())214
)
84
1
    return nullptr;
85
214
  Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front()));
86
214
  return &Objects.back();
87
214
}
88
89
static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx,
90
69
                                               NamespaceDecl *&StdNS) {
91
69
  if (!StdNS) {
92
62
    DeclContextLookupResult Lookup =
93
62
        Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std"));
94
62
    if (!Lookup.empty())
95
56
      StdNS = dyn_cast<NamespaceDecl>(Lookup.front());
96
62
  }
97
69
  return StdNS;
98
69
}
99
100
static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx,
101
                                          const NamespaceDecl *StdNS,
102
63
                                          ComparisonCategoryType Kind) {
103
63
  StringRef Name = ComparisonCategories::getCategoryString(Kind);
104
63
  DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name));
105
63
  if (!Lookup.empty())
106
63
    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front()))
107
63
      return RD;
108
0
  return nullptr;
109
0
}
110
111
const ComparisonCategoryInfo *
112
492
ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const {
113
492
  auto It = Data.find(static_cast<char>(Kind));
114
492
  if (It != Data.end())
115
423
    return &It->second;
116
117
69
  if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS))
118
63
    if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind))
119
63
      return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second;
120
121
6
  return nullptr;
122
6
}
123
124
const ComparisonCategoryInfo *
125
368
ComparisonCategories::lookupInfoForType(QualType Ty) const {
126
368
  assert(!Ty.isNull() && "type must be non-null");
127
368
  using CCT = ComparisonCategoryType;
128
368
  auto *RD = Ty->getAsCXXRecordDecl();
129
368
  if (!RD)
130
2
    return nullptr;
131
132
  // Check to see if we have information for the specified type cached.
133
366
  const auto *CanonRD = RD->getCanonicalDecl();
134
427
  for (auto &KV : Data) {
135
427
    const ComparisonCategoryInfo &Info = KV.second;
136
427
    if (CanonRD == Info.Record->getCanonicalDecl())
137
354
      return &Info;
138
427
  }
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
290
const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const {
161
290
  const ComparisonCategoryInfo *Info = lookupInfoForType(Ty);
162
290
  assert(Info && "info for comparison category not found");
163
290
  return *Info;
164
290
}
165
166
1.03k
QualType ComparisonCategoryInfo::getType() const {
167
1.03k
  assert(Record);
168
1.03k
  return QualType(Record->getTypeForDecl(), 0);
169
1.03k
}
170
171
92
StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
172
92
  using CCKT = ComparisonCategoryType;
173
92
  switch (Kind) {
174
17
  case CCKT::PartialOrdering:
175
17
    return "partial_ordering";
176
8
  case CCKT::WeakOrdering:
177
8
    return "weak_ordering";
178
67
  case CCKT::StrongOrdering:
179
67
    return "strong_ordering";
180
0
  }
181
0
  llvm_unreachable("unhandled cases in switch");
182
0
}
183
184
418
StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) {
185
418
  using CCVT = ComparisonCategoryResult;
186
418
  switch (Kind) {
187
120
  case CCVT::Equal:
188
120
    return "equal";
189
18
  case CCVT::Equivalent:
190
18
    return "equivalent";
191
134
  case CCVT::Less:
192
134
    return "less";
193
133
  case CCVT::Greater:
194
133
    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
67
ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) {
203
67
  using CCT = ComparisonCategoryType;
204
67
  using CCR = ComparisonCategoryResult;
205
67
  std::vector<CCR> Values;
206
67
  Values.reserve(4);
207
67
  bool IsStrong = Type == CCT::StrongOrdering;
208
59
  Values.push_back(IsStrong ? CCR::Equal : 
CCR::Equivalent8
);
209
67
  Values.push_back(CCR::Less);
210
67
  Values.push_back(CCR::Greater);
211
67
  if (Type == CCT::PartialOrdering)
212
7
    Values.push_back(CCR::Unordered);
213
67
  return Values;
214
67
}