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