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
24using namespace clang;
25using namespace llvm::hlsl;
26
27namespace {
28
29struct TemplateParameterListBuilder;
30
31struct 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
317struct 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
374TemplateParameterListBuilder
375BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
376 return TemplateParameterListBuilder(S, *this);
377}
378
379BuiltinTypeDeclBuilder &
380BuiltinTypeDeclBuilder::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
388HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
389
390void 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
428void 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
483void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
484 defineHLSLVectorAlias();
485}
486
487/// Set up common members and attributes for buffer types
488static 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
497void 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
521void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
522 CompletionFunction Fn) {
523 Completions.insert(KV: std::make_pair(x: Record->getCanonicalDecl(), y&: Fn));
524}
525
526void 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