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