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