1 | //===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // |
10 | //===----------------------------------------------------------------------===// |
11 | |
12 | #include "clang/Sema/HLSLExternalSemaSource.h" |
13 | #include "clang/AST/ASTContext.h" |
14 | #include "clang/AST/Attr.h" |
15 | #include "clang/AST/DeclCXX.h" |
16 | #include "clang/Basic/AttrKinds.h" |
17 | #include "clang/Basic/HLSLRuntime.h" |
18 | #include "clang/Sema/Lookup.h" |
19 | #include "clang/Sema/Sema.h" |
20 | #include "llvm/Frontend/HLSL/HLSLResource.h" |
21 | |
22 | #include <functional> |
23 | |
24 | using namespace clang; |
25 | using namespace llvm::hlsl; |
26 | |
27 | namespace { |
28 | |
29 | struct TemplateParameterListBuilder; |
30 | |
31 | struct BuiltinTypeDeclBuilder { |
32 | CXXRecordDecl *Record = nullptr; |
33 | ClassTemplateDecl *Template = nullptr; |
34 | ClassTemplateDecl *PrevTemplate = nullptr; |
35 | NamespaceDecl *HLSLNamespace = nullptr; |
36 | llvm::StringMap<FieldDecl *> Fields; |
37 | |
38 | BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) { |
39 | Record->startDefinition(); |
40 | Template = Record->getDescribedClassTemplate(); |
41 | } |
42 | |
43 | BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name) |
44 | : HLSLNamespace(Namespace) { |
45 | ASTContext &AST = S.getASTContext(); |
46 | IdentifierInfo &II = AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier); |
47 | |
48 | LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName); |
49 | CXXRecordDecl *PrevDecl = nullptr; |
50 | if (S.LookupQualifiedName(R&: Result, LookupCtx: HLSLNamespace)) { |
51 | NamedDecl *Found = Result.getFoundDecl(); |
52 | if (auto *TD = dyn_cast<ClassTemplateDecl>(Val: Found)) { |
53 | PrevDecl = TD->getTemplatedDecl(); |
54 | PrevTemplate = TD; |
55 | } else |
56 | PrevDecl = dyn_cast<CXXRecordDecl>(Val: Found); |
57 | assert(PrevDecl && "Unexpected lookup result type." ); |
58 | } |
59 | |
60 | if (PrevDecl && PrevDecl->isCompleteDefinition()) { |
61 | Record = PrevDecl; |
62 | return; |
63 | } |
64 | |
65 | Record = CXXRecordDecl::Create(C: AST, TK: TagDecl::TagKind::Class, DC: HLSLNamespace, |
66 | StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &II, |
67 | PrevDecl, DelayTypeCreation: true); |
68 | Record->setImplicit(true); |
69 | Record->setLexicalDeclContext(HLSLNamespace); |
70 | Record->setHasExternalLexicalStorage(); |
71 | |
72 | // Don't let anyone derive from built-in types. |
73 | Record->addAttr(A: FinalAttr::CreateImplicit(Ctx&: AST, Range: SourceRange(), |
74 | S: FinalAttr::Keyword_final)); |
75 | } |
76 | |
77 | ~BuiltinTypeDeclBuilder() { |
78 | if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace) |
79 | HLSLNamespace->addDecl(D: Record); |
80 | } |
81 | |
82 | BuiltinTypeDeclBuilder & |
83 | addMemberVariable(StringRef Name, QualType Type, |
84 | AccessSpecifier Access = AccessSpecifier::AS_private) { |
85 | if (Record->isCompleteDefinition()) |
86 | return *this; |
87 | assert(Record->isBeingDefined() && |
88 | "Definition must be started before adding members!" ); |
89 | ASTContext &AST = Record->getASTContext(); |
90 | |
91 | IdentifierInfo &II = AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier); |
92 | TypeSourceInfo *MemTySource = |
93 | AST.getTrivialTypeSourceInfo(T: Type, Loc: SourceLocation()); |
94 | auto *Field = FieldDecl::Create( |
95 | C: AST, DC: Record, StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &II, T: Type, TInfo: MemTySource, |
96 | BW: nullptr, Mutable: false, InitStyle: InClassInitStyle::ICIS_NoInit); |
97 | Field->setAccess(Access); |
98 | Field->setImplicit(true); |
99 | Record->addDecl(D: Field); |
100 | Fields[Name] = Field; |
101 | return *this; |
102 | } |
103 | |
104 | BuiltinTypeDeclBuilder & |
105 | addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) { |
106 | if (Record->isCompleteDefinition()) |
107 | return *this; |
108 | QualType Ty = Record->getASTContext().VoidPtrTy; |
109 | if (Template) { |
110 | if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>( |
111 | Val: Template->getTemplateParameters()->getParam(Idx: 0))) |
112 | Ty = Record->getASTContext().getPointerType( |
113 | T: QualType(TTD->getTypeForDecl(), 0)); |
114 | } |
115 | return addMemberVariable(Name: "h" , Type: Ty, Access); |
116 | } |
117 | |
118 | BuiltinTypeDeclBuilder &annotateHLSLResource(ResourceClass RC, |
119 | ResourceKind RK, bool IsROV) { |
120 | if (Record->isCompleteDefinition()) |
121 | return *this; |
122 | Record->addAttr( |
123 | A: HLSLResourceClassAttr::CreateImplicit(Ctx&: Record->getASTContext(), ResourceClass: RC)); |
124 | Record->addAttr( |
125 | A: HLSLResourceAttr::CreateImplicit(Ctx&: Record->getASTContext(), ResourceKind: RK, IsROV)); |
126 | return *this; |
127 | } |
128 | |
129 | static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, |
130 | StringRef Name) { |
131 | IdentifierInfo &II = AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier); |
132 | DeclarationNameInfo NameInfo = |
133 | DeclarationNameInfo(DeclarationName(&II), SourceLocation()); |
134 | LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); |
135 | // AllowBuiltinCreation is false but LookupDirect will create |
136 | // the builtin when searching the global scope anyways... |
137 | S.LookupName(R, S: S.getCurScope()); |
138 | // FIXME: If the builtin function was user-declared in global scope, |
139 | // this assert *will* fail. Should this call LookupBuiltin instead? |
140 | assert(R.isSingleResult() && |
141 | "Since this is a builtin it should always resolve!" ); |
142 | auto *VD = cast<ValueDecl>(Val: R.getFoundDecl()); |
143 | QualType Ty = VD->getType(); |
144 | return DeclRefExpr::Create(Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), |
145 | D: VD, RefersToEnclosingVariableOrCapture: false, NameInfo, T: Ty, VK: VK_PRValue); |
146 | } |
147 | |
148 | static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) { |
149 | return IntegerLiteral::Create( |
150 | C: AST, |
151 | V: llvm::APInt(AST.getIntWidth(T: AST.UnsignedCharTy), |
152 | static_cast<uint8_t>(RC)), |
153 | type: AST.UnsignedCharTy, l: SourceLocation()); |
154 | } |
155 | |
156 | BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S, |
157 | ResourceClass RC) { |
158 | if (Record->isCompleteDefinition()) |
159 | return *this; |
160 | ASTContext &AST = Record->getASTContext(); |
161 | |
162 | QualType ConstructorType = |
163 | AST.getFunctionType(ResultTy: AST.VoidTy, Args: {}, EPI: FunctionProtoType::ExtProtoInfo()); |
164 | |
165 | CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); |
166 | DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(Ty: CanTy); |
167 | CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( |
168 | C&: AST, RD: Record, StartLoc: SourceLocation(), |
169 | NameInfo: DeclarationNameInfo(Name, SourceLocation()), T: ConstructorType, |
170 | TInfo: AST.getTrivialTypeSourceInfo(T: ConstructorType, Loc: SourceLocation()), |
171 | ES: ExplicitSpecifier(), UsesFPIntrin: false, isInline: true, isImplicitlyDeclared: false, |
172 | ConstexprKind: ConstexprSpecKind::Unspecified); |
173 | |
174 | DeclRefExpr *Fn = |
175 | lookupBuiltinFunction(AST, S, Name: "__builtin_hlsl_create_handle" ); |
176 | Expr *RCExpr = emitResourceClassExpr(AST, RC); |
177 | Expr *Call = CallExpr::Create(Ctx: AST, Fn, Args: {RCExpr}, Ty: AST.VoidPtrTy, VK: VK_PRValue, |
178 | RParenLoc: SourceLocation(), FPFeatures: FPOptionsOverride()); |
179 | |
180 | CXXThisExpr *This = CXXThisExpr::Create( |
181 | Ctx: AST, L: SourceLocation(), Ty: Constructor->getFunctionObjectParameterType(), |
182 | IsImplicit: true); |
183 | Expr *Handle = MemberExpr::CreateImplicit(C: AST, Base: This, IsArrow: false, MemberDecl: Fields["h" ], |
184 | T: Fields["h" ]->getType(), VK: VK_LValue, |
185 | OK: OK_Ordinary); |
186 | |
187 | // If the handle isn't a void pointer, cast the builtin result to the |
188 | // correct type. |
189 | if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) { |
190 | Call = CXXStaticCastExpr::Create( |
191 | Context: AST, T: Handle->getType(), VK: VK_PRValue, K: CK_Dependent, Op: Call, Path: nullptr, |
192 | Written: AST.getTrivialTypeSourceInfo(T: Handle->getType(), Loc: SourceLocation()), |
193 | FPO: FPOptionsOverride(), L: SourceLocation(), RParenLoc: SourceLocation(), |
194 | AngleBrackets: SourceRange()); |
195 | } |
196 | |
197 | BinaryOperator *Assign = BinaryOperator::Create( |
198 | C: AST, lhs: Handle, rhs: Call, opc: BO_Assign, ResTy: Handle->getType(), VK: VK_LValue, OK: OK_Ordinary, |
199 | opLoc: SourceLocation(), FPFeatures: FPOptionsOverride()); |
200 | |
201 | Constructor->setBody( |
202 | CompoundStmt::Create(C: AST, Stmts: {Assign}, FPFeatures: FPOptionsOverride(), |
203 | LB: SourceLocation(), RB: SourceLocation())); |
204 | Constructor->setAccess(AccessSpecifier::AS_public); |
205 | Record->addDecl(D: Constructor); |
206 | return *this; |
207 | } |
208 | |
209 | BuiltinTypeDeclBuilder &addArraySubscriptOperators() { |
210 | if (Record->isCompleteDefinition()) |
211 | return *this; |
212 | addArraySubscriptOperator(IsConst: true); |
213 | addArraySubscriptOperator(IsConst: false); |
214 | return *this; |
215 | } |
216 | |
217 | BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) { |
218 | if (Record->isCompleteDefinition()) |
219 | return *this; |
220 | assert(Fields.count("h" ) > 0 && |
221 | "Subscript operator must be added after the handle." ); |
222 | |
223 | FieldDecl *Handle = Fields["h" ]; |
224 | ASTContext &AST = Record->getASTContext(); |
225 | |
226 | assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy && |
227 | "Not yet supported for void pointer handles." ); |
228 | |
229 | QualType ElemTy = |
230 | QualType(Handle->getType()->getPointeeOrArrayElementType(), 0); |
231 | QualType ReturnTy = ElemTy; |
232 | |
233 | FunctionProtoType::ExtProtoInfo ExtInfo; |
234 | |
235 | // Subscript operators return references to elements, const makes the |
236 | // reference and method const so that the underlying data is not mutable. |
237 | ReturnTy = AST.getLValueReferenceType(T: ReturnTy); |
238 | if (IsConst) { |
239 | ExtInfo.TypeQuals.addConst(); |
240 | ReturnTy.addConst(); |
241 | } |
242 | |
243 | QualType MethodTy = |
244 | AST.getFunctionType(ResultTy: ReturnTy, Args: {AST.UnsignedIntTy}, EPI: ExtInfo); |
245 | auto *TSInfo = AST.getTrivialTypeSourceInfo(T: MethodTy, Loc: SourceLocation()); |
246 | auto *MethodDecl = CXXMethodDecl::Create( |
247 | C&: AST, RD: Record, StartLoc: SourceLocation(), |
248 | NameInfo: DeclarationNameInfo( |
249 | AST.DeclarationNames.getCXXOperatorName(Op: OO_Subscript), |
250 | SourceLocation()), |
251 | T: MethodTy, TInfo: TSInfo, SC: SC_None, UsesFPIntrin: false, isInline: false, ConstexprKind: ConstexprSpecKind::Unspecified, |
252 | EndLocation: SourceLocation()); |
253 | |
254 | IdentifierInfo &II = AST.Idents.get(Name: "Idx" , TokenCode: tok::TokenKind::identifier); |
255 | auto *IdxParam = ParmVarDecl::Create( |
256 | C&: AST, DC: MethodDecl->getDeclContext(), StartLoc: SourceLocation(), IdLoc: SourceLocation(), |
257 | Id: &II, T: AST.UnsignedIntTy, |
258 | TInfo: AST.getTrivialTypeSourceInfo(T: AST.UnsignedIntTy, Loc: SourceLocation()), |
259 | S: SC_None, DefArg: nullptr); |
260 | MethodDecl->setParams({IdxParam}); |
261 | |
262 | // Also add the parameter to the function prototype. |
263 | auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>(); |
264 | FnProtoLoc.setParam(i: 0, VD: IdxParam); |
265 | |
266 | auto *This = |
267 | CXXThisExpr::Create(Ctx: AST, L: SourceLocation(), |
268 | Ty: MethodDecl->getFunctionObjectParameterType(), IsImplicit: true); |
269 | auto *HandleAccess = MemberExpr::CreateImplicit( |
270 | C: AST, Base: This, IsArrow: false, MemberDecl: Handle, T: Handle->getType(), VK: VK_LValue, OK: OK_Ordinary); |
271 | |
272 | auto *IndexExpr = DeclRefExpr::Create( |
273 | Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: IdxParam, RefersToEnclosingVariableOrCapture: false, |
274 | NameInfo: DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()), |
275 | T: AST.UnsignedIntTy, VK: VK_PRValue); |
276 | |
277 | auto *Array = |
278 | new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue, |
279 | OK_Ordinary, SourceLocation()); |
280 | |
281 | auto *Return = ReturnStmt::Create(Ctx: AST, RL: SourceLocation(), E: Array, NRVOCandidate: nullptr); |
282 | |
283 | MethodDecl->setBody(CompoundStmt::Create(C: AST, Stmts: {Return}, FPFeatures: FPOptionsOverride(), |
284 | LB: SourceLocation(), |
285 | RB: SourceLocation())); |
286 | MethodDecl->setLexicalDeclContext(Record); |
287 | MethodDecl->setAccess(AccessSpecifier::AS_public); |
288 | MethodDecl->addAttr(A: AlwaysInlineAttr::CreateImplicit( |
289 | Ctx&: AST, Range: SourceRange(), S: AlwaysInlineAttr::CXX11_clang_always_inline)); |
290 | Record->addDecl(D: MethodDecl); |
291 | |
292 | return *this; |
293 | } |
294 | |
295 | BuiltinTypeDeclBuilder &startDefinition() { |
296 | if (Record->isCompleteDefinition()) |
297 | return *this; |
298 | Record->startDefinition(); |
299 | return *this; |
300 | } |
301 | |
302 | BuiltinTypeDeclBuilder &completeDefinition() { |
303 | if (Record->isCompleteDefinition()) |
304 | return *this; |
305 | assert(Record->isBeingDefined() && |
306 | "Definition must be started before completing it." ); |
307 | |
308 | Record->completeDefinition(); |
309 | return *this; |
310 | } |
311 | |
312 | TemplateParameterListBuilder addTemplateArgumentList(Sema &S); |
313 | BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S, |
314 | ArrayRef<StringRef> Names); |
315 | }; |
316 | |
317 | struct TemplateParameterListBuilder { |
318 | BuiltinTypeDeclBuilder &Builder; |
319 | Sema &S; |
320 | llvm::SmallVector<NamedDecl *> Params; |
321 | |
322 | TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB) |
323 | : Builder(RB), S(S) {} |
324 | |
325 | ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } |
326 | |
327 | TemplateParameterListBuilder & |
328 | addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) { |
329 | if (Builder.Record->isCompleteDefinition()) |
330 | return *this; |
331 | unsigned Position = static_cast<unsigned>(Params.size()); |
332 | auto *Decl = TemplateTypeParmDecl::Create( |
333 | C: S.Context, DC: Builder.Record->getDeclContext(), KeyLoc: SourceLocation(), |
334 | NameLoc: SourceLocation(), /* TemplateDepth */ D: 0, P: Position, |
335 | Id: &S.Context.Idents.get(Name, TokenCode: tok::TokenKind::identifier), |
336 | /* Typename */ false, |
337 | /* ParameterPack */ false); |
338 | if (!DefaultValue.isNull()) |
339 | Decl->setDefaultArgument( |
340 | C: S.Context, DefArg: S.getTrivialTemplateArgumentLoc(Arg: DefaultValue, NTTPType: QualType(), |
341 | Loc: SourceLocation())); |
342 | |
343 | Params.emplace_back(Args&: Decl); |
344 | return *this; |
345 | } |
346 | |
347 | BuiltinTypeDeclBuilder &finalizeTemplateArgs() { |
348 | if (Params.empty()) |
349 | return Builder; |
350 | auto *ParamList = TemplateParameterList::Create(C: S.Context, TemplateLoc: SourceLocation(), |
351 | LAngleLoc: SourceLocation(), Params, |
352 | RAngleLoc: SourceLocation(), RequiresClause: nullptr); |
353 | Builder.Template = ClassTemplateDecl::Create( |
354 | C&: S.Context, DC: Builder.Record->getDeclContext(), L: SourceLocation(), |
355 | Name: DeclarationName(Builder.Record->getIdentifier()), Params: ParamList, |
356 | Decl: Builder.Record); |
357 | Builder.Record->setDescribedClassTemplate(Builder.Template); |
358 | Builder.Template->setImplicit(true); |
359 | Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext()); |
360 | // NOTE: setPreviousDecl before addDecl so new decl replace old decl when |
361 | // make visible. |
362 | Builder.Template->setPreviousDecl(Builder.PrevTemplate); |
363 | Builder.Record->getDeclContext()->addDecl(D: Builder.Template); |
364 | Params.clear(); |
365 | |
366 | QualType T = Builder.Template->getInjectedClassNameSpecialization(); |
367 | T = S.Context.getInjectedClassNameType(Decl: Builder.Record, TST: T); |
368 | |
369 | return Builder; |
370 | } |
371 | }; |
372 | } // namespace |
373 | |
374 | TemplateParameterListBuilder |
375 | BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) { |
376 | return TemplateParameterListBuilder(S, *this); |
377 | } |
378 | |
379 | BuiltinTypeDeclBuilder & |
380 | BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S, |
381 | ArrayRef<StringRef> Names) { |
382 | TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S); |
383 | for (StringRef Name : Names) |
384 | Builder.addTypeParameter(Name); |
385 | return Builder.finalizeTemplateArgs(); |
386 | } |
387 | |
388 | HLSLExternalSemaSource::~HLSLExternalSemaSource() {} |
389 | |
390 | void HLSLExternalSemaSource::InitializeSema(Sema &S) { |
391 | SemaPtr = &S; |
392 | ASTContext &AST = SemaPtr->getASTContext(); |
393 | // If the translation unit has external storage force external decls to load. |
394 | if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage()) |
395 | (void)AST.getTranslationUnitDecl()->decls_begin(); |
396 | |
397 | IdentifierInfo &HLSL = AST.Idents.get(Name: "hlsl" , TokenCode: tok::TokenKind::identifier); |
398 | LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName); |
399 | NamespaceDecl *PrevDecl = nullptr; |
400 | if (S.LookupQualifiedName(R&: Result, LookupCtx: AST.getTranslationUnitDecl())) |
401 | PrevDecl = Result.getAsSingle<NamespaceDecl>(); |
402 | HLSLNamespace = NamespaceDecl::Create( |
403 | C&: AST, DC: AST.getTranslationUnitDecl(), /*Inline=*/false, StartLoc: SourceLocation(), |
404 | IdLoc: SourceLocation(), Id: &HLSL, PrevDecl, /*Nested=*/false); |
405 | HLSLNamespace->setImplicit(true); |
406 | HLSLNamespace->setHasExternalLexicalStorage(); |
407 | AST.getTranslationUnitDecl()->addDecl(D: HLSLNamespace); |
408 | |
409 | // Force external decls in the HLSL namespace to load from the PCH. |
410 | (void)HLSLNamespace->getCanonicalDecl()->decls_begin(); |
411 | defineTrivialHLSLTypes(); |
412 | defineHLSLTypesWithForwardDeclarations(); |
413 | |
414 | // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's |
415 | // built in types inside a namespace, but we are planning to change that in |
416 | // the near future. In order to be source compatible older versions of HLSL |
417 | // will need to implicitly use the hlsl namespace. For now in clang everything |
418 | // will get added to the namespace, and we can remove the using directive for |
419 | // future language versions to match HLSL's evolution. |
420 | auto *UsingDecl = UsingDirectiveDecl::Create( |
421 | C&: AST, DC: AST.getTranslationUnitDecl(), UsingLoc: SourceLocation(), NamespaceLoc: SourceLocation(), |
422 | QualifierLoc: NestedNameSpecifierLoc(), IdentLoc: SourceLocation(), Nominated: HLSLNamespace, |
423 | CommonAncestor: AST.getTranslationUnitDecl()); |
424 | |
425 | AST.getTranslationUnitDecl()->addDecl(D: UsingDecl); |
426 | } |
427 | |
428 | void HLSLExternalSemaSource::defineHLSLVectorAlias() { |
429 | ASTContext &AST = SemaPtr->getASTContext(); |
430 | |
431 | llvm::SmallVector<NamedDecl *> TemplateParams; |
432 | |
433 | auto *TypeParam = TemplateTypeParmDecl::Create( |
434 | C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0, |
435 | Id: &AST.Idents.get(Name: "element" , TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false); |
436 | TypeParam->setDefaultArgument( |
437 | C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc( |
438 | Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation())); |
439 | |
440 | TemplateParams.emplace_back(Args&: TypeParam); |
441 | |
442 | auto *SizeParam = NonTypeTemplateParmDecl::Create( |
443 | C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1, |
444 | Id: &AST.Idents.get(Name: "element_count" , TokenCode: tok::TokenKind::identifier), T: AST.IntTy, |
445 | ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy)); |
446 | llvm::APInt Val(AST.getIntWidth(T: AST.IntTy), 4); |
447 | TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy, |
448 | /*IsDefaulted=*/true); |
449 | SizeParam->setDefaultArgument( |
450 | C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: Default, NTTPType: AST.IntTy, |
451 | Loc: SourceLocation(), TemplateParam: SizeParam)); |
452 | TemplateParams.emplace_back(Args&: SizeParam); |
453 | |
454 | auto *ParamList = |
455 | TemplateParameterList::Create(C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), |
456 | Params: TemplateParams, RAngleLoc: SourceLocation(), RequiresClause: nullptr); |
457 | |
458 | IdentifierInfo &II = AST.Idents.get(Name: "vector" , TokenCode: tok::TokenKind::identifier); |
459 | |
460 | QualType AliasType = AST.getDependentSizedExtVectorType( |
461 | VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam), |
462 | SizeExpr: DeclRefExpr::Create( |
463 | Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: SizeParam, RefersToEnclosingVariableOrCapture: false, |
464 | NameInfo: DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()), |
465 | T: AST.IntTy, VK: VK_LValue), |
466 | AttrLoc: SourceLocation()); |
467 | |
468 | auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), |
469 | IdLoc: SourceLocation(), Id: &II, |
470 | TInfo: AST.getTrivialTypeSourceInfo(T: AliasType)); |
471 | Record->setImplicit(true); |
472 | |
473 | auto *Template = |
474 | TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(), |
475 | Name: Record->getIdentifier(), Params: ParamList, Decl: Record); |
476 | |
477 | Record->setDescribedAliasTemplate(Template); |
478 | Template->setImplicit(true); |
479 | Template->setLexicalDeclContext(Record->getDeclContext()); |
480 | HLSLNamespace->addDecl(D: Template); |
481 | } |
482 | |
483 | void HLSLExternalSemaSource::defineTrivialHLSLTypes() { |
484 | defineHLSLVectorAlias(); |
485 | } |
486 | |
487 | /// Set up common members and attributes for buffer types |
488 | static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, |
489 | ResourceClass RC, ResourceKind RK, |
490 | bool IsROV) { |
491 | return BuiltinTypeDeclBuilder(Decl) |
492 | .addHandleMember() |
493 | .addDefaultHandleConstructor(S, RC) |
494 | .annotateHLSLResource(RC, RK, IsROV); |
495 | } |
496 | |
497 | void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { |
498 | CXXRecordDecl *Decl; |
499 | Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer" ) |
500 | .addSimpleTemplateParams(S&: *SemaPtr, Names: {"element_type" }) |
501 | .Record; |
502 | onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) { |
503 | setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, |
504 | RK: ResourceKind::TypedBuffer, /*IsROV=*/false) |
505 | .addArraySubscriptOperators() |
506 | .completeDefinition(); |
507 | }); |
508 | |
509 | Decl = |
510 | BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer" ) |
511 | .addSimpleTemplateParams(S&: *SemaPtr, Names: {"element_type" }) |
512 | .Record; |
513 | onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) { |
514 | setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, |
515 | RK: ResourceKind::TypedBuffer, /*IsROV=*/true) |
516 | .addArraySubscriptOperators() |
517 | .completeDefinition(); |
518 | }); |
519 | } |
520 | |
521 | void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record, |
522 | CompletionFunction Fn) { |
523 | Completions.insert(KV: std::make_pair(x: Record->getCanonicalDecl(), y&: Fn)); |
524 | } |
525 | |
526 | void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) { |
527 | if (!isa<CXXRecordDecl>(Val: Tag)) |
528 | return; |
529 | auto Record = cast<CXXRecordDecl>(Val: Tag); |
530 | |
531 | // If this is a specialization, we need to get the underlying templated |
532 | // declaration and complete that. |
533 | if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Val: Record)) |
534 | Record = TDecl->getSpecializedTemplate()->getTemplatedDecl(); |
535 | Record = Record->getCanonicalDecl(); |
536 | auto It = Completions.find(Val: Record); |
537 | if (It == Completions.end()) |
538 | return; |
539 | It->second(Record); |
540 | } |
541 | |