Coverage Report

Created: 2023-05-31 04:38

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/Pointer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- Pointer.cpp - Types for the constexpr VM ---------------*- 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
#include "Pointer.h"
10
#include "Function.h"
11
#include "InterpBlock.h"
12
#include "PrimType.h"
13
14
using namespace clang;
15
using namespace clang::interp;
16
17
1.42k
Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
Unexecuted instantiation: clang::interp::Pointer::Pointer(clang::interp::Block*)
clang::interp::Pointer::Pointer(clang::interp::Block*)
Line
Count
Source
17
1.42k
Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
18
19
Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
20
5.14k
    : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
Unexecuted instantiation: clang::interp::Pointer::Pointer(clang::interp::Block*, unsigned int)
clang::interp::Pointer::Pointer(clang::interp::Block*, unsigned int)
Line
Count
Source
20
5.14k
    : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
21
22
3.40k
Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
Unexecuted instantiation: clang::interp::Pointer::Pointer(clang::interp::Pointer const&)
clang::interp::Pointer::Pointer(clang::interp::Pointer const&)
Line
Count
Source
22
3.40k
Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
23
24
Pointer::Pointer(Pointer &&P)
25
12.5k
    : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
26
12.5k
  if (Pointee)
27
12.4k
    Pointee->movePointer(&P, this);
