Coverage Report

Created: 2024-01-17 10:31

/src/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 "Boolean.h"
11
#include "Context.h"
12
#include "Floating.h"
13
#include "Function.h"
14
#include "Integral.h"
15
#include "InterpBlock.h"
16
#include "PrimType.h"
17
#include "Record.h"
18
19
using namespace clang;
20
using namespace clang::interp;
21
22
0
Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
23
24
Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
25
0
    : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
26
27
0
Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
28
29
Pointer::Pointer(Pointer &&P)
30
0
    : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
31
0
  if (Pointee)
32
0
    Pointee->replacePointer(&P, this);
33
0
}
34
35
Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
36
0
    : Pointee(Pointee), Base(Base), Offset(Offset) {
37
0
  assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
38
0
  if (Pointee)
39
0
    Pointee->addPointer(this);
40
0
}
41
42
0
Pointer::~Pointer() {
43
0
  if (Pointee) {
44
0
    Pointee->removePointer(this);
45
0
    Pointee->cleanup();
46
0
  }
47
0
}
48
49
0
void Pointer::operator=(const Pointer &P) {
50
0
  Block *Old = Pointee;
51
52
0
  if (Pointee)
53
0
    Pointee->removePointer(this);
54
55
0
  Offset = P.Offset;
56
0
  Base = P.Base;
57
58
0
  Pointee = P.Pointee;
59
0
  if (Pointee)
60
0
    Pointee->addPointer(this);
61
62
0
  if (Old)
63
0
    Old->cleanup();
64
0
}
65
66
0
void Pointer::operator=(Pointer &&P) {
67
0
  Block *Old = Pointee;
68
69
0
  if (Pointee)
70
0
    Pointee->removePointer(this);
71
72
0
  Offset = P.Offset;
73
0
  Base = P.Base;
74
75
0
  Pointee = P.Pointee;
76
0
  if (Pointee)
77
0
    Pointee->replacePointer(&P, this);
78
79
0
  if (Old)
80
0
    Old->cleanup();
81
0
}
82
83
0
APValue Pointer::toAPValue() const {
84
0
  APValue::LValueBase Base;
85
0
  llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
86
0
  CharUnits Offset;
87
0
  bool IsNullPtr;
88
0
  bool IsOnePastEnd;
89
90
0
  if (isZero()) {
91
0
    Base = static_cast<const Expr *>(nullptr);
92
0
    IsNullPtr = true;
93
0
    IsOnePastEnd = false;
94
0
    Offset = CharUnits::Zero();
95
0
  } else {
96
    // Build the lvalue base from the block.
97
0
    const Descriptor *Desc = getDeclDesc();
98
0
    if (auto *VD = Desc->asValueDecl())
99
0
      Base = VD;
100
0
    else if (auto *E = Desc->asExpr())
101
0
      Base = E;
102
0
    else
103
0
      llvm_unreachable("Invalid allocation type");
104
105
    // Not a null pointer.
106
0
    IsNullPtr = false;
107
108
0
    if (isUnknownSizeArray()) {
109
0
      IsOnePastEnd = false;
110
0
      Offset = CharUnits::Zero();
111
0
    } else if (Desc->asExpr()) {
112
      // Pointer pointing to a an expression.
113
0
      IsOnePastEnd = false;
114
0
      Offset = CharUnits::Zero();
115
0
    } else {
116
      // TODO: compute the offset into the object.
117
0
      Offset = CharUnits::Zero();
118
119
      // Build the path into the object.
120
0
      Pointer Ptr = *this;
121
0
      while (Ptr.isField() || Ptr.isArrayElement()) {
122
0
        if (Ptr.isArrayElement()) {
123
0
          Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
124
0
          Ptr = Ptr.getArray();
125
0
        } else {
126
          // TODO: figure out if base is virtual
127
0
          bool IsVirtual = false;
128
129
          // Create a path entry for the field.
130
0
          const Descriptor *Desc = Ptr.getFieldDesc();
131
0
          if (const auto *BaseOrMember = Desc->asDecl()) {
132
0
            Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
133
0
            Ptr = Ptr.getBase();
134
0
            continue;
135
0
          }
136
0
          llvm_unreachable("Invalid field type");
137
0
        }
138
0
      }
139
140
0
      IsOnePastEnd = isOnePastEnd();
141
0
    }
142
0
  }
143
144
  // We assemble the LValuePath starting from the innermost pointer to the
145
  // outermost one. SO in a.b.c, the first element in Path will refer to
146
  // the field 'c', while later code expects it to refer to 'a'.
147
  // Just invert the order of the elements.
148
0
  std::reverse(Path.begin(), Path.end());
149
150
0
  return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
151
0
}
152
153
0
std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
154
0
  if (!Pointee)
