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