HLSLExternalSemaSource.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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. #include "clang/Sema/HLSLExternalSemaSource.h"
  12. #include "clang/AST/ASTContext.h"
  13. #include "clang/AST/Attr.h"
  14. #include "clang/AST/DeclCXX.h"
  15. #include "clang/Basic/AttrKinds.h"
  16. #include "clang/Basic/HLSLRuntime.h"
  17. #include "clang/Sema/Lookup.h"
  18. #include "clang/Sema/Sema.h"
  19. #include "llvm/Frontend/HLSL/HLSLResource.h"
  20. #include <functional>
  21. using namespace clang;
  22. using namespace llvm::hlsl;
  23. namespace {
  24. struct TemplateParameterListBuilder;
  25. struct BuiltinTypeDeclBuilder {
  26. CXXRecordDecl *Record = nullptr;
  27. ClassTemplateDecl *Template = nullptr;
  28. ClassTemplateDecl *PrevTemplate = nullptr;
  29. NamespaceDecl *HLSLNamespace = nullptr;
  30. llvm::StringMap<FieldDecl *> Fields;
  31. BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
  32. Record->startDefinition();
  33. Template = Record->getDescribedClassTemplate();
  34. }
  35. BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
  36. : HLSLNamespace(Namespace) {
  37. ASTContext &AST = S.getASTContext();
  38. IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
  39. LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
  40. CXXRecordDecl *PrevDecl = nullptr;
  41. if (S.LookupQualifiedName(Result, HLSLNamespace)) {
  42. NamedDecl *Found = Result.getFoundDecl();
  43. if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
  44. PrevDecl = TD->getTemplatedDecl();
  45. PrevTemplate = TD;
  46. } else
  47. PrevDecl = dyn_cast<CXXRecordDecl>(Found);
  48. assert(PrevDecl && "Unexpected lookup result type.");
  49. }
  50. if (PrevDecl && PrevDecl->isCompleteDefinition()) {
  51. Record = PrevDecl;
  52. return;
  53. }
  54. Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::TTK_Class,
  55. HLSLNamespace, SourceLocation(),
  56. SourceLocation(), &II, PrevDecl, true);
  57. Record->setImplicit(true);
  58. Record->setLexicalDeclContext(HLSLNamespace);
  59. Record->setHasExternalLexicalStorage();
  60. // Don't let anyone derive from built-in types.
  61. Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
  62. AttributeCommonInfo::AS_Keyword,
  63. FinalAttr::Keyword_final));
  64. }
  65. ~BuiltinTypeDeclBuilder() {
  66. if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
  67. HLSLNamespace->addDecl(Record);
  68. }
  69. BuiltinTypeDeclBuilder &
  70. addMemberVariable(StringRef Name, QualType Type,
  71. AccessSpecifier Access = AccessSpecifier::AS_private) {
  72. if (Record->isCompleteDefinition())
  73. return *this;
  74. assert(Record->isBeingDefined() &&
  75. "Definition must be started before adding members!");
  76. ASTContext &AST = Record->getASTContext();
  77. IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
  78. TypeSourceInfo *MemTySource =
  79. AST.getTrivialTypeSourceInfo(Type, SourceLocation());
  80. auto *Field = FieldDecl::Create(
  81. AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
  82. nullptr, false, InClassInitStyle::ICIS_NoInit);
  83. Field->setAccess(Access);
  84. Field->setImplicit(true);
  85. Record->addDecl(Field);
  86. Fields[Name] = Field;
  87. return *this;
  88. }
  89. BuiltinTypeDeclBuilder &
  90. addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) {
  91. if (Record->isCompleteDefinition())
  92. return *this;
  93. QualType Ty = Record->getASTContext().VoidPtrTy;
  94. if (Template) {
  95. if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
  96. Template->getTemplateParameters()->getParam(0)))
  97. Ty = Record->getASTContext().getPointerType(
  98. QualType(TTD->getTypeForDecl(), 0));
  99. }
  100. return addMemberVariable("h", Ty, Access);
  101. }
  102. BuiltinTypeDeclBuilder &
  103. annotateResourceClass(HLSLResourceAttr::ResourceClass RC,
  104. HLSLResourceAttr::ResourceKind RK) {
  105. if (Record->isCompleteDefinition())
  106. return *this;
  107. Record->addAttr(
  108. HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RC, RK));
  109. return *this;
  110. }
  111. static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
  112. StringRef Name) {
  113. CXXScopeSpec SS;
  114. IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
  115. DeclarationNameInfo NameInfo =
  116. DeclarationNameInfo(DeclarationName(&II), SourceLocation());
  117. LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
  118. S.LookupParsedName(R, S.getCurScope(), &SS, false);
  119. assert(R.isSingleResult() &&
  120. "Since this is a builtin it should always resolve!");
  121. auto *VD = cast<ValueDecl>(R.getFoundDecl());
  122. QualType Ty = VD->getType();
  123. return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
  124. VD, false, NameInfo, Ty, VK_PRValue);
  125. }
  126. static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
  127. return IntegerLiteral::Create(
  128. AST,
  129. llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
  130. static_cast<uint8_t>(RC)),
  131. AST.UnsignedCharTy, SourceLocation());
  132. }
  133. BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
  134. ResourceClass RC) {
  135. if (Record->isCompleteDefinition())
  136. return *this;
  137. ASTContext &AST = Record->getASTContext();
  138. QualType ConstructorType =
  139. AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
  140. CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
  141. DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
  142. CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
  143. AST, Record, SourceLocation(),
  144. DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
  145. AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
  146. ExplicitSpecifier(), false, true, false,
  147. ConstexprSpecKind::Unspecified);
  148. DeclRefExpr *Fn =
  149. lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
  150. Expr *RCExpr = emitResourceClassExpr(AST, RC);
  151. Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
  152. SourceLocation(), FPOptionsOverride());
  153. CXXThisExpr *This = new (AST) CXXThisExpr(
  154. SourceLocation(),
  155. Constructor->getThisType().getTypePtr()->getPointeeType(), true);
  156. This->setValueKind(ExprValueKind::VK_LValue);
  157. Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
  158. Fields["h"]->getType(), VK_LValue,
  159. OK_Ordinary);
  160. // If the handle isn't a void pointer, cast the builtin result to the
  161. // correct type.
  162. if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
  163. Call = CXXStaticCastExpr::Create(
  164. AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
  165. AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
  166. FPOptionsOverride(), SourceLocation(), SourceLocation(),
  167. SourceRange());
  168. }
  169. BinaryOperator *Assign = BinaryOperator::Create(
  170. AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
  171. SourceLocation(), FPOptionsOverride());
  172. Constructor->setBody(
  173. CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
  174. SourceLocation(), SourceLocation()));
  175. Constructor->setAccess(AccessSpecifier::AS_public);
  176. Record->addDecl(Constructor);
  177. return *this;
  178. }
  179. BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
  180. if (Record->isCompleteDefinition())
  181. return *this;
  182. addArraySubscriptOperator(true);
  183. addArraySubscriptOperator(false);
  184. return *this;
  185. }
  186. BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
  187. if (Record->isCompleteDefinition())
  188. return *this;
  189. assert(Fields.count("h") > 0 &&
  190. "Subscript operator must be added after the handle.");
  191. FieldDecl *Handle = Fields["h"];
  192. ASTContext &AST = Record->getASTContext();
  193. assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
  194. "Not yet supported for void pointer handles.");
  195. QualType ElemTy =
  196. QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
  197. QualType ReturnTy = ElemTy;
  198. FunctionProtoType::ExtProtoInfo ExtInfo;
  199. // Subscript operators return references to elements, const makes the
  200. // reference and method const so that the underlying data is not mutable.
  201. ReturnTy = AST.getLValueReferenceType(ReturnTy);
  202. if (IsConst) {
  203. ExtInfo.TypeQuals.addConst();
  204. ReturnTy.addConst();
  205. }
  206. QualType MethodTy =
  207. AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
  208. auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
  209. auto *MethodDecl = CXXMethodDecl::Create(
  210. AST, Record, SourceLocation(),
  211. DeclarationNameInfo(
  212. AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
  213. SourceLocation()),
  214. MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
  215. SourceLocation());
  216. IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
  217. auto *IdxParam = ParmVarDecl::Create(
  218. AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
  219. &II, AST.UnsignedIntTy,
  220. AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
  221. SC_None, nullptr);
  222. MethodDecl->setParams({IdxParam});
  223. // Also add the parameter to the function prototype.
  224. auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
  225. FnProtoLoc.setParam(0, IdxParam);
  226. auto *This = new (AST) CXXThisExpr(
  227. SourceLocation(),
  228. MethodDecl->getThisType().getTypePtr()->getPointeeType(), true);
  229. This->setValueKind(ExprValueKind::VK_LValue);
  230. auto *HandleAccess = MemberExpr::CreateImplicit(
  231. AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
  232. auto *IndexExpr = DeclRefExpr::Create(
  233. AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
  234. DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
  235. AST.UnsignedIntTy, VK_PRValue);
  236. auto *Array =
  237. new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
  238. OK_Ordinary, SourceLocation());
  239. auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
  240. MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
  241. SourceLocation(),
  242. SourceLocation()));
  243. MethodDecl->setLexicalDeclContext(Record);
  244. MethodDecl->setAccess(AccessSpecifier::AS_public);
  245. MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
  246. AST, SourceRange(), AttributeCommonInfo::AS_Keyword,
  247. AlwaysInlineAttr::CXX11_clang_always_inline));
  248. Record->addDecl(MethodDecl);
  249. return *this;
  250. }
  251. BuiltinTypeDeclBuilder &startDefinition() {
  252. if (Record->isCompleteDefinition())
  253. return *this;
  254. Record->startDefinition();
  255. return *this;
  256. }
  257. BuiltinTypeDeclBuilder &completeDefinition() {
  258. if (Record->isCompleteDefinition())
  259. return *this;
  260. assert(Record->isBeingDefined() &&
  261. "Definition must be started before completing it.");
  262. Record->completeDefinition();
  263. return *this;
  264. }
  265. TemplateParameterListBuilder addTemplateArgumentList();
  266. };
  267. struct TemplateParameterListBuilder {
  268. BuiltinTypeDeclBuilder &Builder;
  269. ASTContext &AST;
  270. llvm::SmallVector<NamedDecl *> Params;
  271. TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB)
  272. : Builder(RB), AST(RB.Record->getASTContext()) {}
  273. ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
  274. TemplateParameterListBuilder &
  275. addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
  276. if (Builder.Record->isCompleteDefinition())
  277. return *this;
  278. unsigned Position = static_cast<unsigned>(Params.size());
  279. auto *Decl = TemplateTypeParmDecl::Create(
  280. AST, Builder.Record->getDeclContext(), SourceLocation(),
  281. SourceLocation(), /* TemplateDepth */ 0, Position,
  282. &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false,
  283. /* ParameterPack */ false);
  284. if (!DefaultValue.isNull())
  285. Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue));
  286. Params.emplace_back(Decl);
  287. return *this;
  288. }
  289. BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
  290. if (Params.empty())
  291. return Builder;
  292. auto *ParamList =
  293. TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
  294. Params, SourceLocation(), nullptr);
  295. Builder.Template = ClassTemplateDecl::Create(
  296. AST, Builder.Record->getDeclContext(), SourceLocation(),
  297. DeclarationName(Builder.Record->getIdentifier()), ParamList,
  298. Builder.Record);
  299. Builder.Record->setDescribedClassTemplate(Builder.Template);
  300. Builder.Template->setImplicit(true);
  301. Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
  302. // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
  303. // make visible.
  304. Builder.Template->setPreviousDecl(Builder.PrevTemplate);
  305. Builder.Record->getDeclContext()->addDecl(Builder.Template);
  306. Params.clear();
  307. QualType T = Builder.Template->getInjectedClassNameSpecialization();
  308. T = AST.getInjectedClassNameType(Builder.Record, T);
  309. return Builder;
  310. }
  311. };
  312. TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
  313. return TemplateParameterListBuilder(*this);
  314. }
  315. } // namespace
  316. HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
  317. void HLSLExternalSemaSource::InitializeSema(Sema &S) {
  318. SemaPtr = &S;
  319. ASTContext &AST = SemaPtr->getASTContext();
  320. // If the translation unit has external storage force external decls to load.
  321. if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
  322. (void)AST.getTranslationUnitDecl()->decls_begin();
  323. IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
  324. LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
  325. NamespaceDecl *PrevDecl = nullptr;
  326. if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
  327. PrevDecl = Result.getAsSingle<NamespaceDecl>();
  328. HLSLNamespace = NamespaceDecl::Create(
  329. AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
  330. SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
  331. HLSLNamespace->setImplicit(true);
  332. HLSLNamespace->setHasExternalLexicalStorage();
  333. AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
  334. // Force external decls in the HLSL namespace to load from the PCH.
  335. (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
  336. defineTrivialHLSLTypes();
  337. forwardDeclareHLSLTypes();
  338. // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
  339. // built in types inside a namespace, but we are planning to change that in
  340. // the near future. In order to be source compatible older versions of HLSL
  341. // will need to implicitly use the hlsl namespace. For now in clang everything
  342. // will get added to the namespace, and we can remove the using directive for
  343. // future language versions to match HLSL's evolution.
  344. auto *UsingDecl = UsingDirectiveDecl::Create(
  345. AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
  346. NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
  347. AST.getTranslationUnitDecl());
  348. AST.getTranslationUnitDecl()->addDecl(UsingDecl);
  349. }
  350. void HLSLExternalSemaSource::defineHLSLVectorAlias() {
  351. ASTContext &AST = SemaPtr->getASTContext();
  352. llvm::SmallVector<NamedDecl *> TemplateParams;
  353. auto *TypeParam = TemplateTypeParmDecl::Create(
  354. AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
  355. &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
  356. TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy));
  357. TemplateParams.emplace_back(TypeParam);
  358. auto *SizeParam = NonTypeTemplateParmDecl::Create(
  359. AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
  360. &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
  361. false, AST.getTrivialTypeSourceInfo(AST.IntTy));
  362. Expr *LiteralExpr =
  363. IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
  364. AST.IntTy, SourceLocation());
  365. SizeParam->setDefaultArgument(LiteralExpr);
  366. TemplateParams.emplace_back(SizeParam);
  367. auto *ParamList =
  368. TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
  369. TemplateParams, SourceLocation(), nullptr);
  370. IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
  371. QualType AliasType = AST.getDependentSizedExtVectorType(
  372. AST.getTemplateTypeParmType(0, 0, false, TypeParam),
  373. DeclRefExpr::Create(
  374. AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
  375. DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
  376. AST.IntTy, VK_LValue),
  377. SourceLocation());
  378. auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
  379. SourceLocation(), &II,
  380. AST.getTrivialTypeSourceInfo(AliasType));
  381. Record->setImplicit(true);
  382. auto *Template =
  383. TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
  384. Record->getIdentifier(), ParamList, Record);
  385. Record->setDescribedAliasTemplate(Template);
  386. Template->setImplicit(true);
  387. Template->setLexicalDeclContext(Record->getDeclContext());
  388. HLSLNamespace->addDecl(Template);
  389. }
  390. void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
  391. defineHLSLVectorAlias();
  392. ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource")
  393. .startDefinition()
  394. .addHandleMember(AccessSpecifier::AS_public)
  395. .completeDefinition()
  396. .Record;
  397. }
  398. void HLSLExternalSemaSource::forwardDeclareHLSLTypes() {
  399. CXXRecordDecl *Decl;
  400. Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
  401. .addTemplateArgumentList()
  402. .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy)
  403. .finalizeTemplateArgs()
  404. .Record;
  405. if (!Decl->isCompleteDefinition())
  406. Completions.insert(
  407. std::make_pair(Decl->getCanonicalDecl(),
  408. std::bind(&HLSLExternalSemaSource::completeBufferType,
  409. this, std::placeholders::_1)));
  410. }
  411. void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
  412. if (!isa<CXXRecordDecl>(Tag))
  413. return;
  414. auto Record = cast<CXXRecordDecl>(Tag);
  415. // If this is a specialization, we need to get the underlying templated
  416. // declaration and complete that.
  417. if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
  418. Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
  419. Record = Record->getCanonicalDecl();
  420. auto It = Completions.find(Record);
  421. if (It == Completions.end())
  422. return;
  423. It->second(Record);
  424. }
  425. void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) {
  426. BuiltinTypeDeclBuilder(Record)
  427. .addHandleMember()
  428. .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV)
  429. .addArraySubscriptOperators()
  430. .annotateResourceClass(HLSLResourceAttr::UAV,
  431. HLSLResourceAttr::TypedBuffer)
  432. .completeDefinition();
  433. }