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
21using namespace clang;
22using namespace clang::interp;
23
24template <typename T>
25static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
26 const Descriptor *) {
27 new (Ptr) T();
28}
29
30template <typename T>
31static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
32 reinterpret_cast<T *>(Ptr)->~T();
33}
34
35template <typename T>
36static 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
43template <typename T>
44static 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
54template <typename T>
55static 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
66template <typename T>
67static 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
84static 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
115static 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
130static 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
152static 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
171static 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: Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
193 InUnion, D: V.Desc, FieldOffset: V.Offset, IsVirtualBase: false);
194 for (const auto &F : D->ElemRecord->fields())
195 initField(B, Ptr: Ptr + FieldOffset, IsConst, IsMutable, IsVolatile, IsActive,
196 IsUnionField: InUnion, InUnion, D: F.Desc, FieldOffset: F.Offset);
197}
198
199static 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, D: V.Desc,
204 FieldOffset: 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: InUnion || IsUnionField, D: F.Desc, FieldOffset: F.Offset);
210 }
211 for (const auto &V : D->ElemRecord->virtual_bases())
212 initBase(B, Ptr, IsConst, IsMutable, IsVolatile, IsActive, InUnion, D: V.Desc,
213 FieldOffset: V.Offset,
214 /*IsVirtualBase=*/true);
215}
216
217static 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
223static 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: Ptr + FieldOffset, D: V.Desc, FieldOffset: V.Offset);
230 for (const auto &F : D->ElemRecord->fields())
231 destroyField(B, Ptr: Ptr + FieldOffset, D: F.Desc, FieldOffset: F.Offset);
232}
233
234static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
235 for (const auto &F : D->ElemRecord->bases())
236 destroyBase(B, Ptr, D: F.Desc, FieldOffset: F.Offset);
237 for (const auto &F : D->ElemRecord->fields())
238 destroyField(B, Ptr, D: F.Desc, FieldOffset: F.Offset);
239 for (const auto &F : D->ElemRecord->virtual_bases())
240 destroyBase(B, Ptr, D: F.Desc, FieldOffset: F.Offset);
241}
242
243static 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(dest: DestDesc, src: SrcDesc, n: 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(dest: DestDesc, src: SrcDesc, n: 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(dest: DestDesc, src: SrcDesc, n: sizeof(InlineDescriptor));
279 }
280}
281
282static 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
297static 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
312static 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
324static BlockCtorFn getCtorArrayPrim(PrimType Type) {
325 TYPE_SWITCH(Type, return ctorArrayTy<T>);
326 llvm_unreachable("unknown Expr");
327}
328
329static BlockDtorFn getDtorArrayPrim(PrimType Type) {
330 TYPE_SWITCH(Type, return dtorArrayTy<T>);
331 llvm_unreachable("unknown Expr");
332}
333
334static BlockMoveFn getMoveArrayPrim(PrimType Type) {
335 TYPE_SWITCH(Type, return moveArrayTy<T>);
336 llvm_unreachable("unknown Expr");
337}
338
339/// Primitives.
340Descriptor::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(u: 0)), AllocSize(align(Size: 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.
353Descriptor::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(u: 0)),
358 AllocSize(align(Size: 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.
367Descriptor::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(u: 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.
379Descriptor::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(u: 0)),
386 AllocSize(std::max<size_t>(a: alignof(void *), b: 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.
394Descriptor::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(u: 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.
405Descriptor::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>(a: alignof(void *), b: R->getFullSize())),
409 Size(ElemSize), MDSize(MD.value_or(u: 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.
417Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
418 : Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(u: 0)),
419 AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
420 IsTemporary(false), IsDummy(true) {
421 assert(Source && "Missing source");
422}
423
424QualType 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>(Val: 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
441QualType 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
465QualType Descriptor::getDataType(const ASTContext &Ctx) const {
466 auto MakeArrayType = [&](QualType ElemType) -> QualType {
467 if (IsArray)
468 return Ctx.getConstantArrayType(
469 EltTy: ElemType, ArySize: APInt(64, static_cast<uint64_t>(getNumElems()), false),
470 SizeExpr: nullptr, ASM: ArraySizeModifier::Normal, IndexTypeQuals: 0);
471 return ElemType;
472 };
473
474 if (const auto *E = asExpr()) {
475 if (isa<CXXNewExpr>(Val: E))
476 return MakeArrayType(E->getType()->getPointeeType());
477
478 // std::allocator.allocate() call.
479 if (const auto *ME = dyn_cast<CXXMemberCallExpr>(Val: 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
489SourceLocation Descriptor::getLocation() const {
490 if (auto *D = dyn_cast<const Decl *>(Val: Source))
491 return D->getLocation();
492 if (auto *E = dyn_cast<const Expr *>(Val: Source))
493 return E->getExprLoc();
494 llvm_unreachable("Invalid descriptor type");
495}
496
497SourceInfo Descriptor::getLoc() const {
498 if (const auto *D = dyn_cast<const Decl *>(Val: Source))
499 return SourceInfo(D);
500 if (const auto *E = dyn_cast<const Expr *>(Val: Source))
501 return SourceInfo(E);
502 llvm_unreachable("Invalid descriptor type");
503}
504
505bool 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
520bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
521
522InitMap::InitMap(unsigned N)
523 : UninitFields(N), Data(std::make_unique<T[]>(num: numFields(N))) {
524 std::fill_n(first: data(), n: numFields(N), value: 0);
525}
526
527bool 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
537bool InitMap::isElementInitialized(unsigned I) const {
538 unsigned Bucket = I / PER_FIELD;
539 return data()[Bucket] & (T(1) << (I % PER_FIELD));
540}
541