xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Descriptor.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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