Rename GetLanguageInfo to GetLanguageSpecificData (#117012)
[llvm-project.git] / clang / lib / Sema / HLSLExternalSemaSource.cpp
bloba14e7d50a6043ff18be5307747285286c39a5fe4
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 //===----------------------------------------------------------------------===//
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/AST/Type.h"
17 #include "clang/Basic/SourceLocation.h"
18 #include "clang/Sema/Lookup.h"
19 #include "clang/Sema/Sema.h"
20 #include "clang/Sema/SemaHLSL.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Frontend/HLSL/HLSLResource.h"
24 #include <functional>
26 using namespace clang;
27 using namespace llvm::hlsl;
29 namespace {
31 struct TemplateParameterListBuilder;
33 struct BuiltinTypeDeclBuilder {
34 CXXRecordDecl *Record = nullptr;
35 ClassTemplateDecl *Template = nullptr;
36 ClassTemplateDecl *PrevTemplate = nullptr;
37 NamespaceDecl *HLSLNamespace = nullptr;
38 llvm::StringMap<FieldDecl *> Fields;
40 BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
41 Record->startDefinition();
42 Template = Record->getDescribedClassTemplate();
45 BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
46 : HLSLNamespace(Namespace) {
47 ASTContext &AST = S.getASTContext();
48 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
50 LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
51 CXXRecordDecl *PrevDecl = nullptr;
52 if (S.LookupQualifiedName(Result, HLSLNamespace)) {
53 NamedDecl *Found = Result.getFoundDecl();
54 if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
55 PrevDecl = TD->getTemplatedDecl();
56 PrevTemplate = TD;
57 } else
58 PrevDecl = dyn_cast<CXXRecordDecl>(Found);
59 assert(PrevDecl && "Unexpected lookup result type.");
62 if (PrevDecl && PrevDecl->isCompleteDefinition()) {
63 Record = PrevDecl;
64 return;
67 Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
68 SourceLocation(), SourceLocation(), &II,
69 PrevDecl, true);
70 Record->setImplicit(true);
71 Record->setLexicalDeclContext(HLSLNamespace);
72 Record->setHasExternalLexicalStorage();
74 // Don't let anyone derive from built-in types.
75 Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
76 FinalAttr::Keyword_final));
79 ~BuiltinTypeDeclBuilder() {
80 if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
81 HLSLNamespace->addDecl(Record);
84 BuiltinTypeDeclBuilder &
85 addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
86 AccessSpecifier Access = AccessSpecifier::AS_private) {
87 if (Record->isCompleteDefinition())
88 return *this;
89 assert(Record->isBeingDefined() &&
90 "Definition must be started before adding members!");
91 ASTContext &AST = Record->getASTContext();
93 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
94 TypeSourceInfo *MemTySource =
95 AST.getTrivialTypeSourceInfo(Type, SourceLocation());
96 auto *Field = FieldDecl::Create(
97 AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
98 nullptr, false, InClassInitStyle::ICIS_NoInit);
99 Field->setAccess(Access);
100 Field->setImplicit(true);
101 for (Attr *A : Attrs) {
102 if (A)
103 Field->addAttr(A);
106 Record->addDecl(Field);
107 Fields[Name] = Field;
108 return *this;
111 BuiltinTypeDeclBuilder &
112 addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
113 bool RawBuffer,
114 AccessSpecifier Access = AccessSpecifier::AS_private) {
115 if (Record->isCompleteDefinition())
116 return *this;
118 ASTContext &Ctx = S.getASTContext();
119 TypeSourceInfo *ElementTypeInfo = nullptr;
121 QualType ElemTy = Ctx.Char8Ty;
122 if (Template) {
123 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
124 Template->getTemplateParameters()->getParam(0))) {
125 ElemTy = QualType(TTD->getTypeForDecl(), 0);
128 ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
130 // add handle member with resource type attributes
131 QualType AttributedResTy = QualType();
132 SmallVector<const Attr *> Attrs = {
133 HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
134 IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
135 RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
136 ElementTypeInfo
137 ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
138 : nullptr};
139 Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
140 if (CreateHLSLAttributedResourceType(S, Ctx.HLSLResourceTy, Attrs,
141 AttributedResTy))
142 addMemberVariable("__handle", AttributedResTy, {ResourceAttr}, Access);
143 return *this;
146 static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
147 StringRef Name) {
148 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
149 DeclarationNameInfo NameInfo =
150 DeclarationNameInfo(DeclarationName(&II), SourceLocation());
151 LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
152 // AllowBuiltinCreation is false but LookupDirect will create
153 // the builtin when searching the global scope anyways...
154 S.LookupName(R, S.getCurScope());
155 // FIXME: If the builtin function was user-declared in global scope,
156 // this assert *will* fail. Should this call LookupBuiltin instead?
157 assert(R.isSingleResult() &&
158 "Since this is a builtin it should always resolve!");
159 auto *VD = cast<ValueDecl>(R.getFoundDecl());
160 QualType Ty = VD->getType();
161 return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
162 VD, false, NameInfo, Ty, VK_PRValue);
165 BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S) {
166 if (Record->isCompleteDefinition())
167 return *this;
168 ASTContext &AST = Record->getASTContext();
170 QualType ConstructorType =
171 AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
173 CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
174 DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
175 CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
176 AST, Record, SourceLocation(),
177 DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
178 AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
179 ExplicitSpecifier(), false, true, false,
180 ConstexprSpecKind::Unspecified);
182 Constructor->setBody(CompoundStmt::Create(
183 AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
184 Constructor->setAccess(AccessSpecifier::AS_public);
185 Record->addDecl(Constructor);
186 return *this;
189 BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
190 if (Record->isCompleteDefinition())
191 return *this;
192 addArraySubscriptOperator(true);
193 addArraySubscriptOperator(false);
194 return *this;
197 BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
198 if (Record->isCompleteDefinition())
199 return *this;
201 ASTContext &AST = Record->getASTContext();
202 QualType ElemTy = AST.Char8Ty;
203 if (Template) {
204 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
205 Template->getTemplateParameters()->getParam(0))) {
206 ElemTy = QualType(TTD->getTypeForDecl(), 0);
209 QualType ReturnTy = ElemTy;
211 FunctionProtoType::ExtProtoInfo ExtInfo;
213 // Subscript operators return references to elements, const makes the
214 // reference and method const so that the underlying data is not mutable.
215 if (IsConst) {
216 ExtInfo.TypeQuals.addConst();
217 ReturnTy.addConst();
219 ReturnTy = AST.getLValueReferenceType(ReturnTy);
221 QualType MethodTy =
222 AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
223 auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
224 auto *MethodDecl = CXXMethodDecl::Create(
225 AST, Record, SourceLocation(),
226 DeclarationNameInfo(
227 AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
228 SourceLocation()),
229 MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
230 SourceLocation());
232 IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
233 auto *IdxParam = ParmVarDecl::Create(
234 AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
235 &II, AST.UnsignedIntTy,
236 AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
237 SC_None, nullptr);
238 MethodDecl->setParams({IdxParam});
240 // Also add the parameter to the function prototype.
241 auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
242 FnProtoLoc.setParam(0, IdxParam);
244 // FIXME: Placeholder to make sure we return the correct type - create
245 // field of element_type and return reference to it. This field will go
246 // away once indexing into resources is properly implemented in
247 // llvm/llvm-project#95956.
248 if (Fields.count("e") == 0) {
249 addMemberVariable("e", ElemTy, {});
251 FieldDecl *ElemFieldDecl = Fields["e"];
253 auto *This =
254 CXXThisExpr::Create(AST, SourceLocation(),
255 MethodDecl->getFunctionObjectParameterType(), true);
256 Expr *ElemField = MemberExpr::CreateImplicit(
257 AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
258 OK_Ordinary);
259 auto *Return =
260 ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);
262 MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
263 SourceLocation(),
264 SourceLocation()));
265 MethodDecl->setLexicalDeclContext(Record);
266 MethodDecl->setAccess(AccessSpecifier::AS_public);
267 MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
268 AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
269 Record->addDecl(MethodDecl);
271 return *this;
274 BuiltinTypeDeclBuilder &startDefinition() {
275 if (Record->isCompleteDefinition())
276 return *this;
277 Record->startDefinition();
278 return *this;
281 BuiltinTypeDeclBuilder &completeDefinition() {
282 if (Record->isCompleteDefinition())
283 return *this;
284 assert(Record->isBeingDefined() &&
285 "Definition must be started before completing it.");
287 Record->completeDefinition();
288 return *this;
291 TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
292 BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S,
293 ArrayRef<StringRef> Names);
296 struct TemplateParameterListBuilder {
297 BuiltinTypeDeclBuilder &Builder;
298 Sema &S;
299 llvm::SmallVector<NamedDecl *> Params;
301 TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
302 : Builder(RB), S(S) {}
304 ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
306 TemplateParameterListBuilder &
307 addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
308 if (Builder.Record->isCompleteDefinition())
309 return *this;
310 unsigned Position = static_cast<unsigned>(Params.size());
311 auto *Decl = TemplateTypeParmDecl::Create(
312 S.Context, Builder.Record->getDeclContext(), SourceLocation(),
313 SourceLocation(), /* TemplateDepth */ 0, Position,
314 &S.Context.Idents.get(Name, tok::TokenKind::identifier),
315 /* Typename */ false,
316 /* ParameterPack */ false);
317 if (!DefaultValue.isNull())
318 Decl->setDefaultArgument(
319 S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
320 SourceLocation()));
322 Params.emplace_back(Decl);
323 return *this;
326 BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
327 if (Params.empty())
328 return Builder;
329 auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
330 SourceLocation(), Params,
331 SourceLocation(), nullptr);
332 Builder.Template = ClassTemplateDecl::Create(
333 S.Context, Builder.Record->getDeclContext(), SourceLocation(),
334 DeclarationName(Builder.Record->getIdentifier()), ParamList,
335 Builder.Record);
336 Builder.Record->setDescribedClassTemplate(Builder.Template);
337 Builder.Template->setImplicit(true);
338 Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
339 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
340 // make visible.
341 Builder.Template->setPreviousDecl(Builder.PrevTemplate);
342 Builder.Record->getDeclContext()->addDecl(Builder.Template);
343 Params.clear();
345 QualType T = Builder.Template->getInjectedClassNameSpecialization();
346 T = S.Context.getInjectedClassNameType(Builder.Record, T);
348 return Builder;
351 } // namespace
353 TemplateParameterListBuilder
354 BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
355 return TemplateParameterListBuilder(S, *this);
358 BuiltinTypeDeclBuilder &
359 BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
360 ArrayRef<StringRef> Names) {
361 TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
362 for (StringRef Name : Names)
363 Builder.addTypeParameter(Name);
364 return Builder.finalizeTemplateArgs();
367 HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
369 void HLSLExternalSemaSource::InitializeSema(Sema &S) {
370 SemaPtr = &S;
371 ASTContext &AST = SemaPtr->getASTContext();
372 // If the translation unit has external storage force external decls to load.
373 if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
374 (void)AST.getTranslationUnitDecl()->decls_begin();
376 IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
377 LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
378 NamespaceDecl *PrevDecl = nullptr;
379 if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
380 PrevDecl = Result.getAsSingle<NamespaceDecl>();
381 HLSLNamespace = NamespaceDecl::Create(
382 AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
383 SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
384 HLSLNamespace->setImplicit(true);
385 HLSLNamespace->setHasExternalLexicalStorage();
386 AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
388 // Force external decls in the HLSL namespace to load from the PCH.
389 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
390 defineTrivialHLSLTypes();
391 defineHLSLTypesWithForwardDeclarations();
393 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
394 // built in types inside a namespace, but we are planning to change that in
395 // the near future. In order to be source compatible older versions of HLSL
396 // will need to implicitly use the hlsl namespace. For now in clang everything
397 // will get added to the namespace, and we can remove the using directive for
398 // future language versions to match HLSL's evolution.
399 auto *UsingDecl = UsingDirectiveDecl::Create(
400 AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
401 NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
402 AST.getTranslationUnitDecl());
404 AST.getTranslationUnitDecl()->addDecl(UsingDecl);
407 void HLSLExternalSemaSource::defineHLSLVectorAlias() {
408 ASTContext &AST = SemaPtr->getASTContext();
410 llvm::SmallVector<NamedDecl *> TemplateParams;
412 auto *TypeParam = TemplateTypeParmDecl::Create(
413 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
414 &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
415 TypeParam->setDefaultArgument(
416 AST, SemaPtr->getTrivialTemplateArgumentLoc(
417 TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
419 TemplateParams.emplace_back(TypeParam);
421 auto *SizeParam = NonTypeTemplateParmDecl::Create(
422 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
423 &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
424 false, AST.getTrivialTypeSourceInfo(AST.IntTy));
425 llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
426 TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
427 /*IsDefaulted=*/true);
428 SizeParam->setDefaultArgument(
429 AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
430 SourceLocation(), SizeParam));
431 TemplateParams.emplace_back(SizeParam);
433 auto *ParamList =
434 TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
435 TemplateParams, SourceLocation(), nullptr);
437 IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
439 QualType AliasType = AST.getDependentSizedExtVectorType(
440 AST.getTemplateTypeParmType(0, 0, false, TypeParam),
441 DeclRefExpr::Create(
442 AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
443 DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
444 AST.IntTy, VK_LValue),
445 SourceLocation());
447 auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
448 SourceLocation(), &II,
449 AST.getTrivialTypeSourceInfo(AliasType));
450 Record->setImplicit(true);
452 auto *Template =
453 TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
454 Record->getIdentifier(), ParamList, Record);
456 Record->setDescribedAliasTemplate(Template);
457 Template->setImplicit(true);
458 Template->setLexicalDeclContext(Record->getDeclContext());
459 HLSLNamespace->addDecl(Template);
462 void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
463 defineHLSLVectorAlias();
466 /// Set up common members and attributes for buffer types
467 static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
468 ResourceClass RC, ResourceKind RK,
469 bool IsROV, bool RawBuffer) {
470 return BuiltinTypeDeclBuilder(Decl)
471 .addHandleMember(S, RC, RK, IsROV, RawBuffer)
472 .addDefaultHandleConstructor(S);
475 void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
476 CXXRecordDecl *Decl;
477 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
478 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
479 .Record;
481 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
482 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
483 ResourceKind::TypedBuffer, /*IsROV=*/false,
484 /*RawBuffer=*/false)
485 .addArraySubscriptOperators()
486 .completeDefinition();
489 Decl =
490 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
491 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
492 .Record;
493 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
494 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
495 ResourceKind::TypedBuffer, /*IsROV=*/true,
496 /*RawBuffer=*/false)
497 .addArraySubscriptOperators()
498 .completeDefinition();
501 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
502 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
503 .Record;
504 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
505 setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, ResourceKind::RawBuffer,
506 /*IsROV=*/false, /*RawBuffer=*/true)
507 .addArraySubscriptOperators()
508 .completeDefinition();
511 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
512 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
513 .Record;
514 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
515 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
516 /*IsROV=*/false, /*RawBuffer=*/true)
517 .addArraySubscriptOperators()
518 .completeDefinition();
521 Decl =
522 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")
523 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
524 .Record;
525 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
526 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
527 /*IsROV=*/false, /*RawBuffer=*/true)
528 .completeDefinition();
531 Decl =
532 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")
533 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
534 .Record;
535 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
536 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
537 /*IsROV=*/false, /*RawBuffer=*/true)
538 .completeDefinition();
541 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
542 "RasterizerOrderedStructuredBuffer")
543 .addSimpleTemplateParams(*SemaPtr, {"element_type"})
544 .Record;
545 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
546 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
547 /*IsROV=*/true, /*RawBuffer=*/true)
548 .addArraySubscriptOperators()
549 .completeDefinition();
553 void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
554 CompletionFunction Fn) {
555 Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
558 void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
559 if (!isa<CXXRecordDecl>(Tag))
560 return;
561 auto Record = cast<CXXRecordDecl>(Tag);
563 // If this is a specialization, we need to get the underlying templated
564 // declaration and complete that.
565 if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
566 Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
567 Record = Record->getCanonicalDecl();
568 auto It = Completions.find(Record);
569 if (It == Completions.end())
570 return;
571 It->second(Record);