1950b70dcSNandor Licker //===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
2950b70dcSNandor Licker //
3950b70dcSNandor Licker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4950b70dcSNandor Licker // See https://llvm.org/LICENSE.txt for license information.
5950b70dcSNandor Licker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6950b70dcSNandor Licker //
7950b70dcSNandor Licker //===----------------------------------------------------------------------===//
8950b70dcSNandor Licker
9950b70dcSNandor Licker #include "Program.h"
10950b70dcSNandor Licker #include "ByteCodeStmtGen.h"
11950b70dcSNandor Licker #include "Context.h"
12950b70dcSNandor Licker #include "Function.h"
13950b70dcSNandor Licker #include "Opcode.h"
14950b70dcSNandor Licker #include "PrimType.h"
15950b70dcSNandor Licker #include "clang/AST/Decl.h"
16950b70dcSNandor Licker #include "clang/AST/DeclCXX.h"
17950b70dcSNandor Licker
18950b70dcSNandor Licker using namespace clang;
19950b70dcSNandor Licker using namespace clang::interp;
20950b70dcSNandor Licker
getOrCreateNativePointer(const void * Ptr)2140080e7eSJessica Clarke unsigned Program::getOrCreateNativePointer(const void *Ptr) {
2240080e7eSJessica Clarke auto It = NativePointerIndices.find(Ptr);
2340080e7eSJessica Clarke if (It != NativePointerIndices.end())
2440080e7eSJessica Clarke return It->second;
2540080e7eSJessica Clarke
2640080e7eSJessica Clarke unsigned Idx = NativePointers.size();
2740080e7eSJessica Clarke NativePointers.push_back(Ptr);
2840080e7eSJessica Clarke NativePointerIndices[Ptr] = Idx;
2940080e7eSJessica Clarke return Idx;
3040080e7eSJessica Clarke }
3140080e7eSJessica Clarke
getNativePointer(unsigned Idx)3240080e7eSJessica Clarke const void *Program::getNativePointer(unsigned Idx) {
3340080e7eSJessica Clarke return NativePointers[Idx];
3440080e7eSJessica Clarke }
3540080e7eSJessica Clarke
createGlobalString(const StringLiteral * S)36950b70dcSNandor Licker unsigned Program::createGlobalString(const StringLiteral *S) {
37950b70dcSNandor Licker const size_t CharWidth = S->getCharByteWidth();
38950b70dcSNandor Licker const size_t BitWidth = CharWidth * Ctx.getCharBit();
39950b70dcSNandor Licker
40950b70dcSNandor Licker PrimType CharType;
41950b70dcSNandor Licker switch (CharWidth) {
42950b70dcSNandor Licker case 1:
43950b70dcSNandor Licker CharType = PT_Sint8;
44950b70dcSNandor Licker break;
45950b70dcSNandor Licker case 2:
46950b70dcSNandor Licker CharType = PT_Uint16;
47950b70dcSNandor Licker break;
48950b70dcSNandor Licker case 4:
49950b70dcSNandor Licker CharType = PT_Uint32;
50950b70dcSNandor Licker break;
51950b70dcSNandor Licker default:
52950b70dcSNandor Licker llvm_unreachable("unsupported character width");
53950b70dcSNandor Licker }
54950b70dcSNandor Licker
55950b70dcSNandor Licker // Create a descriptor for the string.
56950b70dcSNandor Licker Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1,
57950b70dcSNandor Licker /*isConst=*/true,
58950b70dcSNandor Licker /*isTemporary=*/false,
59950b70dcSNandor Licker /*isMutable=*/false);
60950b70dcSNandor Licker
61950b70dcSNandor Licker // Allocate storage for the string.
62950b70dcSNandor Licker // The byte length does not include the null terminator.
63950b70dcSNandor Licker unsigned I = Globals.size();
64950b70dcSNandor Licker unsigned Sz = Desc->getAllocSize();
65950b70dcSNandor Licker auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
66950b70dcSNandor Licker /*isExtern=*/false);
67950b70dcSNandor Licker Globals.push_back(G);
68950b70dcSNandor Licker
69950b70dcSNandor Licker // Construct the string in storage.
70950b70dcSNandor Licker const Pointer Ptr(G->block());
71950b70dcSNandor Licker for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
72950b70dcSNandor Licker Pointer Field = Ptr.atIndex(I).narrow();
73950b70dcSNandor Licker const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
74950b70dcSNandor Licker switch (CharType) {
75950b70dcSNandor Licker case PT_Sint8: {
76950b70dcSNandor Licker using T = PrimConv<PT_Sint8>::T;
77950b70dcSNandor Licker Field.deref<T>() = T::from(CodePoint, BitWidth);
78950b70dcSNandor Licker break;
79950b70dcSNandor Licker }
80950b70dcSNandor Licker case PT_Uint16: {
81950b70dcSNandor Licker using T = PrimConv<PT_Uint16>::T;
82950b70dcSNandor Licker Field.deref<T>() = T::from(CodePoint, BitWidth);
83950b70dcSNandor Licker break;
84950b70dcSNandor Licker }
85950b70dcSNandor Licker case PT_Uint32: {
86950b70dcSNandor Licker using T = PrimConv<PT_Uint32>::T;
87950b70dcSNandor Licker Field.deref<T>() = T::from(CodePoint, BitWidth);
88950b70dcSNandor Licker break;
89950b70dcSNandor Licker }
90950b70dcSNandor Licker default:
91950b70dcSNandor Licker llvm_unreachable("unsupported character type");
92950b70dcSNandor Licker }
93950b70dcSNandor Licker }
94950b70dcSNandor Licker return I;
95950b70dcSNandor Licker }
96950b70dcSNandor Licker
getPtrGlobal(unsigned Idx)97950b70dcSNandor Licker Pointer Program::getPtrGlobal(unsigned Idx) {
98950b70dcSNandor Licker assert(Idx < Globals.size());
99950b70dcSNandor Licker return Pointer(Globals[Idx]->block());
100950b70dcSNandor Licker }
101950b70dcSNandor Licker
getGlobal(const ValueDecl * VD)102950b70dcSNandor Licker llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
103950b70dcSNandor Licker auto It = GlobalIndices.find(VD);
104950b70dcSNandor Licker if (It != GlobalIndices.end())
105950b70dcSNandor Licker return It->second;
106950b70dcSNandor Licker
107*60ab6861SNico Weber // Find any previous declarations which were already evaluated.
108950b70dcSNandor Licker llvm::Optional<unsigned> Index;
109950b70dcSNandor Licker for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
110950b70dcSNandor Licker auto It = GlobalIndices.find(P);
111950b70dcSNandor Licker if (It != GlobalIndices.end()) {
112950b70dcSNandor Licker Index = It->second;
113950b70dcSNandor Licker break;
114950b70dcSNandor Licker }
115950b70dcSNandor Licker }
116950b70dcSNandor Licker
117950b70dcSNandor Licker // Map the decl to the existing index.
118950b70dcSNandor Licker if (Index) {
119950b70dcSNandor Licker GlobalIndices[VD] = *Index;
120950b70dcSNandor Licker return {};
121950b70dcSNandor Licker }
122950b70dcSNandor Licker
123950b70dcSNandor Licker return Index;
124950b70dcSNandor Licker }
125950b70dcSNandor Licker
getOrCreateGlobal(const ValueDecl * VD)126950b70dcSNandor Licker llvm::Optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD) {
127950b70dcSNandor Licker if (auto Idx = getGlobal(VD))
128950b70dcSNandor Licker return Idx;
129950b70dcSNandor Licker
130950b70dcSNandor Licker if (auto Idx = createGlobal(VD)) {
131950b70dcSNandor Licker GlobalIndices[VD] = *Idx;
132950b70dcSNandor Licker return Idx;
133950b70dcSNandor Licker }
134950b70dcSNandor Licker return {};
135950b70dcSNandor Licker }
136950b70dcSNandor Licker
getOrCreateDummy(const ParmVarDecl * PD)137950b70dcSNandor Licker llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
138950b70dcSNandor Licker auto &ASTCtx = Ctx.getASTContext();
139950b70dcSNandor Licker
140950b70dcSNandor Licker // Create a pointer to an incomplete array of the specified elements.
1413459a4c7SSimon Pilgrim QualType ElemTy = PD->getType()->castAs<PointerType>()->getPointeeType();
142950b70dcSNandor Licker QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0);
143950b70dcSNandor Licker
144950b70dcSNandor Licker // Dedup blocks since they are immutable and pointers cannot be compared.
145950b70dcSNandor Licker auto It = DummyParams.find(PD);
146950b70dcSNandor Licker if (It != DummyParams.end())
147950b70dcSNandor Licker return It->second;
148950b70dcSNandor Licker
149950b70dcSNandor Licker if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) {
150950b70dcSNandor Licker DummyParams[PD] = *Idx;
151950b70dcSNandor Licker return Idx;
152950b70dcSNandor Licker }
153950b70dcSNandor Licker return {};
154950b70dcSNandor Licker }
155950b70dcSNandor Licker
createGlobal(const ValueDecl * VD)156950b70dcSNandor Licker llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
157950b70dcSNandor Licker bool IsStatic, IsExtern;
158950b70dcSNandor Licker if (auto *Var = dyn_cast<VarDecl>(VD)) {
159950b70dcSNandor Licker IsStatic = !Var->hasLocalStorage();
160950b70dcSNandor Licker IsExtern = !Var->getAnyInitializer();
161950b70dcSNandor Licker } else {
162950b70dcSNandor Licker IsStatic = false;
163950b70dcSNandor Licker IsExtern = true;
164950b70dcSNandor Licker }
165950b70dcSNandor Licker if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
166950b70dcSNandor Licker for (const Decl *P = VD; P; P = P->getPreviousDecl())
167950b70dcSNandor Licker GlobalIndices[P] = *Idx;
168950b70dcSNandor Licker return *Idx;
169950b70dcSNandor Licker }
170950b70dcSNandor Licker return {};
171950b70dcSNandor Licker }
172950b70dcSNandor Licker
createGlobal(const Expr * E)173950b70dcSNandor Licker llvm::Optional<unsigned> Program::createGlobal(const Expr *E) {
174950b70dcSNandor Licker return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
175950b70dcSNandor Licker }
176950b70dcSNandor Licker
createGlobal(const DeclTy & D,QualType Ty,bool IsStatic,bool IsExtern)177950b70dcSNandor Licker llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
178950b70dcSNandor Licker bool IsStatic, bool IsExtern) {
179950b70dcSNandor Licker // Create a descriptor for the global.
180950b70dcSNandor Licker Descriptor *Desc;
181950b70dcSNandor Licker const bool IsConst = Ty.isConstQualified();
182950b70dcSNandor Licker const bool IsTemporary = D.dyn_cast<const Expr *>();
183950b70dcSNandor Licker if (auto T = Ctx.classify(Ty)) {
184950b70dcSNandor Licker Desc = createDescriptor(D, *T, IsConst, IsTemporary);
185950b70dcSNandor Licker } else {
186950b70dcSNandor Licker Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary);
187950b70dcSNandor Licker }
188950b70dcSNandor Licker if (!Desc)
189950b70dcSNandor Licker return {};
190950b70dcSNandor Licker
191950b70dcSNandor Licker // Allocate a block for storage.
192950b70dcSNandor Licker unsigned I = Globals.size();
193950b70dcSNandor Licker
194950b70dcSNandor Licker auto *G = new (Allocator, Desc->getAllocSize())
195950b70dcSNandor Licker Global(getCurrentDecl(), Desc, IsStatic, IsExtern);
196950b70dcSNandor Licker G->block()->invokeCtor();
197950b70dcSNandor Licker
198950b70dcSNandor Licker Globals.push_back(G);
199950b70dcSNandor Licker
200950b70dcSNandor Licker return I;
201950b70dcSNandor Licker }
202950b70dcSNandor Licker
getFunction(const FunctionDecl * F)203950b70dcSNandor Licker Function *Program::getFunction(const FunctionDecl *F) {
204950b70dcSNandor Licker F = F->getDefinition();
205950b70dcSNandor Licker auto It = Funcs.find(F);
206950b70dcSNandor Licker return It == Funcs.end() ? nullptr : It->second.get();
207950b70dcSNandor Licker }
208950b70dcSNandor Licker
getOrCreateFunction(const FunctionDecl * F)209950b70dcSNandor Licker llvm::Expected<Function *> Program::getOrCreateFunction(const FunctionDecl *F) {
210950b70dcSNandor Licker if (Function *Func = getFunction(F)) {
211950b70dcSNandor Licker return Func;
212950b70dcSNandor Licker }
213950b70dcSNandor Licker
214950b70dcSNandor Licker // Try to compile the function if it wasn't compiled yet.
215950b70dcSNandor Licker if (const FunctionDecl *FD = F->getDefinition())
216950b70dcSNandor Licker return ByteCodeStmtGen<ByteCodeEmitter>(Ctx, *this).compileFunc(FD);
217950b70dcSNandor Licker
218950b70dcSNandor Licker // A relocation which traps if not resolved.
219950b70dcSNandor Licker return nullptr;
220950b70dcSNandor Licker }
221950b70dcSNandor Licker
getOrCreateRecord(const RecordDecl * RD)222950b70dcSNandor Licker Record *Program::getOrCreateRecord(const RecordDecl *RD) {
223950b70dcSNandor Licker // Use the actual definition as a key.
224950b70dcSNandor Licker RD = RD->getDefinition();
225950b70dcSNandor Licker if (!RD)
226950b70dcSNandor Licker return nullptr;
227950b70dcSNandor Licker
228950b70dcSNandor Licker // Deduplicate records.
229950b70dcSNandor Licker auto It = Records.find(RD);
230950b70dcSNandor Licker if (It != Records.end()) {
231950b70dcSNandor Licker return It->second;
232950b70dcSNandor Licker }
233950b70dcSNandor Licker
234950b70dcSNandor Licker // Number of bytes required by fields and base classes.
235950b70dcSNandor Licker unsigned Size = 0;
236950b70dcSNandor Licker // Number of bytes required by virtual base.
237950b70dcSNandor Licker unsigned VirtSize = 0;
238950b70dcSNandor Licker
239950b70dcSNandor Licker // Helper to get a base descriptor.
240950b70dcSNandor Licker auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
241950b70dcSNandor Licker if (!BR)
242950b70dcSNandor Licker return nullptr;
243950b70dcSNandor Licker return allocateDescriptor(BD, BR, /*isConst=*/false,
244950b70dcSNandor Licker /*isTemporary=*/false,
245950b70dcSNandor Licker /*isMutable=*/false);
246950b70dcSNandor Licker };
247950b70dcSNandor Licker
248950b70dcSNandor Licker // Reserve space for base classes.
249950b70dcSNandor Licker Record::BaseList Bases;
250950b70dcSNandor Licker Record::VirtualBaseList VirtBases;
251950b70dcSNandor Licker if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
252950b70dcSNandor Licker for (const CXXBaseSpecifier &Spec : CD->bases()) {
253950b70dcSNandor Licker if (Spec.isVirtual())
254950b70dcSNandor Licker continue;
255950b70dcSNandor Licker
2561cd399c9SSimon Pilgrim const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
257950b70dcSNandor Licker Record *BR = getOrCreateRecord(BD);
258950b70dcSNandor Licker if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
259950b70dcSNandor Licker Size += align(sizeof(InlineDescriptor));
260950b70dcSNandor Licker Bases.push_back({BD, Size, Desc, BR});
261950b70dcSNandor Licker Size += align(BR->getSize());
262950b70dcSNandor Licker continue;
263950b70dcSNandor Licker }
264950b70dcSNandor Licker return nullptr;
265950b70dcSNandor Licker }
266950b70dcSNandor Licker
267950b70dcSNandor Licker for (const CXXBaseSpecifier &Spec : CD->vbases()) {
2681cd399c9SSimon Pilgrim const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
269950b70dcSNandor Licker Record *BR = getOrCreateRecord(BD);
270950b70dcSNandor Licker
271950b70dcSNandor Licker if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
272950b70dcSNandor Licker VirtSize += align(sizeof(InlineDescriptor));
273950b70dcSNandor Licker VirtBases.push_back({BD, VirtSize, Desc, BR});
274950b70dcSNandor Licker VirtSize += align(BR->getSize());
275950b70dcSNandor Licker continue;
276950b70dcSNandor Licker }
277950b70dcSNandor Licker return nullptr;
278950b70dcSNandor Licker }
279950b70dcSNandor Licker }
280950b70dcSNandor Licker
281950b70dcSNandor Licker // Reserve space for fields.
282950b70dcSNandor Licker Record::FieldList Fields;
283950b70dcSNandor Licker for (const FieldDecl *FD : RD->fields()) {
284950b70dcSNandor Licker // Reserve space for the field's descriptor and the offset.
285950b70dcSNandor Licker Size += align(sizeof(InlineDescriptor));
286950b70dcSNandor Licker
287950b70dcSNandor Licker // Classify the field and add its metadata.
288950b70dcSNandor Licker QualType FT = FD->getType();
289950b70dcSNandor Licker const bool IsConst = FT.isConstQualified();
290950b70dcSNandor Licker const bool IsMutable = FD->isMutable();
291950b70dcSNandor Licker Descriptor *Desc;
292950b70dcSNandor Licker if (llvm::Optional<PrimType> T = Ctx.classify(FT)) {
293950b70dcSNandor Licker Desc = createDescriptor(FD, *T, IsConst, /*isTemporary=*/false,
294950b70dcSNandor Licker IsMutable);
295950b70dcSNandor Licker } else {
296950b70dcSNandor Licker Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
297950b70dcSNandor Licker /*isTemporary=*/false, IsMutable);
298950b70dcSNandor Licker }
299950b70dcSNandor Licker if (!Desc)
300950b70dcSNandor Licker return nullptr;
301950b70dcSNandor Licker Fields.push_back({FD, Size, Desc});
302950b70dcSNandor Licker Size += align(Desc->getAllocSize());
303950b70dcSNandor Licker }
304950b70dcSNandor Licker
305950b70dcSNandor Licker Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
306950b70dcSNandor Licker std::move(VirtBases), VirtSize, Size);
307950b70dcSNandor Licker Records.insert({RD, R});
308950b70dcSNandor Licker return R;
309950b70dcSNandor Licker }
310950b70dcSNandor Licker
createDescriptor(const DeclTy & D,const Type * Ty,bool IsConst,bool IsTemporary,bool IsMutable)311950b70dcSNandor Licker Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
312950b70dcSNandor Licker bool IsConst, bool IsTemporary,
313950b70dcSNandor Licker bool IsMutable) {
314950b70dcSNandor Licker // Classes and structures.
315950b70dcSNandor Licker if (auto *RT = Ty->getAs<RecordType>()) {
316950b70dcSNandor Licker if (auto *Record = getOrCreateRecord(RT->getDecl()))
317950b70dcSNandor Licker return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable);
318950b70dcSNandor Licker }
319950b70dcSNandor Licker
320950b70dcSNandor Licker // Arrays.
321950b70dcSNandor Licker if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
322950b70dcSNandor Licker QualType ElemTy = ArrayType->getElementType();
323950b70dcSNandor Licker // Array of well-known bounds.
324950b70dcSNandor Licker if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
325950b70dcSNandor Licker size_t NumElems = CAT->getSize().getZExtValue();
326950b70dcSNandor Licker if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
327950b70dcSNandor Licker // Arrays of primitives.
328950b70dcSNandor Licker unsigned ElemSize = primSize(*T);
329950b70dcSNandor Licker if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
330950b70dcSNandor Licker return {};
331950b70dcSNandor Licker }
332950b70dcSNandor Licker return allocateDescriptor(D, *T, NumElems, IsConst, IsTemporary,
333950b70dcSNandor Licker IsMutable);
334950b70dcSNandor Licker } else {
335950b70dcSNandor Licker // Arrays of composites. In this case, the array is a list of pointers,
336950b70dcSNandor Licker // followed by the actual elements.
337950b70dcSNandor Licker Descriptor *Desc =
338950b70dcSNandor Licker createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
339950b70dcSNandor Licker if (!Desc)
340950b70dcSNandor Licker return nullptr;
341950b70dcSNandor Licker InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
342950b70dcSNandor Licker if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
343950b70dcSNandor Licker return {};
344950b70dcSNandor Licker return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
345950b70dcSNandor Licker IsMutable);
346950b70dcSNandor Licker }
347950b70dcSNandor Licker }
348950b70dcSNandor Licker
349950b70dcSNandor Licker // Array of unknown bounds - cannot be accessed and pointer arithmetic
350950b70dcSNandor Licker // is forbidden on pointers to such objects.
351950b70dcSNandor Licker if (isa<IncompleteArrayType>(ArrayType)) {
352950b70dcSNandor Licker if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
353950b70dcSNandor Licker return allocateDescriptor(D, *T, IsTemporary,
354950b70dcSNandor Licker Descriptor::UnknownSize{});
355950b70dcSNandor Licker } else {
356950b70dcSNandor Licker Descriptor *Desc =
357950b70dcSNandor Licker createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
358950b70dcSNandor Licker if (!Desc)
359950b70dcSNandor Licker return nullptr;
360950b70dcSNandor Licker return allocateDescriptor(D, Desc, IsTemporary,
361950b70dcSNandor Licker Descriptor::UnknownSize{});
362950b70dcSNandor Licker }
363950b70dcSNandor Licker }
364950b70dcSNandor Licker }
365950b70dcSNandor Licker
366950b70dcSNandor Licker // Atomic types.
367950b70dcSNandor Licker if (auto *AT = Ty->getAs<AtomicType>()) {
368950b70dcSNandor Licker const Type *InnerTy = AT->getValueType().getTypePtr();
369950b70dcSNandor Licker return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
370950b70dcSNandor Licker }
371950b70dcSNandor Licker
372950b70dcSNandor Licker // Complex types - represented as arrays of elements.
373950b70dcSNandor Licker if (auto *CT = Ty->getAs<ComplexType>()) {
374950b70dcSNandor Licker PrimType ElemTy = *Ctx.classify(CT->getElementType());
375950b70dcSNandor Licker return allocateDescriptor(D, ElemTy, 2, IsConst, IsTemporary, IsMutable);
376950b70dcSNandor Licker }
377950b70dcSNandor Licker
378950b70dcSNandor Licker return nullptr;
379950b70dcSNandor Licker }
380