clang 20.0.0git
Pointer.h
Go to the documentation of this file.
1//===--- Pointer.h - 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// Defines the classes responsible for pointer tracking.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_POINTER_H
14#define LLVM_CLANG_AST_INTERP_POINTER_H
15
16#include "Descriptor.h"
17#include "FunctionPointer.h"
18#include "InterpBlock.h"
20#include "clang/AST/Decl.h"
21#include "clang/AST/DeclCXX.h"
22#include "clang/AST/Expr.h"
23#include "llvm/Support/raw_ostream.h"
24
25namespace clang {
26namespace interp {
27class Block;
28class DeadBlock;
29class Pointer;
30class Context;
31template <unsigned A, bool B> class Integral;
32enum PrimType : unsigned;
33
34class Pointer;
35inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
36
38 /// The block the pointer is pointing to.
40 /// Start of the current subfield.
41 unsigned Base;
42};
43
44struct IntPointer {
46 uint64_t Value;
47
48 IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const;
49};
50
51enum class Storage { Block, Int, Fn };
52
53/// A pointer to a memory block, live or dead.
54///
55/// This object can be allocated into interpreter stack frames. If pointing to
56/// a live block, it is a link in the chain of pointers pointing to the block.
57///
58/// In the simplest form, a Pointer has a Block* (the pointee) and both Base
59/// and Offset are 0, which means it will point to raw data.
60///
61/// The Base field is used to access metadata about the data. For primitive
62/// arrays, the Base is followed by an InitMap. In a variety of cases, the
63/// Base is preceded by an InlineDescriptor, which is used to track the
64/// initialization state, among other things.
65///
66/// The Offset field is used to access the actual data. In other words, the
67/// data the pointer decribes can be found at
68/// Pointee->rawData() + Pointer.Offset.
69///
70///
71/// Pointee Offset
72/// │ │
73/// │ │
74/// ▼ ▼
75/// ┌───────┬────────────┬─────────┬────────────────────────────┐
76/// │ Block │ InlineDesc │ InitMap │ Actual Data │
77/// └───────┴────────────┴─────────┴────────────────────────────┘
78/// ▲
79/// │
80/// │
81/// Base
82class Pointer {
83private:
84 static constexpr unsigned PastEndMark = ~0u;
85 static constexpr unsigned RootPtrMark = ~0u;
86
87public:
89 StorageKind = Storage::Int;
90 PointeeStorage.Int.Value = 0;
91 PointeeStorage.Int.Desc = nullptr;
92 }
93 Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) {
94 PointeeStorage.Int = std::move(IntPtr);
95 }
96 Pointer(Block *B);
97 Pointer(Block *B, uint64_t BaseAndOffset);
98 Pointer(const Pointer &P);
99 Pointer(Pointer &&P);
100 Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
101 : Offset(Offset), StorageKind(Storage::Int) {
102 PointeeStorage.Int.Value = Address;
103 PointeeStorage.Int.Desc = Desc;
104 }
105 Pointer(const Function *F, uint64_t Offset = 0)
106 : Offset(Offset), StorageKind(Storage::Fn) {
107 PointeeStorage.Fn = FunctionPointer(F);
108 }
109 ~Pointer();
110
111 void operator=(const Pointer &P);
112 void operator=(Pointer &&P);
113
114 /// Equality operators are just for tests.
115 bool operator==(const Pointer &P) const {
116 if (P.StorageKind != StorageKind)
117 return false;
118 if (isIntegralPointer())
119 return P.asIntPointer().Value == asIntPointer().Value &&
120 Offset == P.Offset;
121
122 assert(isBlockPointer());
123 return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&
124 P.asBlockPointer().Base == asBlockPointer().Base &&
125 Offset == P.Offset;
126 }
127
128 bool operator!=(const Pointer &P) const { return !(P == *this); }
129
130 /// Converts the pointer to an APValue.
131 APValue toAPValue(const ASTContext &ASTCtx) const;
132
133 /// Converts the pointer to a string usable in diagnostics.
134 std::string toDiagnosticString(const ASTContext &Ctx) const;
135
136 uint64_t getIntegerRepresentation() const {
137 if (isIntegralPointer())
138 return asIntPointer().Value + (Offset * elemSize());
139 if (isFunctionPointer())
141 return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
142 }
143
144 /// Converts the pointer to an APValue that is an rvalue.
145 std::optional<APValue> toRValue(const Context &Ctx,
146 QualType ResultType) const;
147
148 /// Offsets a pointer inside an array.
149 [[nodiscard]] Pointer atIndex(uint64_t Idx) const {
150 if (isIntegralPointer())
151 return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
152 if (isFunctionPointer())
153 return Pointer(asFunctionPointer().getFunction(), Idx);
154
155 if (asBlockPointer().Base == RootPtrMark)
156 return Pointer(asBlockPointer().Pointee, RootPtrMark,
157 getDeclDesc()->getSize());
158 uint64_t Off = Idx * elemSize();
159 if (getFieldDesc()->ElemDesc)
160 Off += sizeof(InlineDescriptor);
161 else
162 Off += sizeof(InitMapPtr);
163 return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
164 asBlockPointer().Base + Off);
165 }
166
167 /// Creates a pointer to a field.
168 [[nodiscard]] Pointer atField(unsigned Off) const {
169 assert(isBlockPointer());
170 unsigned Field = Offset + Off;
171 return Pointer(asBlockPointer().Pointee, Field, Field);
172 }
173
174 /// Subtract the given offset from the current Base and Offset
175 /// of the pointer.
176 [[nodiscard]] Pointer atFieldSub(unsigned Off) const {
177 assert(Offset >= Off);
178 unsigned O = Offset - Off;
179 return Pointer(asBlockPointer().Pointee, O, O);
180 }
181
182 /// Restricts the scope of an array element pointer.
183 [[nodiscard]] Pointer narrow() const {
184 if (!isBlockPointer())
185 return *this;
186 assert(isBlockPointer());
187 // Null pointers cannot be narrowed.
188 if (isZero() || isUnknownSizeArray())
189 return *this;
190
191 // Pointer to an array of base types - enter block.
192 if (asBlockPointer().Base == RootPtrMark)
193 return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor),
194 Offset == 0 ? Offset : PastEndMark);
195
196 // Pointer is one past end - magic offset marks that.
197 if (isOnePastEnd())
198 return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
199 PastEndMark);
200
201 // Primitive arrays are a bit special since they do not have inline
202 // descriptors. If Offset != Base, then the pointer already points to
203 // an element and there is nothing to do. Otherwise, the pointer is
204 // adjusted to the first element of the array.
205 if (inPrimitiveArray()) {
206 if (Offset != asBlockPointer().Base)
207 return *this;
208 return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
209 Offset + sizeof(InitMapPtr));
210 }
211
212 // Pointer is to a field or array element - enter it.
213 if (Offset != asBlockPointer().Base)
214 return Pointer(asBlockPointer().Pointee, Offset, Offset);
215
216 // Enter the first element of an array.
217 if (!getFieldDesc()->isArray())
218 return *this;
219
220 const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor);
221 return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
222 }
223
224 /// Expands a pointer to the containing array, undoing narrowing.
225 [[nodiscard]] Pointer expand() const {
226 assert(isBlockPointer());
227 Block *Pointee = asBlockPointer().Pointee;
228
229 if (isElementPastEnd()) {
230 // Revert to an outer one-past-end pointer.
231 unsigned Adjust;
232 if (inPrimitiveArray())
233 Adjust = sizeof(InitMapPtr);
234 else
235 Adjust = sizeof(InlineDescriptor);
236 return Pointer(Pointee, asBlockPointer().Base,
237 asBlockPointer().Base + getSize() + Adjust);
238 }
239
240 // Do not step out of array elements.
241 if (asBlockPointer().Base != Offset)
242 return *this;
243
244 // If at base, point to an array of base types.
245 if (isRoot())
246 return Pointer(Pointee, RootPtrMark, 0);
247
248 // Step into the containing array, if inside one.
249 unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
250 const Descriptor *Desc =
251 (Next == Pointee->getDescriptor()->getMetadataSize())
252 ? getDeclDesc()
253 : getDescriptor(Next)->Desc;
254 if (!Desc->IsArray)
255 return *this;
256 return Pointer(Pointee, Next, Offset);
257 }
258
259 /// Checks if the pointer is null.
260 bool isZero() const {
261 if (isBlockPointer())
262 return asBlockPointer().Pointee == nullptr;
263 if (isFunctionPointer())
264 return asFunctionPointer().isZero();
265 assert(isIntegralPointer());
266 return asIntPointer().Value == 0 && Offset == 0;
267 }
268 /// Checks if the pointer is live.
269 bool isLive() const {
270 if (!isBlockPointer())
271 return true;
272 return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;
273 }
274 /// Checks if the item is a field in an object.
275 bool isField() const {
276 if (!isBlockPointer())
277 return false;
278
279 return !isRoot() && getFieldDesc()->asDecl();
280 }
281
282 /// Accessor for information about the declaration site.
283 const Descriptor *getDeclDesc() const {
284 if (isIntegralPointer())
285 return asIntPointer().Desc;
286 if (isFunctionPointer())
287 return nullptr;
288
289 assert(isBlockPointer());
290 assert(asBlockPointer().Pointee);
291 return asBlockPointer().Pointee->Desc;
292 }
294
295 /// Returns the expression or declaration the pointer has been created for.
297 if (isBlockPointer())
298 return getDeclDesc()->getSource();
299 if (isFunctionPointer()) {
301 return F ? F->getDecl() : DeclTy();
302 }
303 assert(isIntegralPointer());
305 }
306
307 /// Returns a pointer to the object of which this pointer is a field.
308 [[nodiscard]] Pointer getBase() const {
309 if (asBlockPointer().Base == RootPtrMark) {
310 assert(Offset == PastEndMark && "cannot get base of a block");
311 return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
312 }
313 unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset;
314 return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
315 }
316 /// Returns the parent array.
317 [[nodiscard]] Pointer getArray() const {
318 if (asBlockPointer().Base == RootPtrMark) {
319 assert(Offset != 0 && Offset != PastEndMark && "not an array element");
320 return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
321 }
322 assert(Offset != asBlockPointer().Base && "not an array element");
323 return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
325 }
326
327 /// Accessors for information about the innermost field.
328 const Descriptor *getFieldDesc() const {
329 if (isIntegralPointer())
330 return asIntPointer().Desc;
331
332 if (isRoot())
333 return getDeclDesc();
334 return getInlineDesc()->Desc;
335 }
336
337 /// Returns the type of the innermost field.
339 if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
340 // Unfortunately, complex and vector types are not array types in clang,
341 // but they are for us.
342 if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
343 return AT->getElementType();
344 if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>())
345 return CT->getElementType();
346 if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>())
347 return CT->getElementType();
348 }
349 return getFieldDesc()->getType();
350 }
351
352 [[nodiscard]] Pointer getDeclPtr() const {
353 return Pointer(asBlockPointer().Pointee);
354 }
355
356 /// Returns the element size of the innermost field.
357 size_t elemSize() const {
358 if (isIntegralPointer()) {
359 if (!asIntPointer().Desc)
360 return 1;
361 return asIntPointer().Desc->getElemSize();
362 }
363
364 if (asBlockPointer().Base == RootPtrMark)
365 return getDeclDesc()->getSize();
366 return getFieldDesc()->getElemSize();
367 }
368 /// Returns the total size of the innermost field.
369 size_t getSize() const {
370 assert(isBlockPointer());
371 return getFieldDesc()->getSize();
372 }
373
374 /// Returns the offset into an array.
375 unsigned getOffset() const {
376 assert(Offset != PastEndMark && "invalid offset");
377 assert(isBlockPointer());
378 if (asBlockPointer().Base == RootPtrMark)
379 return Offset;
380
381 unsigned Adjust = 0;
382 if (Offset != asBlockPointer().Base) {
383 if (getFieldDesc()->ElemDesc)
384 Adjust = sizeof(InlineDescriptor);
385 else
386 Adjust = sizeof(InitMapPtr);
387 }
388 return Offset - asBlockPointer().Base - Adjust;
389 }
390
391 /// Whether this array refers to an array, but not
392 /// to the first element.
393 bool isArrayRoot() const {
394 return inArray() && Offset == asBlockPointer().Base;
395 }
396
397 /// Checks if the innermost field is an array.
398 bool inArray() const {
399 if (isBlockPointer())
400 return getFieldDesc()->IsArray;
401 return false;
402 }
403 bool inUnion() const {
404 if (isBlockPointer())
405 return getInlineDesc()->InUnion;
406 return false;
407 };
408
409 /// Checks if the structure is a primitive array.
410 bool inPrimitiveArray() const {
411 if (isBlockPointer())
412 return getFieldDesc()->isPrimitiveArray();
413 return false;
414 }
415 /// Checks if the structure is an array of unknown size.
416 bool isUnknownSizeArray() const {
417 if (!isBlockPointer())
418 return false;
420 }
421 /// Checks if the pointer points to an array.
422 bool isArrayElement() const {
423 if (isBlockPointer())
424 return inArray() && asBlockPointer().Base != Offset;
425 return false;
426 }
427 /// Pointer points directly to a block.
428 bool isRoot() const {
429 if (isZero() || isIntegralPointer())
430 return true;
431 return (asBlockPointer().Base ==
432 asBlockPointer().Pointee->getDescriptor()->getMetadataSize() ||
433 asBlockPointer().Base == 0);
434 }
435 /// If this pointer has an InlineDescriptor we can use to initialize.
436 bool canBeInitialized() const {
437 if (!isBlockPointer())
438 return false;
439
440 return asBlockPointer().Pointee && asBlockPointer().Base > 0;
441 }
442
443 [[nodiscard]] const BlockPointer &asBlockPointer() const {
444 assert(isBlockPointer());
445 return PointeeStorage.BS;
446 }
447 [[nodiscard]] const IntPointer &asIntPointer() const {
448 assert(isIntegralPointer());
449 return PointeeStorage.Int;
450 }
451 [[nodiscard]] const FunctionPointer &asFunctionPointer() const {
452 assert(isFunctionPointer());
453 return PointeeStorage.Fn;
454 }
455
456 bool isBlockPointer() const { return StorageKind == Storage::Block; }
457 bool isIntegralPointer() const { return StorageKind == Storage::Int; }
458 bool isFunctionPointer() const { return StorageKind == Storage::Fn; }
459
460 /// Returns the record descriptor of a class.
461 const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
462 /// Returns the element record type, if this is a non-primive array.
463 const Record *getElemRecord() const {
464 const Descriptor *ElemDesc = getFieldDesc()->ElemDesc;
465 return ElemDesc ? ElemDesc->ElemRecord : nullptr;
466 }
467 /// Returns the field information.
468 const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
469
470 /// Checks if the object is a union.
471 bool isUnion() const;
472
473 /// Checks if the storage is extern.
474 bool isExtern() const {
475 if (isBlockPointer())
477 return false;
478 }
479 /// Checks if the storage is static.
480 bool isStatic() const {
481 if (!isBlockPointer())
482 return true;
483 assert(asBlockPointer().Pointee);
484 return asBlockPointer().Pointee->isStatic();
485 }
486 /// Checks if the storage is temporary.
487 bool isTemporary() const {
488 if (isBlockPointer()) {
489 assert(asBlockPointer().Pointee);
491 }
492 return false;
493 }
494 /// Checks if the storage is a static temporary.
495 bool isStaticTemporary() const { return isStatic() && isTemporary(); }
496
497 /// Checks if the field is mutable.
498 bool isMutable() const {
499 if (!isBlockPointer())
500 return false;
501 return !isRoot() && getInlineDesc()->IsFieldMutable;
502 }
503
504 bool isWeak() const {
505 if (!isBlockPointer())
506 return false;
507
508 assert(isBlockPointer());
509 if (const ValueDecl *VD = getDeclDesc()->asValueDecl())
510 return VD->isWeak();
511 return false;
512 }
513 /// Checks if an object was initialized.
514 bool isInitialized() const;
515 /// Checks if the object is active.
516 bool isActive() const {
517 if (!isBlockPointer())
518 return true;
519 return isRoot() || getInlineDesc()->IsActive;
520 }
521 /// Checks if a structure is a base class.
522 bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
523 bool isVirtualBaseClass() const {
524 return isField() && getInlineDesc()->IsVirtualBase;
525 }
526 /// Checks if the pointer points to a dummy value.
527 bool isDummy() const {
528 if (!isBlockPointer())
529 return false;
530
531 if (!asBlockPointer().Pointee)
532 return false;
533
534 return getDeclDesc()->isDummy();
535 }
536
537 /// Checks if an object or a subfield is mutable.
538 bool isConst() const {
539 if (isIntegralPointer())
540 return true;
541 return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;
542 }
543
544 /// Returns the declaration ID.
545 std::optional<unsigned> getDeclID() const {
546 if (isBlockPointer()) {
547 assert(asBlockPointer().Pointee);
548 return asBlockPointer().Pointee->getDeclID();
549 }
550 return std::nullopt;
551 }
552
553 /// Returns the byte offset from the start.
554 uint64_t getByteOffset() const {
555 if (isIntegralPointer())
556 return asIntPointer().Value + Offset;
557 if (isOnePastEnd())
558 return PastEndMark;
559 return Offset;
560 }
561
562 /// Returns the number of elements.
563 unsigned getNumElems() const {
564 if (!isBlockPointer())
565 return ~0u;
566 return getSize() / elemSize();
567 }
568
569 const Block *block() const { return asBlockPointer().Pointee; }
570
571 /// Returns the index into an array.
572 int64_t getIndex() const {
573 if (!isBlockPointer())
575
576 if (isZero())
577 return 0;
578
579 // narrow()ed element in a composite array.
580 if (asBlockPointer().Base > sizeof(InlineDescriptor) &&
581 asBlockPointer().Base == Offset)
582 return 0;
583
584 if (auto ElemSize = elemSize())
585 return getOffset() / ElemSize;
586 return 0;
587 }
588
589 /// Checks if the index is one past end.
590 bool isOnePastEnd() const {
592 return false;
593
594 if (!asBlockPointer().Pointee)
595 return false;
596
597 if (isUnknownSizeArray())
598 return false;
599
600 return isElementPastEnd() || isPastEnd() ||
601 (getSize() == getOffset() && !isZeroSizeArray());
602 }
603
604 /// Checks if the pointer points past the end of the object.
605 bool isPastEnd() const {
606 if (isIntegralPointer())
607 return false;
608
609 return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize();
610 }
611
612 /// Checks if the pointer is an out-of-bounds element pointer.
613 bool isElementPastEnd() const { return Offset == PastEndMark; }
614
615 /// Checks if the pointer is pointing to a zero-size array.
616 bool isZeroSizeArray() const {
617 if (isFunctionPointer())
618 return false;
619 if (const auto *Desc = getFieldDesc())
620 return Desc->isZeroSizeArray();
621 return false;
622 }
623
624 /// Dereferences the pointer, if it's live.
625 template <typename T> T &deref() const {
626 assert(isLive() && "Invalid pointer");
627 assert(isBlockPointer());
628 assert(asBlockPointer().Pointee);
629 assert(isDereferencable());
630 assert(Offset + sizeof(T) <=
631 asBlockPointer().Pointee->getDescriptor()->getAllocSize());
632
633 if (isArrayRoot())
634 return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
635 asBlockPointer().Base + sizeof(InitMapPtr));
636
637 return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);
638 }
639
640 /// Dereferences a primitive element.
641 template <typename T> T &elem(unsigned I) const {
642 assert(I < getNumElems());
643 assert(isBlockPointer());
644 assert(asBlockPointer().Pointee);
645 return reinterpret_cast<T *>(asBlockPointer().Pointee->data() +
646 sizeof(InitMapPtr))[I];
647 }
648
649 /// Whether this block can be read from at all. This is only true for
650 /// block pointers that point to a valid location inside that block.
651 bool isDereferencable() const {
652 if (!isBlockPointer())
653 return false;
654 if (isPastEnd())
655 return false;
656
657 return true;
658 }
659
660 /// Initializes a field.
661 void initialize() const;
662 /// Activats a field.
663 void activate() const;
664 /// Deactivates an entire strurcutre.
665 void deactivate() const;
666
667 /// Compare two pointers.
669 if (!hasSameBase(*this, Other))
671
672 if (Offset < Other.Offset)
674 else if (Offset > Other.Offset)
676
678 }
679
680 /// Checks if two pointers are comparable.
681 static bool hasSameBase(const Pointer &A, const Pointer &B);
682 /// Checks if two pointers can be subtracted.
683 static bool hasSameArray(const Pointer &A, const Pointer &B);
684 /// Checks if both given pointers point to the same block.
685 static bool pointToSameBlock(const Pointer &A, const Pointer &B);
686
687 /// Prints the pointer.
688 void print(llvm::raw_ostream &OS) const;
689
690private:
691 friend class Block;
692 friend class DeadBlock;
693 friend class MemberPointer;
694 friend class InterpState;
695 friend struct InitMap;
696 friend class DynamicAllocator;
697
698 Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
699
700 /// Returns the embedded descriptor preceding a field.
701 InlineDescriptor *getInlineDesc() const {
702 assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
703 assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
704 return getDescriptor(asBlockPointer().Base);
705 }
706
707 /// Returns a descriptor at a given offset.
708 InlineDescriptor *getDescriptor(unsigned Offset) const {
709 assert(Offset != 0 && "Not a nested pointer");
710 assert(isBlockPointer());
711 assert(!isZero());
712 return reinterpret_cast<InlineDescriptor *>(
713 asBlockPointer().Pointee->rawData() + Offset) -
714 1;
715 }
716
717 /// Returns a reference to the InitMapPtr which stores the initialization map.
718 InitMapPtr &getInitMap() const {
719 assert(isBlockPointer());
720 assert(!isZero());
721 return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() +
723 }
724
725 /// Offset into the storage.
726 uint64_t Offset = 0;
727
728 /// Previous link in the pointer chain.
729 Pointer *Prev = nullptr;
730 /// Next link in the pointer chain.
731 Pointer *Next = nullptr;
732
733 union {
737 } PointeeStorage;
738 Storage StorageKind = Storage::Int;
739};
740
741inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
742 P.print(OS);
743 return OS;
744}
745
746} // namespace interp
747} // namespace clang
748
749#endif
StringRef P
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
const CFGBlock * Block
Definition: HTMLLogger.cpp:153
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
Represents a member of a struct/union/class.
Definition: Decl.h:3030
A (possibly-)qualified type.
Definition: Type.h:941
Encodes a location in the source.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:667
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
bool isExtern() const
Checks if the block is extern.
Definition: InterpBlock.h:71
std::byte * data()
Returns a pointer to the stored data.
Definition: InterpBlock.h:89
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition: InterpBlock.h:67
bool isStatic() const
Checks if the block has static storage duration.
Definition: InterpBlock.h:73
bool isTemporary() const
Checks if the block is temporary.
Definition: InterpBlock.h:75
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
Definition: InterpBlock.h:102
std::optional< unsigned > getDeclID() const
Returns the declaration ID.
Definition: InterpBlock.h:80
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:40
Descriptor for a dead block.
Definition: InterpBlock.h:181
Manages dynamic memory allocations done during bytecode interpretation.
const Function * getFunction() const
uint64_t getIntegerRepresentation() const
Bytecode function.
Definition: Function.h:81
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:96
Interpreter context.
Definition: InterpState.h:36
A pointer to a memory block, live or dead.
Definition: Pointer.h:82
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:435
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:183
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:431
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:311
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:480
bool inUnion() const
Definition: Pointer.h:403
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition: Pointer.h:616
FunctionPointer Fn
Definition: Pointer.h:736
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:149
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:527
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:176
bool inPrimitiveArray() const
Checks if the structure is a primitive array.
Definition: Pointer.h:410
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition: Pointer.cpp:267
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:474
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:572
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:516
bool isConst() const
Checks if an object or a subfield is mutable.
Definition: Pointer.h:538
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:168
bool isUnion() const
Checks if the object is a union.
bool isWeak() const
Definition: Pointer.h:504
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:625
Pointer(IntPointer &&IntPtr)
Definition: Pointer.h:93
bool isMutable() const
Checks if the field is mutable.
Definition: Pointer.h:498
DeclTy getSource() const
Returns the expression or declaration the pointer has been created for.
Definition: Pointer.h:296
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:563
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:317
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:416
void activate() const
Activats a field.
Definition: Pointer.cpp:395
void operator=(const Pointer &P)
Definition: Pointer.cpp:69
bool isIntegralPointer() const
Definition: Pointer.h:457
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:338
bool operator==(const Pointer &P) const
Equality operators are just for tests.
Definition: Pointer.h:115
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:422
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:393
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:269
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:398
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Definition: Pointer.h:495
T & elem(unsigned I) const
Dereferences a primitive element.
Definition: Pointer.h:641
Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset=0)
Definition: Pointer.h:100
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:308
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:554
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:301
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:260
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:668
const IntPointer & asIntPointer() const
Definition: Pointer.h:447
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:428
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:283
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
Definition: Pointer.h:463
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition: Pointer.cpp:454
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition: Pointer.cpp:140
unsigned getOffset() const
Returns the offset into an array.
Definition: Pointer.h:375
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:590
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:460
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:136
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition: Pointer.h:605
Pointer(const Function *F, uint64_t Offset=0)
Definition: Pointer.h:105
const FieldDecl * getField() const
Returns the field information.
Definition: Pointer.h:468
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:225
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:613
bool isDereferencable() const
Whether this block can be read from at all.
Definition: Pointer.h:651
bool isBlockPointer() const
Definition: Pointer.h:456
bool operator!=(const Pointer &P) const
Definition: Pointer.h:128
BlockPointer BS
Definition: Pointer.h:734
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:466
size_t getSize() const
Returns the total size of the innermost field.
Definition: Pointer.h:369
bool isTemporary() const
Checks if the storage is temporary.
Definition: Pointer.h:487
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:451
SourceLocation getDeclLoc() const
Definition: Pointer.h:293
const Block * block() const
Definition: Pointer.h:569
bool isFunctionPointer() const
Definition: Pointer.h:458
Pointer getDeclPtr() const
Definition: Pointer.h:352
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:328
bool isVirtualBaseClass() const
Definition: Pointer.h:523
std::optional< unsigned > getDeclID() const
Returns the declaration ID.
Definition: Pointer.h:545
bool isBaseClass() const
Checks if a structure is a base class.
Definition: Pointer.h:522
size_t elemSize() const
Returns the element size of the innermost field.
Definition: Pointer.h:357
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:436
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:443
void initialize() const
Initializes a field.
Definition: Pointer.cpp:347
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:275
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:461
Structure/Class descriptor.
Definition: Record.h:25
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
Definition: Descriptor.h:29
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:33
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition: Boolean.h:151
llvm::PointerUnion< const Decl *, const Expr * > DeclTy
Definition: Descriptor.h:28
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
const FunctionProtoType * T
@ Other
Other implicit parameter.
unsigned Base
Start of the current subfield.
Definition: Pointer.h:41
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:39
Describes a memory block created by an allocation site.
Definition: Descriptor.h:111
const bool IsConst
Flag indicating if the block is mutable.
Definition: Descriptor.h:149
unsigned getSize() const
Returns the size of the object without metadata.
Definition: Descriptor.h:219
QualType getType() const
Definition: Descriptor.cpp:391
const DeclTy & getSource() const
Definition: Descriptor.h:200
const Decl * asDecl() const
Definition: Descriptor.h:198
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition: Descriptor.h:143
bool isDummy() const
Checks if this is a dummy descriptor.
Definition: Descriptor.h:260
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition: Descriptor.h:234
SourceLocation getLocation() const
Definition: Descriptor.cpp:413
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
Definition: Descriptor.h:248
unsigned getElemSize() const
returns the size of an element when the structure is viewed as an array.
Definition: Descriptor.h:232
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:155
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:242
const FieldDecl * asFieldDecl() const
Definition: Descriptor.h:210
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:141
Descriptor used for global variables.
Definition: Descriptor.h:58
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition: Descriptor.h:267
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:69
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:91
unsigned IsBase
Flag indicating if the field is an embedded base class.
Definition: Descriptor.h:85
const Descriptor * Desc
Definition: Descriptor.h:99
unsigned IsVirtualBase
Flag inidcating if the field is a virtual base class.
Definition: Descriptor.h:88
unsigned InUnion
Flat indicating if this field is in a union (even if nested).
Definition: Descriptor.h:93
unsigned Offset
Offset inside the structure/array.
Definition: Descriptor.h:71
unsigned IsConst
Flag indicating if the storage is constant or not.
Definition: Descriptor.h:76
unsigned IsFieldMutable
Flag indicating if the field is mutable (if in a record).
Definition: Descriptor.h:97
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:633
const Descriptor * Desc
Definition: Pointer.h:45