xref: /llvm-project/clang/lib/Sema/HLSLExternalSemaSource.cpp (revision 7a4b3b4927bd92e8494dca9dffaf5aeeca4658ba)
1b8dbc6ffSChris Bieneman //===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
2b8dbc6ffSChris Bieneman //
3b8dbc6ffSChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b8dbc6ffSChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
5b8dbc6ffSChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b8dbc6ffSChris Bieneman //
7b8dbc6ffSChris Bieneman //===----------------------------------------------------------------------===//
8b8dbc6ffSChris Bieneman //
9b8dbc6ffSChris Bieneman //
10b8dbc6ffSChris Bieneman //===----------------------------------------------------------------------===//
11b8dbc6ffSChris Bieneman 
12b8dbc6ffSChris Bieneman #include "clang/Sema/HLSLExternalSemaSource.h"
13b8dbc6ffSChris Bieneman #include "clang/AST/ASTContext.h"
1466eabeb6SChris Bieneman #include "clang/AST/Attr.h"
15cac97833SHelena Kotas #include "clang/AST/Decl.h"
16b8dbc6ffSChris Bieneman #include "clang/AST/DeclCXX.h"
17cac97833SHelena Kotas #include "clang/AST/Expr.h"
188e35c869SHelena Kotas #include "clang/AST/Type.h"
190a7a1ef2SHelena Kotas #include "clang/Basic/SourceLocation.h"
2066eabeb6SChris Bieneman #include "clang/Sema/Lookup.h"
21b8dbc6ffSChris Bieneman #include "clang/Sema/Sema.h"
228e35c869SHelena Kotas #include "clang/Sema/SemaHLSL.h"
238e35c869SHelena Kotas #include "llvm/ADT/SmallVector.h"
24a7183a15SXiang Li #include "llvm/Frontend/HLSL/HLSLResource.h"
25cac97833SHelena Kotas #include "llvm/Support/ErrorHandling.h"
26b8dbc6ffSChris Bieneman 
276e56d0dbSChris Bieneman #include <functional>
286e56d0dbSChris Bieneman 
29b8dbc6ffSChris Bieneman using namespace clang;
30a7183a15SXiang Li using namespace llvm::hlsl;
31b8dbc6ffSChris Bieneman 
32cac97833SHelena Kotas static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name);
33cac97833SHelena Kotas 
346e56d0dbSChris Bieneman namespace {
356e56d0dbSChris Bieneman 
366e56d0dbSChris Bieneman struct TemplateParameterListBuilder;
376e56d0dbSChris Bieneman 
381df28554Sjoaosaffran class BuiltinTypeDeclBuilder {
396e56d0dbSChris Bieneman   ClassTemplateDecl *Template = nullptr;
40079a5ffbSXiang Li   ClassTemplateDecl *PrevTemplate = nullptr;
416e56d0dbSChris Bieneman   NamespaceDecl *HLSLNamespace = nullptr;
4266eabeb6SChris Bieneman   llvm::StringMap<FieldDecl *> Fields;
436e56d0dbSChris Bieneman 
441df28554Sjoaosaffran public:
451df28554Sjoaosaffran   Sema &SemaRef;
461df28554Sjoaosaffran   CXXRecordDecl *Record = nullptr;
471df28554Sjoaosaffran   friend struct TemplateParameterListBuilder;
481df28554Sjoaosaffran 
49cac97833SHelena Kotas   BuiltinTypeDeclBuilder(Sema &SemaRef, CXXRecordDecl *R)
50cac97833SHelena Kotas       : SemaRef(SemaRef), Record(R) {
516e56d0dbSChris Bieneman     Record->startDefinition();
526e56d0dbSChris Bieneman     Template = Record->getDescribedClassTemplate();
536e56d0dbSChris Bieneman   }
546e56d0dbSChris Bieneman 
55cac97833SHelena Kotas   BuiltinTypeDeclBuilder(Sema &SemaRef, NamespaceDecl *Namespace,
56cac97833SHelena Kotas                          StringRef Name)
571df28554Sjoaosaffran       : HLSLNamespace(Namespace), SemaRef(SemaRef) {
58cac97833SHelena Kotas     ASTContext &AST = SemaRef.getASTContext();
596e56d0dbSChris Bieneman     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
606e56d0dbSChris Bieneman 
61cac97833SHelena Kotas     LookupResult Result(SemaRef, &II, SourceLocation(), Sema::LookupTagName);
62079a5ffbSXiang Li     CXXRecordDecl *PrevDecl = nullptr;
63cac97833SHelena Kotas     if (SemaRef.LookupQualifiedName(Result, HLSLNamespace)) {
64cac97833SHelena Kotas       // Declaration already exists (from precompiled headers)
65079a5ffbSXiang Li       NamedDecl *Found = Result.getFoundDecl();
66079a5ffbSXiang Li       if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
67079a5ffbSXiang Li         PrevDecl = TD->getTemplatedDecl();
68079a5ffbSXiang Li         PrevTemplate = TD;
69079a5ffbSXiang Li       } else
70079a5ffbSXiang Li         PrevDecl = dyn_cast<CXXRecordDecl>(Found);
71079a5ffbSXiang Li       assert(PrevDecl && "Unexpected lookup result type.");
72079a5ffbSXiang Li     }
73079a5ffbSXiang Li 
74079a5ffbSXiang Li     if (PrevDecl && PrevDecl->isCompleteDefinition()) {
75079a5ffbSXiang Li       Record = PrevDecl;
76cac97833SHelena Kotas       Template = PrevTemplate;
77079a5ffbSXiang Li       return;
78079a5ffbSXiang Li     }
79079a5ffbSXiang Li 
80edd690b0SVlad Serebrennikov     Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
81edd690b0SVlad Serebrennikov                                    SourceLocation(), SourceLocation(), &II,
82edd690b0SVlad Serebrennikov                                    PrevDecl, true);
836e56d0dbSChris Bieneman     Record->setImplicit(true);
846e56d0dbSChris Bieneman     Record->setLexicalDeclContext(HLSLNamespace);
856e56d0dbSChris Bieneman     Record->setHasExternalLexicalStorage();
866e56d0dbSChris Bieneman 
87079a5ffbSXiang Li     // Don't let anyone derive from built-in types.
886e56d0dbSChris Bieneman     Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
896e56d0dbSChris Bieneman                                               FinalAttr::Keyword_final));
906e56d0dbSChris Bieneman   }
916e56d0dbSChris Bieneman 
926e56d0dbSChris Bieneman   ~BuiltinTypeDeclBuilder() {
93079a5ffbSXiang Li     if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
946e56d0dbSChris Bieneman       HLSLNamespace->addDecl(Record);
956e56d0dbSChris Bieneman   }
966e56d0dbSChris Bieneman 
971df28554Sjoaosaffran   CXXRecordDecl *finalizeForwardDeclaration() {
981df28554Sjoaosaffran     // Force the QualType to be generated for the record declaration. In most
991df28554Sjoaosaffran     // cases this will happen naturally when something uses the type the
1001df28554Sjoaosaffran     // QualType gets lazily created. Unfortunately, with our injected types if a
1011df28554Sjoaosaffran     // type isn't used in a translation unit the QualType may not get
1021df28554Sjoaosaffran     // automatically generated before a PCH is generated. To resolve this we
1031df28554Sjoaosaffran     // just force that the QualType is generated after we create a forward
1041df28554Sjoaosaffran     // declaration.
1051df28554Sjoaosaffran     (void)Record->getASTContext().getRecordType(Record);
1061df28554Sjoaosaffran     return Record;
1071df28554Sjoaosaffran   }
1081df28554Sjoaosaffran 
1096e56d0dbSChris Bieneman   BuiltinTypeDeclBuilder &
110ac319a8dSJoshua Batista   addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
1116e56d0dbSChris Bieneman                     AccessSpecifier Access = AccessSpecifier::AS_private) {
112cac97833SHelena Kotas     assert(!Record->isCompleteDefinition() && "record is already complete");
1136e56d0dbSChris Bieneman     assert(Record->isBeingDefined() &&
1146e56d0dbSChris Bieneman            "Definition must be started before adding members!");
1156e56d0dbSChris Bieneman     ASTContext &AST = Record->getASTContext();
1166e56d0dbSChris Bieneman 
1176e56d0dbSChris Bieneman     IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
1186e56d0dbSChris Bieneman     TypeSourceInfo *MemTySource =
1196e56d0dbSChris Bieneman         AST.getTrivialTypeSourceInfo(Type, SourceLocation());
1206e56d0dbSChris Bieneman     auto *Field = FieldDecl::Create(
1216e56d0dbSChris Bieneman         AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
1226e56d0dbSChris Bieneman         nullptr, false, InClassInitStyle::ICIS_NoInit);
1236e56d0dbSChris Bieneman     Field->setAccess(Access);
1246e56d0dbSChris Bieneman     Field->setImplicit(true);
125eae1d65fSJoshua Batista     for (Attr *A : Attrs) {
126eae1d65fSJoshua Batista       if (A)
127ac319a8dSJoshua Batista         Field->addAttr(A);
128eae1d65fSJoshua Batista     }
129eae1d65fSJoshua Batista 
1306e56d0dbSChris Bieneman     Record->addDecl(Field);
13166eabeb6SChris Bieneman     Fields[Name] = Field;
1326e56d0dbSChris Bieneman     return *this;
1336e56d0dbSChris Bieneman   }
1346e56d0dbSChris Bieneman 
1356e56d0dbSChris Bieneman   BuiltinTypeDeclBuilder &
136cac97833SHelena Kotas   addHandleMember(ResourceClass RC, ResourceKind RK, bool IsROV, bool RawBuffer,
137ac319a8dSJoshua Batista                   AccessSpecifier Access = AccessSpecifier::AS_private) {
138cac97833SHelena Kotas     assert(!Record->isCompleteDefinition() && "record is already complete");
1390a7a1ef2SHelena Kotas 
140cac97833SHelena Kotas     ASTContext &Ctx = SemaRef.getASTContext();
141bd92e462SJustin Bogner     TypeSourceInfo *ElementTypeInfo =
142bd92e462SJustin Bogner         Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());
1438e35c869SHelena Kotas 
1448e35c869SHelena Kotas     // add handle member with resource type attributes
1458e35c869SHelena Kotas     QualType AttributedResTy = QualType();
1468e35c869SHelena Kotas     SmallVector<const Attr *> Attrs = {
147e20bf289SHelena Kotas         HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
148e20bf289SHelena Kotas         IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
149e20bf289SHelena Kotas         RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
150e20bf289SHelena Kotas         ElementTypeInfo
151e20bf289SHelena Kotas             ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
1525df1b793SHelena Kotas             : nullptr};
153e20bf289SHelena Kotas     Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
154cac97833SHelena Kotas     if (CreateHLSLAttributedResourceType(SemaRef, Ctx.HLSLResourceTy, Attrs,
155e20bf289SHelena Kotas                                          AttributedResTy))
1564818dd33SJustin Bogner       addMemberVariable("__handle", AttributedResTy, {ResourceAttr}, Access);
157cc47db67SChris Bieneman     return *this;
158cc47db67SChris Bieneman   }
159cc47db67SChris Bieneman 
160cac97833SHelena Kotas   BuiltinTypeDeclBuilder &addDefaultHandleConstructor() {
161079a5ffbSXiang Li     if (Record->isCompleteDefinition())
162079a5ffbSXiang Li       return *this;
16366eabeb6SChris Bieneman     ASTContext &AST = Record->getASTContext();
16466eabeb6SChris Bieneman 
16566eabeb6SChris Bieneman     QualType ConstructorType =
16666eabeb6SChris Bieneman         AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
16766eabeb6SChris Bieneman 
16866eabeb6SChris Bieneman     CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
16966eabeb6SChris Bieneman     DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
17066eabeb6SChris Bieneman     CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
17166eabeb6SChris Bieneman         AST, Record, SourceLocation(),
17266eabeb6SChris Bieneman         DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
17366eabeb6SChris Bieneman         AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
17466eabeb6SChris Bieneman         ExplicitSpecifier(), false, true, false,
17566eabeb6SChris Bieneman         ConstexprSpecKind::Unspecified);
17666eabeb6SChris Bieneman 
17790b7fe42SHelena Kotas     Constructor->setBody(CompoundStmt::Create(
17890b7fe42SHelena Kotas         AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
17966eabeb6SChris Bieneman     Constructor->setAccess(AccessSpecifier::AS_public);
18066eabeb6SChris Bieneman     Record->addDecl(Constructor);
18166eabeb6SChris Bieneman     return *this;
18266eabeb6SChris Bieneman   }
18366eabeb6SChris Bieneman 
18400ecaccaSChris Bieneman   BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
18500ecaccaSChris Bieneman     ASTContext &AST = Record->getASTContext();
186bd92e462SJustin Bogner     DeclarationName Subscript =
187bd92e462SJustin Bogner         AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
18800ecaccaSChris Bieneman 
189bd92e462SJustin Bogner     addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
190bd92e462SJustin Bogner     addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
19100ecaccaSChris Bieneman     return *this;
19200ecaccaSChris Bieneman   }
19300ecaccaSChris Bieneman 
194de401599SJustin Bogner   BuiltinTypeDeclBuilder &addLoadMethods() {
195de401599SJustin Bogner     if (Record->isCompleteDefinition())
196de401599SJustin Bogner       return *this;
197de401599SJustin Bogner 
198de401599SJustin Bogner     ASTContext &AST = Record->getASTContext();
199de401599SJustin Bogner     IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
200de401599SJustin Bogner     DeclarationName Load(&II);
201de401599SJustin Bogner     // TODO: We also need versions with status for CheckAccessFullyMapped.
202de401599SJustin Bogner     addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
203de401599SJustin Bogner 
204de401599SJustin Bogner     return *this;
205de401599SJustin Bogner   }
206de401599SJustin Bogner 
207cac97833SHelena Kotas   FieldDecl *getResourceHandleField() {
208cac97833SHelena Kotas     auto I = Fields.find("__handle");
209cac97833SHelena Kotas     assert(I != Fields.end() &&
210cac97833SHelena Kotas            I->second->getType()->isHLSLAttributedResourceType() &&
211cac97833SHelena Kotas            "record does not have resource handle field");
212cac97833SHelena Kotas     return I->second;
213cac97833SHelena Kotas   }
214cac97833SHelena Kotas 
215cac97833SHelena Kotas   QualType getFirstTemplateTypeParam() {
216cac97833SHelena Kotas     assert(Template && "record it not a template");
217cac97833SHelena Kotas     if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
218cac97833SHelena Kotas             Template->getTemplateParameters()->getParam(0))) {
219cac97833SHelena Kotas       return QualType(TTD->getTypeForDecl(), 0);
220cac97833SHelena Kotas     }
221cac97833SHelena Kotas     return QualType();
222cac97833SHelena Kotas   }
223cac97833SHelena Kotas 
224bd92e462SJustin Bogner   QualType getHandleElementType() {
225bd92e462SJustin Bogner     if (Template)
226bd92e462SJustin Bogner       return getFirstTemplateTypeParam();
227bd92e462SJustin Bogner     // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
228bd92e462SJustin Bogner     return SemaRef.getASTContext().Char8Ty;
229bd92e462SJustin Bogner   }
230bd92e462SJustin Bogner 
2316e56d0dbSChris Bieneman   BuiltinTypeDeclBuilder &startDefinition() {
232cac97833SHelena Kotas     assert(!Record->isCompleteDefinition() && "record is already complete");
2336e56d0dbSChris Bieneman     Record->startDefinition();
2346e56d0dbSChris Bieneman     return *this;
2356e56d0dbSChris Bieneman   }
2366e56d0dbSChris Bieneman 
2376e56d0dbSChris Bieneman   BuiltinTypeDeclBuilder &completeDefinition() {
238cac97833SHelena Kotas     assert(!Record->isCompleteDefinition() && "record is already complete");
2396e56d0dbSChris Bieneman     assert(Record->isBeingDefined() &&
2406e56d0dbSChris Bieneman            "Definition must be started before completing it.");
2416e56d0dbSChris Bieneman 
2426e56d0dbSChris Bieneman     Record->completeDefinition();
2436e56d0dbSChris Bieneman     return *this;
2446e56d0dbSChris Bieneman   }
2456e56d0dbSChris Bieneman 
246cac97833SHelena Kotas   Expr *getConstantIntExpr(int value) {
247cac97833SHelena Kotas     ASTContext &AST = SemaRef.getASTContext();
248cac97833SHelena Kotas     return IntegerLiteral::Create(
249cac97833SHelena Kotas         AST, llvm::APInt(AST.getTypeSize(AST.IntTy), value, true), AST.IntTy,
250cac97833SHelena Kotas         SourceLocation());
251cac97833SHelena Kotas   }
252cac97833SHelena Kotas 
253cac97833SHelena Kotas   TemplateParameterListBuilder addTemplateArgumentList();
254cac97833SHelena Kotas   BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef<StringRef> Names,
255cac97833SHelena Kotas                                                   ConceptDecl *CD);
256cac97833SHelena Kotas 
257cac97833SHelena Kotas   // Builtin types methods
258cac97833SHelena Kotas   BuiltinTypeDeclBuilder &addIncrementCounterMethod();
259cac97833SHelena Kotas   BuiltinTypeDeclBuilder &addDecrementCounterMethod();
260bd92e462SJustin Bogner   BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
261bd92e462SJustin Bogner                                                   bool IsConst, bool IsRef);
262274637d7SHelena Kotas   BuiltinTypeDeclBuilder &addAppendMethod();
263274637d7SHelena Kotas   BuiltinTypeDeclBuilder &addConsumeMethod();
2646e56d0dbSChris Bieneman };
2656e56d0dbSChris Bieneman 
2666e56d0dbSChris Bieneman struct TemplateParameterListBuilder {
2676e56d0dbSChris Bieneman   BuiltinTypeDeclBuilder &Builder;
2686e56d0dbSChris Bieneman   llvm::SmallVector<NamedDecl *> Params;
2696e56d0dbSChris Bieneman 
270cac97833SHelena Kotas   TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) : Builder(RB) {}
2716e56d0dbSChris Bieneman 
2726e56d0dbSChris Bieneman   ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
2736e56d0dbSChris Bieneman 
2746e56d0dbSChris Bieneman   TemplateParameterListBuilder &
2756e56d0dbSChris Bieneman   addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
276cac97833SHelena Kotas     assert(!Builder.Record->isCompleteDefinition() &&
277cac97833SHelena Kotas            "record is already complete");
278cac97833SHelena Kotas     ASTContext &AST = Builder.SemaRef.getASTContext();
2796e56d0dbSChris Bieneman     unsigned Position = static_cast<unsigned>(Params.size());
2806e56d0dbSChris Bieneman     auto *Decl = TemplateTypeParmDecl::Create(
281cac97833SHelena Kotas         AST, Builder.Record->getDeclContext(), SourceLocation(),
2826e56d0dbSChris Bieneman         SourceLocation(), /* TemplateDepth */ 0, Position,
283cac97833SHelena Kotas         &AST.Idents.get(Name, tok::TokenKind::identifier),
284ee0ca4e8SJoshua Batista         /* Typename */ true,
285ee0ca4e8SJoshua Batista         /* ParameterPack */ false,
286ee0ca4e8SJoshua Batista         /* HasTypeConstraint*/ false);
2876e56d0dbSChris Bieneman     if (!DefaultValue.isNull())
288cac97833SHelena Kotas       Decl->setDefaultArgument(AST,
289cac97833SHelena Kotas                                Builder.SemaRef.getTrivialTemplateArgumentLoc(
290cac97833SHelena Kotas                                    DefaultValue, QualType(), SourceLocation()));
291c1f6cb74SJoshua Batista 
2926e56d0dbSChris Bieneman     Params.emplace_back(Decl);
2936e56d0dbSChris Bieneman     return *this;
2946e56d0dbSChris Bieneman   }
2956e56d0dbSChris Bieneman 
296ee0ca4e8SJoshua Batista   // The concept specialization expression (CSE) constructed in
297ee0ca4e8SJoshua Batista   // constructConceptSpecializationExpr is constructed so that it
298ee0ca4e8SJoshua Batista   // matches the CSE that is constructed when parsing the below C++ code:
299ee0ca4e8SJoshua Batista   //
300ee0ca4e8SJoshua Batista   // template<typename T>
301ee0ca4e8SJoshua Batista   // concept is_typed_resource_element_compatible =
302ee0ca4e8SJoshua Batista   // __builtin_hlsl_typed_resource_element_compatible<T>
303ee0ca4e8SJoshua Batista   //
304ee0ca4e8SJoshua Batista   // template<typename element_type> requires
305ee0ca4e8SJoshua Batista   // is_typed_resource_element_compatible<element_type>
306ee0ca4e8SJoshua Batista   // struct RWBuffer {
307ee0ca4e8SJoshua Batista   //     element_type Val;
308ee0ca4e8SJoshua Batista   // };
309ee0ca4e8SJoshua Batista   //
310ee0ca4e8SJoshua Batista   // int fn() {
311ee0ca4e8SJoshua Batista   //     RWBuffer<int> Buf;
312ee0ca4e8SJoshua Batista   // }
313ee0ca4e8SJoshua Batista   //
314ee0ca4e8SJoshua Batista   // When dumping the AST and filtering for "RWBuffer", the resulting AST
315ee0ca4e8SJoshua Batista   // structure is what we're trying to construct below, specifically the
316ee0ca4e8SJoshua Batista   // CSE portion.
317ee0ca4e8SJoshua Batista   ConceptSpecializationExpr *
318ee0ca4e8SJoshua Batista   constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD) {
319ee0ca4e8SJoshua Batista     ASTContext &Context = S.getASTContext();
320ee0ca4e8SJoshua Batista     SourceLocation Loc = Builder.Record->getBeginLoc();
321ee0ca4e8SJoshua Batista     DeclarationNameInfo DNI(CD->getDeclName(), Loc);
322ee0ca4e8SJoshua Batista     NestedNameSpecifierLoc NNSLoc;
323ee0ca4e8SJoshua Batista     DeclContext *DC = Builder.Record->getDeclContext();
324ee0ca4e8SJoshua Batista     TemplateArgumentListInfo TALI(Loc, Loc);
325ee0ca4e8SJoshua Batista 
326ee0ca4e8SJoshua Batista     // Assume that the concept decl has just one template parameter
327ee0ca4e8SJoshua Batista     // This parameter should have been added when CD was constructed
328ee0ca4e8SJoshua Batista     // in getTypedBufferConceptDecl
329ee0ca4e8SJoshua Batista     assert(CD->getTemplateParameters()->size() == 1 &&
330ee0ca4e8SJoshua Batista            "unexpected concept decl parameter count");
331ee0ca4e8SJoshua Batista     TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>(
332ee0ca4e8SJoshua Batista         CD->getTemplateParameters()->getParam(0));
333ee0ca4e8SJoshua Batista 
334ee0ca4e8SJoshua Batista     // this TemplateTypeParmDecl is the template for the resource, and is
335ee0ca4e8SJoshua Batista     // used to construct a template argumentthat will be used
336ee0ca4e8SJoshua Batista     // to construct the ImplicitConceptSpecializationDecl
337ee0ca4e8SJoshua Batista     TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
338ee0ca4e8SJoshua Batista         Context,                          // AST context
339ee0ca4e8SJoshua Batista         Builder.Record->getDeclContext(), // DeclContext
340ee0ca4e8SJoshua Batista         SourceLocation(), SourceLocation(),
341e7e42ef1SJoshua Batista         /*D=*/0,                    // Depth in the template parameter list
342e7e42ef1SJoshua Batista         /*P=*/0,                    // Position in the template parameter list
343e7e42ef1SJoshua Batista         /*Id=*/nullptr,             // Identifier for 'T'
344ee0ca4e8SJoshua Batista         /*Typename=*/true,          // Indicates this is a 'typename' or 'class'
345ee0ca4e8SJoshua Batista         /*ParameterPack=*/false,    // Not a parameter pack
346ee0ca4e8SJoshua Batista         /*HasTypeConstraint=*/false // Has no type constraint
347ee0ca4e8SJoshua Batista     );
348ee0ca4e8SJoshua Batista 
349ee0ca4e8SJoshua Batista     T->setDeclContext(DC);
350ee0ca4e8SJoshua Batista 
351ee0ca4e8SJoshua Batista     QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
352ee0ca4e8SJoshua Batista 
353ee0ca4e8SJoshua Batista     // this is the 2nd template argument node, on which
354ee0ca4e8SJoshua Batista     // the concept constraint is actually being applied: 'element_type'
355ee0ca4e8SJoshua Batista     TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
356ee0ca4e8SJoshua Batista 
357ee0ca4e8SJoshua Batista     QualType CSETType = Context.getTypeDeclType(T);
358ee0ca4e8SJoshua Batista 
359ee0ca4e8SJoshua Batista     // this is the 1st template argument node, which represents
360ee0ca4e8SJoshua Batista     // the abstract type that a concept would refer to: 'T'
361ee0ca4e8SJoshua Batista     TemplateArgument CSETA = TemplateArgument(CSETType);
362ee0ca4e8SJoshua Batista 
363ee0ca4e8SJoshua Batista     ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
364ee0ca4e8SJoshua Batista         ImplicitConceptSpecializationDecl::Create(
365ee0ca4e8SJoshua Batista             Context, Builder.Record->getDeclContext(), Loc, {CSETA});
366ee0ca4e8SJoshua Batista 
367ee0ca4e8SJoshua Batista     // Constraint satisfaction is used to construct the
368ee0ca4e8SJoshua Batista     // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
369ee0ca4e8SJoshua Batista     // located at the bottom of the sample AST above.
370ee0ca4e8SJoshua Batista     const ConstraintSatisfaction CS(CD, {ConceptTA});
371ee0ca4e8SJoshua Batista     TemplateArgumentLoc TAL = S.getTrivialTemplateArgumentLoc(
372ee0ca4e8SJoshua Batista         ConceptTA, QualType(), SourceLocation());
373ee0ca4e8SJoshua Batista 
374ee0ca4e8SJoshua Batista     TALI.addArgument(TAL);
375ee0ca4e8SJoshua Batista     const ASTTemplateArgumentListInfo *ATALI =
376ee0ca4e8SJoshua Batista         ASTTemplateArgumentListInfo::Create(Context, TALI);
377ee0ca4e8SJoshua Batista 
378ee0ca4e8SJoshua Batista     // In the concept reference, ATALI is what adds the extra
379ee0ca4e8SJoshua Batista     // TemplateArgument node underneath CSE
380ee0ca4e8SJoshua Batista     ConceptReference *CR =
381ee0ca4e8SJoshua Batista         ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);
382ee0ca4e8SJoshua Batista 
383ee0ca4e8SJoshua Batista     ConceptSpecializationExpr *CSE =
384ee0ca4e8SJoshua Batista         ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);
385ee0ca4e8SJoshua Batista 
386ee0ca4e8SJoshua Batista     return CSE;
387ee0ca4e8SJoshua Batista   }
388ee0ca4e8SJoshua Batista 
389ee0ca4e8SJoshua Batista   BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr) {
3906e56d0dbSChris Bieneman     if (Params.empty())
3916e56d0dbSChris Bieneman       return Builder;
392dc4c8de1SHelena Kotas 
393cac97833SHelena Kotas     ASTContext &AST = Builder.SemaRef.Context;
394cac97833SHelena Kotas     ConceptSpecializationExpr *CSE =
395cac97833SHelena Kotas         CD ? constructConceptSpecializationExpr(Builder.SemaRef, CD) : nullptr;
396cac97833SHelena Kotas     auto *ParamList = TemplateParameterList::Create(
397cac97833SHelena Kotas         AST, SourceLocation(), SourceLocation(), Params, SourceLocation(), CSE);
3986e56d0dbSChris Bieneman     Builder.Template = ClassTemplateDecl::Create(
399cac97833SHelena Kotas         AST, Builder.Record->getDeclContext(), SourceLocation(),
4006e56d0dbSChris Bieneman         DeclarationName(Builder.Record->getIdentifier()), ParamList,
4016e56d0dbSChris Bieneman         Builder.Record);
402ee0ca4e8SJoshua Batista 
4036e56d0dbSChris Bieneman     Builder.Record->setDescribedClassTemplate(Builder.Template);
4046e56d0dbSChris Bieneman     Builder.Template->setImplicit(true);
4056e56d0dbSChris Bieneman     Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
406ee0ca4e8SJoshua Batista 
407079a5ffbSXiang Li     // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
408079a5ffbSXiang Li     // make visible.
409079a5ffbSXiang Li     Builder.Template->setPreviousDecl(Builder.PrevTemplate);
4106e56d0dbSChris Bieneman     Builder.Record->getDeclContext()->addDecl(Builder.Template);
4116e56d0dbSChris Bieneman     Params.clear();
4126e56d0dbSChris Bieneman 
4136e56d0dbSChris Bieneman     QualType T = Builder.Template->getInjectedClassNameSpecialization();
414cac97833SHelena Kotas     T = AST.getInjectedClassNameType(Builder.Record, T);
4156e56d0dbSChris Bieneman 
4166e56d0dbSChris Bieneman     return Builder;
4176e56d0dbSChris Bieneman   }
4186e56d0dbSChris Bieneman };
41994bde8cdSHelena Kotas 
420cac97833SHelena Kotas // Builder for methods of builtin types. Allows adding methods to builtin types
421cac97833SHelena Kotas // using the builder pattern like this:
422cac97833SHelena Kotas //
423bd92e462SJustin Bogner //   BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
424cac97833SHelena Kotas //       .addParam("param_name", Type, InOutModifier)
4259fde1a49SJustin Bogner //       .callBuiltin("builtin_name", BuiltinParams...)
426cac97833SHelena Kotas //       .finalizeMethod();
427cac97833SHelena Kotas //
428cac97833SHelena Kotas // The builder needs to have all of the method parameters before it can create
429cac97833SHelena Kotas // a CXXMethodDecl. It collects them in addParam calls and when a first
430cac97833SHelena Kotas // method that builds the body is called or when access to 'this` is needed it
431cac97833SHelena Kotas // creates the CXXMethodDecl and ParmVarDecls instances. These can then be
432cac97833SHelena Kotas // referenced from the body building methods. Destructor or an explicit call to
433cac97833SHelena Kotas // finalizeMethod() will complete the method definition.
434cac97833SHelena Kotas //
4359fde1a49SJustin Bogner // The callBuiltin helper method accepts constants via `Expr *` or placeholder
4369fde1a49SJustin Bogner // value arguments to indicate which function arguments to forward to the
4379fde1a49SJustin Bogner // builtin.
438cac97833SHelena Kotas //
439cac97833SHelena Kotas // If the method that is being built has a non-void return type the
440cac97833SHelena Kotas // finalizeMethod will create a return statent with the value of the last
441cac97833SHelena Kotas // statement (unless the last statement is already a ReturnStmt).
442cac97833SHelena Kotas struct BuiltinTypeMethodBuilder {
443cac97833SHelena Kotas   struct MethodParam {
444cac97833SHelena Kotas     const IdentifierInfo &NameII;
445cac97833SHelena Kotas     QualType Ty;
446cac97833SHelena Kotas     HLSLParamModifierAttr::Spelling Modifier;
447cac97833SHelena Kotas     MethodParam(const IdentifierInfo &NameII, QualType Ty,
448cac97833SHelena Kotas                 HLSLParamModifierAttr::Spelling Modifier)
449cac97833SHelena Kotas         : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
450cac97833SHelena Kotas   };
451cac97833SHelena Kotas 
452cac97833SHelena Kotas   BuiltinTypeDeclBuilder &DeclBuilder;
453cac97833SHelena Kotas   DeclarationNameInfo NameInfo;
454cac97833SHelena Kotas   QualType ReturnTy;
455cac97833SHelena Kotas   CXXMethodDecl *Method;
456bd92e462SJustin Bogner   bool IsConst;
457cac97833SHelena Kotas   llvm::SmallVector<MethodParam> Params;
458cac97833SHelena Kotas   llvm::SmallVector<Stmt *> StmtsList;
459cac97833SHelena Kotas 
4609fde1a49SJustin Bogner   // Argument placeholders, inspired by std::placeholder. These are the indices
461274637d7SHelena Kotas   // of arguments to forward to `callBuiltin` and other method builder methods.
462274637d7SHelena Kotas   // Additional special values are:
463274637d7SHelena Kotas   //   Handle   - refers to the resource handle.
464274637d7SHelena Kotas   //   LastStmt - refers to the last statement in the method body; referencing
465274637d7SHelena Kotas   //              LastStmt will remove the statement from the method body since
466274637d7SHelena Kotas   //              it will be linked from the new expression being constructed.
467274637d7SHelena Kotas   enum class PlaceHolder { _0, _1, _2, _3, Handle = 128, LastStmt };
4689fde1a49SJustin Bogner 
4699fde1a49SJustin Bogner   Expr *convertPlaceholder(PlaceHolder PH) {
4709fde1a49SJustin Bogner     if (PH == PlaceHolder::Handle)
4719fde1a49SJustin Bogner       return getResourceHandleExpr();
4729fde1a49SJustin Bogner 
473274637d7SHelena Kotas     if (PH == PlaceHolder::LastStmt) {
474274637d7SHelena Kotas       assert(!StmtsList.empty() && "no statements in the list");
475274637d7SHelena Kotas       Stmt *LastStmt = StmtsList.pop_back_val();
476274637d7SHelena Kotas       assert(isa<ValueStmt>(LastStmt) &&
477274637d7SHelena Kotas              "last statement does not have a value");
478274637d7SHelena Kotas       return cast<ValueStmt>(LastStmt)->getExprStmt();
479274637d7SHelena Kotas     }
480274637d7SHelena Kotas 
4819fde1a49SJustin Bogner     ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
4829fde1a49SJustin Bogner     ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));
4839fde1a49SJustin Bogner     return DeclRefExpr::Create(
4849fde1a49SJustin Bogner         AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
4859fde1a49SJustin Bogner         DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
4869fde1a49SJustin Bogner         ParamDecl->getType(), VK_PRValue);
4879fde1a49SJustin Bogner   }
4889fde1a49SJustin Bogner   Expr *convertPlaceholder(Expr *E) { return E; }
4899fde1a49SJustin Bogner 
490cac97833SHelena Kotas public:
491bd92e462SJustin Bogner   BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
492bd92e462SJustin Bogner                            QualType ReturnTy, bool IsConst = false)
493bd92e462SJustin Bogner       : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
494bd92e462SJustin Bogner         ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}
495bd92e462SJustin Bogner 
496bd92e462SJustin Bogner   BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
497bd92e462SJustin Bogner                            QualType ReturnTy, bool IsConst = false)
498bd92e462SJustin Bogner       : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
499cac97833SHelena Kotas     const IdentifierInfo &II =
500bd92e462SJustin Bogner         DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
501cac97833SHelena Kotas     NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
50294bde8cdSHelena Kotas   }
50394bde8cdSHelena Kotas 
504cac97833SHelena Kotas   BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
505cac97833SHelena Kotas                                      HLSLParamModifierAttr::Spelling Modifier =
506cac97833SHelena Kotas                                          HLSLParamModifierAttr::Keyword_in) {
507cac97833SHelena Kotas     assert(Method == nullptr && "Cannot add param, method already created");
5089fde1a49SJustin Bogner     const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(
5099fde1a49SJustin Bogner         Name, tok::TokenKind::identifier);
5109fde1a49SJustin Bogner     Params.emplace_back(II, Ty, Modifier);
5119fde1a49SJustin Bogner     return *this;
512cac97833SHelena Kotas   }
513cac97833SHelena Kotas 
514cac97833SHelena Kotas private:
515cac97833SHelena Kotas   void createMethodDecl() {
516cac97833SHelena Kotas     assert(Method == nullptr && "Method already created");
517cac97833SHelena Kotas 
518cac97833SHelena Kotas     // create method type
519cac97833SHelena Kotas     ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
520cac97833SHelena Kotas     SmallVector<QualType> ParamTypes;
521cac97833SHelena Kotas     for (MethodParam &MP : Params)
522cac97833SHelena Kotas       ParamTypes.emplace_back(MP.Ty);
523bd92e462SJustin Bogner 
524bd92e462SJustin Bogner     FunctionProtoType::ExtProtoInfo ExtInfo;
525bd92e462SJustin Bogner     if (IsConst)
526bd92e462SJustin Bogner       ExtInfo.TypeQuals.addConst();
527bd92e462SJustin Bogner 
528bd92e462SJustin Bogner     QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
529cac97833SHelena Kotas 
530cac97833SHelena Kotas     // create method decl
531cac97833SHelena Kotas     auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
532cac97833SHelena Kotas     Method =
533cac97833SHelena Kotas         CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
534cac97833SHelena Kotas                               NameInfo, MethodTy, TSInfo, SC_None, false, false,
535cac97833SHelena Kotas                               ConstexprSpecKind::Unspecified, SourceLocation());
536cac97833SHelena Kotas 
537cac97833SHelena Kotas     // create params & set them to the function prototype
538cac97833SHelena Kotas     SmallVector<ParmVarDecl *> ParmDecls;
539cac97833SHelena Kotas     auto FnProtoLoc =
540cac97833SHelena Kotas         Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
541cac97833SHelena Kotas     for (int I = 0, E = Params.size(); I != E; I++) {
542cac97833SHelena Kotas       MethodParam &MP = Params[I];
543cac97833SHelena Kotas       ParmVarDecl *Parm = ParmVarDecl::Create(
544cac97833SHelena Kotas           AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
545cac97833SHelena Kotas           &MP.NameII, MP.Ty,
546cac97833SHelena Kotas           AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None,
547cac97833SHelena Kotas           nullptr);
548cac97833SHelena Kotas       if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
549cac97833SHelena Kotas         auto *Mod =
550cac97833SHelena Kotas             HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
551cac97833SHelena Kotas         Parm->addAttr(Mod);
552cac97833SHelena Kotas       }
553cac97833SHelena Kotas       ParmDecls.push_back(Parm);
554cac97833SHelena Kotas       FnProtoLoc.setParam(I, Parm);
555cac97833SHelena Kotas     }
556cac97833SHelena Kotas     Method->setParams({ParmDecls});
557cac97833SHelena Kotas   }
558cac97833SHelena Kotas 
559cac97833SHelena Kotas public:
560cac97833SHelena Kotas   ~BuiltinTypeMethodBuilder() { finalizeMethod(); }
561cac97833SHelena Kotas 
562fbbf1bedSMariya Podchishchaeva   BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
563fbbf1bedSMariya Podchishchaeva   BuiltinTypeMethodBuilder &
564fbbf1bedSMariya Podchishchaeva   operator=(const BuiltinTypeMethodBuilder &Other) = delete;
565fbbf1bedSMariya Podchishchaeva 
566cac97833SHelena Kotas   Expr *getResourceHandleExpr() {
567cac97833SHelena Kotas     // The first statement added to a method or access to 'this' creates the
568cac97833SHelena Kotas     // declaration.
569cac97833SHelena Kotas     if (!Method)
570cac97833SHelena Kotas       createMethodDecl();
571cac97833SHelena Kotas 
572cac97833SHelena Kotas     ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
573cac97833SHelena Kotas     CXXThisExpr *This = CXXThisExpr::Create(
574cac97833SHelena Kotas         AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
575cac97833SHelena Kotas     FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
576cac97833SHelena Kotas     return MemberExpr::CreateImplicit(AST, This, false, HandleField,
577cac97833SHelena Kotas                                       HandleField->getType(), VK_LValue,
578cac97833SHelena Kotas                                       OK_Ordinary);
579cac97833SHelena Kotas   }
580cac97833SHelena Kotas 
5819fde1a49SJustin Bogner   template <typename... Ts>
582bd92e462SJustin Bogner   BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
583bd92e462SJustin Bogner                                         QualType ReturnType, Ts... ArgSpecs) {
5849fde1a49SJustin Bogner     std::array<Expr *, sizeof...(ArgSpecs)> Args{
5859fde1a49SJustin Bogner         convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
586cac97833SHelena Kotas 
587cac97833SHelena Kotas     // The first statement added to a method or access to 'this` creates the
588cac97833SHelena Kotas     // declaration.
589cac97833SHelena Kotas     if (!Method)
590cac97833SHelena Kotas       createMethodDecl();
591cac97833SHelena Kotas 
592cac97833SHelena Kotas     ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
593cac97833SHelena Kotas     FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
594cac97833SHelena Kotas     DeclRefExpr *DRE = DeclRefExpr::Create(
595cac97833SHelena Kotas         AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
596bd92e462SJustin Bogner         FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);
597cac97833SHelena Kotas 
598bd92e462SJustin Bogner     if (ReturnType.isNull())
599bd92e462SJustin Bogner       ReturnType = FD->getReturnType();
600bd92e462SJustin Bogner 
601bd92e462SJustin Bogner     Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
6029fde1a49SJustin Bogner                                   SourceLocation(), FPOptionsOverride());
603cac97833SHelena Kotas     StmtsList.push_back(Call);
604cac97833SHelena Kotas     return *this;
605cac97833SHelena Kotas   }
606cac97833SHelena Kotas 
607274637d7SHelena Kotas   template <typename TLHS, typename TRHS>
608274637d7SHelena Kotas   BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS) {
609274637d7SHelena Kotas     Expr *LHSExpr = convertPlaceholder(LHS);
610274637d7SHelena Kotas     Expr *RHSExpr = convertPlaceholder(RHS);
611274637d7SHelena Kotas     Stmt *AssignStmt = BinaryOperator::Create(
612274637d7SHelena Kotas         DeclBuilder.SemaRef.getASTContext(), LHSExpr, RHSExpr, BO_Assign,
613274637d7SHelena Kotas         LHSExpr->getType(), ExprValueKind::VK_PRValue,
614274637d7SHelena Kotas         ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());
615274637d7SHelena Kotas     StmtsList.push_back(AssignStmt);
616274637d7SHelena Kotas     return *this;
617274637d7SHelena Kotas   }
618bd92e462SJustin Bogner 
619274637d7SHelena Kotas   template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr) {
620274637d7SHelena Kotas     Expr *PtrExpr = convertPlaceholder(Ptr);
621274637d7SHelena Kotas     Expr *Deref =
622274637d7SHelena Kotas         UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,
623274637d7SHelena Kotas                               UO_Deref, PtrExpr->getType()->getPointeeType(),
624bd92e462SJustin Bogner                               VK_PRValue, OK_Ordinary, SourceLocation(),
625bd92e462SJustin Bogner                               /*CanOverflow=*/false, FPOptionsOverride());
626bd92e462SJustin Bogner     StmtsList.push_back(Deref);
627bd92e462SJustin Bogner     return *this;
628bd92e462SJustin Bogner   }
629bd92e462SJustin Bogner 
630cac97833SHelena Kotas   BuiltinTypeDeclBuilder &finalizeMethod() {
631cac97833SHelena Kotas     assert(!DeclBuilder.Record->isCompleteDefinition() &&
632cac97833SHelena Kotas            "record is already complete");
633cac97833SHelena Kotas     assert(
634cac97833SHelena Kotas         Method != nullptr &&
635cac97833SHelena Kotas         "method decl not created; are you missing a call to build the body?");
636cac97833SHelena Kotas 
637cac97833SHelena Kotas     if (!Method->hasBody()) {
638cac97833SHelena Kotas       ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
639cac97833SHelena Kotas       assert((ReturnTy == AST.VoidTy || !StmtsList.empty()) &&
640cac97833SHelena Kotas              "nothing to return from non-void method");
641cac97833SHelena Kotas       if (ReturnTy != AST.VoidTy) {
642cac97833SHelena Kotas         if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back())) {
643bd92e462SJustin Bogner           assert(AST.hasSameUnqualifiedType(LastExpr->getType(),
644bd92e462SJustin Bogner                                             ReturnTy.getNonReferenceType()) &&
645cac97833SHelena Kotas                  "Return type of the last statement must match the return type "
646cac97833SHelena Kotas                  "of the method");
647cac97833SHelena Kotas           if (!isa<ReturnStmt>(LastExpr)) {
648cac97833SHelena Kotas             StmtsList.pop_back();
649cac97833SHelena Kotas             StmtsList.push_back(
650cac97833SHelena Kotas                 ReturnStmt::Create(AST, SourceLocation(), LastExpr, nullptr));
651cac97833SHelena Kotas           }
652cac97833SHelena Kotas         }
653cac97833SHelena Kotas       }
654cac97833SHelena Kotas 
655cac97833SHelena Kotas       Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),
656cac97833SHelena Kotas                                            SourceLocation(), SourceLocation()));
657cac97833SHelena Kotas       Method->setLexicalDeclContext(DeclBuilder.Record);
658cac97833SHelena Kotas       Method->setAccess(AccessSpecifier::AS_public);
659cac97833SHelena Kotas       Method->addAttr(AlwaysInlineAttr::CreateImplicit(
660cac97833SHelena Kotas           AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
661cac97833SHelena Kotas       DeclBuilder.Record->addDecl(Method);
662cac97833SHelena Kotas     }
663cac97833SHelena Kotas     return DeclBuilder;
664cac97833SHelena Kotas   }
665cac97833SHelena Kotas };
666cac97833SHelena Kotas 
667cac97833SHelena Kotas } // namespace
668cac97833SHelena Kotas 
669cac97833SHelena Kotas TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
670cac97833SHelena Kotas   return TemplateParameterListBuilder(*this);
671cac97833SHelena Kotas }
672cac97833SHelena Kotas 
673cac97833SHelena Kotas BuiltinTypeDeclBuilder &
674cac97833SHelena Kotas BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
675cac97833SHelena Kotas                                                 ConceptDecl *CD = nullptr) {
676cac97833SHelena Kotas   if (Record->isCompleteDefinition()) {
677cac97833SHelena Kotas     assert(Template && "existing record it not a template");
678cac97833SHelena Kotas     assert(Template->getTemplateParameters()->size() == Names.size() &&
679cac97833SHelena Kotas            "template param count mismatch");
680cac97833SHelena Kotas     return *this;
681cac97833SHelena Kotas   }
682cac97833SHelena Kotas 
683cac97833SHelena Kotas   TemplateParameterListBuilder Builder = this->addTemplateArgumentList();
684c502a81bSJustin Bogner   for (StringRef Name : Names)
685c502a81bSJustin Bogner     Builder.addTypeParameter(Name);
686ee0ca4e8SJoshua Batista   return Builder.finalizeTemplateArgs(CD);
687c502a81bSJustin Bogner }
6886e56d0dbSChris Bieneman 
689cac97833SHelena Kotas BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
6909fde1a49SJustin Bogner   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
691bd92e462SJustin Bogner   return BuiltinTypeMethodBuilder(*this, "IncrementCounter",
692cac97833SHelena Kotas                                   SemaRef.getASTContext().UnsignedIntTy)
693bd92e462SJustin Bogner       .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
694bd92e462SJustin Bogner                    PH::Handle, getConstantIntExpr(1))
695cac97833SHelena Kotas       .finalizeMethod();
696cac97833SHelena Kotas }
697cac97833SHelena Kotas 
698cac97833SHelena Kotas BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
6999fde1a49SJustin Bogner   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
700bd92e462SJustin Bogner   return BuiltinTypeMethodBuilder(*this, "DecrementCounter",
701cac97833SHelena Kotas                                   SemaRef.getASTContext().UnsignedIntTy)
702bd92e462SJustin Bogner       .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
703bd92e462SJustin Bogner                    PH::Handle, getConstantIntExpr(-1))
704bd92e462SJustin Bogner       .finalizeMethod();
705bd92e462SJustin Bogner }
706bd92e462SJustin Bogner 
707bd92e462SJustin Bogner BuiltinTypeDeclBuilder &
708bd92e462SJustin Bogner BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
709bd92e462SJustin Bogner                                                 bool IsConst, bool IsRef) {
710bd92e462SJustin Bogner   assert(!Record->isCompleteDefinition() && "record is already complete");
711bd92e462SJustin Bogner   ASTContext &AST = SemaRef.getASTContext();
712bd92e462SJustin Bogner   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
713bd92e462SJustin Bogner 
714bd92e462SJustin Bogner   QualType ElemTy = getHandleElementType();
715bd92e462SJustin Bogner   // TODO: Map to an hlsl_device address space.
716bd92e462SJustin Bogner   QualType ElemPtrTy = AST.getPointerType(ElemTy);
717bd92e462SJustin Bogner   QualType ReturnTy = ElemTy;
718bd92e462SJustin Bogner   if (IsConst)
719bd92e462SJustin Bogner     ReturnTy.addConst();
720bd92e462SJustin Bogner   if (IsRef)
721bd92e462SJustin Bogner     ReturnTy = AST.getLValueReferenceType(ReturnTy);
722bd92e462SJustin Bogner 
723bd92e462SJustin Bogner   return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
724bd92e462SJustin Bogner       .addParam("Index", AST.UnsignedIntTy)
725bd92e462SJustin Bogner       .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
726bd92e462SJustin Bogner                    PH::_0)
727274637d7SHelena Kotas       .dereference(PH::LastStmt)
728274637d7SHelena Kotas       .finalizeMethod();
729274637d7SHelena Kotas }
730274637d7SHelena Kotas 
731274637d7SHelena Kotas BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
732274637d7SHelena Kotas   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
733274637d7SHelena Kotas   ASTContext &AST = SemaRef.getASTContext();
734274637d7SHelena Kotas   QualType ElemTy = getHandleElementType();
735274637d7SHelena Kotas   return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)
736274637d7SHelena Kotas       .addParam("value", ElemTy)
737274637d7SHelena Kotas       .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
738274637d7SHelena Kotas                    PH::Handle, getConstantIntExpr(1))
739274637d7SHelena Kotas       .callBuiltin("__builtin_hlsl_resource_getpointer",
740274637d7SHelena Kotas                    AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
741274637d7SHelena Kotas       .dereference(PH::LastStmt)
742274637d7SHelena Kotas       .assign(PH::LastStmt, PH::_0)
743274637d7SHelena Kotas       .finalizeMethod();
744274637d7SHelena Kotas }
745274637d7SHelena Kotas 
746274637d7SHelena Kotas BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
747274637d7SHelena Kotas   using PH = BuiltinTypeMethodBuilder::PlaceHolder;
748274637d7SHelena Kotas   ASTContext &AST = SemaRef.getASTContext();
749274637d7SHelena Kotas   QualType ElemTy = getHandleElementType();
750274637d7SHelena Kotas   return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)
751274637d7SHelena Kotas       .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
752274637d7SHelena Kotas                    PH::Handle, getConstantIntExpr(-1))
753274637d7SHelena Kotas       .callBuiltin("__builtin_hlsl_resource_getpointer",
754274637d7SHelena Kotas                    AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
755274637d7SHelena Kotas       .dereference(PH::LastStmt)
756cac97833SHelena Kotas       .finalizeMethod();
757cac97833SHelena Kotas }
758cac97833SHelena Kotas 
759b8dbc6ffSChris Bieneman HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
760b8dbc6ffSChris Bieneman 
761b8dbc6ffSChris Bieneman void HLSLExternalSemaSource::InitializeSema(Sema &S) {
762b8dbc6ffSChris Bieneman   SemaPtr = &S;
763b8dbc6ffSChris Bieneman   ASTContext &AST = SemaPtr->getASTContext();
764079a5ffbSXiang Li   // If the translation unit has external storage force external decls to load.
765079a5ffbSXiang Li   if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
766079a5ffbSXiang Li     (void)AST.getTranslationUnitDecl()->decls_begin();
767079a5ffbSXiang Li 
768b8dbc6ffSChris Bieneman   IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
769079a5ffbSXiang Li   LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
770079a5ffbSXiang Li   NamespaceDecl *PrevDecl = nullptr;
771079a5ffbSXiang Li   if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
772079a5ffbSXiang Li     PrevDecl = Result.getAsSingle<NamespaceDecl>();
77315e76eedSNathan James   HLSLNamespace = NamespaceDecl::Create(
77415e76eedSNathan James       AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
77515e76eedSNathan James       SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
776b8dbc6ffSChris Bieneman   HLSLNamespace->setImplicit(true);
777079a5ffbSXiang Li   HLSLNamespace->setHasExternalLexicalStorage();
778b8dbc6ffSChris Bieneman   AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
779079a5ffbSXiang Li 
780079a5ffbSXiang Li   // Force external decls in the HLSL namespace to load from the PCH.
781079a5ffbSXiang Li   (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
7826e56d0dbSChris Bieneman   defineTrivialHLSLTypes();
783c502a81bSJustin Bogner   defineHLSLTypesWithForwardDeclarations();
784b8dbc6ffSChris Bieneman 
785b8dbc6ffSChris Bieneman   // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
786b8dbc6ffSChris Bieneman   // built in types inside a namespace, but we are planning to change that in
787b8dbc6ffSChris Bieneman   // the near future. In order to be source compatible older versions of HLSL
788b8dbc6ffSChris Bieneman   // will need to implicitly use the hlsl namespace. For now in clang everything
789b8dbc6ffSChris Bieneman   // will get added to the namespace, and we can remove the using directive for
790b8dbc6ffSChris Bieneman   // future language versions to match HLSL's evolution.
791b8dbc6ffSChris Bieneman   auto *UsingDecl = UsingDirectiveDecl::Create(
792b8dbc6ffSChris Bieneman       AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
793b8dbc6ffSChris Bieneman       NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
794b8dbc6ffSChris Bieneman       AST.getTranslationUnitDecl());
795b8dbc6ffSChris Bieneman 
796b8dbc6ffSChris Bieneman   AST.getTranslationUnitDecl()->addDecl(UsingDecl);
797b8dbc6ffSChris Bieneman }
798b8dbc6ffSChris Bieneman 
799b8dbc6ffSChris Bieneman void HLSLExternalSemaSource::defineHLSLVectorAlias() {
800b8dbc6ffSChris Bieneman   ASTContext &AST = SemaPtr->getASTContext();
801b8dbc6ffSChris Bieneman 
802b8dbc6ffSChris Bieneman   llvm::SmallVector<NamedDecl *> TemplateParams;
803b8dbc6ffSChris Bieneman 
804b8dbc6ffSChris Bieneman   auto *TypeParam = TemplateTypeParmDecl::Create(
805b8dbc6ffSChris Bieneman       AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
806b8dbc6ffSChris Bieneman       &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
807e42b799bSMatheus Izvekov   TypeParam->setDefaultArgument(
808e42b799bSMatheus Izvekov       AST, SemaPtr->getTrivialTemplateArgumentLoc(
809e42b799bSMatheus Izvekov                TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
810b8dbc6ffSChris Bieneman 
811b8dbc6ffSChris Bieneman   TemplateParams.emplace_back(TypeParam);
812b8dbc6ffSChris Bieneman 
813b8dbc6ffSChris Bieneman   auto *SizeParam = NonTypeTemplateParmDecl::Create(
814b8dbc6ffSChris Bieneman       AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
815b8dbc6ffSChris Bieneman       &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
816b8dbc6ffSChris Bieneman       false, AST.getTrivialTypeSourceInfo(AST.IntTy));
8172bde13cdSMatheus Izvekov   llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
8182bde13cdSMatheus Izvekov   TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
8192bde13cdSMatheus Izvekov                            /*IsDefaulted=*/true);
8202bde13cdSMatheus Izvekov   SizeParam->setDefaultArgument(
8212bde13cdSMatheus Izvekov       AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
8222bde13cdSMatheus Izvekov                                                   SourceLocation(), SizeParam));
823b8dbc6ffSChris Bieneman   TemplateParams.emplace_back(SizeParam);
824b8dbc6ffSChris Bieneman 
825b8dbc6ffSChris Bieneman   auto *ParamList =
826b8dbc6ffSChris Bieneman       TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
827b8dbc6ffSChris Bieneman                                     TemplateParams, SourceLocation(), nullptr);
828b8dbc6ffSChris Bieneman 
829b8dbc6ffSChris Bieneman   IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
830b8dbc6ffSChris Bieneman 
831b8dbc6ffSChris Bieneman   QualType AliasType = AST.getDependentSizedExtVectorType(
832b8dbc6ffSChris Bieneman       AST.getTemplateTypeParmType(0, 0, false, TypeParam),
833b8dbc6ffSChris Bieneman       DeclRefExpr::Create(
834b8dbc6ffSChris Bieneman           AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
835b8dbc6ffSChris Bieneman           DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
836b8dbc6ffSChris Bieneman           AST.IntTy, VK_LValue),
837b8dbc6ffSChris Bieneman       SourceLocation());
838b8dbc6ffSChris Bieneman 
839b8dbc6ffSChris Bieneman   auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
840b8dbc6ffSChris Bieneman                                        SourceLocation(), &II,
841b8dbc6ffSChris Bieneman                                        AST.getTrivialTypeSourceInfo(AliasType));
842b8dbc6ffSChris Bieneman   Record->setImplicit(true);
843b8dbc6ffSChris Bieneman 
844b8dbc6ffSChris Bieneman   auto *Template =
845b8dbc6ffSChris Bieneman       TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
846b8dbc6ffSChris Bieneman                                     Record->getIdentifier(), ParamList, Record);
847b8dbc6ffSChris Bieneman 
848b8dbc6ffSChris Bieneman   Record->setDescribedAliasTemplate(Template);
849b8dbc6ffSChris Bieneman   Template->setImplicit(true);
850b8dbc6ffSChris Bieneman   Template->setLexicalDeclContext(Record->getDeclContext());
851b8dbc6ffSChris Bieneman   HLSLNamespace->addDecl(Template);
852b8dbc6ffSChris Bieneman }
8536e56d0dbSChris Bieneman 
8546e56d0dbSChris Bieneman void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
8556e56d0dbSChris Bieneman   defineHLSLVectorAlias();
8566e56d0dbSChris Bieneman }
8576e56d0dbSChris Bieneman 
858c502a81bSJustin Bogner /// Set up common members and attributes for buffer types
859c502a81bSJustin Bogner static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
86002e02b9aSJustin Bogner                                               ResourceClass RC, ResourceKind RK,
8615df1b793SHelena Kotas                                               bool IsROV, bool RawBuffer) {
862cac97833SHelena Kotas   return BuiltinTypeDeclBuilder(S, Decl)
863cac97833SHelena Kotas       .addHandleMember(RC, RK, IsROV, RawBuffer)
864cac97833SHelena Kotas       .addDefaultHandleConstructor();
865c502a81bSJustin Bogner }
866c502a81bSJustin Bogner 
8676a01ac7dSJoshua Batista // This function is responsible for constructing the constraint expression for
8686a01ac7dSJoshua Batista // this concept:
8696a01ac7dSJoshua Batista // template<typename T> concept is_typed_resource_element_compatible =
8706a01ac7dSJoshua Batista // __is_typed_resource_element_compatible<T>;
871cbdd14eeSCongcong Cai static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
872ee0ca4e8SJoshua Batista                                                 TemplateTypeParmDecl *T) {
873ee0ca4e8SJoshua Batista   ASTContext &Context = S.getASTContext();
874ee0ca4e8SJoshua Batista 
875e7e42ef1SJoshua Batista   // Obtain the QualType for 'bool'
876ee0ca4e8SJoshua Batista   QualType BoolTy = Context.BoolTy;
877ee0ca4e8SJoshua Batista 
878ee0ca4e8SJoshua Batista   // Create a QualType that points to this TemplateTypeParmDecl
879ee0ca4e8SJoshua Batista   QualType TType = Context.getTypeDeclType(T);
880ee0ca4e8SJoshua Batista 
881ee0ca4e8SJoshua Batista   // Create a TypeSourceInfo for the template type parameter 'T'
882ee0ca4e8SJoshua Batista   TypeSourceInfo *TTypeSourceInfo =
883ee0ca4e8SJoshua Batista       Context.getTrivialTypeSourceInfo(TType, NameLoc);
884ee0ca4e8SJoshua Batista 
885ee0ca4e8SJoshua Batista   TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(
886ee0ca4e8SJoshua Batista       Context, BoolTy, NameLoc, UTT_IsTypedResourceElementCompatible,
887ee0ca4e8SJoshua Batista       {TTypeSourceInfo}, NameLoc, true);
888ee0ca4e8SJoshua Batista 
889ee0ca4e8SJoshua Batista   return TypedResExpr;
890ee0ca4e8SJoshua Batista }
891ee0ca4e8SJoshua Batista 
8926a01ac7dSJoshua Batista // This function is responsible for constructing the constraint expression for
8936a01ac7dSJoshua Batista // this concept:
8946a01ac7dSJoshua Batista // template<typename T> concept is_structured_resource_element_compatible =
8956a01ac7dSJoshua Batista // !__is_intangible<T> && sizeof(T) >= 1;
8966a01ac7dSJoshua Batista static Expr *constructStructuredBufferConstraintExpr(Sema &S,
8976a01ac7dSJoshua Batista                                                      SourceLocation NameLoc,
8986a01ac7dSJoshua Batista                                                      TemplateTypeParmDecl *T) {
8996a01ac7dSJoshua Batista   ASTContext &Context = S.getASTContext();
9006a01ac7dSJoshua Batista 
9016a01ac7dSJoshua Batista   // Obtain the QualType for 'bool'
9026a01ac7dSJoshua Batista   QualType BoolTy = Context.BoolTy;
9036a01ac7dSJoshua Batista 
9046a01ac7dSJoshua Batista   // Create a QualType that points to this TemplateTypeParmDecl
9056a01ac7dSJoshua Batista   QualType TType = Context.getTypeDeclType(T);
9066a01ac7dSJoshua Batista 
9076a01ac7dSJoshua Batista   // Create a TypeSourceInfo for the template type parameter 'T'
9086a01ac7dSJoshua Batista   TypeSourceInfo *TTypeSourceInfo =
9096a01ac7dSJoshua Batista       Context.getTrivialTypeSourceInfo(TType, NameLoc);
9106a01ac7dSJoshua Batista 
9116a01ac7dSJoshua Batista   TypeTraitExpr *IsIntangibleExpr =
9126a01ac7dSJoshua Batista       TypeTraitExpr::Create(Context, BoolTy, NameLoc, UTT_IsIntangibleType,
9136a01ac7dSJoshua Batista                             {TTypeSourceInfo}, NameLoc, true);
9146a01ac7dSJoshua Batista 
9156a01ac7dSJoshua Batista   // negate IsIntangibleExpr
9166a01ac7dSJoshua Batista   UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(
9176a01ac7dSJoshua Batista       Context, IsIntangibleExpr, UO_LNot, BoolTy, VK_LValue, OK_Ordinary,
9186a01ac7dSJoshua Batista       NameLoc, false, FPOptionsOverride());
9196a01ac7dSJoshua Batista 
9206a01ac7dSJoshua Batista   // element types also may not be of 0 size
9216a01ac7dSJoshua Batista   UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(
9226a01ac7dSJoshua Batista       UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);
9236a01ac7dSJoshua Batista 
9246a01ac7dSJoshua Batista   // Create a BinaryOperator that checks if the size of the type is not equal to
9256a01ac7dSJoshua Batista   // 1 Empty structs have a size of 1 in HLSL, so we need to check for that
9266a01ac7dSJoshua Batista   IntegerLiteral *rhs = IntegerLiteral::Create(
9276a01ac7dSJoshua Batista       Context, llvm::APInt(Context.getTypeSize(Context.getSizeType()), 1, true),
9286a01ac7dSJoshua Batista       Context.getSizeType(), NameLoc);
9296a01ac7dSJoshua Batista 
9306a01ac7dSJoshua Batista   BinaryOperator *SizeGEQOneExpr =
9316a01ac7dSJoshua Batista       BinaryOperator::Create(Context, SizeOfExpr, rhs, BO_GE, BoolTy, VK_LValue,
9326a01ac7dSJoshua Batista                              OK_Ordinary, NameLoc, FPOptionsOverride());
9336a01ac7dSJoshua Batista 
9346a01ac7dSJoshua Batista   // Combine the two constraints
9356a01ac7dSJoshua Batista   BinaryOperator *CombinedExpr = BinaryOperator::Create(
9366a01ac7dSJoshua Batista       Context, NotIntangibleExpr, SizeGEQOneExpr, BO_LAnd, BoolTy, VK_LValue,
9376a01ac7dSJoshua Batista       OK_Ordinary, NameLoc, FPOptionsOverride());
9386a01ac7dSJoshua Batista 
9396a01ac7dSJoshua Batista   return CombinedExpr;
9406a01ac7dSJoshua Batista }
9416a01ac7dSJoshua Batista 
9426a01ac7dSJoshua Batista static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,
9436a01ac7dSJoshua Batista                                                bool isTypedBuffer) {
944ee0ca4e8SJoshua Batista   ASTContext &Context = S.getASTContext();
945ee0ca4e8SJoshua Batista   DeclContext *DC = NSD->getDeclContext();
946ee0ca4e8SJoshua Batista   SourceLocation DeclLoc = SourceLocation();
947ee0ca4e8SJoshua Batista 
948ee0ca4e8SJoshua Batista   IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");
949ee0ca4e8SJoshua Batista   TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
950ee0ca4e8SJoshua Batista       Context, NSD->getDeclContext(), DeclLoc, DeclLoc,
951e7e42ef1SJoshua Batista       /*D=*/0,
952e7e42ef1SJoshua Batista       /*P=*/0,
953e7e42ef1SJoshua Batista       /*Id=*/&ElementTypeII,
954ee0ca4e8SJoshua Batista       /*Typename=*/true,
955ee0ca4e8SJoshua Batista       /*ParameterPack=*/false);
956ee0ca4e8SJoshua Batista 
957ee0ca4e8SJoshua Batista   T->setDeclContext(DC);
958ee0ca4e8SJoshua Batista   T->setReferenced();
959ee0ca4e8SJoshua Batista 
960ee0ca4e8SJoshua Batista   // Create and Attach Template Parameter List to ConceptDecl
961ee0ca4e8SJoshua Batista   TemplateParameterList *ConceptParams = TemplateParameterList::Create(
962ee0ca4e8SJoshua Batista       Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr);
963ee0ca4e8SJoshua Batista 
9646a01ac7dSJoshua Batista   DeclarationName DeclName;
9656a01ac7dSJoshua Batista   Expr *ConstraintExpr = nullptr;
9666a01ac7dSJoshua Batista 
9676a01ac7dSJoshua Batista   if (isTypedBuffer) {
9686a01ac7dSJoshua Batista     DeclName = DeclarationName(
969ee0ca4e8SJoshua Batista         &Context.Idents.get("__is_typed_resource_element_compatible"));
9706a01ac7dSJoshua Batista     ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);
9716a01ac7dSJoshua Batista   } else {
9726a01ac7dSJoshua Batista     DeclName = DeclarationName(
9736a01ac7dSJoshua Batista         &Context.Idents.get("__is_structured_resource_element_compatible"));
9746a01ac7dSJoshua Batista     ConstraintExpr = constructStructuredBufferConstraintExpr(S, DeclLoc, T);
9756a01ac7dSJoshua Batista   }
976ee0ca4e8SJoshua Batista 
977ee0ca4e8SJoshua Batista   // Create a ConceptDecl
978ee0ca4e8SJoshua Batista   ConceptDecl *CD =
979ee0ca4e8SJoshua Batista       ConceptDecl::Create(Context, NSD->getDeclContext(), DeclLoc, DeclName,
980ee0ca4e8SJoshua Batista                           ConceptParams, ConstraintExpr);
981ee0ca4e8SJoshua Batista 
982ee0ca4e8SJoshua Batista   // Attach the template parameter list to the ConceptDecl
983ee0ca4e8SJoshua Batista   CD->setTemplateParameters(ConceptParams);
984ee0ca4e8SJoshua Batista 
985ee0ca4e8SJoshua Batista   // Add the concept declaration to the Translation Unit Decl
986ee0ca4e8SJoshua Batista   NSD->getDeclContext()->addDecl(CD);
987ee0ca4e8SJoshua Batista 
988ee0ca4e8SJoshua Batista   return CD;
989ee0ca4e8SJoshua Batista }
990ee0ca4e8SJoshua Batista 
991c502a81bSJustin Bogner void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
9926e56d0dbSChris Bieneman   CXXRecordDecl *Decl;
9936a01ac7dSJoshua Batista   ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(
9946a01ac7dSJoshua Batista       *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ true);
9956a01ac7dSJoshua Batista   ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(
9966a01ac7dSJoshua Batista       *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ false);
9976e56d0dbSChris Bieneman   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
998cac97833SHelena Kotas              .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)
9991df28554Sjoaosaffran              .finalizeForwardDeclaration();
1000ebc4a66eSJoshua Batista 
1001c502a81bSJustin Bogner   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1002c502a81bSJustin Bogner     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
10034bd982d5SJustin Bogner                     ResourceKind::TypedBuffer, /*IsROV=*/false,
10044bd982d5SJustin Bogner                     /*RawBuffer=*/false)
100502e02b9aSJustin Bogner         .addArraySubscriptOperators()
1006de401599SJustin Bogner         .addLoadMethods()
100702e02b9aSJustin Bogner         .completeDefinition();
100802e02b9aSJustin Bogner   });
100902e02b9aSJustin Bogner 
101002e02b9aSJustin Bogner   Decl =
101102e02b9aSJustin Bogner       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
10126a01ac7dSJoshua Batista           .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
10131df28554Sjoaosaffran           .finalizeForwardDeclaration();
101402e02b9aSJustin Bogner   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
101502e02b9aSJustin Bogner     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
10165df1b793SHelena Kotas                     ResourceKind::TypedBuffer, /*IsROV=*/true,
10175df1b793SHelena Kotas                     /*RawBuffer=*/false)
1018c502a81bSJustin Bogner         .addArraySubscriptOperators()
1019de401599SJustin Bogner         .addLoadMethods()
1020c502a81bSJustin Bogner         .completeDefinition();
1021c502a81bSJustin Bogner   });
1022b8239e12SJoshua Batista 
1023b8239e12SJoshua Batista   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
10246a01ac7dSJoshua Batista              .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
10251df28554Sjoaosaffran              .finalizeForwardDeclaration();
1026b8239e12SJoshua Batista   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1027d413335cSHelena Kotas     setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, ResourceKind::RawBuffer,
10284bd982d5SJustin Bogner                     /*IsROV=*/false, /*RawBuffer=*/true)
1029b8239e12SJoshua Batista         .addArraySubscriptOperators()
1030*7a4b3b49SHelena Kotas         .addLoadMethods()
1031b8239e12SJoshua Batista         .completeDefinition();
1032b8239e12SJoshua Batista   });
1033af872d54SHelena Kotas 
1034af872d54SHelena Kotas   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
10356a01ac7dSJoshua Batista              .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
10361df28554Sjoaosaffran              .finalizeForwardDeclaration();
1037af872d54SHelena Kotas   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1038d413335cSHelena Kotas     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
10394bd982d5SJustin Bogner                     /*IsROV=*/false, /*RawBuffer=*/true)
1040af872d54SHelena Kotas         .addArraySubscriptOperators()
1041*7a4b3b49SHelena Kotas         .addLoadMethods()
1042cac97833SHelena Kotas         .addIncrementCounterMethod()
1043cac97833SHelena Kotas         .addDecrementCounterMethod()
1044af872d54SHelena Kotas         .completeDefinition();
1045af872d54SHelena Kotas   });
104639f2bae2SHelena Kotas 
1047d413335cSHelena Kotas   Decl =
1048d413335cSHelena Kotas       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")
10496a01ac7dSJoshua Batista           .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
10501df28554Sjoaosaffran           .finalizeForwardDeclaration();
1051d413335cSHelena Kotas   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1052d413335cSHelena Kotas     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
10534bd982d5SJustin Bogner                     /*IsROV=*/false, /*RawBuffer=*/true)
1054274637d7SHelena Kotas         .addAppendMethod()
1055d413335cSHelena Kotas         .completeDefinition();
1056d413335cSHelena Kotas   });
1057d413335cSHelena Kotas 
1058d413335cSHelena Kotas   Decl =
1059d413335cSHelena Kotas       BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")
10606a01ac7dSJoshua Batista           .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
10611df28554Sjoaosaffran           .finalizeForwardDeclaration();
1062d413335cSHelena Kotas   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
1063d413335cSHelena Kotas     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
10644bd982d5SJustin Bogner                     /*IsROV=*/false, /*RawBuffer=*/true)
1065274637d7SHelena Kotas         .addConsumeMethod()
1066d413335cSHelena Kotas         .completeDefinition();
1067d413335cSHelena Kotas   });
1068d413335cSHelena Kotas 
106939f2bae2SHelena Kotas   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
107039f2bae2SHelena Kotas                                 "RasterizerOrderedStructuredBuffer")
10716a01ac7dSJoshua Batista              .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)
10721df28554Sjoaosaffran              .finalizeForwardDeclaration();
107339f2bae2SHelena Kotas   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
10744bd982d5SJustin Bogner     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
10754bd982d5SJustin Bogner                     /*IsROV=*/true, /*RawBuffer=*/true)
107639f2bae2SHelena Kotas         .addArraySubscriptOperators()
1077*7a4b3b49SHelena Kotas         .addLoadMethods()
1078cac97833SHelena Kotas         .addIncrementCounterMethod()
1079cac97833SHelena Kotas         .addDecrementCounterMethod()
108039f2bae2SHelena Kotas         .completeDefinition();
108139f2bae2SHelena Kotas   });
10821df28554Sjoaosaffran 
10831df28554Sjoaosaffran   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")
10841df28554Sjoaosaffran              .finalizeForwardDeclaration();
10851df28554Sjoaosaffran   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
10861df28554Sjoaosaffran     setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, ResourceKind::RawBuffer,
10871df28554Sjoaosaffran                     /*IsROV=*/false,
10881df28554Sjoaosaffran                     /*RawBuffer=*/true)
10891df28554Sjoaosaffran         .completeDefinition();
10901df28554Sjoaosaffran   });
10911df28554Sjoaosaffran   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")
10921df28554Sjoaosaffran              .finalizeForwardDeclaration();
10931df28554Sjoaosaffran   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
10941df28554Sjoaosaffran     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
10951df28554Sjoaosaffran                     /*IsROV=*/false,
10961df28554Sjoaosaffran                     /*RawBuffer=*/true)
10971df28554Sjoaosaffran         .completeDefinition();
10981df28554Sjoaosaffran   });
10991df28554Sjoaosaffran   Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
11001df28554Sjoaosaffran                                 "RasterizerOrderedByteAddressBuffer")
11011df28554Sjoaosaffran              .finalizeForwardDeclaration();
11021df28554Sjoaosaffran   onCompletion(Decl, [this](CXXRecordDecl *Decl) {
11031df28554Sjoaosaffran     setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::RawBuffer,
11041df28554Sjoaosaffran                     /*IsROV=*/true,
11051df28554Sjoaosaffran                     /*RawBuffer=*/true)
11061df28554Sjoaosaffran         .completeDefinition();
11071df28554Sjoaosaffran   });
1108c502a81bSJustin Bogner }
1109c502a81bSJustin Bogner 
1110c502a81bSJustin Bogner void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
1111c502a81bSJustin Bogner                                           CompletionFunction Fn) {
1112cac97833SHelena Kotas   if (!Record->isCompleteDefinition())
1113c502a81bSJustin Bogner     Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
11146e56d0dbSChris Bieneman }
11156e56d0dbSChris Bieneman 
11166e56d0dbSChris Bieneman void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
11176e56d0dbSChris Bieneman   if (!isa<CXXRecordDecl>(Tag))
11186e56d0dbSChris Bieneman     return;
11196e56d0dbSChris Bieneman   auto Record = cast<CXXRecordDecl>(Tag);
11206e56d0dbSChris Bieneman 
11216e56d0dbSChris Bieneman   // If this is a specialization, we need to get the underlying templated
11226e56d0dbSChris Bieneman   // declaration and complete that.
11236e56d0dbSChris Bieneman   if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
11246e56d0dbSChris Bieneman     Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
1125079a5ffbSXiang Li   Record = Record->getCanonicalDecl();
11266e56d0dbSChris Bieneman   auto It = Completions.find(Record);
11276e56d0dbSChris Bieneman   if (It == Completions.end())
11286e56d0dbSChris Bieneman     return;
11296e56d0dbSChris Bieneman   It->second(Record);
11306e56d0dbSChris Bieneman }
1131cac97833SHelena Kotas 
1132cac97833SHelena Kotas static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
1133cac97833SHelena Kotas   IdentifierInfo &II =
1134cac97833SHelena Kotas       S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
1135cac97833SHelena Kotas   DeclarationNameInfo NameInfo =
1136cac97833SHelena Kotas       DeclarationNameInfo(DeclarationName(&II), SourceLocation());
1137cac97833SHelena Kotas   LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
1138cac97833SHelena Kotas   // AllowBuiltinCreation is false but LookupDirect will create
1139cac97833SHelena Kotas   // the builtin when searching the global scope anyways...
1140cac97833SHelena Kotas   S.LookupName(R, S.getCurScope());
1141cac97833SHelena Kotas   // FIXME: If the builtin function was user-declared in global scope,
1142cac97833SHelena Kotas   // this assert *will* fail. Should this call LookupBuiltin instead?
1143cac97833SHelena Kotas   assert(R.isSingleResult() &&
1144cac97833SHelena Kotas          "Since this is a builtin it should always resolve!");
1145cac97833SHelena Kotas   return cast<FunctionDecl>(R.getFoundDecl());
1146cac97833SHelena Kotas }
1147