28
12.5k
}
29
30
Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
31
14.2k
    : Pointee(Pointee), Base(Base), Offset(Offset) {
32
14.2k
  assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
33
14.2k
  if (Pointee)
34
14.1k
    Pointee->addPointer(this);
35
14.2k
}
36
37
39.6k
Pointer::~Pointer() {
38
39.6k
  if (Pointee) {
39
27.1k
    Pointee->removePointer(this);
40
27.1k
    Pointee->cleanup();
41
27.1k
  }
42
39.6k
}
43
44
1.00k
void Pointer::operator=(const Pointer &P) {
45
1.00k
  Block *Old = Pointee;
46
47
1.00k
  if (Pointee)
48
262
    Pointee->removePointer(this);
49
50
1.00k
  Offset = P.Offset;
51
1.00k
  Base = P.Base;
52
53
1.00k
  Pointee = P.Pointee;
54
1.00k
  if (Pointee)
55
995
    Pointee->addPointer(this);
56
57
1.00k
  if (Old)
58
262
    Old->cleanup();
59
1.00k
}
60
61
283
void Pointer::operator=(Pointer &&P) {
62
283
  Block *Old = Pointee;
63
64
283
  if (Pointee)
65
201
    Pointee->removePointer(this);
66
67
283
  Offset = P.Offset;
68
283
  Base = P.Base;
69
70
283
  Pointee = P.Pointee;
71
283
  if (Pointee)
72
272
    Pointee->movePointer(&P, this);
73
74
283
  if (Old)
75
201
    Old->cleanup();
76
283
}
77
78
197
APValue Pointer::toAPValue() const {
79
197
  APValue::LValueBase Base;
80
197
  llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
81
197
  CharUnits Offset;
82
197
  bool IsNullPtr;
83
197
  bool IsOnePastEnd;
84
85
197
  if (isZero()) {
86
28
    Base = static_cast<const Expr *>(nullptr);
87
28
    IsNullPtr = true;
88
28
    IsOnePastEnd = false;
89
28
    Offset = CharUnits::Zero();
90
169
  } else {
91
    // Build the lvalue base from the block.
92
169
    Descriptor *Desc = getDeclDesc();
93
169
    if (auto *VD = Desc->asValueDecl())
94
129
      Base = VD;
95
40
    else if (auto *E = Desc->asExpr())
96
40
      Base = E;
97
0
    else
98
0
      llvm_unreachable("Invalid allocation type");
99
100
    // Not a null pointer.
101
169
    IsNullPtr = false;
102
103
169
    if (isUnknownSizeArray()) {
104
5
      IsOnePastEnd = false;
105
5
      Offset = CharUnits::Zero();
106
164
    } else if (Desc->asExpr()) {
107
      // Pointer pointing to a an expression.
108
40
      IsOnePastEnd = false;
109
40
      Offset = CharUnits::Zero();
110
124
    } else {
111
      // TODO: compute the offset into the object.
112
124
      Offset = CharUnits::Zero();
113
114
      // Build the path into the object.
115
124
      Pointer Ptr = *this;
116
232
      while (Ptr.isField() || 
Ptr.isArrayElement()170
) {
117
108
        if (Ptr.isArrayElement()) {
118
46
          Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
119
46
          Ptr = Ptr.getArray();
120
62
        } else {
121
          // TODO: figure out if base is virtual
122
62
          bool IsVirtual = false;
123
124
          // Create a path entry for the field.
125
62
          Descriptor *Desc = Ptr.getFieldDesc();
126
62
          if (auto *BaseOrMember = Desc->asDecl()) {
127
62
            Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
128
62
            Ptr = Ptr.getBase();
129
62
            continue;
130
62
          }
131
0
          llvm_unreachable("Invalid field type");
132
0
        }
133
108
      }
134
135
124
      IsOnePastEnd = isOnePastEnd();
136
124
    }
137
169
  }
138
139
  // We assemble the LValuePath starting from the innermost pointer to the
140
  // outermost one. SO in a.b.c, the first element in Path will refer to
141
  // the field 'c', while later code expects it to refer to 'a'.
142
  // Just invert the order of the elements.
143
197
  std::reverse(Path.begin(), Path.end());
144
145
197
  return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
146
197
}
147
148
4.50k
bool Pointer::isInitialized() const {
149
4.50k
  assert(Pointee && "Cannot check if null pointer was initialized");
150
4.50k
  const Descriptor *Desc = getFieldDesc();
151
4.50k
  assert(Desc);
152
4.50k
  if (Desc->isPrimitiveArray()) {
153
574
    if (isStatic() && 
Base == 0347
)
154
213
      return true;
155
    // Primitive array field are stored in a bitset.
156
361
    InitMap *Map = getInitMap();
157
361
    if (!Map)
158
4
      return false;
159
357
    if (Map == (InitMap *)-1)
160
357
      return true;
161
0
    return Map->isInitialized(getIndex());
162
3.92k
  } else {
163
    // Field has its bit in an inline descriptor.
164
3.92k
    return Base == 0 || 
getInlineDesc()->IsInitialized3.70k
;
165
3.92k
  }
166
4.50k
}
167
168
2.13k
void Pointer::initialize() const {
169
2.13k
  assert(Pointee && "Cannot initialize null pointer");
170
2.13k
  const Descriptor *Desc = getFieldDesc();
171
172
2.13k
  assert(Desc);
173
2.13k
  if (Desc->isPrimitiveArray()) {
174
    // Primitive global arrays don't have an initmap.
175
510
    if (isStatic() && 
Base == 0177
)
176
112
      return;
177
178
    // Primitive array initializer.
179
398
    InitMap *&Map = getInitMap();
180
398
    if (Map == (InitMap *)-1)
181
50
      return;
182
348
    if (Map == nullptr)
183
97
      Map = InitMap::allocate(Desc->getNumElems());
184
348
    if (Map->initialize(getIndex())) {
185
96
      free(Map);
186
96
      Map = (InitMap *)-1;
187
96
    }
188
1.62k
  } else {
189
    // Field has its bit in an inline descriptor.
190
1.62k
    assert(Base != 0 && "Only composite fields can be initialised");
191
1.62k
    getInlineDesc()->IsInitialized = true;
192
1.62k
  }
193
2.13k
}
194
195
213
void Pointer::activate() const {
196
  // Field has its bit in an inline descriptor.
197
213
  assert(Base != 0 && "Only composite fields can be initialised");
198
213
  getInlineDesc()->IsActive = true;
199
213
}
200
201
0
void Pointer::deactivate() const {
202
  // TODO: this only appears in constructors, so nothing to deactivate.
203
0
}
204
205
206
bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
206
206
  return A.Pointee == B.Pointee;
207
206
}
208
209
7
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
210
7
  return hasSameBase(A, B) && 
A.Base == B.Base4
&&
A.getFieldDesc()->IsArray4
;
211
7
}