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