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 "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/DeclTemplate.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/Type.h"
21#include "clang/Basic/AddressSpaces.h"
22#include "clang/Basic/SourceLocation.h"
23#include "clang/Lex/Preprocessor.h"
24#include "clang/Sema/Lookup.h"
25#include "clang/Sema/Sema.h"
26#include "clang/Sema/SemaHLSL.h"
27#include "clang/Sema/TemplateDeduction.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallVector.h"
30
31using namespace clang;
32using namespace llvm::hlsl;
33
34using clang::hlsl::BuiltinTypeDeclBuilder;
35
36void HLSLExternalSemaSource::InitializeSema(Sema &S) {
37 SemaPtr = &S;
38 ASTContext &AST = SemaPtr->getASTContext();
39 // If the translation unit has external storage force external decls to load.
40 if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
41 (void)AST.getTranslationUnitDecl()->decls_begin();
42
43 IdentifierInfo &HLSL = AST.Idents.get(Name: "hlsl", TokenCode: tok::TokenKind::identifier);
44 LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
45 NamespaceDecl *PrevDecl = nullptr;
46 if (S.LookupQualifiedName(R&: Result, LookupCtx: AST.getTranslationUnitDecl()))
47 PrevDecl = Result.getAsSingle<NamespaceDecl>();
48 HLSLNamespace = NamespaceDecl::Create(
49 C&: AST, DC: AST.getTranslationUnitDecl(), /*Inline=*/false, StartLoc: SourceLocation(),
50 IdLoc: SourceLocation(), Id: &HLSL, PrevDecl, /*Nested=*/false);
51 HLSLNamespace->setImplicit(true);
52 HLSLNamespace->setHasExternalLexicalStorage();
53 AST.getTranslationUnitDecl()->addDecl(D: HLSLNamespace);
54
55 // Force external decls in the HLSL namespace to load from the PCH.
56 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
57 defineTrivialHLSLTypes();
58 defineHLSLTypesWithForwardDeclarations();
59 defineHLSLAtomicIntrinsics();
60
61 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
62 // built in types inside a namespace, but we are planning to change that in
63 // the near future. In order to be source compatible older versions of HLSL
64 // will need to implicitly use the hlsl namespace. For now in clang everything
65 // will get added to the namespace, and we can remove the using directive for
66 // future language versions to match HLSL's evolution.
67 auto *UsingDecl = UsingDirectiveDecl::Create(
68 C&: AST, DC: AST.getTranslationUnitDecl(), UsingLoc: SourceLocation(), NamespaceLoc: SourceLocation(),
69 QualifierLoc: NestedNameSpecifierLoc(), IdentLoc: SourceLocation(), Nominated: HLSLNamespace,
70 CommonAncestor: AST.getTranslationUnitDecl());
71
72 AST.getTranslationUnitDecl()->addDecl(D: UsingDecl);
73}
74
75void HLSLExternalSemaSource::defineHLSLVectorAlias() {
76 ASTContext &AST = SemaPtr->getASTContext();
77
78 llvm::SmallVector<NamedDecl *> TemplateParams;
79
80 auto *TypeParam = TemplateTypeParmDecl::Create(
81 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
82 Id: &AST.Idents.get(Name: "element", TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false);
83 TypeParam->setDefaultArgument(
84 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
85 Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation()));
86
87 TemplateParams.emplace_back(Args&: TypeParam);
88
89 auto *SizeParam = NonTypeTemplateParmDecl::Create(
90 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
91 Id: &AST.Idents.get(Name: "element_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
92 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
93 llvm::APInt Val(AST.getIntWidth(T: AST.IntTy), 4);
94 TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
95 /*IsDefaulted=*/true);
96 SizeParam->setDefaultArgument(C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
97 Arg: Default, NTTPType: AST.IntTy, Loc: SourceLocation()));
98 TemplateParams.emplace_back(Args&: SizeParam);
99
100 auto *ParamList =
101 TemplateParameterList::Create(C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(),
102 Params: TemplateParams, RAngleLoc: SourceLocation(), RequiresClause: nullptr);
103
104 IdentifierInfo &II = AST.Idents.get(Name: "vector", TokenCode: tok::TokenKind::identifier);
105
106 QualType AliasType = AST.getDependentSizedExtVectorType(
107 VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam),
108 SizeExpr: DeclRefExpr::Create(
109 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: SizeParam, RefersToEnclosingVariableOrCapture: false,
110 NameInfo: DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
111 T: AST.IntTy, VK: VK_LValue),
112 AttrLoc: SourceLocation());
113
114 auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(),
115 IdLoc: SourceLocation(), Id: &II,
116 TInfo: AST.getTrivialTypeSourceInfo(T: AliasType));
117 Record->setImplicit(true);
118
119 auto *Template =
120 TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(),
121 Name: Record->getIdentifier(), Params: ParamList, Decl: Record);
122
123 Record->setDescribedAliasTemplate(Template);
124 Template->setImplicit(true);
125 Template->setLexicalDeclContext(Record->getDeclContext());
126 HLSLNamespace->addDecl(D: Template);
127}
128
129void HLSLExternalSemaSource::defineHLSLMatrixAlias() {
130 ASTContext &AST = SemaPtr->getASTContext();
131 llvm::SmallVector<NamedDecl *> TemplateParams;
132
133 auto *TypeParam = TemplateTypeParmDecl::Create(
134 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
135 Id: &AST.Idents.get(Name: "element", TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false);
136 TypeParam->setDefaultArgument(
137 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
138 Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation()));
139
140 TemplateParams.emplace_back(Args&: TypeParam);
141
142 // these should be 64 bit to be consistent with other clang matrices.
143 auto *RowsParam = NonTypeTemplateParmDecl::Create(
144 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
145 Id: &AST.Idents.get(Name: "rows_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
146 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
147 llvm::APInt RVal(AST.getIntWidth(T: AST.IntTy), 4);
148 TemplateArgument RDefault(AST, llvm::APSInt(std::move(RVal)), AST.IntTy,
149 /*IsDefaulted=*/true);
150 RowsParam->setDefaultArgument(
151 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: RDefault, NTTPType: AST.IntTy,
152 Loc: SourceLocation()));
153 TemplateParams.emplace_back(Args&: RowsParam);
154
155 auto *ColsParam = NonTypeTemplateParmDecl::Create(
156 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 2,
157 Id: &AST.Idents.get(Name: "cols_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
158 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
159 llvm::APInt CVal(AST.getIntWidth(T: AST.IntTy), 4);
160 TemplateArgument CDefault(AST, llvm::APSInt(std::move(CVal)), AST.IntTy,
161 /*IsDefaulted=*/true);
162 ColsParam->setDefaultArgument(
163 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: CDefault, NTTPType: AST.IntTy,
164 Loc: SourceLocation()));
165 TemplateParams.emplace_back(Args&: ColsParam);
166
167 const unsigned MaxMatDim = SemaPtr->getLangOpts().MaxMatrixDimension;
168
169 auto *MaxRow = IntegerLiteral::Create(
170 C: AST, V: llvm::APInt(AST.getIntWidth(T: AST.IntTy), MaxMatDim), type: AST.IntTy,
171 l: SourceLocation());
172 auto *MaxCol = IntegerLiteral::Create(
173 C: AST, V: llvm::APInt(AST.getIntWidth(T: AST.IntTy), MaxMatDim), type: AST.IntTy,
174 l: SourceLocation());
175
176 auto *RowsRef = DeclRefExpr::Create(
177 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: RowsParam,
178 /*RefersToEnclosingVariableOrCapture*/ false,
179 NameInfo: DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),
180 T: AST.IntTy, VK: VK_LValue);
181 auto *ColsRef = DeclRefExpr::Create(
182 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ColsParam,
183 /*RefersToEnclosingVariableOrCapture*/ false,
184 NameInfo: DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),
185 T: AST.IntTy, VK: VK_LValue);
186
187 auto *RowsLE = BinaryOperator::Create(C: AST, lhs: RowsRef, rhs: MaxRow, opc: BO_LE, ResTy: AST.BoolTy,
188 VK: VK_PRValue, OK: OK_Ordinary,
189 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
190 auto *ColsLE = BinaryOperator::Create(C: AST, lhs: ColsRef, rhs: MaxCol, opc: BO_LE, ResTy: AST.BoolTy,
191 VK: VK_PRValue, OK: OK_Ordinary,
192 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
193
194 auto *RequiresExpr = BinaryOperator::Create(
195 C: AST, lhs: RowsLE, rhs: ColsLE, opc: BO_LAnd, ResTy: AST.BoolTy, VK: VK_PRValue, OK: OK_Ordinary,
196 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
197
198 auto *ParamList = TemplateParameterList::Create(
199 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: TemplateParams, RAngleLoc: SourceLocation(),
200 RequiresClause: RequiresExpr);
201
202 IdentifierInfo &II = AST.Idents.get(Name: "matrix", TokenCode: tok::TokenKind::identifier);
203
204 QualType AliasType = AST.getDependentSizedMatrixType(
205 ElementType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam),
206 RowExpr: DeclRefExpr::Create(
207 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: RowsParam, RefersToEnclosingVariableOrCapture: false,
208 NameInfo: DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),
209 T: AST.IntTy, VK: VK_LValue),
210 ColumnExpr: DeclRefExpr::Create(
211 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ColsParam, RefersToEnclosingVariableOrCapture: false,
212 NameInfo: DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),
213 T: AST.IntTy, VK: VK_LValue),
214 AttrLoc: SourceLocation());
215
216 auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(),
217 IdLoc: SourceLocation(), Id: &II,
218 TInfo: AST.getTrivialTypeSourceInfo(T: AliasType));
219 Record->setImplicit(true);
220
221 auto *Template =
222 TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(),
223 Name: Record->getIdentifier(), Params: ParamList, Decl: Record);
224
225 Record->setDescribedAliasTemplate(Template);
226 Template->setImplicit(true);
227 Template->setLexicalDeclContext(Record->getDeclContext());
228 HLSLNamespace->addDecl(D: Template);
229}
230
231void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
232 defineHLSLVectorAlias();
233 defineHLSLMatrixAlias();
234}
235
236/// Set up common members and attributes for buffer types
237static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
238 ResourceClass RC, bool IsROV,
239 bool RawBuffer, bool HasCounter) {
240 return BuiltinTypeDeclBuilder(S, Decl)
241 .addBufferHandles(RC, IsROV, RawBuffer, HasCounter)
242 .addDefaultHandleConstructor()
243 .addCopyConstructor()
244 .addCopyAssignmentOperator()
245 .addStaticInitializationFunctions(HasCounter);
246}
247
248/// Set up common members and attributes for sampler types
249static BuiltinTypeDeclBuilder setupSamplerType(CXXRecordDecl *Decl, Sema &S) {
250 return BuiltinTypeDeclBuilder(S, Decl)
251 .addSamplerHandle()
252 .addDefaultHandleConstructor()
253 .addCopyConstructor()
254 .addCopyAssignmentOperator()
255 .addStaticInitializationFunctions(HasCounter: false);
256}
257
258/// Set up common members and attributes for texture types
259static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S,
260 ResourceClass RC, bool IsROV,
261 bool IsArray,
262 ResourceDimension Dim) {
263 return BuiltinTypeDeclBuilder(S, Decl)
264 .addTextureHandle(RC, IsROV, IsArray, RD: Dim)
265 .addTextureLoadMethods(Dim, IsArray)
266 .addArraySubscriptOperators(Dim, IsArray)
267 .addMipsMember(Dim)
268 .addDefaultHandleConstructor()
269 .addCopyConstructor()
270 .addCopyAssignmentOperator()
271 .addStaticInitializationFunctions(HasCounter: false)
272 .addSampleMethods(Dim, IsArray)
273 .addSampleBiasMethods(Dim, IsArray)
274 .addSampleGradMethods(Dim, IsArray)
275 .addSampleLevelMethods(Dim, IsArray)
276 .addSampleCmpMethods(Dim, IsArray)
277 .addSampleCmpLevelZeroMethods(Dim, IsArray)
278 .addCalculateLodMethods(Dim)
279 .addGetDimensionsMethods(Dim)
280 .addGatherMethods(Dim, IsArray)
281 .addGatherCmpMethods(Dim, IsArray);
282}
283
284/// Set up RWTexture type: UAV texture with only operator[] (uint2, read/write),
285/// Load and GetDimensions (no sample/gather/mips/LOD).
286static BuiltinTypeDeclBuilder setupRWTextureType(CXXRecordDecl *Decl, Sema &S,
287 bool IsArray,
288 ResourceDimension Dim) {
289 return BuiltinTypeDeclBuilder(S, Decl)
290 .addTextureHandle(RC: ResourceClass::UAV, /*IsROV=*/false, IsArray, RD: Dim)
291 .addTextureLoadMethods(Dim, IsArray)
292 .addArraySubscriptOperators(Dim, IsArray)
293 .addGetDimensionsMethods(Dim)
294 .addDefaultHandleConstructor()
295 .addCopyConstructor()
296 .addCopyAssignmentOperator()
297 .addStaticInitializationFunctions(HasCounter: false);
298}
299
300// Add a partial specialization for a template. The `TextureTemplate` is
301// `Texture<element_type>`, and it will be specialized for vectors:
302// `Texture<vector<element_type, element_count>>`.
303static ClassTemplatePartialSpecializationDecl *
304addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
305 ClassTemplateDecl *TextureTemplate) {
306 ASTContext &AST = S.getASTContext();
307
308 // Create the template parameters: element_type and element_count.
309 auto *ElementType = TemplateTypeParmDecl::Create(
310 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
311 Id: &AST.Idents.get(Name: "element_type"), Typename: false, ParameterPack: false);
312 auto *ElementCount = NonTypeTemplateParmDecl::Create(
313 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
314 Id: &AST.Idents.get(Name: "element_count"), T: AST.IntTy, ParameterPack: false,
315 TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
316
317 auto *TemplateParams = TemplateParameterList::Create(
318 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: {ElementType, ElementCount},
319 RAngleLoc: SourceLocation(), RequiresClause: nullptr);
320
321 // Create the dependent vector type: vector<element_type, element_count>.
322 QualType VectorType = AST.getDependentSizedExtVectorType(
323 VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: ElementType),
324 SizeExpr: DeclRefExpr::Create(
325 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ElementCount, RefersToEnclosingVariableOrCapture: false,
326 NameInfo: DeclarationNameInfo(ElementCount->getDeclName(), SourceLocation()),
327 T: AST.IntTy, VK: VK_LValue),
328 AttrLoc: SourceLocation());
329
330 // Create the partial specialization declaration.
331 QualType CanonInjectedTST =
332 AST.getCanonicalType(T: AST.getTemplateSpecializationType(
333 Keyword: ElaboratedTypeKeyword::Class, T: TemplateName(TextureTemplate),
334 SpecifiedArgs: {TemplateArgument(VectorType)}, CanonicalArgs: {}));
335
336 auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
337 Context&: AST, TK: TagDecl::TagKind::Class, DC: HLSLNamespace, StartLoc: SourceLocation(),
338 IdLoc: SourceLocation(), Params: TemplateParams, SpecializedTemplate: TextureTemplate,
339 Args: {TemplateArgument(VectorType)},
340 CanonInjectedTST: CanQualType::CreateUnsafe(Other: CanonInjectedTST), PrevDecl: nullptr);
341
342 // Set the template arguments as written.
343 TemplateArgument Arg(VectorType);
344 TemplateArgumentLoc ArgLoc =
345 S.getTrivialTemplateArgumentLoc(Arg, NTTPType: QualType(), Loc: SourceLocation());
346 TemplateArgumentListInfo ArgsInfo =
347 TemplateArgumentListInfo(SourceLocation(), SourceLocation());
348 ArgsInfo.addArgument(Loc: ArgLoc);
349 PartialSpec->setTemplateArgsAsWritten(
350 ASTTemplateArgumentListInfo::Create(C: AST, List: ArgsInfo));
351
352 PartialSpec->setImplicit(true);
353 PartialSpec->setLexicalDeclContext(HLSLNamespace);
354 PartialSpec->setHasExternalLexicalStorage();
355
356 // Add the partial specialization to the namespace and the class template.
357 HLSLNamespace->addDecl(D: PartialSpec);
358 TextureTemplate->AddPartialSpecialization(D: PartialSpec, InsertPos: nullptr);
359
360 return PartialSpec;
361}
362
363// This function is responsible for constructing the constraint expression for
364// this concept:
365// template<typename T> concept is_typed_resource_element_compatible =
366// __is_typed_resource_element_compatible<T>;
367static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
368 TemplateTypeParmDecl *T) {
369 ASTContext &Context = S.getASTContext();
370
371 // Obtain the QualType for 'bool'
372 QualType BoolTy = Context.BoolTy;
373
374 // Create a QualType that points to this TemplateTypeParmDecl
375 QualType TType = Context.getTypeDeclType(Decl: T);
376
377 // Create a TypeSourceInfo for the template type parameter 'T'
378 TypeSourceInfo *TTypeSourceInfo =
379 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
380
381 TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(
382 C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsTypedResourceElementCompatible,
383 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
384
385 return TypedResExpr;
386}
387
388// This function is responsible for constructing the constraint expression for
389// this concept:
390// template<typename T> concept is_constant_buffer_element_compatible =
391// std::is_class_v<T> && !__is_intangible(T);
392static Expr *constructConstantBufferConstraintExpr(Sema &S,
393 SourceLocation NameLoc,
394 TemplateTypeParmDecl *T) {
395 ASTContext &Context = S.getASTContext();
396
397 // Obtain the QualType for 'bool'
398 QualType BoolTy = Context.BoolTy;
399
400 // Create a QualType that points to this TemplateTypeParmDecl
401 QualType TType = Context.getTypeDeclType(Decl: T);
402
403 // Create a TypeSourceInfo for the template type parameter 'T'
404 TypeSourceInfo *TTypeSourceInfo =
405 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
406
407 TypeTraitExpr *ResExpr = TypeTraitExpr::Create(
408 C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsConstantBufferElementCompatible,
409 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
410
411 return ResExpr;
412}
413
414// This function is responsible for constructing the constraint expression for
415// this concept:
416// template<typename T> concept is_structured_resource_element_compatible =
417// !__is_intangible<T> && sizeof(T) >= 1;
418static Expr *constructStructuredBufferConstraintExpr(Sema &S,
419 SourceLocation NameLoc,
420 TemplateTypeParmDecl *T) {
421 ASTContext &Context = S.getASTContext();
422
423 // Obtain the QualType for 'bool'
424 QualType BoolTy = Context.BoolTy;
425
426 // Create a QualType that points to this TemplateTypeParmDecl
427 QualType TType = Context.getTypeDeclType(Decl: T);
428
429 // Create a TypeSourceInfo for the template type parameter 'T'
430 TypeSourceInfo *TTypeSourceInfo =
431 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
432
433 TypeTraitExpr *IsIntangibleExpr =
434 TypeTraitExpr::Create(C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsIntangibleType,
435 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
436
437 // negate IsIntangibleExpr
438 UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(
439 C: Context, input: IsIntangibleExpr, opc: UO_LNot, type: BoolTy, VK: VK_LValue, OK: OK_Ordinary,
440 l: NameLoc, CanOverflow: false, FPFeatures: FPOptionsOverride());
441
442 // element types also may not be of 0 size
443 UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(
444 UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);
445
446 // Create a BinaryOperator that checks if the size of the type is not equal to
447 // 1 Empty structs have a size of 1 in HLSL, so we need to check for that
448 IntegerLiteral *rhs = IntegerLiteral::Create(
449 C: Context, V: llvm::APInt(Context.getTypeSize(T: Context.getSizeType()), 1, true),
450 type: Context.getSizeType(), l: NameLoc);
451
452 BinaryOperator *SizeGEQOneExpr =
453 BinaryOperator::Create(C: Context, lhs: SizeOfExpr, rhs, opc: BO_GE, ResTy: BoolTy, VK: VK_LValue,
454 OK: OK_Ordinary, opLoc: NameLoc, FPFeatures: FPOptionsOverride());
455
456 // Combine the two constraints
457 BinaryOperator *CombinedExpr = BinaryOperator::Create(
458 C: Context, lhs: NotIntangibleExpr, rhs: SizeGEQOneExpr, opc: BO_LAnd, ResTy: BoolTy, VK: VK_LValue,
459 OK: OK_Ordinary, opLoc: NameLoc, FPFeatures: FPOptionsOverride());
460
461 return CombinedExpr;
462}
463
464enum class HLSLBufferType { Typed, Structured, Constant };
465
466static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,
467 HLSLBufferType BT) {
468 ASTContext &Context = S.getASTContext();
469 DeclContext *DC = NSD->getDeclContext();
470 SourceLocation DeclLoc = SourceLocation();
471
472 IdentifierInfo &ElementTypeII = Context.Idents.get(Name: "element_type");
473 TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
474 C: Context, DC: NSD->getDeclContext(), KeyLoc: DeclLoc, NameLoc: DeclLoc,
475 /*D=*/0,
476 /*P=*/0,
477 /*Id=*/&ElementTypeII,
478 /*Typename=*/true,
479 /*ParameterPack=*/false);
480
481 T->setDeclContext(DC);
482 T->setReferenced();
483
484 // Create and Attach Template Parameter List to ConceptDecl
485 TemplateParameterList *ConceptParams = TemplateParameterList::Create(
486 C: Context, TemplateLoc: DeclLoc, LAngleLoc: DeclLoc, Params: {T}, RAngleLoc: DeclLoc, RequiresClause: nullptr);
487
488 DeclarationName DeclName;
489 Expr *ConstraintExpr = nullptr;
490
491 switch (BT) {
492 case HLSLBufferType::Typed:
493 DeclName = DeclarationName(
494 &Context.Idents.get(Name: "__is_typed_resource_element_compatible"));
495 ConstraintExpr = constructTypedBufferConstraintExpr(S, NameLoc: DeclLoc, T);
496 break;
497 case HLSLBufferType::Structured:
498 DeclName = DeclarationName(
499 &Context.Idents.get(Name: "__is_structured_resource_element_compatible"));
500 ConstraintExpr = constructStructuredBufferConstraintExpr(S, NameLoc: DeclLoc, T);
501 break;
502 case HLSLBufferType::Constant:
503 DeclName = DeclarationName(
504 &Context.Idents.get(Name: "__is_constant_buffer_element_compatible"));
505 ConstraintExpr = constructConstantBufferConstraintExpr(S, NameLoc: DeclLoc, T);
506 break;
507 }
508
509 // Create a ConceptDecl
510 ConceptDecl *CD =
511 ConceptDecl::Create(C&: Context, DC: NSD->getDeclContext(), L: DeclLoc, Name: DeclName,
512 Params: ConceptParams, ConstraintExpr);
513
514 // Attach the template parameter list to the ConceptDecl
515 CD->setTemplateParameters(ConceptParams);
516
517 // Add the concept declaration to the Translation Unit Decl
518 NSD->getDeclContext()->addDecl(D: CD);
519
520 return CD;
521}
522
523void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
524 ASTContext &AST = SemaPtr->getASTContext();
525 CXXRecordDecl *Decl;
526 ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(
527 S&: *SemaPtr, NSD: HLSLNamespace, BT: HLSLBufferType::Typed);
528 ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(
529 S&: *SemaPtr, NSD: HLSLNamespace, BT: HLSLBufferType::Structured);
530 ConceptDecl *ConstantBufferConcept = constructBufferConceptDecl(
531 S&: *SemaPtr, NSD: HLSLNamespace, BT: HLSLBufferType::Constant);
532
533 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConstantBuffer")
534 .addSimpleTemplateParams(Names: {"element_type"}, CD: ConstantBufferConcept)
535 .finalizeForwardDeclaration();
536
537 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
538 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::CBuffer, /*IsROV=*/false,
539 /*RawBuffer=*/false, /*HasCounter=*/false)
540 .addConstantBufferConversionToType()
541 .completeDefinition();
542 });
543
544 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Buffer")
545 .addSimpleTemplateParams(Names: {"element_type"}, CD: TypedBufferConcept)
546 .finalizeForwardDeclaration();
547
548 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
549 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
550 /*RawBuffer=*/false, /*HasCounter=*/false)
551 .addArraySubscriptOperators()
552 .addLoadMethods()
553 .addGetDimensionsMethodForBuffer()
554 .completeDefinition();
555 });
556
557 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
558 .addSimpleTemplateParams(Names: {"element_type"}, CD: TypedBufferConcept)
559 .finalizeForwardDeclaration();
560
561 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
562 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
563 /*RawBuffer=*/false, /*HasCounter=*/false)
564 .addArraySubscriptOperators()
565 .addLoadMethods()
566 .addGetDimensionsMethodForBuffer()
567 .completeDefinition();
568 });
569
570 Decl =
571 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
572 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
573 .finalizeForwardDeclaration();
574 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
575 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
576 /*RawBuffer=*/false, /*HasCounter=*/false)
577 .addArraySubscriptOperators()
578 .addLoadMethods()
579 .addGetDimensionsMethodForBuffer()
580 .completeDefinition();
581 });
582
583 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
584 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
585 .finalizeForwardDeclaration();
586 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
587 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
588 /*RawBuffer=*/true, /*HasCounter=*/false)
589 .addArraySubscriptOperators()
590 .addLoadMethods()
591 .addGetDimensionsMethodForBuffer()
592 .completeDefinition();
593 });
594
595 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
596 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
597 .finalizeForwardDeclaration();
598 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
599 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
600 /*RawBuffer=*/true, /*HasCounter=*/true)
601 .addArraySubscriptOperators()
602 .addLoadMethods()
603 .addIncrementCounterMethod()
604 .addDecrementCounterMethod()
605 .addGetDimensionsMethodForBuffer()
606 .completeDefinition();
607 });
608
609 Decl =
610 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")
611 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
612 .finalizeForwardDeclaration();
613 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
614 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
615 /*RawBuffer=*/true, /*HasCounter=*/true)
616 .addAppendMethod()
617 .addGetDimensionsMethodForBuffer()
618 .completeDefinition();
619 });
620
621 Decl =
622 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")
623 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
624 .finalizeForwardDeclaration();
625 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
626 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
627 /*RawBuffer=*/true, /*HasCounter=*/true)
628 .addConsumeMethod()
629 .addGetDimensionsMethodForBuffer()
630 .completeDefinition();
631 });
632
633 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
634 "RasterizerOrderedStructuredBuffer")
635 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
636 .finalizeForwardDeclaration();
637 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
638 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
639 /*RawBuffer=*/true, /*HasCounter=*/true)
640 .addArraySubscriptOperators()
641 .addLoadMethods()
642 .addIncrementCounterMethod()
643 .addDecrementCounterMethod()
644 .addGetDimensionsMethodForBuffer()
645 .completeDefinition();
646 });
647
648 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")
649 .finalizeForwardDeclaration();
650 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
651 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
652 /*RawBuffer=*/true, /*HasCounter=*/false)
653 .addByteAddressBufferLoadMethods()
654 .addGetDimensionsMethodForBuffer()
655 .completeDefinition();
656 });
657 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")
658 .finalizeForwardDeclaration();
659 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
660 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
661 /*RawBuffer=*/true, /*HasCounter=*/false)
662 .addByteAddressBufferLoadMethods()
663 .addByteAddressBufferStoreMethods()
664 .addGetDimensionsMethodForBuffer()
665 .completeDefinition();
666 });
667 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
668 "RasterizerOrderedByteAddressBuffer")
669 .finalizeForwardDeclaration();
670 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
671 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
672 /*RawBuffer=*/true, /*HasCounter=*/false)
673 .addGetDimensionsMethodForBuffer()
674 .completeDefinition();
675 });
676
677 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerState")
678 .finalizeForwardDeclaration();
679 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
680 setupSamplerType(Decl, S&: *SemaPtr).completeDefinition();
681 });
682
683 Decl =
684 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerComparisonState")
685 .finalizeForwardDeclaration();
686 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
687 setupSamplerType(Decl, S&: *SemaPtr).completeDefinition();
688 });
689
690 QualType Float4Ty = AST.getExtVectorType(VectorType: AST.FloatTy, NumElts: 4);
691 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
692 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
693 CD: TypedBufferConcept)
694 .finalizeForwardDeclaration();
695
696 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
697 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
698 /*IsArray=*/false, Dim: ResourceDimension::Dim2D)
699 .completeDefinition();
700 });
701
702 auto *PartialSpec = addVectorTexturePartialSpecialization(
703 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
704 onCompletion(Record: PartialSpec, Fn: [this](CXXRecordDecl *Decl) {
705 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
706 /*IsArray=*/false, Dim: ResourceDimension::Dim2D)
707 .completeDefinition();
708 });
709
710 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWTexture2D")
711 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
712 CD: TypedBufferConcept)
713 .finalizeForwardDeclaration();
714
715 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
716 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/false,
717 Dim: ResourceDimension::Dim2D)
718 .completeDefinition();
719 });
720
721 auto *PartialSpecRW = addVectorTexturePartialSpecialization(
722 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
723 onCompletion(Record: PartialSpecRW, Fn: [this](CXXRecordDecl *Decl) {
724 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/false,
725 Dim: ResourceDimension::Dim2D)
726 .completeDefinition();
727 });
728
729 // Texture2DArray — same as Texture2D but IsArray=true
730 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2DArray")
731 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
732 CD: TypedBufferConcept)
733 .finalizeForwardDeclaration();
734
735 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
736 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
737 /*IsArray=*/true, Dim: ResourceDimension::Dim2D)
738 .completeDefinition();
739 });
740
741 auto *PartialSpec2DA = addVectorTexturePartialSpecialization(
742 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
743 onCompletion(Record: PartialSpec2DA, Fn: [this](CXXRecordDecl *Decl) {
744 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
745 /*IsArray=*/true, Dim: ResourceDimension::Dim2D)
746 .completeDefinition();
747 });
748
749 // RWTexture2DArray — same as RWTexture2D but IsArray=true
750 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWTexture2DArray")
751 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
752 CD: TypedBufferConcept)
753 .finalizeForwardDeclaration();
754
755 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
756 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/true,
757 Dim: ResourceDimension::Dim2D)
758 .completeDefinition();
759 });
760
761 auto *PartialSpecRW2DA = addVectorTexturePartialSpecialization(
762 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
763 onCompletion(Record: PartialSpecRW2DA, Fn: [this](CXXRecordDecl *Decl) {
764 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/true,
765 Dim: ResourceDimension::Dim2D)
766 .completeDefinition();
767 });
768}
769
770// Build a single overload of an HLSL atomic intrinsic in the hlsl namespace.
771// `dest` is an address-space-qualified reference; `original_value` (when
772// present) is a plain reference. The synthesized FunctionDecl aliases the
773// underlying clang builtin via BuiltinAliasAttr.
774static void buildAtomicOverload(Sema &S, NamespaceDecl *NS, StringRef FuncName,
775 StringRef BuiltinName, QualType ElemTy,
776 LangAS DestAS, bool ThreeArg) {
777 ASTContext &AST = S.getASTContext();
778
779 QualType DestTy =
780 AST.getLValueReferenceType(T: AST.getAddrSpaceQualType(T: ElemTy, AddressSpace: DestAS));
781 QualType OrigRefTy = AST.getLValueReferenceType(T: ElemTy);
782
783 SmallVector<QualType, 3> ParamTypes;
784 ParamTypes.push_back(Elt: DestTy);
785 ParamTypes.push_back(Elt: ElemTy);
786 if (ThreeArg)
787 ParamTypes.push_back(Elt: OrigRefTy);
788
789 FunctionProtoType::ExtProtoInfo EPI;
790 QualType FuncTy = AST.getFunctionType(ResultTy: AST.VoidTy, Args: ParamTypes, EPI);
791 auto *TSInfo = AST.getTrivialTypeSourceInfo(T: FuncTy, Loc: SourceLocation());
792
793 IdentifierInfo &FuncII = AST.Idents.get(Name: FuncName, TokenCode: tok::TokenKind::identifier);
794 DeclarationName FuncDeclName(&FuncII);
795
796 FunctionDecl *FD = FunctionDecl::Create(
797 C&: AST, DC: NS, StartLoc: SourceLocation(), NLoc: SourceLocation(), N: FuncDeclName, T: FuncTy, TInfo: TSInfo,
798 SC: SC_Extern, /*UsesFPIntrin=*/false, /*isInlineSpecified=*/false,
799 /*hasWrittenPrototype=*/true);
800
801 constexpr const char *ParamNames[] = {"dest", "value", "original_value"};
802 SmallVector<ParmVarDecl *, 3> ParmDecls;
803 unsigned I = 0;
804 for (auto [ParamType, ParamName] : llvm::zip(t&: ParamTypes, u: ParamNames)) {
805 IdentifierInfo &PII = AST.Idents.get(Name: ParamName, TokenCode: tok::TokenKind::identifier);
806 ParmVarDecl *Parm = ParmVarDecl::Create(
807 C&: AST, DC: FD, StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &PII, T: ParamType,
808 TInfo: AST.getTrivialTypeSourceInfo(T: ParamType, Loc: SourceLocation()), S: SC_None,
809 DefArg: nullptr);
810 Parm->setScopeInfo(scopeDepth: 0, parameterIndex: I++);
811 ParmDecls.push_back(Elt: Parm);
812 }
813 FD->setParams(ParmDecls);
814
815 IdentifierInfo &BuiltinII =
816 S.getPreprocessor().getIdentifierTable().get(Name: BuiltinName);
817 FD->addAttr(A: BuiltinAliasAttr::CreateImplicit(Ctx&: AST, BuiltinName: &BuiltinII));
818 FD->setImplicit();
819 NS->addDecl(D: FD);
820}
821
822// Synthesize the InterlockedFunc overload set: {int, uint, int64_t, uint64_t}
823// x {groupshared, device} x {2-arg, 3-arg}.
824static void defineHLSLInterlockedFunc(Sema &S, NamespaceDecl *NS,
825 StringRef FuncName,
826 StringRef BuiltinName) {
827 ASTContext &AST = S.getASTContext();
828 // HLSL: int64_t == long, uint64_t == unsigned long (see hlsl_basic_types.h).
829 QualType Elems[] = {AST.IntTy, AST.UnsignedIntTy, AST.LongTy,
830 AST.UnsignedLongTy};
831 LangAS AddrSpaces[] = {LangAS::hlsl_groupshared, LangAS::hlsl_device};
832
833 for (QualType ElemTy : Elems)
834 for (LangAS AS : AddrSpaces)
835 for (bool ThreeArg : {false, true})
836 buildAtomicOverload(S, NS, FuncName, BuiltinName, ElemTy, DestAS: AS, ThreeArg);
837}
838
839void HLSLExternalSemaSource::defineHLSLAtomicIntrinsics() {
840 defineHLSLInterlockedFunc(S&: *SemaPtr, NS: HLSLNamespace, FuncName: "InterlockedAdd",
841 BuiltinName: "__builtin_hlsl_interlocked_add");
842 defineHLSLInterlockedFunc(S&: *SemaPtr, NS: HLSLNamespace, FuncName: "InterlockedOr",
843 BuiltinName: "__builtin_hlsl_interlocked_or");
844}
845
846void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
847 CompletionFunction Fn) {
848 if (!Record->isCompleteDefinition())
849 Completions.insert(KV: std::make_pair(x: Record->getCanonicalDecl(), y&: Fn));
850}
851
852void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
853 if (!isa<CXXRecordDecl>(Val: Tag))
854 return;
855 auto Record = cast<CXXRecordDecl>(Val: Tag);
856
857 // If this is a specialization, we need to get the underlying templated
858 // declaration and complete that.
859 if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Val: Record)) {
860 if (!isa<ClassTemplatePartialSpecializationDecl>(Val: TDecl)) {
861 ClassTemplateDecl *Template = TDecl->getSpecializedTemplate();
862 llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Partials;
863 Template->getPartialSpecializations(PS&: Partials);
864 ClassTemplatePartialSpecializationDecl *MatchedPartial = nullptr;
865 for (auto *Partial : Partials) {
866 sema::TemplateDeductionInfo Info(TDecl->getLocation());
867 if (SemaPtr->DeduceTemplateArguments(Partial, TemplateArgs: TDecl->getTemplateArgs(),
868 Info) ==
869 TemplateDeductionResult::Success) {
870 MatchedPartial = Partial;
871 break;
872 }
873 }
874 if (MatchedPartial)
875 Record = MatchedPartial;
876 else
877 Record = Template->getTemplatedDecl();
878 }
879 }
880 Record = Record->getCanonicalDecl();
881 auto It = Completions.find(Val: Record);
882 if (It == Completions.end())
883 return;
884 // Move out the callback and erase before invoking it: the callback can
885 // re-enter CompleteType and mutate Completions, which invalidates It under
886 // backward-shift deletion.
887 CompletionFunction Fn = std::move(It->second);
888 Completions.erase(I: It);
889 Fn(Record);
890}
891