xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Program.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1a7dea167SDimitry Andric //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
9a7dea167SDimitry Andric #include "Program.h"
10a7dea167SDimitry Andric #include "ByteCodeStmtGen.h"
11a7dea167SDimitry Andric #include "Context.h"
12a7dea167SDimitry Andric #include "Function.h"
13a7dea167SDimitry Andric #include "Opcode.h"
14a7dea167SDimitry Andric #include "PrimType.h"
15a7dea167SDimitry Andric #include "clang/AST/Decl.h"
16a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h"
17a7dea167SDimitry Andric 
18a7dea167SDimitry Andric using namespace clang;
19a7dea167SDimitry Andric using namespace clang::interp;
20a7dea167SDimitry Andric 
21349cc55cSDimitry Andric unsigned Program::getOrCreateNativePointer(const void *Ptr) {
22349cc55cSDimitry Andric   auto It = NativePointerIndices.find(Ptr);
23349cc55cSDimitry Andric   if (It != NativePointerIndices.end())
24349cc55cSDimitry Andric     return It->second;
25349cc55cSDimitry Andric 
26349cc55cSDimitry Andric   unsigned Idx = NativePointers.size();
27349cc55cSDimitry Andric   NativePointers.push_back(Ptr);
28349cc55cSDimitry Andric   NativePointerIndices[Ptr] = Idx;
29349cc55cSDimitry Andric   return Idx;
30349cc55cSDimitry Andric }
31349cc55cSDimitry Andric 
32349cc55cSDimitry Andric const void *Program::getNativePointer(unsigned Idx) {
33349cc55cSDimitry Andric   return NativePointers[Idx];
34349cc55cSDimitry Andric }
35349cc55cSDimitry Andric 
36a7dea167SDimitry Andric unsigned Program::createGlobalString(const StringLiteral *S) {
37a7dea167SDimitry Andric   const size_t CharWidth = S->getCharByteWidth();
38a7dea167SDimitry Andric   const size_t BitWidth = CharWidth * Ctx.getCharBit();
39a7dea167SDimitry Andric 
40a7dea167SDimitry Andric   PrimType CharType;
41a7dea167SDimitry Andric   switch (CharWidth) {
42a7dea167SDimitry Andric   case 1:
43a7dea167SDimitry Andric     CharType = PT_Sint8;
44a7dea167SDimitry Andric     break;
45a7dea167SDimitry Andric   case 2:
46a7dea167SDimitry Andric     CharType = PT_Uint16;
47a7dea167SDimitry Andric     break;
48a7dea167SDimitry Andric   case 4:
49a7dea167SDimitry Andric     CharType = PT_Uint32;
50a7dea167SDimitry Andric     break;
51a7dea167SDimitry Andric   default:
52a7dea167SDimitry Andric     llvm_unreachable("unsupported character width");
53a7dea167SDimitry Andric   }
54a7dea167SDimitry Andric 
55a7dea167SDimitry Andric   // Create a descriptor for the string.
56*bdd1243dSDimitry Andric   Descriptor *Desc =
57*bdd1243dSDimitry Andric       allocateDescriptor(S, CharType, std::nullopt, S->getLength() + 1,
58a7dea167SDimitry Andric                          /*isConst=*/true,
59a7dea167SDimitry Andric                          /*isTemporary=*/false,
60a7dea167SDimitry Andric                          /*isMutable=*/false);
61a7dea167SDimitry Andric 
62a7dea167SDimitry Andric   // Allocate storage for the string.
63a7dea167SDimitry Andric   // The byte length does not include the null terminator.
64a7dea167SDimitry Andric   unsigned I = Globals.size();
65a7dea167SDimitry Andric   unsigned Sz = Desc->getAllocSize();
66a7dea167SDimitry Andric   auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
67a7dea167SDimitry Andric                                        /*isExtern=*/false);
68*bdd1243dSDimitry Andric   G->block()->invokeCtor();
69a7dea167SDimitry Andric   Globals.push_back(G);
70a7dea167SDimitry Andric 
71a7dea167SDimitry Andric   // Construct the string in storage.
72a7dea167SDimitry Andric   const Pointer Ptr(G->block());
73a7dea167SDimitry Andric   for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
74a7dea167SDimitry Andric     Pointer Field = Ptr.atIndex(I).narrow();
75a7dea167SDimitry Andric     const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
76a7dea167SDimitry Andric     switch (CharType) {
77a7dea167SDimitry Andric       case PT_Sint8: {
78a7dea167SDimitry Andric         using T = PrimConv<PT_Sint8>::T;
79a7dea167SDimitry Andric         Field.deref<T>() = T::from(CodePoint, BitWidth);
80a7dea167SDimitry Andric         break;
81a7dea167SDimitry Andric       }
82a7dea167SDimitry Andric       case PT_Uint16: {
83a7dea167SDimitry Andric         using T = PrimConv<PT_Uint16>::T;
84a7dea167SDimitry Andric         Field.deref<T>() = T::from(CodePoint, BitWidth);
85a7dea167SDimitry Andric         break;
86a7dea167SDimitry Andric       }
87a7dea167SDimitry Andric       case PT_Uint32: {
88a7dea167SDimitry Andric         using T = PrimConv<PT_Uint32>::T;
89a7dea167SDimitry Andric         Field.deref<T>() = T::from(CodePoint, BitWidth);
90a7dea167SDimitry Andric         break;
91a7dea167SDimitry Andric       }
92a7dea167SDimitry Andric       default:
93a7dea167SDimitry Andric         llvm_unreachable("unsupported character type");
94a7dea167SDimitry Andric     }
95a7dea167SDimitry Andric   }
96a7dea167SDimitry Andric   return I;
97a7dea167SDimitry Andric }
98a7dea167SDimitry Andric 
99a7dea167SDimitry Andric Pointer Program::getPtrGlobal(unsigned Idx) {
100a7dea167SDimitry Andric   assert(Idx < Globals.size());
101a7dea167SDimitry Andric   return Pointer(Globals[Idx]->block());
102a7dea167SDimitry Andric }
103a7dea167SDimitry Andric 
104*bdd1243dSDimitry Andric std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
105a7dea167SDimitry Andric   auto It = GlobalIndices.find(VD);
106a7dea167SDimitry Andric   if (It != GlobalIndices.end())
107a7dea167SDimitry Andric     return It->second;
108a7dea167SDimitry Andric 
109349cc55cSDimitry Andric   // Find any previous declarations which were already evaluated.
110*bdd1243dSDimitry Andric   std::optional<unsigned> Index;
111a7dea167SDimitry Andric   for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
112a7dea167SDimitry Andric     auto It = GlobalIndices.find(P);
113a7dea167SDimitry Andric     if (It != GlobalIndices.end()) {
114a7dea167SDimitry Andric       Index = It->second;
115a7dea167SDimitry Andric       break;
116a7dea167SDimitry Andric     }
117a7dea167SDimitry Andric   }
118a7dea167SDimitry Andric 
119a7dea167SDimitry Andric   // Map the decl to the existing index.
120a7dea167SDimitry Andric   if (Index) {
121a7dea167SDimitry Andric     GlobalIndices[VD] = *Index;
122a7dea167SDimitry Andric     return {};
123a7dea167SDimitry Andric   }
124a7dea167SDimitry Andric 
125a7dea167SDimitry Andric   return Index;
126a7dea167SDimitry Andric }
127a7dea167SDimitry Andric 
128*bdd1243dSDimitry Andric std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
129*bdd1243dSDimitry Andric                                                    const Expr *Init) {
130a7dea167SDimitry Andric   if (auto Idx = getGlobal(VD))
131a7dea167SDimitry Andric     return Idx;
132a7dea167SDimitry Andric 
133*bdd1243dSDimitry Andric   if (auto Idx = createGlobal(VD, Init)) {
134a7dea167SDimitry Andric     GlobalIndices[VD] = *Idx;
135a7dea167SDimitry Andric     return Idx;
136a7dea167SDimitry Andric   }
137a7dea167SDimitry Andric   return {};
138a7dea167SDimitry Andric }
139a7dea167SDimitry Andric 
140*bdd1243dSDimitry Andric std::optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
141a7dea167SDimitry Andric   auto &ASTCtx = Ctx.getASTContext();
142a7dea167SDimitry Andric 
143a7dea167SDimitry Andric   // Create a pointer to an incomplete array of the specified elements.
144a7dea167SDimitry Andric   QualType ElemTy = PD->getType()->castAs<PointerType>()->getPointeeType();
145a7dea167SDimitry Andric   QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0);
146a7dea167SDimitry Andric 
147a7dea167SDimitry Andric   // Dedup blocks since they are immutable and pointers cannot be compared.
148a7dea167SDimitry Andric   auto It = DummyParams.find(PD);
149a7dea167SDimitry Andric   if (It != DummyParams.end())
150a7dea167SDimitry Andric     return It->second;
151a7dea167SDimitry Andric 
152a7dea167SDimitry Andric   if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) {
153a7dea167SDimitry Andric     DummyParams[PD] = *Idx;
154a7dea167SDimitry Andric     return Idx;
155a7dea167SDimitry Andric   }
156a7dea167SDimitry Andric   return {};
157a7dea167SDimitry Andric }
158a7dea167SDimitry Andric 
159*bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
160*bdd1243dSDimitry Andric                                               const Expr *Init) {
161*bdd1243dSDimitry Andric   assert(!getGlobal(VD));
162a7dea167SDimitry Andric   bool IsStatic, IsExtern;
163a7dea167SDimitry Andric   if (auto *Var = dyn_cast<VarDecl>(VD)) {
164a7dea167SDimitry Andric     IsStatic = !Var->hasLocalStorage();
165a7dea167SDimitry Andric     IsExtern = !Var->getAnyInitializer();
166a7dea167SDimitry Andric   } else {
167a7dea167SDimitry Andric     IsStatic = false;
168a7dea167SDimitry Andric     IsExtern = true;
169a7dea167SDimitry Andric   }
170*bdd1243dSDimitry Andric   if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {
171a7dea167SDimitry Andric     for (const Decl *P = VD; P; P = P->getPreviousDecl())
172a7dea167SDimitry Andric       GlobalIndices[P] = *Idx;
173a7dea167SDimitry Andric     return *Idx;
174a7dea167SDimitry Andric   }
175a7dea167SDimitry Andric   return {};
176a7dea167SDimitry Andric }
177a7dea167SDimitry Andric 
178*bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const Expr *E) {
179a7dea167SDimitry Andric   return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
180a7dea167SDimitry Andric }
181a7dea167SDimitry Andric 
182*bdd1243dSDimitry Andric std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
183*bdd1243dSDimitry Andric                                               bool IsStatic, bool IsExtern,
184*bdd1243dSDimitry Andric                                               const Expr *Init) {
185a7dea167SDimitry Andric   // Create a descriptor for the global.
186a7dea167SDimitry Andric   Descriptor *Desc;
187a7dea167SDimitry Andric   const bool IsConst = Ty.isConstQualified();
188a7dea167SDimitry Andric   const bool IsTemporary = D.dyn_cast<const Expr *>();
189a7dea167SDimitry Andric   if (auto T = Ctx.classify(Ty)) {
190*bdd1243dSDimitry Andric     Desc = createDescriptor(D, *T, std::nullopt, IsConst, IsTemporary);
191a7dea167SDimitry Andric   } else {
192*bdd1243dSDimitry Andric     Desc = createDescriptor(D, Ty.getTypePtr(), std::nullopt, IsConst,
193*bdd1243dSDimitry Andric                             IsTemporary);
194a7dea167SDimitry Andric   }
195a7dea167SDimitry Andric   if (!Desc)
196a7dea167SDimitry Andric     return {};
197a7dea167SDimitry Andric 
198a7dea167SDimitry Andric   // Allocate a block for storage.
199a7dea167SDimitry Andric   unsigned I = Globals.size();
200a7dea167SDimitry Andric 
201a7dea167SDimitry Andric   auto *G = new (Allocator, Desc->getAllocSize())
202a7dea167SDimitry Andric       Global(getCurrentDecl(), Desc, IsStatic, IsExtern);
203a7dea167SDimitry Andric   G->block()->invokeCtor();
204a7dea167SDimitry Andric 
205a7dea167SDimitry Andric   Globals.push_back(G);
206a7dea167SDimitry Andric 
207a7dea167SDimitry Andric   return I;
208a7dea167SDimitry Andric }
209a7dea167SDimitry Andric 
210a7dea167SDimitry Andric Function *Program::getFunction(const FunctionDecl *F) {
211*bdd1243dSDimitry Andric   F = F->getCanonicalDecl();
212*bdd1243dSDimitry Andric   assert(F);
213a7dea167SDimitry Andric   auto It = Funcs.find(F);
214a7dea167SDimitry Andric   return It == Funcs.end() ? nullptr : It->second.get();
215a7dea167SDimitry Andric }
216a7dea167SDimitry Andric 
217a7dea167SDimitry Andric Record *Program::getOrCreateRecord(const RecordDecl *RD) {
218a7dea167SDimitry Andric   // Use the actual definition as a key.
219a7dea167SDimitry Andric   RD = RD->getDefinition();
220a7dea167SDimitry Andric   if (!RD)
221a7dea167SDimitry Andric     return nullptr;
222a7dea167SDimitry Andric 
223a7dea167SDimitry Andric   // Deduplicate records.
224a7dea167SDimitry Andric   auto It = Records.find(RD);
225a7dea167SDimitry Andric   if (It != Records.end()) {
226a7dea167SDimitry Andric     return It->second;
227a7dea167SDimitry Andric   }
228a7dea167SDimitry Andric 
229*bdd1243dSDimitry Andric   // We insert nullptr now and replace that later, so recursive calls
230*bdd1243dSDimitry Andric   // to this function with the same RecordDecl don't run into
231*bdd1243dSDimitry Andric   // infinite recursion.
232*bdd1243dSDimitry Andric   Records.insert({RD, nullptr});
233*bdd1243dSDimitry Andric 
234a7dea167SDimitry Andric   // Number of bytes required by fields and base classes.
235*bdd1243dSDimitry Andric   unsigned BaseSize = 0;
236a7dea167SDimitry Andric   // Number of bytes required by virtual base.
237a7dea167SDimitry Andric   unsigned VirtSize = 0;
238a7dea167SDimitry Andric 
239a7dea167SDimitry Andric   // Helper to get a base descriptor.
240a7dea167SDimitry Andric   auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
241a7dea167SDimitry Andric     if (!BR)
242a7dea167SDimitry Andric       return nullptr;
243*bdd1243dSDimitry Andric     return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
244a7dea167SDimitry Andric                               /*isTemporary=*/false,
245a7dea167SDimitry Andric                               /*isMutable=*/false);
246a7dea167SDimitry Andric   };
247a7dea167SDimitry Andric 
248a7dea167SDimitry Andric   // Reserve space for base classes.
249a7dea167SDimitry Andric   Record::BaseList Bases;
250a7dea167SDimitry Andric   Record::VirtualBaseList VirtBases;
251a7dea167SDimitry Andric   if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
252a7dea167SDimitry Andric     for (const CXXBaseSpecifier &Spec : CD->bases()) {
253a7dea167SDimitry Andric       if (Spec.isVirtual())
254a7dea167SDimitry Andric         continue;
255a7dea167SDimitry Andric 
256a7dea167SDimitry Andric       const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
257a7dea167SDimitry Andric       Record *BR = getOrCreateRecord(BD);
258a7dea167SDimitry Andric       if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
259*bdd1243dSDimitry Andric         BaseSize += align(sizeof(InlineDescriptor));
260*bdd1243dSDimitry Andric         Bases.push_back({BD, BaseSize, Desc, BR});
261*bdd1243dSDimitry Andric         BaseSize += align(BR->getSize());
262a7dea167SDimitry Andric         continue;
263a7dea167SDimitry Andric       }
264a7dea167SDimitry Andric       return nullptr;
265a7dea167SDimitry Andric     }
266a7dea167SDimitry Andric 
267a7dea167SDimitry Andric     for (const CXXBaseSpecifier &Spec : CD->vbases()) {
268a7dea167SDimitry Andric       const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
269a7dea167SDimitry Andric       Record *BR = getOrCreateRecord(BD);
270a7dea167SDimitry Andric 
271a7dea167SDimitry Andric       if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
272a7dea167SDimitry Andric         VirtSize += align(sizeof(InlineDescriptor));
273a7dea167SDimitry Andric         VirtBases.push_back({BD, VirtSize, Desc, BR});
274a7dea167SDimitry Andric         VirtSize += align(BR->getSize());
275a7dea167SDimitry Andric         continue;
276a7dea167SDimitry Andric       }
277a7dea167SDimitry Andric       return nullptr;
278a7dea167SDimitry Andric     }
279a7dea167SDimitry Andric   }
280a7dea167SDimitry Andric 
281a7dea167SDimitry Andric   // Reserve space for fields.
282a7dea167SDimitry Andric   Record::FieldList Fields;
283a7dea167SDimitry Andric   for (const FieldDecl *FD : RD->fields()) {
284a7dea167SDimitry Andric     // Reserve space for the field's descriptor and the offset.
285*bdd1243dSDimitry Andric     BaseSize += align(sizeof(InlineDescriptor));
286a7dea167SDimitry Andric 
287a7dea167SDimitry Andric     // Classify the field and add its metadata.
288a7dea167SDimitry Andric     QualType FT = FD->getType();
289a7dea167SDimitry Andric     const bool IsConst = FT.isConstQualified();
290a7dea167SDimitry Andric     const bool IsMutable = FD->isMutable();
291a7dea167SDimitry Andric     Descriptor *Desc;
292*bdd1243dSDimitry Andric     if (std::optional<PrimType> T = Ctx.classify(FT)) {
293*bdd1243dSDimitry Andric       Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
294*bdd1243dSDimitry Andric                               /*isTemporary=*/false, IsMutable);
295a7dea167SDimitry Andric     } else {
296*bdd1243dSDimitry Andric       Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
297a7dea167SDimitry Andric                               /*isTemporary=*/false, IsMutable);
298a7dea167SDimitry Andric     }
299a7dea167SDimitry Andric     if (!Desc)
300a7dea167SDimitry Andric       return nullptr;
301*bdd1243dSDimitry Andric     Fields.push_back({FD, BaseSize, Desc});
302*bdd1243dSDimitry Andric     BaseSize += align(Desc->getAllocSize());
303a7dea167SDimitry Andric   }
304a7dea167SDimitry Andric 
305a7dea167SDimitry Andric   Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
306*bdd1243dSDimitry Andric                                      std::move(VirtBases), VirtSize, BaseSize);
307*bdd1243dSDimitry Andric   Records[RD] = R;
308a7dea167SDimitry Andric   return R;
309a7dea167SDimitry Andric }
310a7dea167SDimitry Andric 
311a7dea167SDimitry Andric Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
312*bdd1243dSDimitry Andric                                       Descriptor::MetadataSize MDSize,
313a7dea167SDimitry Andric                                       bool IsConst, bool IsTemporary,
314*bdd1243dSDimitry Andric                                       bool IsMutable, const Expr *Init) {
315a7dea167SDimitry Andric   // Classes and structures.
316a7dea167SDimitry Andric   if (auto *RT = Ty->getAs<RecordType>()) {
317a7dea167SDimitry Andric     if (auto *Record = getOrCreateRecord(RT->getDecl()))
318*bdd1243dSDimitry Andric       return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
319*bdd1243dSDimitry Andric                                 IsMutable);
320a7dea167SDimitry Andric   }
321a7dea167SDimitry Andric 
322a7dea167SDimitry Andric   // Arrays.
323a7dea167SDimitry Andric   if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
324a7dea167SDimitry Andric     QualType ElemTy = ArrayType->getElementType();
325a7dea167SDimitry Andric     // Array of well-known bounds.
326a7dea167SDimitry Andric     if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
327a7dea167SDimitry Andric       size_t NumElems = CAT->getSize().getZExtValue();
328*bdd1243dSDimitry Andric       if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
329a7dea167SDimitry Andric         // Arrays of primitives.
330a7dea167SDimitry Andric         unsigned ElemSize = primSize(*T);
331a7dea167SDimitry Andric         if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
332a7dea167SDimitry Andric           return {};
333a7dea167SDimitry Andric         }
334*bdd1243dSDimitry Andric         return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary,
335a7dea167SDimitry Andric                                   IsMutable);
336a7dea167SDimitry Andric       } else {
337a7dea167SDimitry Andric         // Arrays of composites. In this case, the array is a list of pointers,
338a7dea167SDimitry Andric         // followed by the actual elements.
339*bdd1243dSDimitry Andric         Descriptor *ElemDesc = createDescriptor(
340*bdd1243dSDimitry Andric             D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
341*bdd1243dSDimitry Andric         if (!ElemDesc)
342a7dea167SDimitry Andric           return nullptr;
343*bdd1243dSDimitry Andric         InterpSize ElemSize =
344*bdd1243dSDimitry Andric             ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
345a7dea167SDimitry Andric         if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
346a7dea167SDimitry Andric           return {};
347*bdd1243dSDimitry Andric         return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst,
348*bdd1243dSDimitry Andric                                   IsTemporary, IsMutable);
349a7dea167SDimitry Andric       }
350a7dea167SDimitry Andric     }
351a7dea167SDimitry Andric 
352a7dea167SDimitry Andric     // Array of unknown bounds - cannot be accessed and pointer arithmetic
353a7dea167SDimitry Andric     // is forbidden on pointers to such objects.
354a7dea167SDimitry Andric     if (isa<IncompleteArrayType>(ArrayType)) {
355*bdd1243dSDimitry Andric       if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
356a7dea167SDimitry Andric         return allocateDescriptor(D, *T, IsTemporary,
357a7dea167SDimitry Andric                                   Descriptor::UnknownSize{});
358a7dea167SDimitry Andric       } else {
359*bdd1243dSDimitry Andric         Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize,
360*bdd1243dSDimitry Andric                                             IsConst, IsTemporary);
361a7dea167SDimitry Andric         if (!Desc)
362a7dea167SDimitry Andric           return nullptr;
363a7dea167SDimitry Andric         return allocateDescriptor(D, Desc, IsTemporary,
364a7dea167SDimitry Andric                                   Descriptor::UnknownSize{});
365a7dea167SDimitry Andric       }
366a7dea167SDimitry Andric     }
367a7dea167SDimitry Andric   }
368a7dea167SDimitry Andric 
369a7dea167SDimitry Andric   // Atomic types.
370a7dea167SDimitry Andric   if (auto *AT = Ty->getAs<AtomicType>()) {
371a7dea167SDimitry Andric     const Type *InnerTy = AT->getValueType().getTypePtr();
372*bdd1243dSDimitry Andric     return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
373*bdd1243dSDimitry Andric                             IsMutable);
374a7dea167SDimitry Andric   }
375a7dea167SDimitry Andric 
376a7dea167SDimitry Andric   // Complex types - represented as arrays of elements.
377a7dea167SDimitry Andric   if (auto *CT = Ty->getAs<ComplexType>()) {
378a7dea167SDimitry Andric     PrimType ElemTy = *Ctx.classify(CT->getElementType());
379*bdd1243dSDimitry Andric     return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
380*bdd1243dSDimitry Andric                               IsMutable);
381a7dea167SDimitry Andric   }
382a7dea167SDimitry Andric 
383a7dea167SDimitry Andric   return nullptr;
384a7dea167SDimitry Andric }
385