Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/Descriptor.cpp
Line
Count
Source (jump to first uncovered line)
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 "Floating.h"
12
#include "FunctionPointer.h"
13
#include "IntegralAP.h"
14
#include "Pointer.h"
15
#include "PrimType.h"
16
#include "Record.h"
17
18
using namespace clang;
19
using namespace clang::interp;
20
21
template <typename T>
22
static void ctorTy(Block *, std::byte *Ptr, bool, bool, bool,
23
0
                   const Descriptor *) {
24
0
  new (Ptr) T();
25
0
}
Unexecuted instantiation: Descriptor.cpp:void ctorTy<clang::interp::Floating>(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorTy<clang::interp::IntegralAP<false> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorTy<clang::interp::IntegralAP<true> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorTy<clang::interp::Pointer>(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
26
27
template <typename T>
28
0
static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
29
0
  reinterpret_cast<T *>(Ptr)->~T();
30
0
}
Unexecuted instantiation: Descriptor.cpp:void dtorTy<clang::interp::Floating>(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorTy<clang::interp::IntegralAP<false> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorTy<clang::interp::IntegralAP<true> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorTy<clang::interp::Pointer>(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
31
32
template <typename T>
33
static void moveTy(Block *, const std::byte *Src, std::byte *Dst,
34
0
                   const Descriptor *) {
35
0
  const auto *SrcPtr = reinterpret_cast<const T *>(Src);
36
0
  auto *DstPtr = reinterpret_cast<T *>(Dst);
37
0
  new (DstPtr) T(std::move(*SrcPtr));
38
0
}
39
40
template <typename T>
41
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool,
42
0
                        const Descriptor *D) {
43
0
  new (Ptr) InitMapPtr(std::nullopt);
44
45
0
  Ptr += sizeof(InitMapPtr);
46
0
  for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
47
0
    new (&reinterpret_cast<T *>(Ptr)[I]) T();
48
0
  }
49
0
}
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<8u, true> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<8u, false> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<16u, true> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<16u, false> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<32u, true> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<32u, false> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<64u, true> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Integral<64u, false> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::IntegralAP<false> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::IntegralAP<true> >(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Floating>(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Boolean>(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::Pointer>(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void ctorArrayTy<clang::interp::FunctionPointer>(clang::interp::Block*, std::byte*, bool, bool, bool, clang::interp::Descriptor const*)
50
51
template <typename T>
52
0
static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
53
0
  InitMapPtr &IMP = *reinterpret_cast<InitMapPtr *>(Ptr);
54
55
0
  if (IMP)
56
0
    IMP = std::nullopt;
57
0
  Ptr += sizeof(InitMapPtr);
58
0
  for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
59
0
    reinterpret_cast<T *>(Ptr)[I].~T();
60
0
  }
61
0
}
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<8u, true> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<8u, false> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<16u, true> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<16u, false> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<32u, true> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<32u, false> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<64u, true> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Integral<64u, false> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::IntegralAP<false> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::IntegralAP<true> >(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Floating>(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Boolean>(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::Pointer>(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void dtorArrayTy<clang::interp::FunctionPointer>(clang::interp::Block*, std::byte*, clang::interp::Descriptor const*)
62
63
template <typename T>
64
static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst,
65
0
                        const Descriptor *D) {
66
0
  for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
67
0
    const auto *SrcPtr = &reinterpret_cast<const T *>(Src)[I];
68
0
    auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
69
0
    new (DstPtr) T(std::move(*SrcPtr));
70
0
  }
71
0
}
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<8u, true> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<8u, false> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<16u, true> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<16u, false> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<32u, true> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<32u, false> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<64u, true> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Integral<64u, false> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::IntegralAP<false> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::IntegralAP<true> >(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Floating>(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Boolean>(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::Pointer>(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
Unexecuted instantiation: Descriptor.cpp:void moveArrayTy<clang::interp::FunctionPointer>(clang::interp::Block*, std::byte const*, std::byte*, clang::interp::Descriptor const*)
72
73
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
74
0
                          bool IsMutable, bool IsActive, const Descriptor *D) {
75
0
  const unsigned NumElems = D->getNumElems();
76
0
  const unsigned ElemSize =
77
0
      D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
78
79
0
  unsigned ElemOffset = 0;
80
0
  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
81
0
    auto *ElemPtr = Ptr + ElemOffset;
82
0
    auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
83
0
    auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
84
0
    auto *SD = D->ElemDesc;
85
86
0
    Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
87
0
    Desc->Desc = SD;
88
0
    Desc->IsInitialized = true;
89
0
    Desc->IsBase = false;
90
0
    Desc->IsActive = IsActive;
91
0
    Desc->IsConst = IsConst || D->IsConst;
92
0
    Desc->IsFieldMutable = IsMutable || D->IsMutable;
93
0
    if (auto Fn = D->ElemDesc->CtorFn)
94
0
      Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsActive,
95
0
         D->ElemDesc);
96
0
  }
97
0
}
98
99
0
static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
100
0
  const unsigned NumElems = D->getNumElems();
101
0
  const unsigned ElemSize =
102
0
      D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
103
104
0
  unsigned ElemOffset = 0;
105
0
  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
106
0
    auto *ElemPtr = Ptr + ElemOffset;
107
0
    auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
108
0
    auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
109
0
    if (auto Fn = D->ElemDesc->DtorFn)
110
0
      Fn(B, ElemLoc, D->ElemDesc);
111
0
  }
112
0
}
113
114
static void moveArrayDesc(Block *B, const std::byte *Src, std::byte *Dst,
115
0
                          const Descriptor *D) {
116
0
  const unsigned NumElems = D->getNumElems();
117
0
  const unsigned ElemSize =
118
0
      D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
119
120
0
  unsigned ElemOffset = 0;
121
0
  for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
122
0
    const auto *SrcPtr = Src + ElemOffset;
123
0
    auto *DstPtr = Dst + ElemOffset;
124
125
0
    const auto *SrcDesc = reinterpret_cast<const InlineDescriptor *>(SrcPtr);
126
0
    const auto *SrcElemLoc = reinterpret_cast<const std::byte *>(SrcDesc + 1);
127
0
    auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
128
0
    auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1);
129
130
0
    *DstDesc = *SrcDesc;
131
0
    if (auto Fn = D->ElemDesc->MoveFn)
132
0
      Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
133
0
  }
134
0
}
135
136
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
137
0
                       bool IsActive, const Descriptor *D) {
138
0
  const bool IsUnion = D->ElemRecord->isUnion();
139
0
  auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) {
140
0
    auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
141
0
    Desc->Offset = SubOff;
142
0
    Desc->Desc = F;
143
0
    Desc->IsInitialized = F->IsArray && !IsBase;
144
0
    Desc->IsBase = IsBase;
145
0
    Desc->IsActive = IsActive && !IsUnion;
146
0
    Desc->IsConst = IsConst || F->IsConst;
147
0
    Desc->IsFieldMutable = IsMutable || F->IsMutable;
148
0
    if (auto Fn = F->CtorFn)
149
0
      Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsFieldMutable, Desc->IsActive,
150
0
         F);
151
0
  };
