brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.8 KiB · 6be84f1 Raw
526 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9//10//===----------------------------------------------------------------------===//11 12#include "clang/Sema/HLSLExternalSemaSource.h"13#include "HLSLBuiltinTypeDeclBuilder.h"14#include "clang/AST/ASTContext.h"15#include "clang/AST/Attr.h"16#include "clang/AST/Decl.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/Expr.h"19#include "clang/AST/Type.h"20#include "clang/Basic/SourceLocation.h"21#include "clang/Sema/Lookup.h"22#include "clang/Sema/Sema.h"23#include "clang/Sema/SemaHLSL.h"24#include "llvm/ADT/SmallVector.h"25 26using namespace clang;27using namespace llvm::hlsl;28 29using clang::hlsl::BuiltinTypeDeclBuilder;30 31void HLSLExternalSemaSource::InitializeSema(Sema &S) {32  SemaPtr = &S;33  ASTContext &AST = SemaPtr->getASTContext();34  // If the translation unit has external storage force external decls to load.35  if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())36    (void)AST.getTranslationUnitDecl()->decls_begin();37 38  IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);39  LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);40  NamespaceDecl *PrevDecl = nullptr;41  if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))42    PrevDecl = Result.getAsSingle<NamespaceDecl>();43  HLSLNamespace = NamespaceDecl::Create(44      AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),45      SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);46  HLSLNamespace->setImplicit(true);47  HLSLNamespace->setHasExternalLexicalStorage();48  AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);49 50  // Force external decls in the HLSL namespace to load from the PCH.51  (void)HLSLNamespace->getCanonicalDecl()->decls_begin();52  defineTrivialHLSLTypes();53  defineHLSLTypesWithForwardDeclarations();54 55  // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's56  // built in types inside a namespace, but we are planning to change that in57  // the near future. In order to be source compatible older versions of HLSL58  // will need to implicitly use the hlsl namespace. For now in clang everything59  // will get added to the namespace, and we can remove the using directive for60  // future language versions to match HLSL's evolution.61  auto *UsingDecl = UsingDirectiveDecl::Create(62      AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),63      NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,64      AST.getTranslationUnitDecl());65 66  AST.getTranslationUnitDecl()->addDecl(UsingDecl);67}68 69void HLSLExternalSemaSource::defineHLSLVectorAlias() {70  ASTContext &AST = SemaPtr->getASTContext();71 72  llvm::SmallVector<NamedDecl *> TemplateParams;73 74  auto *TypeParam = TemplateTypeParmDecl::Create(75      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,76      &AST.Idents.get("element", tok::TokenKind::identifier), false, false);77  TypeParam->setDefaultArgument(78      AST, SemaPtr->getTrivialTemplateArgumentLoc(79               TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));80 81  TemplateParams.emplace_back(TypeParam);82 83  auto *SizeParam = NonTypeTemplateParmDecl::Create(84      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,85      &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,86      false, AST.getTrivialTypeSourceInfo(AST.IntTy));87  llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);88  TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,89                           /*IsDefaulted=*/true);90  SizeParam->setDefaultArgument(91      AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,92                                                  SourceLocation(), SizeParam));93  TemplateParams.emplace_back(SizeParam);94 95  auto *ParamList =96      TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),97                                    TemplateParams, SourceLocation(), nullptr);98 99  IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);100 101  QualType AliasType = AST.getDependentSizedExtVectorType(102      AST.getTemplateTypeParmType(0, 0, false, TypeParam),103      DeclRefExpr::Create(104          AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,105          DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),106          AST.IntTy, VK_LValue),107      SourceLocation());108 109  auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),110                                       SourceLocation(), &II,111                                       AST.getTrivialTypeSourceInfo(AliasType));112  Record->setImplicit(true);113 114  auto *Template =115      TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),116                                    Record->getIdentifier(), ParamList, Record);117 118  Record->setDescribedAliasTemplate(Template);119  Template->setImplicit(true);120  Template->setLexicalDeclContext(Record->getDeclContext());121  HLSLNamespace->addDecl(Template);122}123 124void HLSLExternalSemaSource::defineHLSLMatrixAlias() {125  ASTContext &AST = SemaPtr->getASTContext();126  llvm::SmallVector<NamedDecl *> TemplateParams;127 128  auto *TypeParam = TemplateTypeParmDecl::Create(129      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,130      &AST.Idents.get("element", tok::TokenKind::identifier), false, false);131  TypeParam->setDefaultArgument(132      AST, SemaPtr->getTrivialTemplateArgumentLoc(133               TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));134 135  TemplateParams.emplace_back(TypeParam);136 137  // these should be 64 bit to be consistent with other clang matrices.138  auto *RowsParam = NonTypeTemplateParmDecl::Create(139      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,140      &AST.Idents.get("rows_count", tok::TokenKind::identifier), AST.IntTy,141      false, AST.getTrivialTypeSourceInfo(AST.IntTy));142  llvm::APInt RVal(AST.getIntWidth(AST.IntTy), 4);143  TemplateArgument RDefault(AST, llvm::APSInt(std::move(RVal)), AST.IntTy,144                            /*IsDefaulted=*/true);145  RowsParam->setDefaultArgument(146      AST, SemaPtr->getTrivialTemplateArgumentLoc(RDefault, AST.IntTy,147                                                  SourceLocation(), RowsParam));148  TemplateParams.emplace_back(RowsParam);149 150  auto *ColsParam = NonTypeTemplateParmDecl::Create(151      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 2,152      &AST.Idents.get("cols_count", tok::TokenKind::identifier), AST.IntTy,153      false, AST.getTrivialTypeSourceInfo(AST.IntTy));154  llvm::APInt CVal(AST.getIntWidth(AST.IntTy), 4);155  TemplateArgument CDefault(AST, llvm::APSInt(std::move(CVal)), AST.IntTy,156                            /*IsDefaulted=*/true);157  ColsParam->setDefaultArgument(158      AST, SemaPtr->getTrivialTemplateArgumentLoc(CDefault, AST.IntTy,159                                                  SourceLocation(), ColsParam));160  TemplateParams.emplace_back(ColsParam);161 162  const unsigned MaxMatDim = SemaPtr->getLangOpts().MaxMatrixDimension;163 164  auto *MaxRow = IntegerLiteral::Create(165      AST, llvm::APInt(AST.getIntWidth(AST.IntTy), MaxMatDim), AST.IntTy,166      SourceLocation());167  auto *MaxCol = IntegerLiteral::Create(168      AST, llvm::APInt(AST.getIntWidth(AST.IntTy), MaxMatDim), AST.IntTy,169      SourceLocation());170 171  auto *RowsRef = DeclRefExpr::Create(172      AST, NestedNameSpecifierLoc(), SourceLocation(), RowsParam,173      /*RefersToEnclosingVariableOrCapture*/ false,174      DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),175      AST.IntTy, VK_LValue);176  auto *ColsRef = DeclRefExpr::Create(177      AST, NestedNameSpecifierLoc(), SourceLocation(), ColsParam,178      /*RefersToEnclosingVariableOrCapture*/ false,179      DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),180      AST.IntTy, VK_LValue);181 182  auto *RowsLE = BinaryOperator::Create(AST, RowsRef, MaxRow, BO_LE, AST.BoolTy,183                                        VK_PRValue, OK_Ordinary,184                                        SourceLocation(), FPOptionsOverride());185  auto *ColsLE = BinaryOperator::Create(AST, ColsRef, MaxCol, BO_LE, AST.BoolTy,186                                        VK_PRValue, OK_Ordinary,187                                        SourceLocation(), FPOptionsOverride());188 189  auto *RequiresExpr = BinaryOperator::Create(190      AST, RowsLE, ColsLE, BO_LAnd, AST.BoolTy, VK_PRValue, OK_Ordinary,191      SourceLocation(), FPOptionsOverride());192 193  auto *ParamList = TemplateParameterList::Create(194      AST, SourceLocation(), SourceLocation(), TemplateParams, SourceLocation(),195      RequiresExpr);196 197  IdentifierInfo &II = AST.Idents.get("matrix", tok::TokenKind::identifier);198 199  QualType AliasType = AST.getDependentSizedMatrixType(200      AST.getTemplateTypeParmType(0, 0, false, TypeParam),201      DeclRefExpr::Create(202          AST, NestedNameSpecifierLoc(), SourceLocation(), RowsParam, false,203          DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),204          AST.IntTy, VK_LValue),205      DeclRefExpr::Create(206          AST, NestedNameSpecifierLoc(), SourceLocation(), ColsParam, false,207          DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),208          AST.IntTy, VK_LValue),209      SourceLocation());210 211  auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),212                                       SourceLocation(), &II,213                                       AST.getTrivialTypeSourceInfo(AliasType));214  Record->setImplicit(true);215 216  auto *Template =217      TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),218                                    Record->getIdentifier(), ParamList, Record);219 220  Record->setDescribedAliasTemplate(Template);221  Template->setImplicit(true);222  Template->setLexicalDeclContext(Record->getDeclContext());223  HLSLNamespace->addDecl(Template);224}225 226void HLSLExternalSemaSource::defineTrivialHLSLTypes() {227  defineHLSLVectorAlias();228  defineHLSLMatrixAlias();229}230 231/// Set up common members and attributes for buffer types232static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,233                                              ResourceClass RC, bool IsROV,234                                              bool RawBuffer, bool HasCounter) {235  return BuiltinTypeDeclBuilder(S, Decl)236      .addBufferHandles(RC, IsROV, RawBuffer, HasCounter)237      .addDefaultHandleConstructor()238      .addCopyConstructor()239      .addCopyAssignmentOperator()240      .addStaticInitializationFunctions(HasCounter);241}242 243// This function is responsible for constructing the constraint expression for244// this concept:245// template<typename T> concept is_typed_resource_element_compatible =246// __is_typed_resource_element_compatible<T>;247static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,248                                                TemplateTypeParmDecl *T) {249  ASTContext &Context = S.getASTContext();250 251  // Obtain the QualType for 'bool'252  QualType BoolTy = Context.BoolTy;253 254  // Create a QualType that points to this TemplateTypeParmDecl255  QualType TType = Context.getTypeDeclType(T);256 257  // Create a TypeSourceInfo for the template type parameter 'T'258  TypeSourceInfo *TTypeSourceInfo =259      Context.getTrivialTypeSourceInfo(TType, NameLoc);260 261  TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(262      Context, BoolTy, NameLoc, UTT_IsTypedResourceElementCompatible,263      {TTypeSourceInfo}, NameLoc, true);264 265  return TypedResExpr;266}267 268// This function is responsible for constructing the constraint expression for269// this concept:270// template<typename T> concept is_structured_resource_element_compatible =271// !__is_intangible<T> && sizeof(T) >= 1;272static Expr *constructStructuredBufferConstraintExpr(Sema &S,273                                                     SourceLocation NameLoc,274                                                     TemplateTypeParmDecl *T) {275  ASTContext &Context = S.getASTContext();276 277  // Obtain the QualType for 'bool'278  QualType BoolTy = Context.BoolTy;279 280  // Create a QualType that points to this TemplateTypeParmDecl281  QualType TType = Context.getTypeDeclType(T);282 283  // Create a TypeSourceInfo for the template type parameter 'T'284  TypeSourceInfo *TTypeSourceInfo =285      Context.getTrivialTypeSourceInfo(TType, NameLoc);286 287  TypeTraitExpr *IsIntangibleExpr =288      TypeTraitExpr::Create(Context, BoolTy, NameLoc, UTT_IsIntangibleType,289                            {TTypeSourceInfo}, NameLoc, true);290 291  // negate IsIntangibleExpr292  UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(293      Context, IsIntangibleExpr, UO_LNot, BoolTy, VK_LValue, OK_Ordinary,294      NameLoc, false, FPOptionsOverride());295 296  // element types also may not be of 0 size297  UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(298      UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);299 300  // Create a BinaryOperator that checks if the size of the type is not equal to301  // 1 Empty structs have a size of 1 in HLSL, so we need to check for that302  IntegerLiteral *rhs = IntegerLiteral::Create(303      Context, llvm::APInt(Context.getTypeSize(Context.getSizeType()), 1, true),304      Context.getSizeType(), NameLoc);305 306  BinaryOperator *SizeGEQOneExpr =307      BinaryOperator::Create(Context, SizeOfExpr, rhs, BO_GE, BoolTy, VK_LValue,308                             OK_Ordinary, NameLoc, FPOptionsOverride());309 310  // Combine the two constraints311  BinaryOperator *CombinedExpr = BinaryOperator::Create(312      Context, NotIntangibleExpr, SizeGEQOneExpr, BO_LAnd, BoolTy, VK_LValue,313      OK_Ordinary, NameLoc, FPOptionsOverride());314 315  return CombinedExpr;316}317 318static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,319                                               bool isTypedBuffer) {320  ASTContext &Context = S.getASTContext();321  DeclContext *DC = NSD->getDeclContext();322  SourceLocation DeclLoc = SourceLocation();323 324  IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");325  TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(326      Context, NSD->getDeclContext(), DeclLoc, DeclLoc,327      /*D=*/0,328      /*P=*/0,329      /*Id=*/&ElementTypeII,330      /*Typename=*/true,331      /*ParameterPack=*/false);332 333  T->setDeclContext(DC);334  T->setReferenced();335 336  // Create and Attach Template Parameter List to ConceptDecl337  TemplateParameterList *ConceptParams = TemplateParameterList::Create(338      Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr);339 340  DeclarationName DeclName;341  Expr *ConstraintExpr = nullptr;342 343  if (isTypedBuffer) {344    DeclName = DeclarationName(345        &Context.Idents.get("__is_typed_resource_element_compatible"));346    ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);347  } else {348    DeclName = DeclarationName(349        &Context.Idents.get("__is_structured_resource_element_compatible"));350    ConstraintExpr = constructStructuredBufferConstraintExpr(S, DeclLoc, T);351  }352 353  // Create a ConceptDecl354  ConceptDecl *CD =355      ConceptDecl::Create(Context, NSD->getDeclContext(), DeclLoc, DeclName,356                          ConceptParams, ConstraintExpr);357 358  // Attach the template parameter list to the ConceptDecl359  CD->setTemplateParameters(ConceptParams);360 361  // Add the concept declaration to the Translation Unit Decl362  NSD->getDeclContext()->addDecl(CD);363 364  return CD;365}366 367void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {368  CXXRecordDecl *Decl;369  ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(370      *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ true);371  ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(372      *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ false);373 374  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Buffer")375             .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)376             .finalizeForwardDeclaration();377 378  onCompletion(Decl, [this](CXXRecordDecl *Decl) {379    setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,380                    /*RawBuffer=*/false, /*HasCounter=*/false)381        .addArraySubscriptOperators()382        .addLoadMethods()383        .addGetDimensionsMethodForBuffer()384        .completeDefinition();385  });386 387  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")388             .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)389             .finalizeForwardDeclaration();390 391  onCompletion(Decl, [this](CXXRecordDecl *Decl) {392    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,393                    /*RawBuffer=*/false, /*HasCounter=*/false)394        .addArraySubscriptOperators()395        .addLoadMethods()396        .addGetDimensionsMethodForBuffer()397        .completeDefinition();398  });399 400  Decl =401      BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")402          .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)403          .finalizeForwardDeclaration();404  onCompletion(Decl, [this](CXXRecordDecl *Decl) {405    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true,406                    /*RawBuffer=*/false, /*HasCounter=*/false)407        .addArraySubscriptOperators()408        .addLoadMethods()409        .addGetDimensionsMethodForBuffer()410        .completeDefinition();411  });412 413  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")414             .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)415             .finalizeForwardDeclaration();416  onCompletion(Decl, [this](CXXRecordDecl *Decl) {417    setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,418                    /*RawBuffer=*/true, /*HasCounter=*/false)419        .addArraySubscriptOperators()420        .addLoadMethods()421        .addGetDimensionsMethodForBuffer()422        .completeDefinition();423  });424 425  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")426             .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)427             .finalizeForwardDeclaration();428  onCompletion(Decl, [this](CXXRecordDecl *Decl) {429    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,430                    /*RawBuffer=*/true, /*HasCounter=*/true)431        .addArraySubscriptOperators()432        .addLoadMethods()433        .addIncrementCounterMethod()434        .addDecrementCounterMethod()435        .addGetDimensionsMethodForBuffer()436        .completeDefinition();437  });438 439  Decl =440      BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")441          .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)442          .finalizeForwardDeclaration();443  onCompletion(Decl, [this](CXXRecordDecl *Decl) {444    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,445                    /*RawBuffer=*/true, /*HasCounter=*/true)446        .addAppendMethod()447        .addGetDimensionsMethodForBuffer()448        .completeDefinition();449  });450 451  Decl =452      BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")453          .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)454          .finalizeForwardDeclaration();455  onCompletion(Decl, [this](CXXRecordDecl *Decl) {456    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,457                    /*RawBuffer=*/true, /*HasCounter=*/true)458        .addConsumeMethod()459        .addGetDimensionsMethodForBuffer()460        .completeDefinition();461  });462 463  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,464                                "RasterizerOrderedStructuredBuffer")465             .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)466             .finalizeForwardDeclaration();467  onCompletion(Decl, [this](CXXRecordDecl *Decl) {468    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true,469                    /*RawBuffer=*/true, /*HasCounter=*/true)470        .addArraySubscriptOperators()471        .addLoadMethods()472        .addIncrementCounterMethod()473        .addDecrementCounterMethod()474        .addGetDimensionsMethodForBuffer()475        .completeDefinition();476  });477 478  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")479             .finalizeForwardDeclaration();480  onCompletion(Decl, [this](CXXRecordDecl *Decl) {481    setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,482                    /*RawBuffer=*/true, /*HasCounter=*/false)483        .addGetDimensionsMethodForBuffer()484        .completeDefinition();485  });486  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")487             .finalizeForwardDeclaration();488  onCompletion(Decl, [this](CXXRecordDecl *Decl) {489    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,490                    /*RawBuffer=*/true, /*HasCounter=*/false)491        .addGetDimensionsMethodForBuffer()492        .completeDefinition();493  });494  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,495                                "RasterizerOrderedByteAddressBuffer")496             .finalizeForwardDeclaration();497  onCompletion(Decl, [this](CXXRecordDecl *Decl) {498    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true,499                    /*RawBuffer=*/true, /*HasCounter=*/false)500        .addGetDimensionsMethodForBuffer()501        .completeDefinition();502  });503}504 505void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,506                                          CompletionFunction Fn) {507  if (!Record->isCompleteDefinition())508    Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));509}510 511void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {512  if (!isa<CXXRecordDecl>(Tag))513    return;514  auto Record = cast<CXXRecordDecl>(Tag);515 516  // If this is a specialization, we need to get the underlying templated517  // declaration and complete that.518  if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))519    Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();520  Record = Record->getCanonicalDecl();521  auto It = Completions.find(Record);522  if (It == Completions.end())523    return;524  It->second(Record);525}526