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 "ExprConstShared.h"
13#include "FixedPoint.h"
14#include "Floating.h"
15#include "Integral.h"
16#include "IntegralAP.h"
17#include "MemberPointer.h"
18#include "Pointer.h"
19#include "PrimType.h"
20#include "Record.h"
21#include "Reflect.h"
22#include "Source.h"
23#include "clang/AST/ExprCXX.h"
25#include "llvm/Support/ErrorHandling.h"
26
27using namespace clang;
28using namespace clang::interp;
29
30template <typename T> static constexpr bool needsDtor() {
31 return std::is_same_v<T, Pointer> || std::is_same_v<T, MemberPointer>;
32}
33
34template <typename T>
35static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
36 static_assert(needsDtor<T>());
37 reinterpret_cast<T *>(Ptr)->~T();
38}
39
40template <typename T>
41static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
42 InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
43 IMP.deleteInitMap();
44
45 if constexpr (needsDtor<T>()) {
46 Ptr += sizeof(InitMapPtr);
47 for (unsigned I = 0, NE = D->getNumElems(); I != NE; ++I) {
48 reinterpret_cast<T *>(Ptr)[I].~T();
49 }
50 }
51}
52
53static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
54 bool IsMutable, bool IsVolatile, bool IsActive,
55 bool InUnion, const Descriptor *D) {
56 const unsigned NumElems = D->getNumElems();
57 const unsigned ElemSize =
59
60 unsigned ElemOffset = 0;
61 for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
62 auto *ElemPtr = Ptr + ElemOffset;
63 auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
64 auto *SD = D->ElemDesc;
65
66 Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
67 Desc->Desc = SD;
68 Desc->IsInitialized = true;
69 Desc->IsBase = false;
70 Desc->IsActive = IsActive;
71 Desc->IsConst = IsConst || D->IsConst;
72 Desc->IsFieldMutable = IsMutable || D->IsMutable;
73 Desc->InUnion = InUnion;
74 Desc->IsArrayElement = true;
75 Desc->IsVolatile = IsVolatile;
76
77 if (auto Fn = D->ElemDesc->CtorFn) {
78 auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
79 Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,
80 Desc->InUnion || SD->isUnion(), D->ElemDesc);
81 }
82 }
83}
84
85static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
86 const unsigned NumElems = D->getNumElems();
87 const unsigned ElemSize =
89
90 unsigned ElemOffset = 0;
91 auto Dtor = D->ElemDesc->DtorFn;
92 assert(Dtor &&
93 "a composite array without an elem dtor shouldn't have a dtor itself");
94 for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
95 auto *ElemPtr = Ptr + ElemOffset;
96 auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
97 auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
98 Dtor(B, ElemLoc, D->ElemDesc);
99 }
100}
101
102static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
103 bool IsVolatile, bool IsActive, bool IsUnionField,
104 bool InUnion, const Descriptor *D, unsigned FieldOffset) {
105 auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
106 Desc->Offset = FieldOffset;
107 Desc->Desc = D;
108 Desc->IsInitialized = D->IsArray;
109 Desc->IsBase = false;
110 Desc->IsActive = IsActive && !IsUnionField;
111 Desc->InUnion = InUnion;
112 Desc->IsConst = IsConst || D->IsConst;
113 Desc->IsFieldMutable = IsMutable || D->IsMutable;
114 Desc->IsVolatile = IsVolatile || D->IsVolatile;
115 // True if this field is const AND the parent is mutable.
116 Desc->IsConstInMutable = Desc->IsConst && IsMutable;
117 Desc->LifeState =
120 : (Desc->IsActive ? Lifetime::NotStarted : Lifetime::Started);
121
122 if (auto Fn = D->CtorFn)
123 Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
124 Desc->IsVolatile, Desc->IsActive, InUnion || D->isUnion(), D);
125}
126
127static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
128 bool IsVolatile, bool IsActive, bool InUnion,
129 const Descriptor *D, unsigned FieldOffset,
130 bool IsVirtualBase) {
131 assert(D);
132 assert(D->ElemRecord);
133 assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes.
134
135 auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
136 Desc->Offset = FieldOffset;
137 Desc->Desc = D;
138 Desc->IsInitialized = D->IsArray;
139 Desc->IsBase = true;
140 Desc->IsVirtualBase = IsVirtualBase;
141 Desc->IsActive = IsActive && !InUnion;
142 Desc->IsConst = IsConst || D->IsConst;
143 Desc->IsFieldMutable = IsMutable || D->IsMutable;
144 Desc->InUnion = InUnion;
145 Desc->IsVolatile = false;
146
147 for (const auto &V : D->ElemRecord->bases())
148 initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
149 InUnion, V.Desc, V.Offset, false);
150 for (const auto &F : D->ElemRecord->fields())
151 initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
152 InUnion, InUnion, F.Desc, F.Offset);
153}
154
155static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
156 bool IsVolatile, bool IsActive, bool InUnion,
157 const Descriptor *D) {
158 for (const auto &V : D->ElemRecord->bases())
159 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
160 V.Offset,
161 /*IsVirtualBase=*/false);
162 for (const auto &F : D->ElemRecord->fields()) {
163 bool IsUnionField = D->isUnion();
164 initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,
165 InUnion || IsUnionField, F.Desc, F.Offset);
166 }
167 for (const auto &V : D->ElemRecord->virtual_bases())
168 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
169 V.Offset,
170 /*IsVirtualBase=*/true);
171}
172
173static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,
174 unsigned FieldOffset) {
175 if (auto Fn = D->DtorFn)
176 Fn(B, Ptr + FieldOffset, D);
177}
178
179static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,
180 unsigned FieldOffset) {
181 assert(D);
182 assert(D->ElemRecord);
183
184 for (const auto &V : D->ElemRecord->bases())
185 destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);
186 for (const auto &F : D->ElemRecord->fields())
187 destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);
188}
189
190static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
191 for (const auto &F : D->ElemRecord->bases())
192 destroyBase(B, Ptr, F.Desc, F.Offset);
193 for (const auto &F : D->ElemRecord->fields())
194 destroyField(B, Ptr, F.Desc, F.Offset);
195 for (const auto &F : D->ElemRecord->virtual_bases())
196 destroyBase(B, Ptr, F.Desc, F.Offset);
197}
198
199/// Whether a record needs its descriptor dtor function called.
200static bool needsRecordDtor(const Record *R) {
201 for (const auto &B : R->bases()) {
202 if (B.Desc->DtorFn)
203 return true;
204 }
205
206 for (const auto &F : R->fields()) {
207 if (F.Desc->DtorFn)
208 return true;
209 }
210
211 for (const auto &V : R->virtual_bases()) {
212 if (V.Desc->DtorFn)
213 return true;
214 }
215 return false;
216}
217
219 switch (T) {
220 case PT_Ptr:
222 case PT_MemberPtr:
224 default:
225 return nullptr;
226 }
227 llvm_unreachable("Unhandled PrimType");
228}
229
230// NOTE: The following #if-ed out code is for calling constructors of primitive
231// types. It is currently not needed but I'm not sure if it will stay this way
232// forever so I'm leaving it here for now.
233#if 0
234template <typename T> static constexpr bool needsCtor() {
235 return false;
236 if constexpr (std::is_same_v<T, Char<true>> ||
237 std::is_same_v<T, Char<false>> ||
238 std::is_same_v<T, Integral<16, true>> ||
239 std::is_same_v<T, Integral<16, false>> ||
240 std::is_same_v<T, Integral<32, true>> ||
241 std::is_same_v<T, Integral<32, false>> ||
242 std::is_same_v<T, Integral<64, true>> ||
243 std::is_same_v<T, Integral<64, false>> ||
244 std::is_same_v<T, IntegralAP<true>> ||
245 std::is_same_v<T, IntegralAP<false>> ||
246 std::is_same_v<T, Floating> || std::is_same_v<T, Boolean>)
247 return false;
248
249 return true;
250}
251
252
253static BlockCtorFn getCtorArrayPrim(PrimType Type) {
254 TYPE_SWITCH(Type, if constexpr (!needsCtor<T>()) return nullptr;
255 return ctorArrayTy<T>);
256 llvm_unreachable("unknown Expr");
257}
258static BlockCtorFn getCtorPrim(PrimType T) {
259 return nullptr;
260 switch (T) {
261 // case PT_Ptr:
262 // return ctorTy<PrimConv<PT_Ptr>::T>;
263 // case PT_MemberPtr:
264 // return ctorTy<PrimConv<PT_MemberPtr>::T>;
265 default:
266 return nullptr;
267 }
268 llvm_unreachable("Unhandled PrimType");
269}
270
271
272template <typename T>
273static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
274 const Descriptor *D) {
275 new (Ptr) InitMapPtr();
276
277 if constexpr (needsCtor<T>()) {
278 Ptr += sizeof(InitMapPtr);
279 for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
280 new (&reinterpret_cast<T *>(Ptr)[I]) T();
281 }
282 }
283}
284template <typename T>
285static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
286 const Descriptor *) {
287 static_assert(needsCtor<T>());
288 new (Ptr) T();
289}
290#endif
291
294 llvm_unreachable("unknown Expr");
295}
296
297/// Primitives.
299 bool IsConst, bool IsTemporary, bool IsMutable,
300 bool IsVolatile)
301 : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),
302 AllocSize(align(ElemSize)), PrimT(Type), IsConst(IsConst),
305 assert(Source && "Missing source");
306}
307
308/// Primitive arrays.
310 size_t NumElems, bool IsConst, bool IsTemporary,
311 bool IsMutable, bool IsVolatile)
312 : Source(D), SourceType(SourceTy), ElemSize(primSize(Type)),
313 Size(ElemSize * NumElems), AllocSize(align(Size) + sizeof(InitMapPtr)),
317 assert(Source && "Missing source");
318 assert(NumElems <= (MaxArrayElemBytes / ElemSize));
319}
320
321/// Primitive unknown-size arrays.
324 : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
325 AllocSize(sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
328 assert(Source && "Missing source");
329}
330
331/// Arrays of composite elements.
333 const Descriptor *Elem, unsigned NumElems, bool IsConst,
334 bool IsTemporary, bool IsMutable)
335 : Source(D), SourceType(SourceTy),
336 ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
337 Size(ElemSize * NumElems),
338 AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem),
342 assert(Source && "Missing source");
343}
344
345/// Unknown-size arrays of composite elements.
348 : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
349 Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem),
352 assert(Source && "Missing source");
353}
354
355/// Composite records.
357 bool IsTemporary, bool IsMutable, bool IsVolatile)
358 : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
359 Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst),
362 assert(Source && "Missing source");
363}
364
365/// Dummy.
367 : Source(D), ElemSize(1), Size(1), AllocSize(0), ElemDesc(nullptr),
369 assert(Source && "Missing source");
370}
371
373 if (SourceType)
374 return QualType(SourceType, 0);
375
376 if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))
377 return T->getASTContext().getTypeDeclType(T);
378
379 // The Source sometimes has a different type than the once
380 // we really save. Try to consult the Record first.
381 if (isRecord()) {
382 const RecordDecl *RD = ElemRecord->getDecl();
384 std::nullopt, RD, false);
385 if (IsConst)
386 return T.withConst();
387 return T;
388 }
389
390 if (const auto *E = asExpr()) {
391 if (isa<CXXNewExpr>(E))
392 return E->getType()->getPointeeType();
393
394 // std::allocator.allocate() call.
395 if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
396 ME && ME->getRecordDecl()->getName() == "allocator" &&
397 ME->getMethodDecl()->getName() == "allocate")
398 return E->getType()->getPointeeType();
399 return E->getType();
400 }
401
402 if (const auto *D = asValueDecl())
403 return D->getType();
404
405 llvm_unreachable("Invalid descriptor type");
406}
407
409 assert(isArray());
410 QualType T;
411
412 if (SourceType) {
413 T = QualType(SourceType, 0);
414 } else if (const auto *TDecl = dyn_cast_if_present<TypeDecl>(asDecl())) {
415 T = TDecl->getASTContext().getTypeDeclType(TDecl);
416 } else if (isRecord()) {
417 const RecordDecl *RD = ElemRecord->getDecl();
419 std::nullopt, RD, false);
420 if (IsConst)
421 T.addConst();
422 } else if (const auto *E = asExpr()) {
423 T = E->getType();
424 } else if (const auto *D = asValueDecl()) {
425 T = D->getType();
426 }
427
428 assert(!T.isNull());
429
430 if (const auto *AT = T->getAs<AtomicType>())
431 T = AT->getValueType();
432 if (T->isPointerOrReferenceType())
433 T = T->getPointeeType();
434
435 if (const auto *AT = T->getAsArrayTypeUnsafe()) {
436 // For primitive arrays, we don't save a QualType at all,
437 // just a PrimType. Try to figure out the QualType here.
438 if (isPrimitiveArray()) {
439 while (T->isArrayType())
440 T = T->getAsArrayTypeUnsafe()->getElementType();
441 return T;
442 }
443 return AT->getElementType();
444 }
445 if (const auto *CT = T->getAs<ComplexType>())
446 return CT->getElementType();
447 if (const auto *CT = T->getAs<VectorType>())
448 return CT->getElementType();
449
450 return T;
451}
452
454 auto MakeArrayType = [&](QualType ElemType) -> QualType {
455 if (IsArray)
456 return Ctx.getConstantArrayType(
457 ElemType, APInt(64, static_cast<uint64_t>(getNumElems()), false),
458 nullptr, ArraySizeModifier::Normal, 0);
459 return ElemType;
460 };
461
462 if (isDynAlloc())
463 return MakeArrayType(asExpr()->getType()->getPointeeType());
464
465 return getType();
466}
467
469 if (const auto *D = Source.asDecl())
470 return SourceInfo(D);
471 if (const auto *E = Source.asExpr())
472 return SourceInfo(E);
473 llvm_unreachable("Invalid descriptor type");
474}
475
477 if (isPrimitive() || isPrimitiveArray())
478 return true;
479
480 if (isRecord()) {
481 assert(ElemRecord);
482 return ElemRecord->hasTrivialDtor();
483 }
484
485 if (!ElemDesc)
486 return true;
487 // Composite arrays.
488 return ElemDesc->hasTrivialDtor();
489}
490
491bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
492
494 if ((isPrimitive() || isPrimitiveArray()) &&
496 if (getPrimType() == PT_Bool)
497 return 1;
498 FIXED_SIZE_INT_TYPE_SWITCH(getPrimType(), { return T::bitWidth() / 8; });
499 }
500 return ElemSize;
501}
502
504 // new or new[] expression
505 if (const auto *NE = dyn_cast<CXXNewExpr>(E))
506 return NE->isArray() ? DynAllocKind::ArrayNew : DynAllocKind::New;
507 // std::allocator::allocate call
508 if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
509 ME && ME->getRecordDecl()->getName() == "allocator" &&
510 ME->getMethodDecl()->getName() == "allocate")
512 // __builtin_operator_new call
513 if (const auto *CE = dyn_cast<CallExpr>(E);
514 CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
516 return DynAllocKind::None;
517}
518
#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
static QualType getPointeeType(const MemRegion *R)
__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:245
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
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3362
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
This represents one expression.
Definition Expr.h:114
A (possibly-)qualified type.
Definition TypeBase.h:938
Represents a struct/union/class.
Definition Decl.h:4476
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 Block.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
Defines the clang::TargetInfo interface.
void(*)(Block *Storage, std::byte *FieldPtr, const Descriptor *FieldDesc) BlockDtorFn
Invoked when a block is destroyed.
Definition Descriptor.h:40
bool NE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1513
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:34
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
DynAllocKind
Kind of source for a dynamic allocation.
Definition APValue.h:69
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
CharUnits GetAlignOfDynamicAlloc(const ASTContext &Ctx, QualType AllocType, DynAllocKind AllocKind)
#define false
Definition stdbool.h:26
#define true
Definition stdbool.h:25
Token to denote structures of unknown size.
Definition Descriptor.h:140
Describes a memory block created by an allocation site.
Definition Descriptor.h:123
const bool IsConst
Flag indicating if the block is mutable.
Definition Descriptor.h:155
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition Descriptor.h:238
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:247
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:261
QualType getElemQualType() const
bool hasTrivialDtor() const
Whether variables of this descriptor need their destructor called or not.
const BlockDtorFn DtorFn
Definition Descriptor.h:167
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:153
const ValueDecl * asValueDecl() const
Definition Descriptor.h:206
const BlockCtorFn CtorFn
Storage management methods.
Definition Descriptor.h:166
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
Definition Descriptor.h:143
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:202
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition Descriptor.h:149
SourceInfo getLoc() const
const bool IsMutable
Flag indicating if a field is mutable.
Definition Descriptor.h:157
QualType getDataType(const ASTContext &Ctx) const
bool isDynAlloc() const
Checks if the descriptor is of a dynamic allocation.
Definition Descriptor.h:280
static DynAllocKind getDynAllocKindForExpr(const Expr *E)
Returns the kind of dynamic allocation source of this block.
const bool IsArray
Flag indicating if the block is an array.
Definition Descriptor.h:162
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:252
DynAllocKind getDynAllocKind() const
Returns the kind of dynamic allocation source of this block.
Definition Descriptor.h:276
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:232
CharUnits computeAlignForDynamicAlloc(const ASTContext &Ctx) const
Compute the alignment for a dynamic allocation.
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:266
const bool IsTemporary
Flag indicating if the block is a temporary.
Definition Descriptor.h:159
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:147
bool isUnion() const
Checks if the descriptor is of a union.
const Expr * asExpr() const
Definition Descriptor.h:203
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:264
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:68
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:70