152
0
  for (const auto &B : D->ElemRecord->bases())
153
0
    CtorSub(B.Offset, B.Desc, /*isBase=*/true);
154
0
  for (const auto &F : D->ElemRecord->fields())
155
0
    CtorSub(F.Offset, F.Desc, /*isBase=*/false);
156
0
  for (const auto &V : D->ElemRecord->virtual_bases())
157
0
    CtorSub(V.Offset, V.Desc, /*isBase=*/true);
158
0
}
159
160
0
static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
161
0
  auto DtorSub = [=](unsigned SubOff, Descriptor *F) {
162
0
    if (auto Fn = F->DtorFn)
163
0
      Fn(B, Ptr + SubOff, F);
164
0
  };
165
0
  for (const auto &F : D->ElemRecord->bases())
166
0
    DtorSub(F.Offset, F.Desc);
167
0
  for (const auto &F : D->ElemRecord->fields())
168
0
    DtorSub(F.Offset, F.Desc);
169
0
  for (const auto &F : D->ElemRecord->virtual_bases())
170
0
    DtorSub(F.Offset, F.Desc);
171
0
}
172
173
static void moveRecord(Block *B, const std::byte *Src, std::byte *Dst,
174
0
                       const Descriptor *D) {
175
0
  for (const auto &F : D->ElemRecord->fields()) {
176
0
    auto FieldOff = F.Offset;
177
0
    auto *FieldDesc = F.Desc;
178
179
0
    if (auto Fn = FieldDesc->MoveFn)
180
0
      Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);
181
0
  }
182
0
}
183
184
0
static BlockCtorFn getCtorPrim(PrimType Type) {
185
  // Floating types are special. They are primitives, but need their
186
  // constructor called.
187
0
  if (Type == PT_Float)
188
0
    return ctorTy<PrimConv<PT_Float>::T>;
189
0
  if (Type == PT_IntAP)
190
0
    return ctorTy<PrimConv<PT_IntAP>::T>;
191
0
  if (Type == PT_IntAPS)
192
0
    return ctorTy<PrimConv<PT_IntAPS>::T>;
193
194
0
  COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
195
0
}
196
197
0
static BlockDtorFn getDtorPrim(PrimType Type) {
198
  // Floating types are special. They are primitives, but need their
199
  // destructor called, since they might allocate memory.
200
0
  if (Type == PT_Float)
201
0
    return dtorTy<PrimConv<PT_Float>::T>;
202
0
  if (Type == PT_IntAP)
203
0
    return dtorTy<PrimConv<PT_IntAP>::T>;
204
0
  if (Type == PT_IntAPS)
205
0
    return dtorTy<PrimConv<PT_IntAPS>::T>;
206
207
0
  COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
208
0
}
209
210
0
static BlockMoveFn getMovePrim(PrimType Type) {
211
0
  COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
212
0
}
213
214
0
static BlockCtorFn getCtorArrayPrim(PrimType Type) {
215
0
  TYPE_SWITCH(Type, return ctorArrayTy<T>);
216
0
  llvm_unreachable("unknown Expr");
217
0
}
218
219
0
static BlockDtorFn getDtorArrayPrim(PrimType Type) {
220
0
  TYPE_SWITCH(Type, return dtorArrayTy<T>);
221
0
  llvm_unreachable("unknown Expr");
222
0
}
223
224
0
static BlockMoveFn getMoveArrayPrim(PrimType Type) {
225
0
  TYPE_SWITCH(Type, return moveArrayTy<T>);
226
0
  llvm_unreachable("unknown Expr");
227
0
}
228
229
/// Primitives.
230
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
231
                       bool IsConst, bool IsTemporary, bool IsMutable)
