Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Descriptor.cpp
213799 views
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 "FixedPoint.h"
12
#include "Floating.h"
13
#include "IntegralAP.h"
14
#include "MemberPointer.h"
15
#include "Pointer.h"
16
#include "PrimType.h"
17
#include "Record.h"
18
#include "Source.h"
19
#include "clang/AST/ExprCXX.h"
20
21
using namespace clang;
22
using namespace clang::interp;
23
24
template <typename T>
25
static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
26
const Descriptor *) {
27
new (Ptr) T();
28
}
29
30
template <typename T>
31
static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
32
reinterpret_cast<T *>(Ptr)->~T();
33
}
34
35
template <typename T>
36
static void moveTy(Block *, std::byte *Src, std::byte *Dst,
37
const Descriptor *) {
38
auto *SrcPtr = reinterpret_cast<T *>(Src);
39
auto *DstPtr = reinterpret_cast<T *>(Dst);
40
new (DstPtr) T(std::move(*SrcPtr));
41
}
42
43
template <typename T>
44
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
45
const Descriptor *D) {
46
new (Ptr) InitMapPtr(std::nullopt);
47
48
Ptr += sizeof(InitMapPtr);
49
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
50
new (&reinterpret_cast<T *>(Ptr)[I]) T();
51
}
52
}
53
54
template <typename T>
55
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
56
InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
57
58
if (IMP)
59
IMP = std::nullopt;
60
Ptr += sizeof(InitMapPtr);
61
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
62
reinterpret_cast<T *>(Ptr)[I].~T();
63
}
64
}
65
66
template <typename T>
67
static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst,
68
const Descriptor *D) {
69
InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src);
70
if (SrcIMP) {
71
// We only ever invoke the moveFunc when moving block contents to a
72
// DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here.
73
SrcIMP = std::nullopt;
74
}
75
Src += sizeof(InitMapPtr);
76
Dst += sizeof(InitMapPtr);
77
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
78
auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
79
auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
80
new (DstPtr) T(std::move(*SrcPtr));
81
}
82
}
83
84
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
85
bool IsMutable, bool IsVolatile, bool IsActive,
86
bool InUnion, const Descriptor *D) {
87
const unsigned NumElems = D->getNumElems();
88
const unsigned ElemSize =
89
D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
90
91
unsigned ElemOffset = 0;
92
for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
93
auto *ElemPtr = Ptr + ElemOffset;
94
auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
95
auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
96
auto *SD = D->ElemDesc;
97
98
Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
99
Desc->Desc = SD;
100
Desc->IsInitialized = true;
101
Desc->IsBase = false;
102
Desc->IsActive = IsActive;
103
Desc->IsConst = IsConst || D->IsConst;
104
Desc->IsFieldMutable = IsMutable || D->IsMutable;
105
Desc->InUnion = InUnion;
106
Desc->IsArrayElement = true;
107
Desc->IsVolatile = IsVolatile;
108
109
if (auto Fn = D->ElemDesc->CtorFn)
110
Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsVolatile, IsActive,
111
Desc->InUnion || SD->isUnion(), D->ElemDesc);
112
}
113
}
114
115
static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
116
const unsigned NumElems = D->getNumElems();
117
const unsigned ElemSize =
118
D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
119
120
unsigned ElemOffset = 0;
121
for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
122
auto *ElemPtr = Ptr + ElemOffset;
123
auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
124
auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
125
if (auto Fn = D->ElemDesc->DtorFn)
126
Fn(B, ElemLoc, D->ElemDesc);
127
}
128
}
129
130
static void moveArrayDesc(Block *B, std::byte *Src, std::byte *Dst,
131
const Descriptor *D) {
132
const unsigned NumElems = D->getNumElems();
133
const unsigned ElemSize =
134
D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
135
136
unsigned ElemOffset = 0;
137
for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
138
auto *SrcPtr = Src + ElemOffset;
139
auto *DstPtr = Dst + ElemOffset;
140
141
auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
142
auto *SrcElemLoc = reinterpret_cast<std::byte *>(SrcDesc + 1);
143
auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
144
auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);
145
146
*DstDesc = *SrcDesc;
147
if (auto Fn = D->ElemDesc->MoveFn)
148
Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
149
}
150
}
151
152
static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
153
bool IsVolatile, bool IsActive, bool IsUnionField,
154
bool InUnion, const Descriptor *D, unsigned FieldOffset) {
155
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
156
Desc->Offset = FieldOffset;
157
Desc->Desc = D;
158
Desc->IsInitialized = D->IsArray;
159
Desc->IsBase = false;
160
Desc->IsActive = IsActive && !IsUnionField;
161
Desc->InUnion = InUnion;
162
Desc->IsConst = IsConst || D->IsConst;
163
Desc->IsFieldMutable = IsMutable || D->IsMutable;
164
Desc->IsVolatile = IsVolatile || D->IsVolatile;
165
166
if (auto Fn = D->CtorFn)
167
Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,
168
Desc->IsVolatile, Desc->IsActive, InUnion || D->isUnion(), D);
169
}
170
171
static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
172
bool IsVolatile, bool IsActive, bool InUnion,
173
const Descriptor *D, unsigned FieldOffset,
174
bool IsVirtualBase) {
175
assert(D);
176
assert(D->ElemRecord);
177
assert(!D->ElemRecord->isUnion()); // Unions cannot be base classes.
178
179
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + FieldOffset) - 1;
180
Desc->Offset = FieldOffset;
181
Desc->Desc = D;
182
Desc->IsInitialized = D->IsArray;
183
Desc->IsBase = true;
184
Desc->IsVirtualBase = IsVirtualBase;
185
Desc->IsActive = IsActive && !InUnion;
186
Desc->IsConst = IsConst || D->IsConst;
187
Desc->IsFieldMutable = IsMutable || D->IsMutable;
188
Desc->InUnion = InUnion;
189
Desc->IsVolatile = false;
190
191
for (const auto &V : D->ElemRecord->bases())
192
initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
193
InUnion, V.Desc, V.Offset, false);
194
for (const auto &F : D->ElemRecord->fields())
195
initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
196
InUnion, InUnion, F.Desc, F.Offset);
197
}
198
199
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
200
bool IsVolatile, bool IsActive, bool InUnion,
201
const Descriptor *D) {
202
for (const auto &V : D->ElemRecord->bases())
203
initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
204
V.Offset,
205
/*IsVirtualBase=*/false);
206
for (const auto &F : D->ElemRecord->fields()) {
207
bool IsUnionField = D->isUnion();
208
initField(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, IsUnionField,
209
InUnion || IsUnionField, F.Desc, F.Offset);
210
}
211
for (const auto &V : D->ElemRecord->virtual_bases())
212
initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, V.Desc,
213
V.Offset,
214
/*IsVirtualBase=*/true);
215
}
216
217
static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,
218
unsigned FieldOffset) {
219
if (auto Fn = D->DtorFn)
220
Fn(B, Ptr + FieldOffset, D);
221
}
222
223
static void destroyBase(Block *B, std::byte *Ptr, const Descriptor *D,
224
unsigned FieldOffset) {
225
assert(D);
226
assert(D->ElemRecord);
227
228
for (const auto &V : D->ElemRecord->bases())
229
destroyBase(B, Ptr + FieldOffset, V.Desc, V.Offset);
230
for (const auto &F : D->ElemRecord->fields())
231
destroyField(B, Ptr + FieldOffset, F.Desc, F.Offset);
232
}
233
234
static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
235
for (const auto &F : D->ElemRecord->bases())
236
destroyBase(B, Ptr, F.Desc, F.Offset);
237
for (const auto &F : D->ElemRecord->fields())
238
destroyField(B, Ptr, F.Desc, F.Offset);
239
for (const auto &F : D->ElemRecord->virtual_bases())
240
destroyBase(B, Ptr, F.Desc, F.Offset);
241
}
242
243
static void moveRecord(Block *B, std::byte *Src, std::byte *Dst,
244
const Descriptor *D) {
245
assert(D);
246
assert(D->ElemRecord);
247
248
// FIXME: Code duplication.
249
for (const auto &F : D->ElemRecord->fields()) {
250
auto FieldOffset = F.Offset;
251
const auto *SrcDesc =
252
reinterpret_cast<const InlineDescriptor *>(Src + FieldOffset) - 1;
253
auto *DestDesc =
254
reinterpret_cast<InlineDescriptor *>(Dst + FieldOffset) - 1;
255
std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));
256
257
if (auto Fn = F.Desc->MoveFn)
258
Fn(B, Src + FieldOffset, Dst + FieldOffset, F.Desc);
259
}
260
261
for (const auto &Base : D->ElemRecord->bases()) {
262
auto BaseOffset = Base.Offset;
263
const auto *SrcDesc =
264
reinterpret_cast<const InlineDescriptor *>(Src + BaseOffset) - 1;
265
auto *DestDesc = reinterpret_cast<InlineDescriptor *>(Dst + BaseOffset) - 1;
266
std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));
267
268
if (auto Fn = Base.Desc->MoveFn)
269
Fn(B, Src + BaseOffset, Dst + BaseOffset, Base.Desc);
270
}
271
272
for (const auto &VBase : D->ElemRecord->virtual_bases()) {
273
auto VBaseOffset = VBase.Offset;
274
const auto *SrcDesc =
275
reinterpret_cast<const InlineDescriptor *>(Src + VBaseOffset) - 1;
276
auto *DestDesc =
277
reinterpret_cast<InlineDescriptor *>(Dst + VBaseOffset) - 1;
278
std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor));
279
}
280
}
281
282
static BlockCtorFn getCtorPrim(PrimType Type) {
283
// Floating types are special. They are primitives, but need their
284
// constructor called.
285
if (Type == PT_Float)
286
return ctorTy<PrimConv<PT_Float>::T>;
287
if (Type == PT_IntAP)
288
return ctorTy<PrimConv<PT_IntAP>::T>;
289
if (Type == PT_IntAPS)
290
return ctorTy<PrimConv<PT_IntAPS>::T>;
291
if (Type == PT_MemberPtr)
292
return ctorTy<PrimConv<PT_MemberPtr>::T>;
293
294
COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
295
}
296
297
static BlockDtorFn getDtorPrim(PrimType Type) {
298
// Floating types are special. They are primitives, but need their
299
// destructor called, since they might allocate memory.
300
if (Type == PT_Float)
301
return dtorTy<PrimConv<PT_Float>::T>;
302
if (Type == PT_IntAP)
303
return dtorTy<PrimConv<PT_IntAP>::T>;
304
if (Type == PT_IntAPS)
305
return dtorTy<PrimConv<PT_IntAPS>::T>;
306
if (Type == PT_MemberPtr)
307
return dtorTy<PrimConv<PT_MemberPtr>::T>;
308
309
COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
310
}
311
312
static BlockMoveFn getMovePrim(PrimType Type) {
313
if (Type == PT_Float)
314
return moveTy<PrimConv<PT_Float>::T>;
315
if (Type == PT_IntAP)
316
return moveTy<PrimConv<PT_IntAP>::T>;
317
if (Type == PT_IntAPS)
318
return moveTy<PrimConv<PT_IntAPS>::T>;
319
if (Type == PT_MemberPtr)
320
return moveTy<PrimConv<PT_MemberPtr>::T>;
321
COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
322
}
323
324
static BlockCtorFn getCtorArrayPrim(PrimType Type) {
325
TYPE_SWITCH(Type, return ctorArrayTy<T>);
326
llvm_unreachable("unknown Expr");
327
}
328
329
static BlockDtorFn getDtorArrayPrim(PrimType Type) {
330
TYPE_SWITCH(Type, return dtorArrayTy<T>);
331
llvm_unreachable("unknown Expr");
332
}
333
334
static BlockMoveFn getMoveArrayPrim(PrimType Type) {
335
TYPE_SWITCH(Type, return moveArrayTy<T>);
336
llvm_unreachable("unknown Expr");
337
}
338
339
/// Primitives.
340
Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
341
MetadataSize MD, bool IsConst, bool IsTemporary,
342
bool IsMutable, bool IsVolatile)
343
: Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),
344
MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),
345
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
346
IsVolatile(IsVolatile), CtorFn(getCtorPrim(Type)),
347
DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
348
assert(AllocSize >= Size);
349
assert(Source && "Missing source");
350
}
351
352
/// Primitive arrays.
353
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
354
size_t NumElems, bool IsConst, bool IsTemporary,
355
bool IsMutable)
356
: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
357
MDSize(MD.value_or(0)),
358
AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type),
359
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
360
IsArray(true), CtorFn(getCtorArrayPrim(Type)),
361
DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
362
assert(Source && "Missing source");
363
assert(NumElems <= (MaxArrayElemBytes / ElemSize));
364
}
365
366
/// Primitive unknown-size arrays.
367
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
368
bool IsTemporary, bool IsConst, UnknownSize)
369
: Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
370
MDSize(MD.value_or(0)),
371
AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type),
372
IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary),
373
IsArray(true), CtorFn(getCtorArrayPrim(Type)),
374
DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
375
assert(Source && "Missing source");
376
}
377
378
/// Arrays of composite elements.
379
Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy,
380
const Descriptor *Elem, MetadataSize MD,
381
unsigned NumElems, bool IsConst, bool IsTemporary,
382
bool IsMutable)
383
: Source(D), SourceType(SourceTy),
384
ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
385
Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
386
AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
387
ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
388
IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
389
DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
390
assert(Source && "Missing source");
391
}
392
393
/// Unknown-size arrays of composite elements.
394
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
395
bool IsTemporary, UnknownSize)
396
: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
397
Size(UnknownSizeMark), MDSize(MD.value_or(0)),
398
AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),
399
IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
400
CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
401
assert(Source && "Missing source");
402
}
403
404
/// Composite records.
405
Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
406
bool IsConst, bool IsTemporary, bool IsMutable,
407
bool IsVolatile)
408
: Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
409
Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
410
ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
411
IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord),
412
DtorFn(dtorRecord), MoveFn(moveRecord) {
413
assert(Source && "Missing source");
414
}
415
416
/// Dummy.
417
Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
418
: Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),
419
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
420
IsTemporary(false), IsDummy(true) {
421
assert(Source && "Missing source");
422
}
423
424
QualType Descriptor::getType() const {
425
if (SourceType)
426
return QualType(SourceType, 0);
427
if (const auto *D = asValueDecl())
428
return D->getType();
429
if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))
430
return QualType(T->getTypeForDecl(), 0);
431
432
// The Source sometimes has a different type than the once
433
// we really save. Try to consult the Record first.
434
if (isRecord())
435
return QualType(ElemRecord->getDecl()->getTypeForDecl(), 0);
436
if (const auto *E = asExpr())
437
return E->getType();
438
llvm_unreachable("Invalid descriptor type");
439
}
440
441
QualType Descriptor::getElemQualType() const {
442
assert(isArray());
443
QualType T = getType();
444
if (T->isPointerOrReferenceType())
445
T = T->getPointeeType();
446
447
if (const auto *AT = T->getAsArrayTypeUnsafe()) {
448
// For primitive arrays, we don't save a QualType at all,
449
// just a PrimType. Try to figure out the QualType here.
450
if (isPrimitiveArray()) {
451
while (T->isArrayType())
452
T = T->getAsArrayTypeUnsafe()->getElementType();
453
return T;
454
}
455
return AT->getElementType();
456
}
457
if (const auto *CT = T->getAs<ComplexType>())
458
return CT->getElementType();
459
if (const auto *CT = T->getAs<VectorType>())
460
return CT->getElementType();
461
462
return T;
463
}
464
465
QualType Descriptor::getDataType(const ASTContext &Ctx) const {
466
auto MakeArrayType = [&](QualType ElemType) -> QualType {
467
if (IsArray)
468
return Ctx.getConstantArrayType(
469
ElemType, APInt(64, static_cast<uint64_t>(getNumElems()), false),
470
nullptr, ArraySizeModifier::Normal, 0);
471
return ElemType;
472
};
473
474
if (const auto *E = asExpr()) {
475
if (isa<CXXNewExpr>(E))
476
return MakeArrayType(E->getType()->getPointeeType());
477
478
// std::allocator.allocate() call.
479
if (const auto *ME = dyn_cast<CXXMemberCallExpr>(E);
480
ME && ME->getRecordDecl()->getName() == "allocator" &&
481
ME->getMethodDecl()->getName() == "allocate")
482
return MakeArrayType(E->getType()->getPointeeType());
483
return E->getType();
484
}
485
486
return getType();
487
}
488
489
SourceLocation Descriptor::getLocation() const {
490
if (auto *D = dyn_cast<const Decl *>(Source))
491
return D->getLocation();
492
if (auto *E = dyn_cast<const Expr *>(Source))
493
return E->getExprLoc();
494
llvm_unreachable("Invalid descriptor type");
495
}
496
497
SourceInfo Descriptor::getLoc() const {
498
if (const auto *D = dyn_cast<const Decl *>(Source))
499
return SourceInfo(D);
500
if (const auto *E = dyn_cast<const Expr *>(Source))
501
return SourceInfo(E);
502
llvm_unreachable("Invalid descriptor type");
503
}
504
505
bool Descriptor::hasTrivialDtor() const {
506
if (isPrimitive() || isPrimitiveArray() || isDummy())
507
return true;
508
509
if (isRecord()) {
510
assert(ElemRecord);
511
const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
512
return !Dtor || Dtor->isTrivial();
513
}
514
515
// Composite arrays.
516
assert(ElemDesc);
517
return ElemDesc->hasTrivialDtor();
518
}
519
520
bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
521
522
InitMap::InitMap(unsigned N)
523
: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {
524
std::fill_n(data(), numFields(N), 0);
525
}
526
527
bool InitMap::initializeElement(unsigned I) {
528
unsigned Bucket = I / PER_FIELD;
529
T Mask = T(1) << (I % PER_FIELD);
530
if (!(data()[Bucket] & Mask)) {
531
data()[Bucket] |= Mask;
532
UninitFields -= 1;
533
}
534
return UninitFields == 0;
535
}
536
537
bool InitMap::isElementInitialized(unsigned I) const {
538
unsigned Bucket = I / PER_FIELD;
539
return data()[Bucket] & (T(1) << (I % PER_FIELD));
540
}
541
542