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