232
    : Source(D), ElemSize(primSize(Type)), Size(ElemSize),
233
      MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), IsConst(IsConst),
234
      IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(getCtorPrim(Type)),
235
0
      DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
236
0
  assert(AllocSize >= Size);
237
0
  assert(Source && "Missing source");
238
0
}
239
240
/// Primitive arrays.
241
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
242
                       size_t NumElems, bool IsConst, bool IsTemporary,
243
                       bool IsMutable)
244
    : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
245
      MDSize(MD.value_or(0)),
246
      AllocSize(align(Size) + sizeof(InitMapPtr) + MDSize), IsConst(IsConst),
247
      IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
248
      CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
249
0
      MoveFn(getMoveArrayPrim(Type)) {
250
0
  assert(Source && "Missing source");
251
0
}
252
253
/// Primitive unknown-size arrays.
254
Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
255
                       UnknownSize)
256
    : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(0),
257
      AllocSize(alignof(void *) + sizeof(InitMapPtr)), IsConst(true),
258
      IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
259
      CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
260
0
      MoveFn(getMoveArrayPrim(Type)) {
261
0
  assert(Source && "Missing source");
262
0
}
263
264
/// Arrays of composite elements.
265
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
266
                       unsigned NumElems, bool IsConst, bool IsTemporary,
267
                       bool IsMutable)
268
    : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
269
      Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
270
      AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
271
      ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
272
      IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
273
0
      DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
274
0
  assert(Source && "Missing source");
275
0
}
276
277
/// Unknown-size arrays of composite elements.
278
Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem,
279
                       bool IsTemporary, UnknownSize)
280
    : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
281
      Size(UnknownSizeMark), MDSize(0),
282
      AllocSize(alignof(void *) + sizeof(InitMapPtr)), ElemDesc(Elem),
283
      IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
284
0
      CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
285
0
  assert(Source && "Missing source");
286
0
}
287
288
/// Composite records.
289
Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
290
                       bool IsConst, bool IsTemporary, bool IsMutable)
291
    : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
292
      Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
293
      ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
294
      IsTemporary(IsTemporary), CtorFn(ctorRecord), DtorFn(dtorRecord),
295
0
      MoveFn(moveRecord) {
296
0
  assert(Source && "Missing source");
297
0
}
298
299
Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
300
    : Source(D), ElemSize(1), Size(ElemSize), MDSize(MD.value_or(0)),
301
      AllocSize(Size + MDSize), ElemRecord(nullptr), IsConst(true),
302
0
      IsMutable(false), IsTemporary(false), IsDummy(true) {
303
0
  assert(Source && "Missing source");
304
0
}
305
306
0
QualType Descriptor::getType() const {
307
0
  if (auto *E = asExpr())
308
0
    return E->getType();
309
0
  if (auto *D = asValueDecl())
310
0
    return D->getType();
311
0
  if (auto *T = dyn_cast<TypeDecl>(asDecl()))
312
0
    return QualType(T->getTypeForDecl(), 0);
313
0
  llvm_unreachable("Invalid descriptor type");
314
0
}
315
316
0
QualType Descriptor::getElemQualType() const {
317
0
  assert(isArray());
318
0
  const auto *AT = cast<ArrayType>(getType());
319
0
  return AT->getElementType();
320
0
}
321
322
0
SourceLocation Descriptor::getLocation() const {
323
0
  if (auto *D = Source.dyn_cast<const Decl *>())
324
0
    return D->getLocation();
325
0
  if (auto *E = Source.dyn_cast<const Expr *>())
326
0
    return E->getExprLoc();
327
0
  llvm_unreachable("Invalid descriptor type");
328
0
}
329
330
InitMap::InitMap(unsigned N)
331
0
    : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {
332
0
  std::fill_n(data(), numFields(N), 0);
333
0
}
334
335
0
bool InitMap::initializeElement(unsigned I) {
336
0
  unsigned Bucket = I / PER_FIELD;
337
0
  T Mask = T(1) << (I % PER_FIELD);
338
0
  if (!(data()[Bucket] & Mask)) {
339
0
    data()[Bucket] |= Mask;
340
0
    UninitFields -= 1;
341
0
  }
342
0
  return UninitFields == 0;
343
0
}
344
345
0
bool InitMap::isElementInitialized(unsigned I) const {
346
0
  unsigned Bucket = I / PER_FIELD;
347
0
  return data()[Bucket] & (T(1) << (I % PER_FIELD));
348
0
}