155
0
    return "nullptr";
156
157
0
  return toAPValue().getAsString(Ctx, getType());
158
0
}
159
160
0
bool Pointer::isInitialized() const {
161
0
  assert(Pointee && "Cannot check if null pointer was initialized");
162
0
  const Descriptor *Desc = getFieldDesc();
163
0
  assert(Desc);
164
0
  if (Desc->isPrimitiveArray()) {
165
0
    if (isStatic() && Base == 0)
166
0
      return true;
167
168
0
    InitMapPtr &IM = getInitMap();
169
170
0
    if (!IM)
171
0
      return false;
172
173
0
    if (IM->first)
174
0
      return true;
175
176
0
    return IM->second->isElementInitialized(getIndex());
177
0
  }
178
179
  // Field has its bit in an inline descriptor.
180
0
  return Base == 0 || getInlineDesc()->IsInitialized;
181
0
}
182
183
0
void Pointer::initialize() const {
184
0
  assert(Pointee && "Cannot initialize null pointer");
185
0
  const Descriptor *Desc = getFieldDesc();
186
187
0
  assert(Desc);
188
0
  if (Desc->isPrimitiveArray()) {
189
    // Primitive global arrays don't have an initmap.
190
0
    if (isStatic() && Base == 0)
191
0
      return;
192
193
0
    InitMapPtr &IM = getInitMap();
194
0
    if (!IM)
195
0
      IM =
196
0
          std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
197
198
0
    assert(IM);
199
200
    // All initialized.
201
0
    if (IM->first)
202
0
      return;
203
204
0
    if (IM->second->initializeElement(getIndex())) {
205
0
      IM->first = true;
206
0
      IM->second.reset();
207
0
    }
208
0
    return;
209
0
  }
210
211
  // Field has its bit in an inline descriptor.
212
0
  assert(Base != 0 && "Only composite fields can be initialised");
213
0
  getInlineDesc()->IsInitialized = true;
214
0
}
215
216
0
void Pointer::activate() const {
217
  // Field has its bit in an inline descriptor.
218
0
  assert(Base != 0 && "Only composite fields can be initialised");
219
0
  getInlineDesc()->IsActive = true;
220
0
}
221
222
0
void Pointer::deactivate() const {
223
  // TODO: this only appears in constructors, so nothing to deactivate.
224
0
}
225
226
0
bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
227
0
  return A.Pointee == B.Pointee;
228
0
}
229
230
0
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
231
0
  return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
232
0
}
233
234
0
APValue Pointer::toRValue(const Context &Ctx) const {
235
  // Primitives.
236
0
  if (getFieldDesc()->isPrimitive()) {
237
0
    PrimType PT = *Ctx.classify(getType());
238
0
    TYPE_SWITCH(PT, return deref<T>().toAPValue());
239
0
    llvm_unreachable("Unhandled PrimType?");
240
0
  }
241
242
0
  APValue Result;
243
  // Records.
244
0
  if (getFieldDesc()->isRecord()) {
245
0
    const Record *R = getRecord();
246
0
    Result =
247
0
        APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields());
248
249
0
    for (unsigned I = 0; I != R->getNumFields(); ++I) {
250
0
      const Pointer &FieldPtr = this->atField(R->getField(I)->Offset);
251
0
      Result.getStructField(I) = FieldPtr.toRValue(Ctx);
252
0
    }
253
254
0
    for (unsigned I = 0; I != R->getNumBases(); ++I) {
255
0
      const Pointer &BasePtr = this->atField(R->getBase(I)->Offset);
256
0
      Result.getStructBase(I) = BasePtr.toRValue(Ctx);
257
0
    }
258
0
  }
259
260
  // TODO: Arrays
261
262
0
  return Result;
263
0
}