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