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