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>
ctorTy(Block *,std::byte * Ptr,bool,bool,bool,bool,bool,const Descriptor *)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>
dtorTy(Block *,std::byte * Ptr,const Descriptor *)31 static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
32 reinterpret_cast<T *>(Ptr)->~T();
33 }
34
35 template <typename T>
moveTy(Block *,std::byte * Src,std::byte * Dst,const Descriptor *)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>
ctorArrayTy(Block *,std::byte * Ptr,bool,bool,bool,bool,bool,const Descriptor * D)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>
dtorArrayTy(Block *,std::byte * Ptr,const Descriptor * D)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>
moveArrayTy(Block *,std::byte * Src,std::byte * Dst,const Descriptor * D)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
ctorArrayDesc(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool InUnion,const Descriptor * D)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
dtorArrayDesc(Block * B,std::byte * Ptr,const Descriptor * D)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
moveArrayDesc(Block * B,std::byte * Src,std::byte * Dst,const Descriptor * D)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
initField(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool IsUnionField,bool InUnion,const Descriptor * D,unsigned FieldOffset)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
initBase(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool InUnion,const Descriptor * D,unsigned FieldOffset,bool IsVirtualBase)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
ctorRecord(Block * B,std::byte * Ptr,bool IsConst,bool IsMutable,bool IsVolatile,bool IsActive,bool InUnion,const Descriptor * D)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
destroyField(Block * B,std::byte * Ptr,const Descriptor * D,unsigned FieldOffset)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
destroyBase(Block * B,std::byte * Ptr,const Descriptor * D,unsigned FieldOffset)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
dtorRecord(Block * B,std::byte * Ptr,const Descriptor * D)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
moveRecord(Block * B,std::byte * Src,std::byte * Dst,const Descriptor * D)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
getCtorPrim(PrimType Type)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
getDtorPrim(PrimType Type)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
getMovePrim(PrimType Type)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
getCtorArrayPrim(PrimType Type)324 static BlockCtorFn getCtorArrayPrim(PrimType Type) {
325 TYPE_SWITCH(Type, return ctorArrayTy<T>);
326 llvm_unreachable("unknown Expr");
327 }
328
getDtorArrayPrim(PrimType Type)329 static BlockDtorFn getDtorArrayPrim(PrimType Type) {
330 TYPE_SWITCH(Type, return dtorArrayTy<T>);
331 llvm_unreachable("unknown Expr");
332 }
333
getMoveArrayPrim(PrimType Type)334 static BlockMoveFn getMoveArrayPrim(PrimType Type) {
335 TYPE_SWITCH(Type, return moveArrayTy<T>);
336 llvm_unreachable("unknown Expr");
337 }
338
339 /// Primitives.
Descriptor(const DeclTy & D,const Type * SourceTy,PrimType Type,MetadataSize MD,bool IsConst,bool IsTemporary,bool IsMutable,bool IsVolatile)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.
Descriptor(const DeclTy & D,PrimType Type,MetadataSize MD,size_t NumElems,bool IsConst,bool IsTemporary,bool IsMutable)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.
Descriptor(const DeclTy & D,PrimType Type,MetadataSize MD,bool IsTemporary,bool IsConst,UnknownSize)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.
Descriptor(const DeclTy & D,const Type * SourceTy,const Descriptor * Elem,MetadataSize MD,unsigned NumElems,bool IsConst,bool IsTemporary,bool IsMutable)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.
Descriptor(const DeclTy & D,const Descriptor * Elem,MetadataSize MD,bool IsTemporary,UnknownSize)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.
Descriptor(const DeclTy & D,const Record * R,MetadataSize MD,bool IsConst,bool IsTemporary,bool IsMutable,bool IsVolatile)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.
Descriptor(const DeclTy & D,MetadataSize MD)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
getType() const424 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
getElemQualType() const441 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
getDataType(const ASTContext & Ctx) const465 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
getLocation() const489 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
getLoc() const497 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
hasTrivialDtor() const505 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
isUnion() const520 bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
521
InitMap(unsigned N)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
initializeElement(unsigned I)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
isElementInitialized(unsigned I) const537 bool InitMap::isElementInitialized(unsigned I) const {
538 unsigned Bucket = I / PER_FIELD;
539 return data()[Bucket] & (T(1) << (I % PER_FIELD));
540 }
541