clang 24.0.0git
Descriptor.cpp
Go to the documentation of this file.
1//===--- Descriptor.cpp - 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#include "Descriptor.h"
10#include "Boolean.h"
11#include "Char.h"
12#include "FixedPoint.h"
13#include "Floating.h"
14#include "Integral.h"
15#include "IntegralAP.h"
16#include "MemberPointer.h"
17#include "Pointer.h"
18#include "PrimType.h"
19#include "Record.h"
20#include "Reflect.h"
21#include "Source.h"
22#include "clang/AST/ExprCXX.h"
23
24using namespace clang;
25using namespace clang::interp;
26
27template <typename T> static constexpr bool needsDtor() {
28 return std::is_same_v<T, Pointer> || std::is_same_v<T, MemberPointer>;
29}
30
31template <typename T>
32static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
33 static_assert(needsDtor<T>());
34 reinterpret_cast<T *>(Ptr)->~T();
35}
36
37template <typename T>
38static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
39 InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
40 IMP.deleteInitMap();
41
42 if constexpr (needsDtor<T>()) {
43 Ptr += sizeof(InitMapPtr);
44 for (unsigned I = 0, NE = D->getNumElems(); I != NE; ++I) {
45 reinterpret_cast<T *>(Ptr)[I].~T();
46 }
47 }
48}
49
50static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
51 bool IsMutable, bool IsVolatile, bool IsActive,
52 bool InUnion, const Descriptor *D) {
53 const unsigned NumElems = D->getNumElems();
54 const unsigned ElemSize =
56
57 unsigned ElemOffset = 0;
58 for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
59 auto *ElemPtr = Ptr + ElemOffset;
60 auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
61 auto *SD = D->ElemDesc;
62
63 Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
64 Desc->Desc = SD;
65 Desc->IsInitialized = true;
66 Desc->IsBase = false;
67 Desc->IsActive = IsActive;
68 Desc->IsConst = IsConst || D->IsConst;
69 Desc->IsFieldMutable = IsMutable || D->IsMutable;
70 Desc->InUnion = InUnion;
71 Desc->IsArrayElement = true;
72 Desc->IsVolatile = IsVolatile;
73
74 if (auto Fn = D->ElemDesc->CtorFn) {
75 auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
76 Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,
77 Desc->InUnion || SD->isUnion(), D->ElemDesc);
78 }
79 }
80}
81
82static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
83 const unsigned NumElems = D->getNumElems();
84 const unsigned ElemSize =
86
87 unsigned ElemOffset = 0;
88 auto Dtor = D->ElemDesc->DtorFn;
89 assert(Dtor &&
90 "a composite array without an elem dtor shouldn't have a dtor itself");
91 for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
92 auto *ElemPtr = Ptr + ElemOffset;
93 auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
94 auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
95 Dtor(B, ElemLoc, D->ElemDesc);
96 }
97}
98
99static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
100 bool IsVolatile, bool IsActive, bool IsUnionField,
101 bool InUnion, const Descriptor *D, unsigned FieldOffset) {
102 auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
103 Desc->Offset = FieldOffset;
104 Desc->Desc = D;
105 Desc->IsInitialized = D->IsArray;
106 Desc->IsBase = false;
107 Desc->IsActive = IsActive && !IsUnionField;
108 Desc->InUnion = InUnion;
109 Desc->IsConst = IsConst || D->IsConst;
110 Desc->IsFieldMutable = IsMutable || D->IsMutable;
111 Desc->IsVolatile = IsVolatile || D->IsVolatile;
112 // True if this field is const AND the parent is mutable.
113 Desc->IsConstInMutable = Desc->IsConst && IsMutable;
114 Desc->LifeState =
117 : (Desc->IsActive ? Lifetime::NotStarted : Lifetime::Started);
118
119 if (auto Fn = D->CtorFn)
120 Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
121 Desc->IsVolatile, Desc->IsActive, InUnion || D->isUnion(), D);
122}
123
124static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
125 bool IsVolatile, bool IsActive, bool InUnion,
126 const Descriptor *D, unsigned FieldOffset,
127 bool IsVirtualBase) {
128 assert(D);
129 assert(D->ElemRecord);
130 assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes.
131
132 auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
133 Desc->Offset = FieldOffset;
134 Desc->Desc = D;
135 Desc->IsInitialized = D->IsArray;
136 Desc->IsBase = true;
137 Desc->IsVirtualBase = IsVirtualBase;
138 Desc->IsActive = IsActive && !InUnion;
139 Desc->IsConst = IsConst || D->IsConst;
140 Desc->IsFieldMutable = IsMutable || D->IsMutable;
141 Desc->InUnion = InUnion;
142 Desc->IsVolatile = false;
143
144 for (const auto &V : D->ElemRecord->bases())
145 initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
146 InUnion, V.Desc, V.Offset, false);
147 for (const auto &F : D->ElemRecord->fields())
148 initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
149 InUnion, InUnion, F.Desc, F.Offset);
150}
151
152static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
153 bool IsVolatile, bool IsActive, bool InUnion,
154 const Descriptor *D) {
155 for (const auto &V : D->ElemRecord->bases())
156 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
157 V.Offset,
158 /*IsVirtualBase=*/false);
159 for (const auto &F : D->ElemRecord->fields()) {
160 bool IsUnionField = D->isUnion();
161 initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,
162 InUnion || IsUnionField, F.Desc, F.Offset);
163 }
164 for (const auto &V : D->ElemRecord->virtual_bases())
165 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
166 V.Offset,
167 /*IsVirtualBase=*/true);
168}
169
170static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,
171 unsigned FieldOffset) {
172 if (auto Fn = D->DtorFn)
173 Fn(B, Ptr + FieldOffset, D);
174}
175
176static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,
177 unsigned FieldOffset) {
178 assert(D);
179 assert(D->ElemRecord);
180
181 for (const auto &V : D->ElemRecord->bases())
182 destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);
183 for (const auto &F : D->ElemRecord->fields())
184 destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);
185}
186
187static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
188 for (const auto &F : D->ElemRecord->bases())
189 destroyBase(B, Ptr, F.Desc, F.Offset);
190 for (const auto &F : D->ElemRecord->fields())
191 destroyField(B, Ptr, F.Desc, F.Offset);
192 for (const auto &F : D->ElemRecord->virtual_bases())
193 destroyBase(B, Ptr, F.Desc, F.Offset);
194}
195
196/// Whether a record needs its descriptor dtor function called.
197static bool needsRecordDtor(const Record *R) {
198 for (const auto &B : R->bases()) {
199 if (B.Desc->DtorFn)
200 return true;
201 }
202
203 for (const auto &F : R->fields()) {
204 if (F.Desc->DtorFn)
205 return true;
206 }
207
208 for (const auto &V : R->virtual_bases()) {
209 if (V.Desc->DtorFn)
210 return true;
211 }
212 return false;
213}
214
216 switch (T) {
217 case PT_Ptr:
219 case PT_MemberPtr:
221 default:
222 return nullptr;
223 }
224 llvm_unreachable("Unhandled PrimType");
225}
226
227// NOTE: The following #if-ed out code is for calling constructors of primitive
228// types. It is currently not needed but I'm not sure if it will stay this way
229// forever so I'm leaving it here for now.
230#if 0
231template <typename T> static constexpr bool needsCtor() {
232 return false;
233 if constexpr (std::is_same_v<T, Char<true>> ||
234 std::is_same_v<T, Char<false>> ||
235 std::is_same_v<T, Integral<16, true>> ||
236 std::is_same_v<T, Integral<16, false>> ||
237 std::is_same_v<T, Integral<32, true>> ||
238 std::is_same_v<T, Integral<32, false>> ||
239 std::is_same_v<T, Integral<64, true>> ||
240 std::is_same_v<T, Integral<64, false>> ||
241 std::is_same_v<T, IntegralAP<true>> ||
242 std::is_same_v<T, IntegralAP<false>> ||
243 std::is_same_v<T, Floating> || std::is_same_v<T, Boolean>)
244 return false;
245
246 return true;
247}
248
249
250static BlockCtorFn getCtorArrayPrim(PrimType Type) {
251 TYPE_SWITCH(Type, if constexpr (!needsCtor<T>()) return nullptr;
252 return ctorArrayTy<T>);
253 llvm_unreachable("unknown Expr");
254}
255static BlockCtorFn getCtorPrim(PrimType T) {
256 return nullptr;
257 switch (T) {
258 // case PT_Ptr:
259 // return ctorTy<PrimConv<PT_Ptr>::T>;
260 // case PT_MemberPtr:
261 // return ctorTy<PrimConv<PT_MemberPtr>::T>;
262 default:
263 return nullptr;
264 }
265 llvm_unreachable("Unhandled PrimType");
266}
267
268
269template <typename T>
270static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
271 const Descriptor *D) {
272 new (Ptr) InitMapPtr();
273
274 if constexpr (needsCtor<T>()) {
275 Ptr += sizeof(InitMapPtr);
276 for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
277 new (&reinterpret_cast<T *>(Ptr)[I]) T();
278 }
279 }
280}
281template <typename T>
282static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
283 const Descriptor *) {
284 static_assert(needsCtor<T>());
285 new (Ptr) T();
286}
287#endif
288
291 llvm_unreachable("unknown Expr");
292}
293
294/// Primitives.
296 bool IsConst, bool IsTemporary, bool IsMutable,
297 bool IsVolatile)
298 : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),
299 AllocSize(align(ElemSize)), PrimT(Type), IsConst(IsConst),
302 assert(Source && "Missing source");
303}
304
305/// Primitive arrays.
307 size_t NumElems, bool IsConst, bool IsTemporary,
308 bool IsMutable, bool IsVolatile)
309 : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)),
310 Size(ElemSize * NumElems), AllocSize(align(Size) + sizeof(InitMapPtr)),
314 assert(Source && "Missing source");
315 assert(NumElems <= (MaxArrayElemBytes / ElemSize));
316}
317
318/// Primitive unknown-size arrays.
321 : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
322 AllocSize(sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
325 assert(Source && "Missing source");
326}
327
328/// Arrays of composite elements.
330 const Descriptor *Elem, unsigned NumElems, bool IsConst,
331 bool IsTemporary, bool IsMutable)
332 : Source(D), SourceType(SourceTy),
333 ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
334 Size(ElemSize * NumElems),
335 AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem),
339 assert(Source && "Missing source");
340}
341
342/// Unknown-size arrays of composite elements.
345 : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
346 Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem),
349 assert(Source && "Missing source");
350}
351
352/// Composite records.
354 bool IsTemporary, bool IsMutable, bool IsVolatile)
355 : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
356 Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst),
359 assert(Source && "Missing source");
360}
361
362/// Dummy.
364 : Source(D), ElemSize(1), Size(1), AllocSize(0), ElemDesc(nullptr),
366 assert(Source && "Missing source");
367}
368
370 if (SourceType)
371 return QualType(SourceType, 0);
372
373 if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))
374 return T->getASTContext().getTypeDeclType(T);
375
376 // The Source sometimes has a different type than the once
377 // we really save. Try to consult the Record first.
378 if (isRecord()) {
379 const RecordDecl *RD = ElemRecord->getDecl();
381 std::nullopt, RD, false);
382 if (IsConst)
383 return T.withConst();
384 return T;
385 }
386
387 if (const auto *E = asExpr()) {
388 if (isa<CXXNewExpr>(E))
389 return E->getType()->getPointeeType();
390
391 // std::allocator.allocate() call.
392 if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
393 ME && ME->getRecordDecl()->getName() == "allocator" &&
394 ME->getMethodDecl()->getName() == "allocate")
395 return E->getType()->getPointeeType();
396 return E->getType();
397 }
398
399 if (const auto *D = asValueDecl())
400 return D->getType();
401
402 llvm_unreachable("Invalid descriptor type");
403}
404
406 assert(isArray());
407 QualType T;
408
409 if (SourceType) {
410 T = QualType(SourceType, 0);
411 } else if (const auto *TDecl = dyn_cast_if_present<TypeDecl>(asDecl())) {
412 T = TDecl->getASTContext().getTypeDeclType(TDecl);
413 } else if (isRecord()) {
414 const RecordDecl *RD = ElemRecord->getDecl();
416 std::nullopt, RD, false);
417 if (IsConst)
418 T.addConst();
419 } else if (const auto *E = asExpr()) {
420 T = E->getType();
421 } else if (const auto *D = asValueDecl()) {
422 T = D->getType();
423 }
424
425 assert(!T.isNull());
426
427 if (const auto *AT = T->getAs<AtomicType>())
428 T = AT->getValueType();
429 if (T->isPointerOrReferenceType())
430 T = T->getPointeeType();
431
432 if (const auto *AT = T->getAsArrayTypeUnsafe()) {
433 // For primitive arrays, we don't save a QualType at all,
434 // just a PrimType. Try to figure out the QualType here.
435 if (isPrimitiveArray()) {
436 while (T->isArrayType())
437 T = T->getAsArrayTypeUnsafe()->getElementType();
438 return T;
439 }
440 return AT->getElementType();
441 }
442 if (const auto *CT = T->getAs<ComplexType>())
443 return CT->getElementType();
444 if (const auto *CT = T->getAs<VectorType>())
445 return CT->getElementType();
446
447 return T;
448}
449
451 auto MakeArrayType = [&](QualType ElemType) -> QualType {
452 if (IsArray)
453 return Ctx.getConstantArrayType(
454 ElemType, APInt(64, static_cast<uint64_t>(getNumElems()), false),
455 nullptr, ArraySizeModifier::Normal, 0);
456 return ElemType;
457 };
458
459 if (const auto *E = asExpr()) {
460 if (isa<CXXNewExpr>(E))
461 return MakeArrayType(E->getType()->getPointeeType());
462
463 // std::allocator.allocate() call.
464 if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
465 ME && ME->getRecordDecl()->getName() == "allocator" &&
466 ME->getMethodDecl()->getName() == "allocate")
467 return MakeArrayType(E->getType()->getPointeeType());
468 return E->getType();
469 }
470
471 return getType();
472}
473
475 if (const auto *D = Source.asDecl())
476 return SourceInfo(D);
477 if (const auto *E = Source.asExpr())
478 return SourceInfo(E);
479 llvm_unreachable("Invalid descriptor type");
480}
481
483 if (isPrimitive() || isPrimitiveArray())
484 return true;
485
486 if (isRecord()) {
487 assert(ElemRecord);
488 return ElemRecord->hasTrivialDtor();
489 }
490
491 if (!ElemDesc)
492 return true;
493 // Composite arrays.
494 return ElemDesc->hasTrivialDtor();
495}
496
497bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
498
500 if ((isPrimitive() || isPrimitiveArray()) &&
502 if (getPrimType() == PT_Bool)
503 return 1;
504 FIXED_SIZE_INT_TYPE_SWITCH(getPrimType(), { return T::bitWidth() / 8; });
505 }
506 return ElemSize;
507}
#define V(N, I)
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D)
static void dtorTy(Block *, std::byte *Ptr, const Descriptor *)
static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D, unsigned FieldOffset)
static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset)
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D)
static constexpr bool needsDtor()
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D)
static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D, unsigned FieldOffset)
static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D)
static bool needsRecordDtor(const Record *R)
Whether a record needs its descriptor dtor function called.
static BlockDtorFn getDtorArrayPrim(PrimType Type)
static BlockDtorFn getDtorPrim(PrimType T)
static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D)
static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D, unsigned FieldOffset, bool IsVirtualBase)
Defines the clang::Expr interface and subclasses for C++ expressions.
#define FIXED_SIZE_INT_TYPE_SWITCH(Expr, B)
Definition PrimType.h:281
#define TYPE_SWITCH(Expr, B)
Definition PrimType.h:240
__DEVICE__ int max(int __a, int __b)
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
QualType getTagType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag) const
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3362
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
A (possibly-)qualified type.
Definition TypeBase.h:938
Represents a struct/union/class.
Definition Decl.h:4460
The base class of the type hierarchy.
Definition TypeBase.h:1879
Represents a GCC generic vector type.
Definition TypeBase.h:4273
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:43
Structure/Class descriptor.
Definition Record.h:27
bool isUnion() const
Checks if the record is a union.
Definition Record.h:71
llvm::iterator_range< const_base_iter > bases() const
Definition Record.h:107
llvm::iterator_range< const_base_iter > virtual_bases() const
Definition Record.h:123
llvm::iterator_range< const_field_iter > fields() const
Definition Record.h:92
Describes the statement/declaration an opcode was generated from.
Definition Source.h:77
void(*)(Block *Storage, std::byte *FieldPtr, const Descriptor *FieldDesc) BlockDtorFn
Invoked when a block is destroyed.
Definition Descriptor.h:39
bool NE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1519
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:218
constexpr bool isIntegerOrBoolType(PrimType T)
Definition PrimType.h:54
llvm::APInt APInt
Definition FixedPoint.h:19
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:35
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition PrimType.cpp:25
void(*)(Block *Storage, std::byte *FieldPtr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *FieldDesc) BlockCtorFn
Invoked whenever a block is created.
Definition Descriptor.h:33
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
const FunctionProtoType * T
@ None
No keyword precedes the qualified type name.
Definition TypeBase.h:6035
#define false
Definition stdbool.h:26
#define true
Definition stdbool.h:25
Token to denote structures of unknown size.
Definition Descriptor.h:139
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:154
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition Descriptor.h:237
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:246
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:260
QualType getElemQualType() const
bool hasTrivialDtor() const
Whether variables of this descriptor need their destructor called or not.
const BlockDtorFn DtorFn
Definition Descriptor.h:166
const OptPrimType PrimT
The primitive type this descriptor was created for, or the primitive element type in case this is a p...
Definition Descriptor.h:152
const ValueDecl * asValueDecl() const
Definition Descriptor.h:205
const BlockCtorFn CtorFn
Storage management methods.
Definition Descriptor.h:165
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
Definition Descriptor.h:142
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:201
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition Descriptor.h:148
SourceInfo getLoc() const
const bool IsMutable
Flag indicating if a field is mutable.
Definition Descriptor.h:156
QualType getDataType(const ASTContext &Ctx) const
const bool IsArray
Flag indicating if the block is an array.
Definition Descriptor.h:161
unsigned getElemDataSize() const
Returns the element data size, i.e.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:251
Descriptor(DeclOrExpr D, const Type *SourceTy, PrimType Type, bool IsConst, bool IsTemporary, bool IsMutable, bool IsVolatile)
Allocates a descriptor for a primitive.
PrimType getPrimType() const
Definition Descriptor.h:231
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:265
const bool IsTemporary
Flag indicating if the block is a temporary.
Definition Descriptor.h:158
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:146
bool isUnion() const
Checks if the descriptor is of a union.
const Expr * asExpr() const
Definition Descriptor.h:202
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:263
A pointer-sized struct we use to allocate into data storage.
Definition InitMap.h:79
void deleteInitMap()
Delete the InitMap if one exists.
Definition InitMap.h:113
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:69