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