xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/HLSLExternalSemaSource.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
65*5f757f3fSDimitry Andric     Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
66*5f757f3fSDimitry Andric                                    SourceLocation(), SourceLocation(), &II,
67*5f757f3fSDimitry 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*5f757f3fSDimitry Andric   BuiltinTypeDeclBuilder &annotateResourceClass(ResourceClass RC,
119*5f757f3fSDimitry Andric                                                 ResourceKind RK, bool IsROV) {
120bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
121bdd1243dSDimitry Andric       return *this;
122*5f757f3fSDimitry Andric     Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(),
123*5f757f3fSDimitry Andric                                                      RC, RK, IsROV));
124bdd1243dSDimitry Andric     return *this;
125bdd1243dSDimitry Andric   }
126bdd1243dSDimitry Andric 
127bdd1243dSDimitry Andric   static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
128bdd1243dSDimitry Andric                                             StringRef Name) {
129bdd1243dSDimitry Andric     CXXScopeSpec SS;
130bdd1243dSDimitry Andric     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
131bdd1243dSDimitry Andric     DeclarationNameInfo NameInfo =
132bdd1243dSDimitry Andric         DeclarationNameInfo(DeclarationName(&II), SourceLocation());
133bdd1243dSDimitry Andric     LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
134bdd1243dSDimitry Andric     S.LookupParsedName(R, S.getCurScope(), &SS, false);
135bdd1243dSDimitry Andric     assert(R.isSingleResult() &&
136bdd1243dSDimitry Andric            "Since this is a builtin it should always resolve!");
137bdd1243dSDimitry Andric     auto *VD = cast<ValueDecl>(R.getFoundDecl());
138bdd1243dSDimitry Andric     QualType Ty = VD->getType();
139bdd1243dSDimitry Andric     return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
140bdd1243dSDimitry Andric                                VD, false, NameInfo, Ty, VK_PRValue);
141bdd1243dSDimitry Andric   }
142bdd1243dSDimitry Andric 
143bdd1243dSDimitry Andric   static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
144bdd1243dSDimitry Andric     return IntegerLiteral::Create(
145bdd1243dSDimitry Andric         AST,
146bdd1243dSDimitry Andric         llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
147bdd1243dSDimitry Andric                     static_cast<uint8_t>(RC)),
148bdd1243dSDimitry Andric         AST.UnsignedCharTy, SourceLocation());
149bdd1243dSDimitry Andric   }
150bdd1243dSDimitry Andric 
151bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
152bdd1243dSDimitry Andric                                                       ResourceClass RC) {
153bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
154bdd1243dSDimitry Andric       return *this;
155bdd1243dSDimitry Andric     ASTContext &AST = Record->getASTContext();
156bdd1243dSDimitry Andric 
157bdd1243dSDimitry Andric     QualType ConstructorType =
158bdd1243dSDimitry Andric         AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
159bdd1243dSDimitry Andric 
160bdd1243dSDimitry Andric     CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
161bdd1243dSDimitry Andric     DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
162bdd1243dSDimitry Andric     CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
163bdd1243dSDimitry Andric         AST, Record, SourceLocation(),
164bdd1243dSDimitry Andric         DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
165bdd1243dSDimitry Andric         AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
166bdd1243dSDimitry Andric         ExplicitSpecifier(), false, true, false,
167bdd1243dSDimitry Andric         ConstexprSpecKind::Unspecified);
168bdd1243dSDimitry Andric 
169bdd1243dSDimitry Andric     DeclRefExpr *Fn =
170bdd1243dSDimitry Andric         lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
171bdd1243dSDimitry Andric 
172bdd1243dSDimitry Andric     Expr *RCExpr = emitResourceClassExpr(AST, RC);
173bdd1243dSDimitry Andric     Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
174bdd1243dSDimitry Andric                                   SourceLocation(), FPOptionsOverride());
175bdd1243dSDimitry Andric 
176*5f757f3fSDimitry Andric     CXXThisExpr *This = CXXThisExpr::Create(
177*5f757f3fSDimitry Andric         AST, SourceLocation(), Constructor->getFunctionObjectParameterType(),
178*5f757f3fSDimitry Andric         true);
179bdd1243dSDimitry Andric     Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
180bdd1243dSDimitry Andric                                               Fields["h"]->getType(), VK_LValue,
181bdd1243dSDimitry Andric                                               OK_Ordinary);
182bdd1243dSDimitry Andric 
183bdd1243dSDimitry Andric     // If the handle isn't a void pointer, cast the builtin result to the
184bdd1243dSDimitry Andric     // correct type.
185bdd1243dSDimitry Andric     if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
186bdd1243dSDimitry Andric       Call = CXXStaticCastExpr::Create(
187bdd1243dSDimitry Andric           AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
188bdd1243dSDimitry Andric           AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
189bdd1243dSDimitry Andric           FPOptionsOverride(), SourceLocation(), SourceLocation(),
190bdd1243dSDimitry Andric           SourceRange());
191bdd1243dSDimitry Andric     }
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric     BinaryOperator *Assign = BinaryOperator::Create(
194bdd1243dSDimitry Andric         AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
195bdd1243dSDimitry Andric         SourceLocation(), FPOptionsOverride());
196bdd1243dSDimitry Andric 
197bdd1243dSDimitry Andric     Constructor->setBody(
198bdd1243dSDimitry Andric         CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
199bdd1243dSDimitry Andric                              SourceLocation(), SourceLocation()));
200bdd1243dSDimitry Andric     Constructor->setAccess(AccessSpecifier::AS_public);
201bdd1243dSDimitry Andric     Record->addDecl(Constructor);
202bdd1243dSDimitry Andric     return *this;
203bdd1243dSDimitry Andric   }
204bdd1243dSDimitry Andric 
205bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
206bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
207bdd1243dSDimitry Andric       return *this;
208bdd1243dSDimitry Andric     addArraySubscriptOperator(true);
209bdd1243dSDimitry Andric     addArraySubscriptOperator(false);
210bdd1243dSDimitry Andric     return *this;
211bdd1243dSDimitry Andric   }
212bdd1243dSDimitry Andric 
213bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
214bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
215bdd1243dSDimitry Andric       return *this;
216bdd1243dSDimitry Andric     assert(Fields.count("h") > 0 &&
217bdd1243dSDimitry Andric            "Subscript operator must be added after the handle.");
218bdd1243dSDimitry Andric 
219bdd1243dSDimitry Andric     FieldDecl *Handle = Fields["h"];
220bdd1243dSDimitry Andric     ASTContext &AST = Record->getASTContext();
221bdd1243dSDimitry Andric 
222bdd1243dSDimitry Andric     assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
223bdd1243dSDimitry Andric            "Not yet supported for void pointer handles.");
224bdd1243dSDimitry Andric 
225bdd1243dSDimitry Andric     QualType ElemTy =
226bdd1243dSDimitry Andric         QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
227bdd1243dSDimitry Andric     QualType ReturnTy = ElemTy;
228bdd1243dSDimitry Andric 
229bdd1243dSDimitry Andric     FunctionProtoType::ExtProtoInfo ExtInfo;
230bdd1243dSDimitry Andric 
231bdd1243dSDimitry Andric     // Subscript operators return references to elements, const makes the
232bdd1243dSDimitry Andric     // reference and method const so that the underlying data is not mutable.
233bdd1243dSDimitry Andric     ReturnTy = AST.getLValueReferenceType(ReturnTy);
234bdd1243dSDimitry Andric     if (IsConst) {
235bdd1243dSDimitry Andric       ExtInfo.TypeQuals.addConst();
236bdd1243dSDimitry Andric       ReturnTy.addConst();
237bdd1243dSDimitry Andric     }
238bdd1243dSDimitry Andric 
239bdd1243dSDimitry Andric     QualType MethodTy =
240bdd1243dSDimitry Andric         AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
241bdd1243dSDimitry Andric     auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
242bdd1243dSDimitry Andric     auto *MethodDecl = CXXMethodDecl::Create(
243bdd1243dSDimitry Andric         AST, Record, SourceLocation(),
244bdd1243dSDimitry Andric         DeclarationNameInfo(
245bdd1243dSDimitry Andric             AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
246bdd1243dSDimitry Andric             SourceLocation()),
247bdd1243dSDimitry Andric         MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
248bdd1243dSDimitry Andric         SourceLocation());
249bdd1243dSDimitry Andric 
250bdd1243dSDimitry Andric     IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
251bdd1243dSDimitry Andric     auto *IdxParam = ParmVarDecl::Create(
252bdd1243dSDimitry Andric         AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
253bdd1243dSDimitry Andric         &II, AST.UnsignedIntTy,
254bdd1243dSDimitry Andric         AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
255bdd1243dSDimitry Andric         SC_None, nullptr);
256bdd1243dSDimitry Andric     MethodDecl->setParams({IdxParam});
257bdd1243dSDimitry Andric 
258bdd1243dSDimitry Andric     // Also add the parameter to the function prototype.
259bdd1243dSDimitry Andric     auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
260bdd1243dSDimitry Andric     FnProtoLoc.setParam(0, IdxParam);
261bdd1243dSDimitry Andric 
262*5f757f3fSDimitry Andric     auto *This =
263*5f757f3fSDimitry Andric         CXXThisExpr::Create(AST, SourceLocation(),
264*5f757f3fSDimitry Andric                             MethodDecl->getFunctionObjectParameterType(), true);
265bdd1243dSDimitry Andric     auto *HandleAccess = MemberExpr::CreateImplicit(
266bdd1243dSDimitry Andric         AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
267bdd1243dSDimitry Andric 
268bdd1243dSDimitry Andric     auto *IndexExpr = DeclRefExpr::Create(
269bdd1243dSDimitry Andric         AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
270bdd1243dSDimitry Andric         DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
271bdd1243dSDimitry Andric         AST.UnsignedIntTy, VK_PRValue);
272bdd1243dSDimitry Andric 
273bdd1243dSDimitry Andric     auto *Array =
274bdd1243dSDimitry Andric         new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
275bdd1243dSDimitry Andric                                      OK_Ordinary, SourceLocation());
276bdd1243dSDimitry Andric 
277bdd1243dSDimitry Andric     auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
278bdd1243dSDimitry Andric 
279bdd1243dSDimitry Andric     MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
280bdd1243dSDimitry Andric                                              SourceLocation(),
281bdd1243dSDimitry Andric                                              SourceLocation()));
282bdd1243dSDimitry Andric     MethodDecl->setLexicalDeclContext(Record);
283bdd1243dSDimitry Andric     MethodDecl->setAccess(AccessSpecifier::AS_public);
284bdd1243dSDimitry Andric     MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
28506c3fb27SDimitry Andric         AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
286bdd1243dSDimitry Andric     Record->addDecl(MethodDecl);
287bdd1243dSDimitry Andric 
288bdd1243dSDimitry Andric     return *this;
289bdd1243dSDimitry Andric   }
290bdd1243dSDimitry Andric 
291bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &startDefinition() {
292bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
293bdd1243dSDimitry Andric       return *this;
294bdd1243dSDimitry Andric     Record->startDefinition();
295bdd1243dSDimitry Andric     return *this;
296bdd1243dSDimitry Andric   }
297bdd1243dSDimitry Andric 
298bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &completeDefinition() {
299bdd1243dSDimitry Andric     if (Record->isCompleteDefinition())
300bdd1243dSDimitry Andric       return *this;
301bdd1243dSDimitry Andric     assert(Record->isBeingDefined() &&
302bdd1243dSDimitry Andric            "Definition must be started before completing it.");
303bdd1243dSDimitry Andric 
304bdd1243dSDimitry Andric     Record->completeDefinition();
305bdd1243dSDimitry Andric     return *this;
306bdd1243dSDimitry Andric   }
307bdd1243dSDimitry Andric 
308bdd1243dSDimitry Andric   TemplateParameterListBuilder addTemplateArgumentList();
309*5f757f3fSDimitry Andric   BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef<StringRef> Names);
310bdd1243dSDimitry Andric };
311bdd1243dSDimitry Andric 
312bdd1243dSDimitry Andric struct TemplateParameterListBuilder {
313bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &Builder;
314bdd1243dSDimitry Andric   ASTContext &AST;
315bdd1243dSDimitry Andric   llvm::SmallVector<NamedDecl *> Params;
316bdd1243dSDimitry Andric 
317bdd1243dSDimitry Andric   TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB)
318bdd1243dSDimitry Andric       : Builder(RB), AST(RB.Record->getASTContext()) {}
319bdd1243dSDimitry Andric 
320bdd1243dSDimitry Andric   ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
321bdd1243dSDimitry Andric 
322bdd1243dSDimitry Andric   TemplateParameterListBuilder &
323bdd1243dSDimitry Andric   addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
324bdd1243dSDimitry Andric     if (Builder.Record->isCompleteDefinition())
325bdd1243dSDimitry Andric       return *this;
326bdd1243dSDimitry Andric     unsigned Position = static_cast<unsigned>(Params.size());
327bdd1243dSDimitry Andric     auto *Decl = TemplateTypeParmDecl::Create(
328bdd1243dSDimitry Andric         AST, Builder.Record->getDeclContext(), SourceLocation(),
329bdd1243dSDimitry Andric         SourceLocation(), /* TemplateDepth */ 0, Position,
330bdd1243dSDimitry Andric         &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false,
331bdd1243dSDimitry Andric         /* ParameterPack */ false);
332bdd1243dSDimitry Andric     if (!DefaultValue.isNull())
333bdd1243dSDimitry Andric       Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue));
334bdd1243dSDimitry Andric 
335bdd1243dSDimitry Andric     Params.emplace_back(Decl);
336bdd1243dSDimitry Andric     return *this;
337bdd1243dSDimitry Andric   }
338bdd1243dSDimitry Andric 
339bdd1243dSDimitry Andric   BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
340bdd1243dSDimitry Andric     if (Params.empty())
341bdd1243dSDimitry Andric       return Builder;
342bdd1243dSDimitry Andric     auto *ParamList =
343bdd1243dSDimitry Andric         TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
344bdd1243dSDimitry Andric                                       Params, SourceLocation(), nullptr);
345bdd1243dSDimitry Andric     Builder.Template = ClassTemplateDecl::Create(
346bdd1243dSDimitry Andric         AST, Builder.Record->getDeclContext(), SourceLocation(),
347bdd1243dSDimitry Andric         DeclarationName(Builder.Record->getIdentifier()), ParamList,
348bdd1243dSDimitry Andric         Builder.Record);
349bdd1243dSDimitry Andric     Builder.Record->setDescribedClassTemplate(Builder.Template);
350bdd1243dSDimitry Andric     Builder.Template->setImplicit(true);
351bdd1243dSDimitry Andric     Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
352bdd1243dSDimitry Andric     // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
353bdd1243dSDimitry Andric     // make visible.
354bdd1243dSDimitry Andric     Builder.Template->setPreviousDecl(Builder.PrevTemplate);
355bdd1243dSDimitry Andric     Builder.Record->getDeclContext()->addDecl(Builder.Template);
356bdd1243dSDimitry Andric     Params.clear();
357bdd1243dSDimitry Andric 
358bdd1243dSDimitry Andric     QualType T = Builder.Template->getInjectedClassNameSpecialization();
359bdd1243dSDimitry Andric     T = AST.getInjectedClassNameType(Builder.Record, T);
360bdd1243dSDimitry Andric 
361bdd1243dSDimitry Andric     return Builder;
362bdd1243dSDimitry Andric   }
363bdd1243dSDimitry Andric };
364*5f757f3fSDimitry Andric } // namespace
365bdd1243dSDimitry Andric 
366bdd1243dSDimitry Andric TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
367bdd1243dSDimitry Andric   return TemplateParameterListBuilder(*this);
368bdd1243dSDimitry Andric }
369*5f757f3fSDimitry Andric 
370*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder &
371*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names) {
372*5f757f3fSDimitry Andric   TemplateParameterListBuilder Builder = this->addTemplateArgumentList();
373*5f757f3fSDimitry Andric   for (StringRef Name : Names)
374*5f757f3fSDimitry Andric     Builder.addTypeParameter(Name);
375*5f757f3fSDimitry Andric   return Builder.finalizeTemplateArgs();
376*5f757f3fSDimitry Andric }
377753f127fSDimitry Andric 
378753f127fSDimitry Andric HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
379753f127fSDimitry Andric 
380753f127fSDimitry Andric void HLSLExternalSemaSource::InitializeSema(Sema &S) {
381753f127fSDimitry Andric   SemaPtr = &S;
382753f127fSDimitry Andric   ASTContext &AST = SemaPtr->getASTContext();
383bdd1243dSDimitry Andric   // If the translation unit has external storage force external decls to load.
384bdd1243dSDimitry Andric   if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
385bdd1243dSDimitry Andric     (void)AST.getTranslationUnitDecl()->decls_begin();
386bdd1243dSDimitry Andric 
387753f127fSDimitry Andric   IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
388bdd1243dSDimitry Andric   LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
389bdd1243dSDimitry Andric   NamespaceDecl *PrevDecl = nullptr;
390bdd1243dSDimitry Andric   if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
391bdd1243dSDimitry Andric     PrevDecl = Result.getAsSingle<NamespaceDecl>();
392bdd1243dSDimitry Andric   HLSLNamespace = NamespaceDecl::Create(
393bdd1243dSDimitry Andric       AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
394bdd1243dSDimitry Andric       SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
395753f127fSDimitry Andric   HLSLNamespace->setImplicit(true);
396bdd1243dSDimitry Andric   HLSLNamespace->setHasExternalLexicalStorage();
397753f127fSDimitry Andric   AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
398bdd1243dSDimitry Andric 
399bdd1243dSDimitry Andric   // Force external decls in the HLSL namespace to load from the PCH.
400bdd1243dSDimitry Andric   (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
401bdd1243dSDimitry Andric   defineTrivialHLSLTypes();
402*5f757f3fSDimitry Andric   defineHLSLTypesWithForwardDeclarations();
403753f127fSDimitry Andric 
404753f127fSDimitry Andric   // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
405753f127fSDimitry Andric   // built in types inside a namespace, but we are planning to change that in
406753f127fSDimitry Andric   // the near future. In order to be source compatible older versions of HLSL
407753f127fSDimitry Andric   // will need to implicitly use the hlsl namespace. For now in clang everything
408753f127fSDimitry Andric   // will get added to the namespace, and we can remove the using directive for
409753f127fSDimitry Andric   // future language versions to match HLSL's evolution.
410753f127fSDimitry Andric   auto *UsingDecl = UsingDirectiveDecl::Create(
411753f127fSDimitry Andric       AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
412753f127fSDimitry Andric       NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
413753f127fSDimitry Andric       AST.getTranslationUnitDecl());
414753f127fSDimitry Andric 
415753f127fSDimitry Andric   AST.getTranslationUnitDecl()->addDecl(UsingDecl);
416753f127fSDimitry Andric }
417753f127fSDimitry Andric 
418753f127fSDimitry Andric void HLSLExternalSemaSource::defineHLSLVectorAlias() {
419753f127fSDimitry Andric   ASTContext &AST = SemaPtr->getASTContext();
420753f127fSDimitry Andric 
421753f127fSDimitry Andric   llvm::SmallVector<NamedDecl *> TemplateParams;
422753f127fSDimitry Andric 
423753f127fSDimitry Andric   auto *TypeParam = TemplateTypeParmDecl::Create(
424753f127fSDimitry Andric       AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
425753f127fSDimitry Andric       &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
426753f127fSDimitry Andric   TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy));
427753f127fSDimitry Andric 
428753f127fSDimitry Andric   TemplateParams.emplace_back(TypeParam);
429753f127fSDimitry Andric 
430753f127fSDimitry Andric   auto *SizeParam = NonTypeTemplateParmDecl::Create(
431753f127fSDimitry Andric       AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
432753f127fSDimitry Andric       &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
433753f127fSDimitry Andric       false, AST.getTrivialTypeSourceInfo(AST.IntTy));
434753f127fSDimitry Andric   Expr *LiteralExpr =
435753f127fSDimitry Andric       IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
436753f127fSDimitry Andric                              AST.IntTy, SourceLocation());
437753f127fSDimitry Andric   SizeParam->setDefaultArgument(LiteralExpr);
438753f127fSDimitry Andric   TemplateParams.emplace_back(SizeParam);
439753f127fSDimitry Andric 
440753f127fSDimitry Andric   auto *ParamList =
441753f127fSDimitry Andric       TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
442753f127fSDimitry Andric                                     TemplateParams, SourceLocation(), nullptr);
443753f127fSDimitry Andric 
444753f127fSDimitry Andric   IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
445753f127fSDimitry Andric 
446753f127fSDimitry Andric   QualType AliasType = AST.getDependentSizedExtVectorType(
447753f127fSDimitry Andric       AST.getTemplateTypeParmType(0, 0, false, TypeParam),
448753f127fSDimitry Andric       DeclRefExpr::Create(
449753f127fSDimitry Andric           AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
450753f127fSDimitry Andric           DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
451753f127fSDimitry Andric           AST.IntTy, VK_LValue),
452753f127fSDimitry Andric       SourceLocation());
453753f127fSDimitry Andric 
454753f127fSDimitry Andric   auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
455753f127fSDimitry Andric                                        SourceLocation(), &II,
456753f127fSDimitry Andric                                        AST.getTrivialTypeSourceInfo(AliasType));
457753f127fSDimitry Andric   Record->setImplicit(true);
458753f127fSDimitry Andric 
459753f127fSDimitry Andric   auto *Template =
460753f127fSDimitry Andric       TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
461753f127fSDimitry Andric                                     Record->getIdentifier(), ParamList, Record);
462753f127fSDimitry Andric 
463753f127fSDimitry Andric   Record->setDescribedAliasTemplate(Template);
464753f127fSDimitry Andric   Template->setImplicit(true);
465753f127fSDimitry Andric   Template->setLexicalDeclContext(Record->getDeclContext());
466753f127fSDimitry Andric   HLSLNamespace->addDecl(Template);
467753f127fSDimitry Andric }
468bdd1243dSDimitry Andric 
469bdd1243dSDimitry Andric void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
470bdd1243dSDimitry Andric   defineHLSLVectorAlias();
471bdd1243dSDimitry Andric 
472bdd1243dSDimitry Andric   ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource")
473bdd1243dSDimitry Andric                      .startDefinition()
474bdd1243dSDimitry Andric                      .addHandleMember(AccessSpecifier::AS_public)
475bdd1243dSDimitry Andric                      .completeDefinition()
476bdd1243dSDimitry Andric                      .Record;
477bdd1243dSDimitry Andric }
478bdd1243dSDimitry Andric 
479*5f757f3fSDimitry Andric /// Set up common members and attributes for buffer types
480*5f757f3fSDimitry Andric static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
481*5f757f3fSDimitry Andric                                               ResourceClass RC, ResourceKind RK,
482*5f757f3fSDimitry Andric                                               bool IsROV) {
483*5f757f3fSDimitry Andric   return BuiltinTypeDeclBuilder(Decl)
484*5f757f3fSDimitry Andric       .addHandleMember()
485*5f757f3fSDimitry Andric       .addDefaultHandleConstructor(S, RC)
486*5f757f3fSDimitry Andric       .annotateResourceClass(RC, RK, IsROV);
487*5f757f3fSDimitry Andric }
488*5f757f3fSDimitry Andric 
489*5f757f3fSDimitry Andric void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
490bdd1243dSDimitry Andric   CXXRecordDecl *Decl;
491bdd1243dSDimitry Andric   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
492*5f757f3fSDimitry Andric              .addSimpleTemplateParams({"element_type"})
493bdd1243dSDimitry Andric              .Record;
494*5f757f3fSDimitry Andric   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
495*5f757f3fSDimitry Andric     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
496*5f757f3fSDimitry Andric                     ResourceKind::TypedBuffer, /*IsROV=*/false)
497*5f757f3fSDimitry Andric         .addArraySubscriptOperators()
498*5f757f3fSDimitry Andric         .completeDefinition();
499*5f757f3fSDimitry Andric   });
500*5f757f3fSDimitry Andric 
501*5f757f3fSDimitry Andric   Decl =
502*5f757f3fSDimitry Andric       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
503*5f757f3fSDimitry Andric           .addSimpleTemplateParams({"element_type"})
504*5f757f3fSDimitry Andric           .Record;
505*5f757f3fSDimitry Andric   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
506*5f757f3fSDimitry Andric     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
507*5f757f3fSDimitry Andric                     ResourceKind::TypedBuffer, /*IsROV=*/true)
508*5f757f3fSDimitry Andric         .addArraySubscriptOperators()
509*5f757f3fSDimitry Andric         .completeDefinition();
510*5f757f3fSDimitry Andric   });
511*5f757f3fSDimitry Andric }
512*5f757f3fSDimitry Andric 
513*5f757f3fSDimitry Andric void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
514*5f757f3fSDimitry Andric                                           CompletionFunction Fn) {
515*5f757f3fSDimitry Andric   Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
516bdd1243dSDimitry Andric }
517bdd1243dSDimitry Andric 
518bdd1243dSDimitry Andric void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
519bdd1243dSDimitry Andric   if (!isa<CXXRecordDecl>(Tag))
520bdd1243dSDimitry Andric     return;
521bdd1243dSDimitry Andric   auto Record = cast<CXXRecordDecl>(Tag);
522bdd1243dSDimitry Andric 
523bdd1243dSDimitry Andric   // If this is a specialization, we need to get the underlying templated
524bdd1243dSDimitry Andric   // declaration and complete that.
525bdd1243dSDimitry Andric   if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
526bdd1243dSDimitry Andric     Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
527bdd1243dSDimitry Andric   Record = Record->getCanonicalDecl();
528bdd1243dSDimitry Andric   auto It = Completions.find(Record);
529bdd1243dSDimitry Andric   if (It == Completions.end())
530bdd1243dSDimitry Andric     return;
531bdd1243dSDimitry Andric   It->second(Record);
532bdd1243dSDimitry Andric }
533