xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/HLSLExternalSemaSource.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1753f127fSDimitry Andric //===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
2753f127fSDimitry Andric //
3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6753f127fSDimitry Andric //
7753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8753f127fSDimitry Andric //
9753f127fSDimitry Andric //
10753f127fSDimitry Andric //===----------------------------------------------------------------------===//
11753f127fSDimitry Andric 
12753f127fSDimitry Andric #include "clang/Sema/HLSLExternalSemaSource.h"
13753f127fSDimitry Andric #include "clang/AST/ASTContext.h"
14bdd1243dSDimitry Andric #include "clang/AST/Attr.h"
15753f127fSDimitry Andric #include "clang/AST/DeclCXX.h"
16753f127fSDimitry Andric #include "clang/Basic/AttrKinds.h"
17bdd1243dSDimitry Andric #include "clang/Basic/HLSLRuntime.h"
18bdd1243dSDimitry Andric #include "clang/Sema/Lookup.h"
19753f127fSDimitry Andric #include "clang/Sema/Sema.h"
20bdd1243dSDimitry Andric #include "llvm/Frontend/HLSL/HLSLResource.h"
21bdd1243dSDimitry Andric 
22bdd1243dSDimitry Andric #include <functional>
23753f127fSDimitry Andric 
24753f127fSDimitry Andric using namespace clang;
25bdd1243dSDimitry Andric using namespace llvm::hlsl;
26bdd1243dSDimitry Andric 
27bdd1243dSDimitry Andric namespace {
28bdd1243dSDimitry Andric 
29bdd1243dSDimitry Andric struct TemplateParameterListBuilder;
30bdd1243dSDimitry Andric 
31bdd1243dSDimitry Andric struct BuiltinTypeDeclBuilder {
32bdd1243dSDimitry Andric   CXXRecordDecl *Record = nullptr;
33bdd1243dSDimitry Andric   ClassTemplateDecl *Template = nullptr;
34bdd1243dSDimitry Andric   ClassTemplateDecl *PrevTemplate = nullptr;
35bdd1243dSDimitry Andric   NamespaceDecl *HLSLNamespace = nullptr;
36bdd1243dSDimitry Andric   llvm::StringMap<FieldDecl *> Fields;
37bdd1243dSDimitry Andric 
38bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
39bdd1243dSDimitry Andric     Record->startDefinition();
40bdd1243dSDimitry Andric     Template = Record->getDescribedClassTemplate();
41bdd1243dSDimitry Andric   }
42bdd1243dSDimitry Andric 
43bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
44bdd1243dSDimitry Andric       : HLSLNamespace(Namespace) {
45bdd1243dSDimitry Andric     ASTContext &AST = S.getASTContext();
46bdd1243dSDimitry Andric     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
47bdd1243dSDimitry Andric 
48bdd1243dSDimitry Andric     LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
49bdd1243dSDimitry Andric     CXXRecordDecl *PrevDecl = nullptr;
50bdd1243dSDimitry Andric     if (S.LookupQualifiedName(Result, HLSLNamespace)) {
51bdd1243dSDimitry Andric       NamedDecl *Found = Result.getFoundDecl();
52bdd1243dSDimitry Andric       if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
53bdd1243dSDimitry Andric         PrevDecl = TD->getTemplatedDecl();
54bdd1243dSDimitry Andric         PrevTemplate = TD;
55bdd1243dSDimitry Andric       } else
56bdd1243dSDimitry Andric         PrevDecl = dyn_cast<CXXRecordDecl>(Found);
57bdd1243dSDimitry Andric       assert(PrevDecl && "Unexpected lookup result type.");
58bdd1243dSDimitry Andric     }
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric     if (PrevDecl && PrevDecl->isCompleteDefinition()) {
61bdd1243dSDimitry Andric       Record = PrevDecl;
62bdd1243dSDimitry Andric       return;
63bdd1243dSDimitry Andric     }
64bdd1243dSDimitry Andric 
655f757f3fSDimitry Andric     Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
665f757f3fSDimitry Andric                                    SourceLocation(), SourceLocation(), &II,
675f757f3fSDimitry Andric                                    PrevDecl, true);
68bdd1243dSDimitry Andric     Record->setImplicit(true);
69bdd1243dSDimitry Andric     Record->setLexicalDeclContext(HLSLNamespace);
70bdd1243dSDimitry Andric     Record->setHasExternalLexicalStorage();
71bdd1243dSDimitry Andric 
72bdd1243dSDimitry Andric     // Don't let anyone derive from built-in types.
73bdd1243dSDimitry Andric     Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
74bdd1243dSDimitry Andric                                               FinalAttr::Keyword_final));
75bdd1243dSDimitry Andric   }
76bdd1243dSDimitry Andric 
77bdd1243dSDimitry Andric   ~BuiltinTypeDeclBuilder() {
78bdd1243dSDimitry Andric     if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
79bdd1243dSDimitry Andric       HLSLNamespace->addDecl(Record);
80bdd1243dSDimitry Andric   }
81bdd1243dSDimitry Andric 
82bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &
83bdd1243dSDimitry Andric   addMemberVariable(StringRef Name, QualType Type,
84bdd1243dSDimitry Andric                     AccessSpecifier Access = AccessSpecifier::AS_private) {
85bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
86bdd1243dSDimitry Andric       return *this;
87bdd1243dSDimitry Andric     assert(Record->isBeingDefined() &&
88bdd1243dSDimitry Andric            "Definition must be started before adding members!");
89bdd1243dSDimitry Andric     ASTContext &AST = Record->getASTContext();
90bdd1243dSDimitry Andric 
91bdd1243dSDimitry Andric     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
92bdd1243dSDimitry Andric     TypeSourceInfo *MemTySource =
93bdd1243dSDimitry Andric         AST.getTrivialTypeSourceInfo(Type, SourceLocation());
94bdd1243dSDimitry Andric     auto *Field = FieldDecl::Create(
95bdd1243dSDimitry Andric         AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
96bdd1243dSDimitry Andric         nullptr, false, InClassInitStyle::ICIS_NoInit);
97bdd1243dSDimitry Andric     Field->setAccess(Access);
98bdd1243dSDimitry Andric     Field->setImplicit(true);
99bdd1243dSDimitry Andric     Record->addDecl(Field);
100bdd1243dSDimitry Andric     Fields[Name] = Field;
101bdd1243dSDimitry Andric     return *this;
102bdd1243dSDimitry Andric   }
103bdd1243dSDimitry Andric 
104bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &
105bdd1243dSDimitry Andric   addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) {
106bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
107bdd1243dSDimitry Andric       return *this;
108bdd1243dSDimitry Andric     QualType Ty = Record->getASTContext().VoidPtrTy;
109bdd1243dSDimitry Andric     if (Template) {
110bdd1243dSDimitry Andric       if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
111bdd1243dSDimitry Andric               Template->getTemplateParameters()->getParam(0)))
112bdd1243dSDimitry Andric         Ty = Record->getASTContext().getPointerType(
113bdd1243dSDimitry Andric             QualType(TTD->getTypeForDecl(), 0));
114bdd1243dSDimitry Andric     }
115bdd1243dSDimitry Andric     return addMemberVariable("h", Ty, Access);
116bdd1243dSDimitry Andric   }
117bdd1243dSDimitry Andric 
118*0fca6ea1SDimitry Andric   BuiltinTypeDeclBuilder &annotateHLSLResource(ResourceClass RC,
1195f757f3fSDimitry Andric                                                ResourceKind RK, bool IsROV) {
120bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
121bdd1243dSDimitry Andric       return *this;
122*0fca6ea1SDimitry Andric     Record->addAttr(
123*0fca6ea1SDimitry Andric         HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC));
124*0fca6ea1SDimitry Andric     Record->addAttr(
125*0fca6ea1SDimitry Andric         HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK, IsROV));
126bdd1243dSDimitry Andric     return *this;
127bdd1243dSDimitry Andric   }
128bdd1243dSDimitry Andric 
129bdd1243dSDimitry Andric   static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
130bdd1243dSDimitry Andric                                             StringRef Name) {
131bdd1243dSDimitry Andric     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
132bdd1243dSDimitry Andric     DeclarationNameInfo NameInfo =
133bdd1243dSDimitry Andric         DeclarationNameInfo(DeclarationName(&II), SourceLocation());
134bdd1243dSDimitry Andric     LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
135*0fca6ea1SDimitry Andric     // AllowBuiltinCreation is false but LookupDirect will create
136*0fca6ea1SDimitry Andric     // the builtin when searching the global scope anyways...
137*0fca6ea1SDimitry Andric     S.LookupName(R, S.getCurScope());
138*0fca6ea1SDimitry Andric     // FIXME: If the builtin function was user-declared in global scope,
139*0fca6ea1SDimitry Andric     // this assert *will* fail. Should this call LookupBuiltin instead?
140bdd1243dSDimitry Andric     assert(R.isSingleResult() &&
141bdd1243dSDimitry Andric            "Since this is a builtin it should always resolve!");
142bdd1243dSDimitry Andric     auto *VD = cast<ValueDecl>(R.getFoundDecl());
143bdd1243dSDimitry Andric     QualType Ty = VD->getType();
144bdd1243dSDimitry Andric     return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
145bdd1243dSDimitry Andric                                VD, false, NameInfo, Ty, VK_PRValue);
146bdd1243dSDimitry Andric   }
147bdd1243dSDimitry Andric 
148bdd1243dSDimitry Andric   static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
149bdd1243dSDimitry Andric     return IntegerLiteral::Create(
150bdd1243dSDimitry Andric         AST,
151bdd1243dSDimitry Andric         llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
152bdd1243dSDimitry Andric                     static_cast<uint8_t>(RC)),
153bdd1243dSDimitry Andric         AST.UnsignedCharTy, SourceLocation());
154bdd1243dSDimitry Andric   }
155bdd1243dSDimitry Andric 
156bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
157bdd1243dSDimitry Andric                                                       ResourceClass RC) {
158bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
159bdd1243dSDimitry Andric       return *this;
160bdd1243dSDimitry Andric     ASTContext &AST = Record->getASTContext();
161bdd1243dSDimitry Andric 
162bdd1243dSDimitry Andric     QualType ConstructorType =
163bdd1243dSDimitry Andric         AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
164bdd1243dSDimitry Andric 
165bdd1243dSDimitry Andric     CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
166bdd1243dSDimitry Andric     DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
167bdd1243dSDimitry Andric     CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
168bdd1243dSDimitry Andric         AST, Record, SourceLocation(),
169bdd1243dSDimitry Andric         DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
170bdd1243dSDimitry Andric         AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
171bdd1243dSDimitry Andric         ExplicitSpecifier(), false, true, false,
172bdd1243dSDimitry Andric         ConstexprSpecKind::Unspecified);
173bdd1243dSDimitry Andric 
174bdd1243dSDimitry Andric     DeclRefExpr *Fn =
175bdd1243dSDimitry Andric         lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
176bdd1243dSDimitry Andric     Expr *RCExpr = emitResourceClassExpr(AST, RC);
177bdd1243dSDimitry Andric     Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
178bdd1243dSDimitry Andric                                   SourceLocation(), FPOptionsOverride());
179bdd1243dSDimitry Andric 
1805f757f3fSDimitry Andric     CXXThisExpr *This = CXXThisExpr::Create(
1815f757f3fSDimitry Andric         AST, SourceLocation(), Constructor->getFunctionObjectParameterType(),
1825f757f3fSDimitry Andric         true);
183bdd1243dSDimitry Andric     Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
184bdd1243dSDimitry Andric                                               Fields["h"]->getType(), VK_LValue,
185bdd1243dSDimitry Andric                                               OK_Ordinary);
186bdd1243dSDimitry Andric 
187bdd1243dSDimitry Andric     // If the handle isn't a void pointer, cast the builtin result to the
188bdd1243dSDimitry Andric     // correct type.
189bdd1243dSDimitry Andric     if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
190bdd1243dSDimitry Andric       Call = CXXStaticCastExpr::Create(
191bdd1243dSDimitry Andric           AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
192bdd1243dSDimitry Andric           AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
193bdd1243dSDimitry Andric           FPOptionsOverride(), SourceLocation(), SourceLocation(),
194bdd1243dSDimitry Andric           SourceRange());
195bdd1243dSDimitry Andric     }
196bdd1243dSDimitry Andric 
197bdd1243dSDimitry Andric     BinaryOperator *Assign = BinaryOperator::Create(
198bdd1243dSDimitry Andric         AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
199bdd1243dSDimitry Andric         SourceLocation(), FPOptionsOverride());
200bdd1243dSDimitry Andric 
201bdd1243dSDimitry Andric     Constructor->setBody(
202bdd1243dSDimitry Andric         CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
203bdd1243dSDimitry Andric                              SourceLocation(), SourceLocation()));
204bdd1243dSDimitry Andric     Constructor->setAccess(AccessSpecifier::AS_public);
205bdd1243dSDimitry Andric     Record->addDecl(Constructor);
206bdd1243dSDimitry Andric     return *this;
207bdd1243dSDimitry Andric   }
208bdd1243dSDimitry Andric 
209bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
210bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
211bdd1243dSDimitry Andric       return *this;
212bdd1243dSDimitry Andric     addArraySubscriptOperator(true);
213bdd1243dSDimitry Andric     addArraySubscriptOperator(false);
214bdd1243dSDimitry Andric     return *this;
215bdd1243dSDimitry Andric   }
216bdd1243dSDimitry Andric 
217bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
218bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
219bdd1243dSDimitry Andric       return *this;
220bdd1243dSDimitry Andric     assert(Fields.count("h") > 0 &&
221bdd1243dSDimitry Andric            "Subscript operator must be added after the handle.");
222bdd1243dSDimitry Andric 
223bdd1243dSDimitry Andric     FieldDecl *Handle = Fields["h"];
224bdd1243dSDimitry Andric     ASTContext &AST = Record->getASTContext();
225bdd1243dSDimitry Andric 
226bdd1243dSDimitry Andric     assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
227bdd1243dSDimitry Andric            "Not yet supported for void pointer handles.");
228bdd1243dSDimitry Andric 
229bdd1243dSDimitry Andric     QualType ElemTy =
230bdd1243dSDimitry Andric         QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
231bdd1243dSDimitry Andric     QualType ReturnTy = ElemTy;
232bdd1243dSDimitry Andric 
233bdd1243dSDimitry Andric     FunctionProtoType::ExtProtoInfo ExtInfo;
234bdd1243dSDimitry Andric 
235bdd1243dSDimitry Andric     // Subscript operators return references to elements, const makes the
236bdd1243dSDimitry Andric     // reference and method const so that the underlying data is not mutable.
237bdd1243dSDimitry Andric     ReturnTy = AST.getLValueReferenceType(ReturnTy);
238bdd1243dSDimitry Andric     if (IsConst) {
239bdd1243dSDimitry Andric       ExtInfo.TypeQuals.addConst();
240bdd1243dSDimitry Andric       ReturnTy.addConst();
241bdd1243dSDimitry Andric     }
242bdd1243dSDimitry Andric 
243bdd1243dSDimitry Andric     QualType MethodTy =
244bdd1243dSDimitry Andric         AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
245bdd1243dSDimitry Andric     auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
246bdd1243dSDimitry Andric     auto *MethodDecl = CXXMethodDecl::Create(
247bdd1243dSDimitry Andric         AST, Record, SourceLocation(),
248bdd1243dSDimitry Andric         DeclarationNameInfo(
249bdd1243dSDimitry Andric             AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
250bdd1243dSDimitry Andric             SourceLocation()),
251bdd1243dSDimitry Andric         MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
252bdd1243dSDimitry Andric         SourceLocation());
253bdd1243dSDimitry Andric 
254bdd1243dSDimitry Andric     IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
255bdd1243dSDimitry Andric     auto *IdxParam = ParmVarDecl::Create(
256bdd1243dSDimitry Andric         AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
257bdd1243dSDimitry Andric         &II, AST.UnsignedIntTy,
258bdd1243dSDimitry Andric         AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
259bdd1243dSDimitry Andric         SC_None, nullptr);
260bdd1243dSDimitry Andric     MethodDecl->setParams({IdxParam});
261bdd1243dSDimitry Andric 
262bdd1243dSDimitry Andric     // Also add the parameter to the function prototype.
263bdd1243dSDimitry Andric     auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
264bdd1243dSDimitry Andric     FnProtoLoc.setParam(0, IdxParam);
265bdd1243dSDimitry Andric 
2665f757f3fSDimitry Andric     auto *This =
2675f757f3fSDimitry Andric         CXXThisExpr::Create(AST, SourceLocation(),
2685f757f3fSDimitry Andric                             MethodDecl->getFunctionObjectParameterType(), true);
269bdd1243dSDimitry Andric     auto *HandleAccess = MemberExpr::CreateImplicit(
270bdd1243dSDimitry Andric         AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
271bdd1243dSDimitry Andric 
272bdd1243dSDimitry Andric     auto *IndexExpr = DeclRefExpr::Create(
273bdd1243dSDimitry Andric         AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
274bdd1243dSDimitry Andric         DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
275bdd1243dSDimitry Andric         AST.UnsignedIntTy, VK_PRValue);
276bdd1243dSDimitry Andric 
277bdd1243dSDimitry Andric     auto *Array =
278bdd1243dSDimitry Andric         new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
279bdd1243dSDimitry Andric                                      OK_Ordinary, SourceLocation());
280bdd1243dSDimitry Andric 
281bdd1243dSDimitry Andric     auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
282bdd1243dSDimitry Andric 
283bdd1243dSDimitry Andric     MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
284bdd1243dSDimitry Andric                                              SourceLocation(),
285bdd1243dSDimitry Andric                                              SourceLocation()));
286bdd1243dSDimitry Andric     MethodDecl->setLexicalDeclContext(Record);
287bdd1243dSDimitry Andric     MethodDecl->setAccess(AccessSpecifier::AS_public);
288bdd1243dSDimitry Andric     MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
28906c3fb27SDimitry Andric         AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
290bdd1243dSDimitry Andric     Record->addDecl(MethodDecl);
291bdd1243dSDimitry Andric 
292bdd1243dSDimitry Andric     return *this;
293bdd1243dSDimitry Andric   }
294bdd1243dSDimitry Andric 
295bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &startDefinition() {
296bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
297bdd1243dSDimitry Andric       return *this;
298bdd1243dSDimitry Andric     Record->startDefinition();
299bdd1243dSDimitry Andric     return *this;
300bdd1243dSDimitry Andric   }
301bdd1243dSDimitry Andric 
302bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &completeDefinition() {
303bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
304bdd1243dSDimitry Andric       return *this;
305bdd1243dSDimitry Andric     assert(Record->isBeingDefined() &&
306bdd1243dSDimitry Andric            "Definition must be started before completing it.");
307bdd1243dSDimitry Andric 
308bdd1243dSDimitry Andric     Record->completeDefinition();
309bdd1243dSDimitry Andric     return *this;
310bdd1243dSDimitry Andric   }
311bdd1243dSDimitry Andric 
312*0fca6ea1SDimitry Andric   TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
313*0fca6ea1SDimitry Andric   BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S,
314*0fca6ea1SDimitry Andric                                                   ArrayRef<StringRef> Names);
315bdd1243dSDimitry Andric };
316bdd1243dSDimitry Andric 
317bdd1243dSDimitry Andric struct TemplateParameterListBuilder {
318bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &Builder;
319*0fca6ea1SDimitry Andric   Sema &S;
320bdd1243dSDimitry Andric   llvm::SmallVector<NamedDecl *> Params;
321bdd1243dSDimitry Andric 
322*0fca6ea1SDimitry Andric   TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
323*0fca6ea1SDimitry Andric       : Builder(RB), S(S) {}
324bdd1243dSDimitry Andric 
325bdd1243dSDimitry Andric   ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
326bdd1243dSDimitry Andric 
327bdd1243dSDimitry Andric   TemplateParameterListBuilder &
328bdd1243dSDimitry Andric   addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
329bdd1243dSDimitry Andric     if (Builder.Record->isCompleteDefinition())
330bdd1243dSDimitry Andric       return *this;
331bdd1243dSDimitry Andric     unsigned Position = static_cast<unsigned>(Params.size());
332bdd1243dSDimitry Andric     auto *Decl = TemplateTypeParmDecl::Create(
333*0fca6ea1SDimitry Andric         S.Context, Builder.Record->getDeclContext(), SourceLocation(),
334bdd1243dSDimitry Andric         SourceLocation(), /* TemplateDepth */ 0, Position,
335*0fca6ea1SDimitry Andric         &S.Context.Idents.get(Name, tok::TokenKind::identifier),
336*0fca6ea1SDimitry Andric         /* Typename */ false,
337bdd1243dSDimitry Andric         /* ParameterPack */ false);
338bdd1243dSDimitry Andric     if (!DefaultValue.isNull())
339*0fca6ea1SDimitry Andric       Decl->setDefaultArgument(
340*0fca6ea1SDimitry Andric           S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
341*0fca6ea1SDimitry Andric                                                      SourceLocation()));
342bdd1243dSDimitry Andric 
343bdd1243dSDimitry Andric     Params.emplace_back(Decl);
344bdd1243dSDimitry Andric     return *this;
345bdd1243dSDimitry Andric   }
346bdd1243dSDimitry Andric 
347bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
348bdd1243dSDimitry Andric     if (Params.empty())
349bdd1243dSDimitry Andric       return Builder;
350*0fca6ea1SDimitry Andric     auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
351*0fca6ea1SDimitry Andric                                                     SourceLocation(), Params,
352*0fca6ea1SDimitry Andric                                                     SourceLocation(), nullptr);
353bdd1243dSDimitry Andric     Builder.Template = ClassTemplateDecl::Create(
354*0fca6ea1SDimitry Andric         S.Context, Builder.Record->getDeclContext(), SourceLocation(),
355bdd1243dSDimitry Andric         DeclarationName(Builder.Record->getIdentifier()), ParamList,
356bdd1243dSDimitry Andric         Builder.Record);
357bdd1243dSDimitry Andric     Builder.Record->setDescribedClassTemplate(Builder.Template);
358bdd1243dSDimitry Andric     Builder.Template->setImplicit(true);
359bdd1243dSDimitry Andric     Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
360bdd1243dSDimitry Andric     // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
361bdd1243dSDimitry Andric     // make visible.
362bdd1243dSDimitry Andric     Builder.Template->setPreviousDecl(Builder.PrevTemplate);
363bdd1243dSDimitry Andric     Builder.Record->getDeclContext()->addDecl(Builder.Template);
364bdd1243dSDimitry Andric     Params.clear();
365bdd1243dSDimitry Andric 
366bdd1243dSDimitry Andric     QualType T = Builder.Template->getInjectedClassNameSpecialization();
367*0fca6ea1SDimitry Andric     T = S.Context.getInjectedClassNameType(Builder.Record, T);
368bdd1243dSDimitry Andric 
369bdd1243dSDimitry Andric     return Builder;
370bdd1243dSDimitry Andric   }
371bdd1243dSDimitry Andric };
3725f757f3fSDimitry Andric } // namespace
373bdd1243dSDimitry Andric 
374*0fca6ea1SDimitry Andric TemplateParameterListBuilder
375*0fca6ea1SDimitry Andric BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
376*0fca6ea1SDimitry Andric   return TemplateParameterListBuilder(S, *this);
377bdd1243dSDimitry Andric }
3785f757f3fSDimitry Andric 
3795f757f3fSDimitry Andric BuiltinTypeDeclBuilder &
380*0fca6ea1SDimitry Andric BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
381*0fca6ea1SDimitry Andric                                                 ArrayRef<StringRef> Names) {
382*0fca6ea1SDimitry Andric   TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
3835f757f3fSDimitry Andric   for (StringRef Name : Names)
3845f757f3fSDimitry Andric     Builder.addTypeParameter(Name);
3855f757f3fSDimitry Andric   return Builder.finalizeTemplateArgs();
3865f757f3fSDimitry Andric }
387753f127fSDimitry Andric 
388753f127fSDimitry Andric HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
389753f127fSDimitry Andric 
390753f127fSDimitry Andric void HLSLExternalSemaSource::InitializeSema(Sema &S) {
391753f127fSDimitry Andric   SemaPtr = &S;
392753f127fSDimitry Andric   ASTContext &AST = SemaPtr->getASTContext();
393bdd1243dSDimitry Andric   // If the translation unit has external storage force external decls to load.
394bdd1243dSDimitry Andric   if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
395bdd1243dSDimitry Andric     (void)AST.getTranslationUnitDecl()->decls_begin();
396bdd1243dSDimitry Andric 
397753f127fSDimitry Andric   IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
398bdd1243dSDimitry Andric   LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
399bdd1243dSDimitry Andric   NamespaceDecl *PrevDecl = nullptr;
400bdd1243dSDimitry Andric   if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
401bdd1243dSDimitry Andric     PrevDecl = Result.getAsSingle<NamespaceDecl>();
402bdd1243dSDimitry Andric   HLSLNamespace = NamespaceDecl::Create(
403bdd1243dSDimitry Andric       AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
404bdd1243dSDimitry Andric       SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
405753f127fSDimitry Andric   HLSLNamespace->setImplicit(true);
406bdd1243dSDimitry Andric   HLSLNamespace->setHasExternalLexicalStorage();
407753f127fSDimitry Andric   AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
408bdd1243dSDimitry Andric 
409bdd1243dSDimitry Andric   // Force external decls in the HLSL namespace to load from the PCH.
410bdd1243dSDimitry Andric   (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
411bdd1243dSDimitry Andric   defineTrivialHLSLTypes();
4125f757f3fSDimitry Andric   defineHLSLTypesWithForwardDeclarations();
413753f127fSDimitry Andric 
414753f127fSDimitry Andric   // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
415753f127fSDimitry Andric   // built in types inside a namespace, but we are planning to change that in
416753f127fSDimitry Andric   // the near future. In order to be source compatible older versions of HLSL
417753f127fSDimitry Andric   // will need to implicitly use the hlsl namespace. For now in clang everything
418753f127fSDimitry Andric   // will get added to the namespace, and we can remove the using directive for
419753f127fSDimitry Andric   // future language versions to match HLSL's evolution.
420753f127fSDimitry Andric   auto *UsingDecl = UsingDirectiveDecl::Create(
421753f127fSDimitry Andric       AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
422753f127fSDimitry Andric       NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
423753f127fSDimitry Andric       AST.getTranslationUnitDecl());
424753f127fSDimitry Andric 
425753f127fSDimitry Andric   AST.getTranslationUnitDecl()->addDecl(UsingDecl);
426753f127fSDimitry Andric }
427753f127fSDimitry Andric 
428753f127fSDimitry Andric void HLSLExternalSemaSource::defineHLSLVectorAlias() {
429753f127fSDimitry Andric   ASTContext &AST = SemaPtr->getASTContext();
430753f127fSDimitry Andric 
431753f127fSDimitry Andric   llvm::SmallVector<NamedDecl *> TemplateParams;
432753f127fSDimitry Andric 
433753f127fSDimitry Andric   auto *TypeParam = TemplateTypeParmDecl::Create(
434753f127fSDimitry Andric       AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
435753f127fSDimitry Andric       &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
436*0fca6ea1SDimitry Andric   TypeParam->setDefaultArgument(
437*0fca6ea1SDimitry Andric       AST, SemaPtr->getTrivialTemplateArgumentLoc(
438*0fca6ea1SDimitry Andric                TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
439753f127fSDimitry Andric 
440753f127fSDimitry Andric   TemplateParams.emplace_back(TypeParam);
441753f127fSDimitry Andric 
442753f127fSDimitry Andric   auto *SizeParam = NonTypeTemplateParmDecl::Create(
443753f127fSDimitry Andric       AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
444753f127fSDimitry Andric       &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
445753f127fSDimitry Andric       false, AST.getTrivialTypeSourceInfo(AST.IntTy));
446*0fca6ea1SDimitry Andric   llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
447*0fca6ea1SDimitry Andric   TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
448*0fca6ea1SDimitry Andric                            /*IsDefaulted=*/true);
449*0fca6ea1SDimitry Andric   SizeParam->setDefaultArgument(
450*0fca6ea1SDimitry Andric       AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
451*0fca6ea1SDimitry Andric                                                   SourceLocation(), SizeParam));
452753f127fSDimitry Andric   TemplateParams.emplace_back(SizeParam);
453753f127fSDimitry Andric 
454753f127fSDimitry Andric   auto *ParamList =
455753f127fSDimitry Andric       TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
456753f127fSDimitry Andric                                     TemplateParams, SourceLocation(), nullptr);
457753f127fSDimitry Andric 
458753f127fSDimitry Andric   IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
459753f127fSDimitry Andric 
460753f127fSDimitry Andric   QualType AliasType = AST.getDependentSizedExtVectorType(
461753f127fSDimitry Andric       AST.getTemplateTypeParmType(0, 0, false, TypeParam),
462753f127fSDimitry Andric       DeclRefExpr::Create(
463753f127fSDimitry Andric           AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
464753f127fSDimitry Andric           DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
465753f127fSDimitry Andric           AST.IntTy, VK_LValue),
466753f127fSDimitry Andric       SourceLocation());
467753f127fSDimitry Andric 
468753f127fSDimitry Andric   auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
469753f127fSDimitry Andric                                        SourceLocation(), &II,
470753f127fSDimitry Andric                                        AST.getTrivialTypeSourceInfo(AliasType));
471753f127fSDimitry Andric   Record->setImplicit(true);
472753f127fSDimitry Andric 
473753f127fSDimitry Andric   auto *Template =
474753f127fSDimitry Andric       TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
475753f127fSDimitry Andric                                     Record->getIdentifier(), ParamList, Record);
476753f127fSDimitry Andric 
477753f127fSDimitry Andric   Record->setDescribedAliasTemplate(Template);
478753f127fSDimitry Andric   Template->setImplicit(true);
479753f127fSDimitry Andric   Template->setLexicalDeclContext(Record->getDeclContext());
480753f127fSDimitry Andric   HLSLNamespace->addDecl(Template);
481753f127fSDimitry Andric }
482bdd1243dSDimitry Andric 
483bdd1243dSDimitry Andric void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
484bdd1243dSDimitry Andric   defineHLSLVectorAlias();
485bdd1243dSDimitry Andric }
486bdd1243dSDimitry Andric 
4875f757f3fSDimitry Andric /// Set up common members and attributes for buffer types
4885f757f3fSDimitry Andric static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
4895f757f3fSDimitry Andric                                               ResourceClass RC, ResourceKind RK,
4905f757f3fSDimitry Andric                                               bool IsROV) {
4915f757f3fSDimitry Andric   return BuiltinTypeDeclBuilder(Decl)
4925f757f3fSDimitry Andric       .addHandleMember()
4935f757f3fSDimitry Andric       .addDefaultHandleConstructor(S, RC)
494*0fca6ea1SDimitry Andric       .annotateHLSLResource(RC, RK, IsROV);
4955f757f3fSDimitry Andric }
4965f757f3fSDimitry Andric 
4975f757f3fSDimitry Andric void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
498bdd1243dSDimitry Andric   CXXRecordDecl *Decl;
499bdd1243dSDimitry Andric   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
500*0fca6ea1SDimitry Andric              .addSimpleTemplateParams(*SemaPtr, {"element_type"})
501bdd1243dSDimitry Andric              .Record;
5025f757f3fSDimitry Andric   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
5035f757f3fSDimitry Andric     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
5045f757f3fSDimitry Andric                     ResourceKind::TypedBuffer, /*IsROV=*/false)
5055f757f3fSDimitry Andric         .addArraySubscriptOperators()
5065f757f3fSDimitry Andric         .completeDefinition();
5075f757f3fSDimitry Andric   });
5085f757f3fSDimitry Andric 
5095f757f3fSDimitry Andric   Decl =
5105f757f3fSDimitry Andric       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
511*0fca6ea1SDimitry Andric           .addSimpleTemplateParams(*SemaPtr, {"element_type"})
5125f757f3fSDimitry Andric           .Record;
5135f757f3fSDimitry Andric   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
5145f757f3fSDimitry Andric     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
5155f757f3fSDimitry Andric                     ResourceKind::TypedBuffer, /*IsROV=*/true)
5165f757f3fSDimitry Andric         .addArraySubscriptOperators()
5175f757f3fSDimitry Andric         .completeDefinition();
5185f757f3fSDimitry Andric   });
5195f757f3fSDimitry Andric }
5205f757f3fSDimitry Andric 
5215f757f3fSDimitry Andric void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
5225f757f3fSDimitry Andric                                           CompletionFunction Fn) {
5235f757f3fSDimitry Andric   Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
524bdd1243dSDimitry Andric }
525bdd1243dSDimitry Andric 
526bdd1243dSDimitry Andric void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
527bdd1243dSDimitry Andric   if (!isa<CXXRecordDecl>(Tag))
528bdd1243dSDimitry Andric     return;
529bdd1243dSDimitry Andric   auto Record = cast<CXXRecordDecl>(Tag);
530bdd1243dSDimitry Andric 
531bdd1243dSDimitry Andric   // If this is a specialization, we need to get the underlying templated
532bdd1243dSDimitry Andric   // declaration and complete that.
533bdd1243dSDimitry Andric   if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
534bdd1243dSDimitry Andric     Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
535bdd1243dSDimitry Andric   Record = Record->getCanonicalDecl();
536bdd1243dSDimitry Andric   auto It = Completions.find(Record);
537bdd1243dSDimitry Andric   if (It == Completions.end())
538bdd1243dSDimitry Andric     return;
539bdd1243dSDimitry Andric   It->second(Record);
540bdd1243dSDimitry Andric }
541