Coverage Report

Created: 2020-02-15 09:57

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