clang 20.0.0git
HLSLExternalSemaSource.cpp
Go to the documentation of this file.
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
14#include "clang/AST/Attr.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/Type.h"
20#include "clang/Sema/Lookup.h"
21#include "clang/Sema/Sema.h"
22#include "clang/Sema/SemaHLSL.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/Frontend/HLSL/HLSLResource.h"
25#include "llvm/Support/ErrorHandling.h"
26
27#include <functional>
28
29using namespace clang;
30using namespace llvm::hlsl;
31
32static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name);
33
34namespace {
35
36struct TemplateParameterListBuilder;
37
38class BuiltinTypeDeclBuilder {
39 ClassTemplateDecl *Template = nullptr;
40 ClassTemplateDecl *PrevTemplate = nullptr;
41 NamespaceDecl *HLSLNamespace = nullptr;
42 llvm::StringMap<FieldDecl *> Fields;
43
44public:
45 Sema &SemaRef;
46 CXXRecordDecl *Record = nullptr;
47 friend struct TemplateParameterListBuilder;
48
49 BuiltinTypeDeclBuilder(Sema &SemaRef, CXXRecordDecl *R)
50 : SemaRef(SemaRef), Record(R) {
51 Record->startDefinition();
52 Template = Record->getDescribedClassTemplate();
53 }
54
55 BuiltinTypeDeclBuilder(Sema &SemaRef, NamespaceDecl *Namespace,
56 StringRef Name)
57 : HLSLNamespace(Namespace), SemaRef(SemaRef) {
58 ASTContext &AST = SemaRef.getASTContext();
59 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
60
61 LookupResult Result(SemaRef, &II, SourceLocation(), Sema::LookupTagName);
62 CXXRecordDecl *PrevDecl = nullptr;
63 if (SemaRef.LookupQualifiedName(Result, HLSLNamespace)) {
64 // Declaration already exists (from precompiled headers)
65 NamedDecl *Found = Result.getFoundDecl();
66 if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
67 PrevDecl = TD->getTemplatedDecl();
68 PrevTemplate = TD;
69 } else
70 PrevDecl = dyn_cast<CXXRecordDecl>(Found);
71 assert(PrevDecl && "Unexpected lookup result type.");
72 }
73
74 if (PrevDecl && PrevDecl->isCompleteDefinition()) {
75 Record = PrevDecl;
76 Template = PrevTemplate;
77 return;
78 }
79
80 Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
82 PrevDecl, true);
83 Record->setImplicit(true);
84 Record->setLexicalDeclContext(HLSLNamespace);
85 Record->setHasExternalLexicalStorage();
86
87 // Don't let anyone derive from built-in types.
88 Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
89 FinalAttr::Keyword_final));
90 }
91
92 ~BuiltinTypeDeclBuilder() {
93 if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
94 HLSLNamespace->addDecl(Record);
95 }
96
97 CXXRecordDecl *finalizeForwardDeclaration() {
98 // Force the QualType to be generated for the record declaration. In most
99 // cases this will happen naturally when something uses the type the
100 // QualType gets lazily created. Unfortunately, with our injected types if a
101 // type isn't used in a translation unit the QualType may not get
102 // automatically generated before a PCH is generated. To resolve this we
103 // just force that the QualType is generated after we create a forward
104 // declaration.
106 return Record;
107 }
108
109 BuiltinTypeDeclBuilder &
110 addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
111 AccessSpecifier Access = AccessSpecifier::AS_private) {
112 assert(!Record->isCompleteDefinition() && "record is already complete");
113 assert(Record->isBeingDefined() &&
114 "Definition must be started before adding members!");
115 ASTContext &AST = Record->getASTContext();
116
117 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
118 TypeSourceInfo *MemTySource =
120 auto *Field = FieldDecl::Create(
121 AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
122 nullptr, false, InClassInitStyle::ICIS_NoInit);
123 Field->setAccess(Access);
124 Field->setImplicit(true);
125 for (Attr *A : Attrs) {
126 if (A)
127 Field->addAttr(A);
128 }
129
130 Record->addDecl(Field);
131 Fields[Name] = Field;
132 return *this;
133 }
134
135 BuiltinTypeDeclBuilder &
136 addHandleMember(ResourceClass RC, ResourceKind RK, bool IsROV, bool RawBuffer,
137 AccessSpecifier Access = AccessSpecifier::AS_private) {
138 assert(!Record->isCompleteDefinition() && "record is already complete");
139
140 ASTContext &Ctx = SemaRef.getASTContext();
141 TypeSourceInfo *ElementTypeInfo =
142 Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());
143
144 // add handle member with resource type attributes
145 QualType AttributedResTy = QualType();
147 HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
148 IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
149 RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
150 ElementTypeInfo
151 ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
152 : nullptr};
153 Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
154 if (CreateHLSLAttributedResourceType(SemaRef, Ctx.HLSLResourceTy, Attrs,
155 AttributedResTy))
156 addMemberVariable("__handle", AttributedResTy, {ResourceAttr}, Access);
157 return *this;
158 }
159
160 BuiltinTypeDeclBuilder &addDefaultHandleConstructor() {
161 if (Record->isCompleteDefinition())
162 return *this;
163 ASTContext &AST = Record->getASTContext();
164
165 QualType ConstructorType =
167
168 CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
171 AST, Record, SourceLocation(),
172 DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
173 AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
174 ExplicitSpecifier(), false, true, false,
175 ConstexprSpecKind::Unspecified);
176
179 Constructor->setAccess(AccessSpecifier::AS_public);
180 Record->addDecl(Constructor);
181 return *this;
182 }
183
184 BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
185 ASTContext &AST = Record->getASTContext();
186 DeclarationName Subscript =
187 AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
188
189 addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
190 addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
191 return *this;
192 }
193
194 BuiltinTypeDeclBuilder &addLoadMethods() {
195 if (Record->isCompleteDefinition())
196 return *this;
197
198 ASTContext &AST = Record->getASTContext();
199 IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
201 // TODO: We also need versions with status for CheckAccessFullyMapped.
202 addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
203
204 return *this;
205 }
206
207 FieldDecl *getResourceHandleField() {
208 auto I = Fields.find("__handle");
209 assert(I != Fields.end() &&
210 I->second->getType()->isHLSLAttributedResourceType() &&
211 "record does not have resource handle field");
212 return I->second;
213 }
214
215 QualType getFirstTemplateTypeParam() {
216 assert(Template && "record it not a template");
217 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
218 Template->getTemplateParameters()->getParam(0))) {
219 return QualType(TTD->getTypeForDecl(), 0);
220 }
221 return QualType();
222 }
223
224 QualType getHandleElementType() {
225 if (Template)
226 return getFirstTemplateTypeParam();
227 // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
228 return SemaRef.getASTContext().Char8Ty;
229 }
230
231 BuiltinTypeDeclBuilder &startDefinition() {
232 assert(!Record->isCompleteDefinition() && "record is already complete");
233 Record->startDefinition();
234 return *this;
235 }
236
237 BuiltinTypeDeclBuilder &completeDefinition() {
238 assert(!Record->isCompleteDefinition() && "record is already complete");
239 assert(Record->isBeingDefined() &&
240 "Definition must be started before completing it.");
241
242 Record->completeDefinition();
243 return *this;
244 }
245
246 Expr *getConstantIntExpr(int value) {
247 ASTContext &AST = SemaRef.getASTContext();
249 AST, llvm::APInt(AST.getTypeSize(AST.IntTy), value, true), AST.IntTy,
251 }
252
253 TemplateParameterListBuilder addTemplateArgumentList();
254 BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef<StringRef> Names,
255 ConceptDecl *CD);
256
257 // Builtin types methods
258 BuiltinTypeDeclBuilder &addIncrementCounterMethod();
259 BuiltinTypeDeclBuilder &addDecrementCounterMethod();
260 BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
261 bool IsConst, bool IsRef);
262 BuiltinTypeDeclBuilder &addAppendMethod();
263 BuiltinTypeDeclBuilder &addConsumeMethod();
264};
265
266struct TemplateParameterListBuilder {
267 BuiltinTypeDeclBuilder &Builder;
269
270 TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) : Builder(RB) {}
271
272 ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
273
274 TemplateParameterListBuilder &
275 addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
276 assert(!Builder.Record->isCompleteDefinition() &&
277 "record is already complete");
278 ASTContext &AST = Builder.SemaRef.getASTContext();
279 unsigned Position = static_cast<unsigned>(Params.size());
281 AST, Builder.Record->getDeclContext(), SourceLocation(),
282 SourceLocation(), /* TemplateDepth */ 0, Position,
283 &AST.Idents.get(Name, tok::TokenKind::identifier),
284 /* Typename */ true,
285 /* ParameterPack */ false,
286 /* HasTypeConstraint*/ false);
287 if (!DefaultValue.isNull())
288 Decl->setDefaultArgument(AST,
289 Builder.SemaRef.getTrivialTemplateArgumentLoc(
290 DefaultValue, QualType(), SourceLocation()));
291
292 Params.emplace_back(Decl);
293 return *this;
294 }
295
296 // The concept specialization expression (CSE) constructed in
297 // constructConceptSpecializationExpr is constructed so that it
298 // matches the CSE that is constructed when parsing the below C++ code:
299 //
300 // template<typename T>
301 // concept is_typed_resource_element_compatible =
302 // __builtin_hlsl_typed_resource_element_compatible<T>
303 //
304 // template<typename element_type> requires
305 // is_typed_resource_element_compatible<element_type>
306 // struct RWBuffer {
307 // element_type Val;
308 // };
309 //
310 // int fn() {
311 // RWBuffer<int> Buf;
312 // }
313 //
314 // When dumping the AST and filtering for "RWBuffer", the resulting AST
315 // structure is what we're trying to construct below, specifically the
316 // CSE portion.
318 constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD) {
319 ASTContext &Context = S.getASTContext();
320 SourceLocation Loc = Builder.Record->getBeginLoc();
323 DeclContext *DC = Builder.Record->getDeclContext();
325
326 // Assume that the concept decl has just one template parameter
327 // This parameter should have been added when CD was constructed
328 // in getTypedBufferConceptDecl
329 assert(CD->getTemplateParameters()->size() == 1 &&
330 "unexpected concept decl parameter count");
331 TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>(
333
334 // this TemplateTypeParmDecl is the template for the resource, and is
335 // used to construct a template argumentthat will be used
336 // to construct the ImplicitConceptSpecializationDecl
338 Context, // AST context
339 Builder.Record->getDeclContext(), // DeclContext
341 /*D=*/0, // Depth in the template parameter list
342 /*P=*/0, // Position in the template parameter list
343 /*Id=*/nullptr, // Identifier for 'T'
344 /*Typename=*/true, // Indicates this is a 'typename' or 'class'
345 /*ParameterPack=*/false, // Not a parameter pack
346 /*HasTypeConstraint=*/false // Has no type constraint
347 );
348
349 T->setDeclContext(DC);
350
351 QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
352
353 // this is the 2nd template argument node, on which
354 // the concept constraint is actually being applied: 'element_type'
355 TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
356
357 QualType CSETType = Context.getTypeDeclType(T);
358
359 // this is the 1st template argument node, which represents
360 // the abstract type that a concept would refer to: 'T'
361 TemplateArgument CSETA = TemplateArgument(CSETType);
362
363 ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
365 Context, Builder.Record->getDeclContext(), Loc, {CSETA});
366
367 // Constraint satisfaction is used to construct the
368 // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
369 // located at the bottom of the sample AST above.
370 const ConstraintSatisfaction CS(CD, {ConceptTA});
372 ConceptTA, QualType(), SourceLocation());
373
374 TALI.addArgument(TAL);
375 const ASTTemplateArgumentListInfo *ATALI =
377
378 // In the concept reference, ATALI is what adds the extra
379 // TemplateArgument node underneath CSE
380 ConceptReference *CR =
381 ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);
382
384 ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);
385
386 return CSE;
387 }
388
389 BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr) {
390 if (Params.empty())
391 return Builder;
392
393 ASTContext &AST = Builder.SemaRef.Context;
395 CD ? constructConceptSpecializationExpr(Builder.SemaRef, CD) : nullptr;
396 auto *ParamList = TemplateParameterList::Create(
397 AST, SourceLocation(), SourceLocation(), Params, SourceLocation(), CSE);
398 Builder.Template = ClassTemplateDecl::Create(
399 AST, Builder.Record->getDeclContext(), SourceLocation(),
400 DeclarationName(Builder.Record->getIdentifier()), ParamList,
401 Builder.Record);
402
403 Builder.Record->setDescribedClassTemplate(Builder.Template);
404 Builder.Template->setImplicit(true);
405 Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
406
407 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
408 // make visible.
409 Builder.Template->setPreviousDecl(Builder.PrevTemplate);
410 Builder.Record->getDeclContext()->addDecl(Builder.Template);
411 Params.clear();
412
413 QualType T = Builder.Template->getInjectedClassNameSpecialization();
414 T = AST.getInjectedClassNameType(Builder.Record, T);
415
416 return Builder;
417 }
418};
419
420// Builder for methods of builtin types. Allows adding methods to builtin types
421// using the builder pattern like this:
422//
423// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
424// .addParam("param_name", Type, InOutModifier)
425// .callBuiltin("builtin_name", BuiltinParams...)
426// .finalizeMethod();
427//
428// The builder needs to have all of the method parameters before it can create
429// a CXXMethodDecl. It collects them in addParam calls and when a first
430// method that builds the body is called or when access to 'this` is needed it
431// creates the CXXMethodDecl and ParmVarDecls instances. These can then be
432// referenced from the body building methods. Destructor or an explicit call to
433// finalizeMethod() will complete the method definition.
434//
435// The callBuiltin helper method accepts constants via `Expr *` or placeholder
436// value arguments to indicate which function arguments to forward to the
437// builtin.
438//
439// If the method that is being built has a non-void return type the
440// finalizeMethod will create a return statent with the value of the last
441// statement (unless the last statement is already a ReturnStmt).
442struct BuiltinTypeMethodBuilder {
443 struct MethodParam {
444 const IdentifierInfo &NameII;
445 QualType Ty;
446 HLSLParamModifierAttr::Spelling Modifier;
447 MethodParam(const IdentifierInfo &NameII, QualType Ty,
448 HLSLParamModifierAttr::Spelling Modifier)
449 : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
450 };
451
452 BuiltinTypeDeclBuilder &DeclBuilder;
453 DeclarationNameInfo NameInfo;
454 QualType ReturnTy;
455 CXXMethodDecl *Method;
456 bool IsConst;
459
460 // Argument placeholders, inspired by std::placeholder. These are the indices
461 // of arguments to forward to `callBuiltin` and other method builder methods.
462 // Additional special values are:
463 // Handle - refers to the resource handle.
464 // LastStmt - refers to the last statement in the method body; referencing
465 // LastStmt will remove the statement from the method body since
466 // it will be linked from the new expression being constructed.
467 enum class PlaceHolder { _0, _1, _2, _3, Handle = 128, LastStmt };
468
469 Expr *convertPlaceholder(PlaceHolder PH) {
470 if (PH == PlaceHolder::Handle)
471 return getResourceHandleExpr();
472
473 if (PH == PlaceHolder::LastStmt) {
474 assert(!StmtsList.empty() && "no statements in the list");
475 Stmt *LastStmt = StmtsList.pop_back_val();
476 assert(isa<ValueStmt>(LastStmt) &&
477 "last statement does not have a value");
478 return cast<ValueStmt>(LastStmt)->getExprStmt();
479 }
480
481 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
482 ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));
483 return DeclRefExpr::Create(
484 AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
486 ParamDecl->getType(), VK_PRValue);
487 }
488 Expr *convertPlaceholder(Expr *E) { return E; }
489
490public:
491 BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
492 QualType ReturnTy, bool IsConst = false)
493 : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
494 ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}
495
496 BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
497 QualType ReturnTy, bool IsConst = false)
498 : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
499 const IdentifierInfo &II =
500 DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
502 }
503
504 BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
505 HLSLParamModifierAttr::Spelling Modifier =
506 HLSLParamModifierAttr::Keyword_in) {
507 assert(Method == nullptr && "Cannot add param, method already created");
508 const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(
509 Name, tok::TokenKind::identifier);
510 Params.emplace_back(II, Ty, Modifier);
511 return *this;
512 }
513
514private:
515 void createMethodDecl() {
516 assert(Method == nullptr && "Method already created");
517
518 // create method type
519 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
520 SmallVector<QualType> ParamTypes;
521 for (MethodParam &MP : Params)
522 ParamTypes.emplace_back(MP.Ty);
523
525 if (IsConst)
526 ExtInfo.TypeQuals.addConst();
527
528 QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
529
530 // create method decl
531 auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
532 Method =
533 CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
534 NameInfo, MethodTy, TSInfo, SC_None, false, false,
535 ConstexprSpecKind::Unspecified, SourceLocation());
536
537 // create params & set them to the function prototype
539 auto FnProtoLoc =
541 for (int I = 0, E = Params.size(); I != E; I++) {
542 MethodParam &MP = Params[I];
544 AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
545 &MP.NameII, MP.Ty,
547 nullptr);
548 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
549 auto *Mod =
550 HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
551 Parm->addAttr(Mod);
552 }
553 ParmDecls.push_back(Parm);
554 FnProtoLoc.setParam(I, Parm);
555 }
556 Method->setParams({ParmDecls});
557 }
558
559public:
560 ~BuiltinTypeMethodBuilder() { finalizeMethod(); }
561
562 BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
563 BuiltinTypeMethodBuilder &
564 operator=(const BuiltinTypeMethodBuilder &Other) = delete;
565
566 Expr *getResourceHandleExpr() {
567 // The first statement added to a method or access to 'this' creates the
568 // declaration.
569 if (!Method)
570 createMethodDecl();
571
572 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
574 AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
575 FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
576 return MemberExpr::CreateImplicit(AST, This, false, HandleField,
577 HandleField->getType(), VK_LValue,
579 }
580
581 template <typename... Ts>
582 BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
583 QualType ReturnType, Ts... ArgSpecs) {
584 std::array<Expr *, sizeof...(ArgSpecs)> Args{
585 convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
586
587 // The first statement added to a method or access to 'this` creates the
588 // declaration.
589 if (!Method)
590 createMethodDecl();
591
592 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
593 FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
595 AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
597
598 if (ReturnType.isNull())
599 ReturnType = FD->getReturnType();
600
601 Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
603 StmtsList.push_back(Call);
604 return *this;
605 }
606
607 template <typename TLHS, typename TRHS>
608 BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS) {
609 Expr *LHSExpr = convertPlaceholder(LHS);
610 Expr *RHSExpr = convertPlaceholder(RHS);
611 Stmt *AssignStmt = BinaryOperator::Create(
612 DeclBuilder.SemaRef.getASTContext(), LHSExpr, RHSExpr, BO_Assign,
613 LHSExpr->getType(), ExprValueKind::VK_PRValue,
614 ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());
615 StmtsList.push_back(AssignStmt);
616 return *this;
617 }
618
619 template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr) {
620 Expr *PtrExpr = convertPlaceholder(Ptr);
621 Expr *Deref =
622 UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,
623 UO_Deref, PtrExpr->getType()->getPointeeType(),
625 /*CanOverflow=*/false, FPOptionsOverride());
626 StmtsList.push_back(Deref);
627 return *this;
628 }
629
630 BuiltinTypeDeclBuilder &finalizeMethod() {
631 assert(!DeclBuilder.Record->isCompleteDefinition() &&
632 "record is already complete");
633 assert(
634 Method != nullptr &&
635 "method decl not created; are you missing a call to build the body?");
636
637 if (!Method->hasBody()) {
638 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
639 assert((ReturnTy == AST.VoidTy || !StmtsList.empty()) &&
640 "nothing to return from non-void method");
641 if (ReturnTy != AST.VoidTy) {
642 if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back())) {
643 assert(AST.hasSameUnqualifiedType(LastExpr->getType(),
644 ReturnTy.getNonReferenceType()) &&
645 "Return type of the last statement must match the return type "
646 "of the method");
647 if (!isa<ReturnStmt>(LastExpr)) {
648 StmtsList.pop_back();
649 StmtsList.push_back(
650 ReturnStmt::Create(AST, SourceLocation(), LastExpr, nullptr));
651 }
652 }
653 }
654
655 Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),
657 Method->setLexicalDeclContext(DeclBuilder.Record);
658 Method->setAccess(AccessSpecifier::AS_public);
659 Method->addAttr(AlwaysInlineAttr::CreateImplicit(
660 AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
661 DeclBuilder.Record->addDecl(Method);
662 }
663 return DeclBuilder;
664 }
665};
666
667} // namespace
668
669TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
670 return TemplateParameterListBuilder(*this);
671}
672
673BuiltinTypeDeclBuilder &
674BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
675 ConceptDecl *CD = nullptr) {
676 if (Record->isCompleteDefinition()) {
677 assert(Template && "existing record it not a template");
678 assert(Template->getTemplateParameters()->size() == Names.size() &&
679 "template param count mismatch");
680 return *this;
681 }
682
683 TemplateParameterListBuilder Builder = this->addTemplateArgumentList();
684 for (StringRef Name : Names)
685 Builder.addTypeParameter(Name);
686 return Builder.finalizeTemplateArgs(CD);
687}
688
689BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
690 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
691 return BuiltinTypeMethodBuilder(*this, "IncrementCounter",
693 .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
694 PH::Handle, getConstantIntExpr(1))
695 .finalizeMethod();
696}
697
698BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
699 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
700 return BuiltinTypeMethodBuilder(*this, "DecrementCounter",
702 .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
703 PH::Handle, getConstantIntExpr(-1))
704 .finalizeMethod();
705}
706
707BuiltinTypeDeclBuilder &
708BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
709 bool IsConst, bool IsRef) {
710 assert(!Record->isCompleteDefinition() && "record is already complete");
711 ASTContext &AST = SemaRef.getASTContext();
712 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
713
714 QualType ElemTy = getHandleElementType();
715 // TODO: Map to an hlsl_device address space.
716 QualType ElemPtrTy = AST.getPointerType(ElemTy);
717 QualType ReturnTy = ElemTy;
718 if (IsConst)
719 ReturnTy.addConst();
720 if (IsRef)
721 ReturnTy = AST.getLValueReferenceType(ReturnTy);
722
723 return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
724 .addParam("Index", AST.UnsignedIntTy)
725 .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
726 PH::_0)
727 .dereference(PH::LastStmt)
728 .finalizeMethod();
729}
730
731BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
732 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
733 ASTContext &AST = SemaRef.getASTContext();
734 QualType ElemTy = getHandleElementType();
735 return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)
736 .addParam("value", ElemTy)
737 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
738 PH::Handle, getConstantIntExpr(1))
739 .callBuiltin("__builtin_hlsl_resource_getpointer",
740 AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
741 .dereference(PH::LastStmt)
742 .assign(PH::LastStmt, PH::_0)
743 .finalizeMethod();
744}
745
746BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
747 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
748 ASTContext &AST = SemaRef.getASTContext();
749 QualType ElemTy = getHandleElementType();
750 return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)
751 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
752 PH::Handle, getConstantIntExpr(-1))
753 .callBuiltin("__builtin_hlsl_resource_getpointer",
754 AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
755 .dereference(PH::LastStmt)
756 .finalizeMethod();
757}
758
760
762 SemaPtr = &S;
763 ASTContext &AST = SemaPtr->getASTContext();
764 // If the translation unit has external storage force external decls to load.
766 (void)AST.getTranslationUnitDecl()->decls_begin();
767
768 IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
770 NamespaceDecl *PrevDecl = nullptr;
772 PrevDecl = Result.getAsSingle<NamespaceDecl>();
773 HLSLNamespace = NamespaceDecl::Create(
774 AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
775 SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
776 HLSLNamespace->setImplicit(true);
777 HLSLNamespace->setHasExternalLexicalStorage();
778 AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
779
780 // Force external decls in the HLSL namespace to load from the PCH.
781 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
782 defineTrivialHLSLTypes();
783 defineHLSLTypesWithForwardDeclarations();
784
785 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
786 // built in types inside a namespace, but we are planning to change that in
787 // the near future. In order to be source compatible older versions of HLSL
788 // will need to implicitly use the hlsl namespace. For now in clang everything
789 // will get added to the namespace, and we can remove the using directive for
790 // future language versions to match HLSL's evolution.
793 NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
795
797}
798
799void HLSLExternalSemaSource::defineHLSLVectorAlias() {
800 ASTContext &AST = SemaPtr->getASTContext();
801
802 llvm::SmallVector<NamedDecl *> TemplateParams;
803
804 auto *TypeParam = TemplateTypeParmDecl::Create(
805 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
806 &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
807 TypeParam->setDefaultArgument(
808 AST, SemaPtr->getTrivialTemplateArgumentLoc(
810
811 TemplateParams.emplace_back(TypeParam);
812
813 auto *SizeParam = NonTypeTemplateParmDecl::Create(
814 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
815 &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
816 false, AST.getTrivialTypeSourceInfo(AST.IntTy));
817 llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
818 TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
819 /*IsDefaulted=*/true);
820 SizeParam->setDefaultArgument(
822 SourceLocation(), SizeParam));
823 TemplateParams.emplace_back(SizeParam);
824
825 auto *ParamList =
827 TemplateParams, SourceLocation(), nullptr);
828
829 IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
830
832 AST.getTemplateTypeParmType(0, 0, false, TypeParam),
834 AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
835 DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
836 AST.IntTy, VK_LValue),
838
839 auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
840 SourceLocation(), &II,
841 AST.getTrivialTypeSourceInfo(AliasType));
842 Record->setImplicit(true);
843
844 auto *Template =
845 TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
846 Record->getIdentifier(), ParamList, Record);
847
848 Record->setDescribedAliasTemplate(Template);
849 Template->setImplicit(true);
850 Template->setLexicalDeclContext(Record->getDeclContext());
851 HLSLNamespace->addDecl(Template);
852}
853
854void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
855 defineHLSLVectorAlias();
856}
857
858/// Set up common members and attributes for buffer types
859static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
860 ResourceClass RC, ResourceKind RK,
861 bool IsROV, bool RawBuffer) {
862 return BuiltinTypeDeclBuilder(S, Decl)
863 .addHandleMember(RC, RK, IsROV, RawBuffer)
864 .addDefaultHandleConstructor();
865}
866
867// This function is responsible for constructing the constraint expression for
868// this concept:
869// template<typename T> concept is_typed_resource_element_compatible =
870// __is_typed_resource_element_compatible<T>;
873 ASTContext &Context = S.getASTContext();
874
875 // Obtain the QualType for 'bool'
876 QualType BoolTy = Context.BoolTy;
877
878 // Create a QualType that points to this TemplateTypeParmDecl
879 QualType TType = Context.getTypeDeclType(T);
880
881 // Create a TypeSourceInfo for the template type parameter 'T'
882 TypeSourceInfo *TTypeSourceInfo =
883 Context.getTrivialTypeSourceInfo(TType, NameLoc);
884
885 TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(
886 Context, BoolTy, NameLoc, UTT_IsTypedResourceElementCompatible,
887 {TTypeSourceInfo}, NameLoc, true);
888
889 return TypedResExpr;
890}
891
892// This function is responsible for constructing the constraint expression for
893// this concept:
894// template<typename T> concept is_structured_resource_element_compatible =
895// !__is_intangible<T> && sizeof(T) >= 1;
897 SourceLocation NameLoc,
899 ASTContext &Context = S.getASTContext();
900
901 // Obtain the QualType for 'bool'
902 QualType BoolTy = Context.BoolTy;
903
904 // Create a QualType that points to this TemplateTypeParmDecl
905 QualType TType = Context.getTypeDeclType(T);
906
907 // Create a TypeSourceInfo for the template type parameter 'T'
908 TypeSourceInfo *TTypeSourceInfo =
909 Context.getTrivialTypeSourceInfo(TType, NameLoc);
910
911 TypeTraitExpr *IsIntangibleExpr =
912 TypeTraitExpr::Create(Context, BoolTy, NameLoc, UTT_IsIntangibleType,
913 {TTypeSourceInfo}, NameLoc, true);
914
915 // negate IsIntangibleExpr
916 UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(
917 Context, IsIntangibleExpr, UO_LNot, BoolTy, VK_LValue, OK_Ordinary,
918 NameLoc, false, FPOptionsOverride());
919
920 // element types also may not be of 0 size
921 UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(
922 UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);
923
924 // Create a BinaryOperator that checks if the size of the type is not equal to
925 // 1 Empty structs have a size of 1 in HLSL, so we need to check for that
927 Context, llvm::APInt(Context.getTypeSize(Context.getSizeType()), 1, true),
928 Context.getSizeType(), NameLoc);
929
930 BinaryOperator *SizeGEQOneExpr =
931 BinaryOperator::Create(Context, SizeOfExpr, rhs, BO_GE, BoolTy, VK_LValue,
932 OK_Ordinary, NameLoc, FPOptionsOverride());
933
934 // Combine the two constraints
936 Context, NotIntangibleExpr, SizeGEQOneExpr, BO_LAnd, BoolTy, VK_LValue,
937 OK_Ordinary, NameLoc, FPOptionsOverride());
938
939 return CombinedExpr;
940}
941
943 bool isTypedBuffer) {
944 ASTContext &Context = S.getASTContext();
945 DeclContext *DC = NSD->getDeclContext();
946 SourceLocation DeclLoc = SourceLocation();
947
948 IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");
950 Context, NSD->getDeclContext(), DeclLoc, DeclLoc,
951 /*D=*/0,
952 /*P=*/0,
953 /*Id=*/&ElementTypeII,
954 /*Typename=*/true,
955 /*ParameterPack=*/false);
956
957 T->setDeclContext(DC);
958 T->setReferenced();
959
960 // Create and Attach Template Parameter List to ConceptDecl
962 Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr);
963
964 DeclarationName DeclName;
965 Expr *ConstraintExpr = nullptr;
966
967 if (isTypedBuffer) {
968 DeclName = DeclarationName(
969 &Context.Idents.get("__is_typed_resource_element_compatible"));
970 ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);
971 } else {
972 DeclName = DeclarationName(
973 &Context.Idents.get("__is_structured_resource_element_compatible"));
974 ConstraintExpr = constructStructuredBufferConstraintExpr(S, DeclLoc, T);
975 }
976
977 // Create a ConceptDecl
978 ConceptDecl *CD =
979 ConceptDecl::Create(Context, NSD->getDeclContext(), DeclLoc, DeclName,
980 ConceptParams, ConstraintExpr);
981
982 // Attach the template parameter list to the ConceptDecl
983 CD->setTemplateParameters(ConceptParams);
984
985 // Add the concept declaration to the Translation Unit Decl
986 NSD->getDeclContext()->addDecl(CD);
987
988 return CD;
989}
990
991void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
993 ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(
994 *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ true);
995 ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(
996 *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ false);
997 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
998 .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)
999 .finalizeForwardDeclaration();
1000
1001 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1002 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
1003 ResourceKind::TypedBuffer, /*IsROV=*/false,
1004 /*RawBuffer=*/false)
1005 .addArraySubscriptOperators()
1006 .addLoadMethods()
1007 .completeDefinition();
1008 });
1009
1010 Decl =
1011 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
1012 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
1013 .finalizeForwardDeclaration();
1014 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1015 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
1016 ResourceKind::TypedBuffer, /*IsROV=*/true,
1017 /*RawBuffer=*/false)
1018 .addArraySubscriptOperators()
1019 .addLoadMethods()
1020 .completeDefinition();
1021 });
1022
1023 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
1024 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
1025 .finalizeForwardDeclaration();
1026 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1027 setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, ResourceKind::RawBuffer,
1028 /*IsROV=*/false, /*RawBuffer=*/true)
1029 .addArraySubscriptOperators()
1030 .addLoadMethods()
1031 .completeDefinition();
1032 });
1033
1034 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
1035 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
1036 .finalizeForwardDeclaration();
1037 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1038 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
1039 /*IsROV=*/false, /*RawBuffer=*/true)
1040 .addArraySubscriptOperators()
1041 .addLoadMethods()
1042 .addIncrementCounterMethod()
1043 .addDecrementCounterMethod()
1044 .completeDefinition();
1045 });
1046
1047 Decl =
1048 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")
1049 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
1050 .finalizeForwardDeclaration();
1051 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1052 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
1053 /*IsROV=*/false, /*RawBuffer=*/true)
1054 .addAppendMethod()
1055 .completeDefinition();
1056 });
1057
1058 Decl =
1059 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")
1060 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
1061 .finalizeForwardDeclaration();
1062 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1063 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
1064 /*IsROV=*/false, /*RawBuffer=*/true)
1065 .addConsumeMethod()
1066 .completeDefinition();
1067 });
1068
1069 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
1070 "RasterizerOrderedStructuredBuffer")
1071 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
1072 .finalizeForwardDeclaration();
1073 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1074 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
1075 /*IsROV=*/true, /*RawBuffer=*/true)
1076 .addArraySubscriptOperators()
1077 .addLoadMethods()
1078 .addIncrementCounterMethod()
1079 .addDecrementCounterMethod()
1080 .completeDefinition();
1081 });
1082
1083 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")
1084 .finalizeForwardDeclaration();
1085 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1086 setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, ResourceKind::RawBuffer,
1087 /*IsROV=*/false,
1088 /*RawBuffer=*/true)
1089 .completeDefinition();
1090 });
1091 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")
1092 .finalizeForwardDeclaration();
1093 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1094 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
1095 /*IsROV=*/false,
1096 /*RawBuffer=*/true)
1097 .completeDefinition();
1098 });
1099 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
1100 "RasterizerOrderedByteAddressBuffer")
1101 .finalizeForwardDeclaration();
1102 onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1103 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
1104 /*IsROV=*/true,
1105 /*RawBuffer=*/true)
1106 .completeDefinition();
1107 });
1108}
1109
1110void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
1111 CompletionFunction Fn) {
1112 if (!Record->isCompleteDefinition())
1113 Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
1114}
1115
1117 if (!isa<CXXRecordDecl>(Tag))
1118 return;
1119 auto Record = cast<CXXRecordDecl>(Tag);
1120
1121 // If this is a specialization, we need to get the underlying templated
1122 // declaration and complete that.
1123 if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
1124 Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
1125 Record = Record->getCanonicalDecl();
1126 auto It = Completions.find(Record);
1127 if (It == Completions.end())
1128 return;
1129 It->second(Record);
1130}
1131
1132static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
1133 IdentifierInfo &II =
1134 S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
1135 DeclarationNameInfo NameInfo =
1137 LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
1138 // AllowBuiltinCreation is false but LookupDirect will create
1139 // the builtin when searching the global scope anyways...
1140 S.LookupName(R, S.getCurScope());
1141 // FIXME: If the builtin function was user-declared in global scope,
1142 // this assert *will* fail. Should this call LookupBuiltin instead?
1143 assert(R.isSingleResult() &&
1144 "Since this is a builtin it should always resolve!");
1145 return cast<FunctionDecl>(R.getFoundDecl());
1146}
Defines the clang::ASTContext interface.
Expr * E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV, bool RawBuffer)
Set up common members and attributes for buffer types.
static ConceptDecl * constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD, bool isTypedBuffer)
static Expr * constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc, TemplateTypeParmDecl *T)
static FunctionDecl * lookupBuiltinFunction(Sema &S, StringRef Name)
static Expr * constructStructuredBufferConstraintExpr(Sema &S, SourceLocation NameLoc, TemplateTypeParmDecl *T)
llvm::MachO::Record Record
Definition: MachO.h:31
This file declares semantic analysis for HLSL constructs.
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the clang::SourceLocation class and associated facilities.
C Language Family Type Representation.
static std::optional< DereferenceInfo > dereference(ProgramStateRef State, const FieldRegion *FR)
Dereferences FR and returns with the pointee's region, and whether it needs to be casted back to it's...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1141
unsigned getIntWidth(QualType T) const
DeclarationNameTable DeclarationNames
Definition: ASTContext.h:684
QualType getRecordType(const RecordDecl *Decl) const
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const
getInjectedClassNameType - Return the unique reference to the injected class name type for the specif...
CanQualType FloatTy
Definition: ASTContext.h:1172
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
QualType getTypeDeclType(const TypeDecl *Decl, const TypeDecl *PrevDecl=nullptr) const
Return the unique reference to the type for the specified type declaration.
Definition: ASTContext.h:1703
IdentifierTable & Idents
Definition: ASTContext.h:680
CanQualType BoolTy
Definition: ASTContext.h:1161
QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, TemplateTypeParmDecl *ParmDecl=nullptr) const
Retrieve the template type parameter type for a template parameter or parameter pack with the given d...
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
CanQualType IntTy
Definition: ASTContext.h:1169
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2763
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2482
CanQualType BuiltinFnTy
Definition: ASTContext.h:1190
CanQualType VoidTy
Definition: ASTContext.h:1160
CanQualType UnsignedIntTy
Definition: ASTContext.h:1170
QualType getFunctionType(QualType ResultTy, ArrayRef< QualType > Args, const FunctionProtoType::ExtProtoInfo &EPI) const
Return a normal function type with a typed argument list.
Definition: ASTContext.h:1681
QualType getDependentSizedExtVectorType(QualType VectorType, Expr *SizeExpr, SourceLocation AttrLoc) const
CanQualType Char8Ty
Definition: ASTContext.h:1166
Attr - This represents one attribute.
Definition: Attr.h:43
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3909
static BinaryOperator * Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptionsOverride FPFeatures)
Definition: Expr.cpp:4895
Represents a C++ constructor within a class.
Definition: DeclCXX.h:2553
static CXXConstructorDecl * Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited=InheritedConstructor(), Expr *TrailingRequiresClause=nullptr)
Definition: DeclCXX.cpp:2815
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2078
static CXXMethodDecl * Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, bool isInline, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, Expr *TrailingRequiresClause=nullptr)
Definition: DeclCXX.cpp:2368
QualType getFunctionObjectParameterType() const
Definition: DeclCXX.h:2228
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
static CXXRecordDecl * Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl=nullptr, bool DelayTypeCreation=false)
Definition: DeclCXX.cpp:131
Represents the this expression in C++.
Definition: ExprCXX.h:1152
static CXXThisExpr * Create(const ASTContext &Ctx, SourceLocation L, QualType Ty, bool IsImplicit)
Definition: ExprCXX.cpp:1568
static CallExpr * Create(const ASTContext &Ctx, Expr *Fn, ArrayRef< Expr * > Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs=0, ADLCallKind UsesADL=NotADL)
Create a call expression.
Definition: Expr.cpp:1492
Declaration of a class template.
static ClassTemplateDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl)
Create a class template node.
static CompoundStmt * Create(const ASTContext &C, ArrayRef< Stmt * > Stmts, FPOptionsOverride FPFeatures, SourceLocation LB, SourceLocation RB)
Definition: Stmt.cpp:390
Declaration of a C++20 concept.
static ConceptDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, Expr *ConstraintExpr=nullptr)
A reference to a concept and its template args, as it appears in the code.
Definition: ASTConcept.h:124
static ConceptReference * Create(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten)
Definition: ASTConcept.cpp:87
Represents the specialization of a concept - evaluates to a prvalue of type bool.
Definition: ExprConcepts.h:42
static ConceptSpecializationExpr * Create(const ASTContext &C, ConceptReference *ConceptRef, ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction)
The result of a constraint satisfaction check, containing the necessary information to diagnose an un...
Definition: ASTConcept.h:35
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1435
void addDecl(Decl *D)
Add the declaration D into this context.
Definition: DeclBase.cpp:1768
bool hasExternalLexicalStorage() const
Whether this DeclContext has external storage containing additional declarations that are lexically i...
Definition: DeclBase.h:2664
void setHasExternalLexicalStorage(bool ES=true) const
State whether this DeclContext has external storage for declarations lexically in this context.
Definition: DeclBase.h:2670
decl_iterator decls_begin() const
Definition: DeclBase.cpp:1624
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD=nullptr, const TemplateArgumentListInfo *TemplateArgs=nullptr, NonOdrUseReason NOUR=NOUR_None)
Definition: Expr.cpp:488
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:520
void addAttr(Attr *A)
Definition: DeclBase.cpp:1010
void setAccess(AccessSpecifier AS)
Definition: DeclBase.h:505
void setImplicit(bool I=true)
Definition: DeclBase.h:597
DeclContext * getDeclContext()
Definition: DeclBase.h:451
void setLexicalDeclContext(DeclContext *DC)
Definition: DeclBase.cpp:359
DeclarationName getCXXOperatorName(OverloadedOperatorKind Op)
Get the name of the overloadable C++ operator corresponding to Op.
DeclarationName getCXXConstructorName(CanQualType Ty)
Returns the name of a C++ constructor for the given Type.
The name of a declaration.
TypeSourceInfo * getTypeSourceInfo() const
Definition: Decl.h:764
Store information needed for an explicit specifier.
Definition: DeclCXX.h:1912
This represents one expression.
Definition: Expr.h:110
QualType getType() const
Definition: Expr.h:142
Represents difference between two FPOptions values.
Definition: LangOptions.h:978
Represents a member of a struct/union/class.
Definition: Decl.h:3033
static FieldDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle)
Definition: Decl.cpp:4555
Represents a function declaration or definition.
Definition: Decl.h:1935
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2672
QualType getReturnType() const
Definition: Decl.h:2720
void setBody(Stmt *B)
Definition: Decl.cpp:3255
DeclarationNameInfo getNameInfo() const
Definition: Decl.h:2146
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3163
void setParams(ArrayRef< ParmVarDecl * > NewParamInfo)
Definition: Decl.h:2680
void CompleteType(TagDecl *Tag) override
Complete an incomplete HLSL builtin type.
void InitializeSema(Sema &S) override
Initialize the semantic source with the Sema instance being used to perform semantic analysis on the ...
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
static ImplicitConceptSpecializationDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, ArrayRef< TemplateArgument > ConvertedArgs)
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Definition: Expr.cpp:973
Represents the results of name lookup.
Definition: Lookup.h:46
NamedDecl * getFoundDecl() const
Fetch the unique decl found by this lookup.
Definition: Lookup.h:568
bool isSingleResult() const
Determines if this names a single result which is not an unresolved value using decl.
Definition: Lookup.h:331
static MemberExpr * CreateImplicit(const ASTContext &C, Expr *Base, bool IsArrow, ValueDecl *MemberDecl, QualType T, ExprValueKind VK, ExprObjectKind OK)
Create an implicit MemberExpr, with no location, qualifier, template arguments, and so on.
Definition: Expr.h:3297
This represents a decl that may have a name.
Definition: Decl.h:253
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:319
Represent a C++ namespace.
Definition: Decl.h:551
NamespaceDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this namespace.
Definition: Decl.h:643
static NamespaceDecl * Create(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl, bool Nested)
Definition: DeclCXX.cpp:3067
A C++ nested-name-specifier augmented with source location information.
static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo)
Represents a parameter to a function.
Definition: Decl.h:1725
static ParmVarDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
Definition: Decl.cpp:2922
A (possibly-)qualified type.
Definition: Type.h:929
void addConst()
Add the const type qualifier to this QualType.
Definition: Type.h:1151
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:996
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition: Type.h:8134
void addConst()
Definition: Type.h:453
static ReturnStmt * Create(const ASTContext &Ctx, SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
Create a return statement.
Definition: Stmt.cpp:1211
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:463
TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc, NamedDecl *TemplateParam=nullptr)
Allocate a TemplateArgumentLoc where all locations have been initialized to the given location.
Scope * getCurScope() const
Retrieve the parser's current scope.
Definition: Sema.h:731
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition: Sema.h:8983
@ LookupNamespaceName
Look up a namespace name within a C++ using directive or namespace alias definition,...
Definition: Sema.h:9006
@ LookupTagName
Tag name lookup, which finds the names of enums, classes, structs, and unions.
Definition: Sema.h:8986
ASTContext & getASTContext() const
Definition: Sema.h:531
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup=false)
Perform qualified name lookup into a given context.
bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation=false, bool ForceNoCPlusPlus=false)
Perform unqualified name lookup starting from a given scope.
Encodes a location in the source.
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition: Stmt.h:84
Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:3564
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition: Decl.h:3667
A convenient class for passing around template argument information.
Definition: TemplateBase.h:632
Location wrapper for a TemplateArgument.
Definition: TemplateBase.h:524
Represents a template argument.
Definition: TemplateBase.h:61
void setTemplateParameters(TemplateParameterList *TParams)
Definition: DeclTemplate.h:453
TemplateParameterList * getTemplateParameters() const
Get the list of template parameters.
Definition: DeclTemplate.h:418
Stores a list of template parameters for a TemplateDecl and its derived classes.
Definition: DeclTemplate.h:73
NamedDecl * getParam(unsigned Idx)
Definition: DeclTemplate.h:147
static TemplateParameterList * Create(const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef< NamedDecl * > Params, SourceLocation RAngleLoc, Expr *RequiresClause)
Declaration of a template type parameter.
static TemplateTypeParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation KeyLoc, SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id, bool Typename, bool ParameterPack, bool HasTypeConstraint=false, std::optional< unsigned > NumExpanded=std::nullopt)
static TypeAliasDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, TypeSourceInfo *TInfo)
Definition: Decl.cpp:5576
static TypeAliasTemplateDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl)
Create a function template node.
T getAs() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
Definition: TypeLoc.h:89
A container of type source information.
Definition: Type.h:7902
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:256
A type trait used in the implementation of various C++11 and Library TR1 trait templates.
Definition: ExprCXX.h:2768
static TypeTraitExpr * Create(const ASTContext &C, QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef< TypeSourceInfo * > Args, SourceLocation RParenLoc, bool Value)
Create a new type trait expression.
Definition: ExprCXX.cpp:1876
The base class of the type hierarchy.
Definition: Type.h:1828
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:738
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
Definition: Expr.h:2622
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2232
static UnaryOperator * Create(const ASTContext &C, Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow, FPOptionsOverride FPFeatures)
Definition: Expr.cpp:4952
Represents a C++ using-declaration.
Definition: DeclCXX.h:3530
static UsingDirectiveDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceLocation NamespaceLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, NamedDecl *Nominated, DeclContext *CommonAncestor)
Definition: DeclCXX.cpp:3029
QualType getType() const
Definition: Decl.h:682
__inline void unsigned int _2
Definition: larchintrin.h:181
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2445
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1748
The JSON file list parser is used to communicate input to InstallAPI.
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition: Specifiers.h:151
@ SC_None
Definition: Specifiers.h:250
@ Result
The result type of a method or function.
bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, ArrayRef< const Attr * > AttrList, QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo=nullptr)
Definition: SemaHLSL.cpp:877
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition: Specifiers.h:135
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition: Specifiers.h:139
const FunctionProtoType * T
@ Other
Other implicit parameter.
AccessSpecifier
A C++ access specifier (public, private, protected), plus the special value "none" which means differ...
Definition: Specifiers.h:123
Represents an explicit template argument list in C++, e.g., the "<int>" in "sort<int>".
Definition: TemplateBase.h:676
static const ASTTemplateArgumentListInfo * Create(const ASTContext &C, const TemplateArgumentListInfo &List)
DeclarationNameInfo - A collector data type for bundling together a DeclarationName and the correspon...
Extra information about a function prototype.
Definition: Type.h:5187