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