1 //===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
26 using namespace clang
;
27 using namespace llvm::hlsl
;
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();
58 PrevDecl
= dyn_cast
<CXXRecordDecl
>(Found
);
59 assert(PrevDecl
&& "Unexpected lookup result type.");
62 if (PrevDecl
&& PrevDecl
->isCompleteDefinition()) {
67 Record
= CXXRecordDecl::Create(AST
, TagDecl::TagKind::Class
, HLSLNamespace
,
68 SourceLocation(), SourceLocation(), &II
,
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())
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
) {
106 Record
->addDecl(Field
);
107 Fields
[Name
] = Field
;
111 BuiltinTypeDeclBuilder
&
112 addHandleMember(Sema
&S
, ResourceClass RC
, ResourceKind RK
, bool IsROV
,
114 AccessSpecifier Access
= AccessSpecifier::AS_private
) {
115 if (Record
->isCompleteDefinition())
118 ASTContext
&Ctx
= S
.getASTContext();
119 TypeSourceInfo
*ElementTypeInfo
= nullptr;
121 QualType ElemTy
= Ctx
.Char8Ty
;
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,
137 ? HLSLContainedTypeAttr::CreateImplicit(Ctx
, ElementTypeInfo
)
139 Attr
*ResourceAttr
= HLSLResourceAttr::CreateImplicit(Ctx
, RK
);
140 if (CreateHLSLAttributedResourceType(S
, Ctx
.HLSLResourceTy
, Attrs
,
142 addMemberVariable("__handle", AttributedResTy
, {ResourceAttr
}, Access
);
146 static DeclRefExpr
*lookupBuiltinFunction(ASTContext
&AST
, Sema
&S
,
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())
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
);
189 BuiltinTypeDeclBuilder
&addArraySubscriptOperators() {
190 if (Record
->isCompleteDefinition())
192 addArraySubscriptOperator(true);
193 addArraySubscriptOperator(false);
197 BuiltinTypeDeclBuilder
&addArraySubscriptOperator(bool IsConst
) {
198 if (Record
->isCompleteDefinition())
201 ASTContext
&AST
= Record
->getASTContext();
202 QualType ElemTy
= AST
.Char8Ty
;
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.
216 ExtInfo
.TypeQuals
.addConst();
219 ReturnTy
= AST
.getLValueReferenceType(ReturnTy
);
222 AST
.getFunctionType(ReturnTy
, {AST
.UnsignedIntTy
}, ExtInfo
);
223 auto *TSInfo
= AST
.getTrivialTypeSourceInfo(MethodTy
, SourceLocation());
224 auto *MethodDecl
= CXXMethodDecl::Create(
225 AST
, Record
, SourceLocation(),
227 AST
.DeclarationNames
.getCXXOperatorName(OO_Subscript
),
229 MethodTy
, TSInfo
, SC_None
, false, false, ConstexprSpecKind::Unspecified
,
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()),
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"];
254 CXXThisExpr::Create(AST
, SourceLocation(),
255 MethodDecl
->getFunctionObjectParameterType(), true);
256 Expr
*ElemField
= MemberExpr::CreateImplicit(
257 AST
, This
, false, ElemFieldDecl
, ElemFieldDecl
->getType(), VK_LValue
,
260 ReturnStmt::Create(AST
, SourceLocation(), ElemField
, nullptr);
262 MethodDecl
->setBody(CompoundStmt::Create(AST
, {Return
}, FPOptionsOverride(),
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
);
274 BuiltinTypeDeclBuilder
&startDefinition() {
275 if (Record
->isCompleteDefinition())
277 Record
->startDefinition();
281 BuiltinTypeDeclBuilder
&completeDefinition() {
282 if (Record
->isCompleteDefinition())
284 assert(Record
->isBeingDefined() &&
285 "Definition must be started before completing it.");
287 Record
->completeDefinition();
291 TemplateParameterListBuilder
addTemplateArgumentList(Sema
&S
);
292 BuiltinTypeDeclBuilder
&addSimpleTemplateParams(Sema
&S
,
293 ArrayRef
<StringRef
> Names
);
296 struct TemplateParameterListBuilder
{
297 BuiltinTypeDeclBuilder
&Builder
;
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())
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(),
322 Params
.emplace_back(Decl
);
326 BuiltinTypeDeclBuilder
&finalizeTemplateArgs() {
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
,
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
341 Builder
.Template
->setPreviousDecl(Builder
.PrevTemplate
);
342 Builder
.Record
->getDeclContext()->addDecl(Builder
.Template
);
345 QualType T
= Builder
.Template
->getInjectedClassNameSpecialization();
346 T
= S
.Context
.getInjectedClassNameType(Builder
.Record
, T
);
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
) {
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
);
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
),
442 AST
, NestedNameSpecifierLoc(), SourceLocation(), SizeParam
, false,
443 DeclarationNameInfo(SizeParam
->getDeclName(), SourceLocation()),
444 AST
.IntTy
, VK_LValue
),
447 auto *Record
= TypeAliasDecl::Create(AST
, HLSLNamespace
, SourceLocation(),
448 SourceLocation(), &II
,
449 AST
.getTrivialTypeSourceInfo(AliasType
));
450 Record
->setImplicit(true);
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() {
477 Decl
= BuiltinTypeDeclBuilder(*SemaPtr
, HLSLNamespace
, "RWBuffer")
478 .addSimpleTemplateParams(*SemaPtr
, {"element_type"})
481 onCompletion(Decl
, [this](CXXRecordDecl
*Decl
) {
482 setupBufferType(Decl
, *SemaPtr
, ResourceClass::UAV
,
483 ResourceKind::TypedBuffer
, /*IsROV=*/false,
485 .addArraySubscriptOperators()
486 .completeDefinition();
490 BuiltinTypeDeclBuilder(*SemaPtr
, HLSLNamespace
, "RasterizerOrderedBuffer")
491 .addSimpleTemplateParams(*SemaPtr
, {"element_type"})
493 onCompletion(Decl
, [this](CXXRecordDecl
*Decl
) {
494 setupBufferType(Decl
, *SemaPtr
, ResourceClass::UAV
,
495 ResourceKind::TypedBuffer
, /*IsROV=*/true,
497 .addArraySubscriptOperators()
498 .completeDefinition();
501 Decl
= BuiltinTypeDeclBuilder(*SemaPtr
, HLSLNamespace
, "StructuredBuffer")
502 .addSimpleTemplateParams(*SemaPtr
, {"element_type"})
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"})
514 onCompletion(Decl
, [this](CXXRecordDecl
*Decl
) {
515 setupBufferType(Decl
, *SemaPtr
, ResourceClass::UAV
, ResourceKind::RawBuffer
,
516 /*IsROV=*/false, /*RawBuffer=*/true)
517 .addArraySubscriptOperators()
518 .completeDefinition();
522 BuiltinTypeDeclBuilder(*SemaPtr
, HLSLNamespace
, "AppendStructuredBuffer")
523 .addSimpleTemplateParams(*SemaPtr
, {"element_type"})
525 onCompletion(Decl
, [this](CXXRecordDecl
*Decl
) {
526 setupBufferType(Decl
, *SemaPtr
, ResourceClass::UAV
, ResourceKind::RawBuffer
,
527 /*IsROV=*/false, /*RawBuffer=*/true)
528 .completeDefinition();
532 BuiltinTypeDeclBuilder(*SemaPtr
, HLSLNamespace
, "ConsumeStructuredBuffer")
533 .addSimpleTemplateParams(*SemaPtr
, {"element_type"})
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"})
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
))
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())