1753f127fSDimitry Andric //===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===// 2753f127fSDimitry Andric // 3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6753f127fSDimitry Andric // 7753f127fSDimitry Andric //===----------------------------------------------------------------------===// 8753f127fSDimitry Andric // 9753f127fSDimitry Andric // 10753f127fSDimitry Andric //===----------------------------------------------------------------------===// 11753f127fSDimitry Andric 12753f127fSDimitry Andric #include "clang/Sema/HLSLExternalSemaSource.h" 13753f127fSDimitry Andric #include "clang/AST/ASTContext.h" 14bdd1243dSDimitry Andric #include "clang/AST/Attr.h" 15753f127fSDimitry Andric #include "clang/AST/DeclCXX.h" 16753f127fSDimitry Andric #include "clang/Basic/AttrKinds.h" 17bdd1243dSDimitry Andric #include "clang/Basic/HLSLRuntime.h" 18bdd1243dSDimitry Andric #include "clang/Sema/Lookup.h" 19753f127fSDimitry Andric #include "clang/Sema/Sema.h" 20bdd1243dSDimitry Andric #include "llvm/Frontend/HLSL/HLSLResource.h" 21bdd1243dSDimitry Andric 22bdd1243dSDimitry Andric #include <functional> 23753f127fSDimitry Andric 24753f127fSDimitry Andric using namespace clang; 25bdd1243dSDimitry Andric using namespace llvm::hlsl; 26bdd1243dSDimitry Andric 27bdd1243dSDimitry Andric namespace { 28bdd1243dSDimitry Andric 29bdd1243dSDimitry Andric struct TemplateParameterListBuilder; 30bdd1243dSDimitry Andric 31bdd1243dSDimitry Andric struct BuiltinTypeDeclBuilder { 32bdd1243dSDimitry Andric CXXRecordDecl *Record = nullptr; 33bdd1243dSDimitry Andric ClassTemplateDecl *Template = nullptr; 34bdd1243dSDimitry Andric ClassTemplateDecl *PrevTemplate = nullptr; 35bdd1243dSDimitry Andric NamespaceDecl *HLSLNamespace = nullptr; 36bdd1243dSDimitry Andric llvm::StringMap<FieldDecl *> Fields; 37bdd1243dSDimitry Andric 38bdd1243dSDimitry Andric BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) { 39bdd1243dSDimitry Andric Record->startDefinition(); 40bdd1243dSDimitry Andric Template = Record->getDescribedClassTemplate(); 41bdd1243dSDimitry Andric } 42bdd1243dSDimitry Andric 43bdd1243dSDimitry Andric BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name) 44bdd1243dSDimitry Andric : HLSLNamespace(Namespace) { 45bdd1243dSDimitry Andric ASTContext &AST = S.getASTContext(); 46bdd1243dSDimitry Andric IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName); 49bdd1243dSDimitry Andric CXXRecordDecl *PrevDecl = nullptr; 50bdd1243dSDimitry Andric if (S.LookupQualifiedName(Result, HLSLNamespace)) { 51bdd1243dSDimitry Andric NamedDecl *Found = Result.getFoundDecl(); 52bdd1243dSDimitry Andric if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) { 53bdd1243dSDimitry Andric PrevDecl = TD->getTemplatedDecl(); 54bdd1243dSDimitry Andric PrevTemplate = TD; 55bdd1243dSDimitry Andric } else 56bdd1243dSDimitry Andric PrevDecl = dyn_cast<CXXRecordDecl>(Found); 57bdd1243dSDimitry Andric assert(PrevDecl && "Unexpected lookup result type."); 58bdd1243dSDimitry Andric } 59bdd1243dSDimitry Andric 60bdd1243dSDimitry Andric if (PrevDecl && PrevDecl->isCompleteDefinition()) { 61bdd1243dSDimitry Andric Record = PrevDecl; 62bdd1243dSDimitry Andric return; 63bdd1243dSDimitry Andric } 64bdd1243dSDimitry Andric 655f757f3fSDimitry Andric Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace, 665f757f3fSDimitry Andric SourceLocation(), SourceLocation(), &II, 675f757f3fSDimitry Andric PrevDecl, true); 68bdd1243dSDimitry Andric Record->setImplicit(true); 69bdd1243dSDimitry Andric Record->setLexicalDeclContext(HLSLNamespace); 70bdd1243dSDimitry Andric Record->setHasExternalLexicalStorage(); 71bdd1243dSDimitry Andric 72bdd1243dSDimitry Andric // Don't let anyone derive from built-in types. 73bdd1243dSDimitry Andric Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(), 74bdd1243dSDimitry Andric FinalAttr::Keyword_final)); 75bdd1243dSDimitry Andric } 76bdd1243dSDimitry Andric 77bdd1243dSDimitry Andric ~BuiltinTypeDeclBuilder() { 78bdd1243dSDimitry Andric if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace) 79bdd1243dSDimitry Andric HLSLNamespace->addDecl(Record); 80bdd1243dSDimitry Andric } 81bdd1243dSDimitry Andric 82bdd1243dSDimitry Andric BuiltinTypeDeclBuilder & 83bdd1243dSDimitry Andric addMemberVariable(StringRef Name, QualType Type, 84bdd1243dSDimitry Andric AccessSpecifier Access = AccessSpecifier::AS_private) { 85bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 86bdd1243dSDimitry Andric return *this; 87bdd1243dSDimitry Andric assert(Record->isBeingDefined() && 88bdd1243dSDimitry Andric "Definition must be started before adding members!"); 89bdd1243dSDimitry Andric ASTContext &AST = Record->getASTContext(); 90bdd1243dSDimitry Andric 91bdd1243dSDimitry Andric IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); 92bdd1243dSDimitry Andric TypeSourceInfo *MemTySource = 93bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(Type, SourceLocation()); 94bdd1243dSDimitry Andric auto *Field = FieldDecl::Create( 95bdd1243dSDimitry Andric AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource, 96bdd1243dSDimitry Andric nullptr, false, InClassInitStyle::ICIS_NoInit); 97bdd1243dSDimitry Andric Field->setAccess(Access); 98bdd1243dSDimitry Andric Field->setImplicit(true); 99bdd1243dSDimitry Andric Record->addDecl(Field); 100bdd1243dSDimitry Andric Fields[Name] = Field; 101bdd1243dSDimitry Andric return *this; 102bdd1243dSDimitry Andric } 103bdd1243dSDimitry Andric 104bdd1243dSDimitry Andric BuiltinTypeDeclBuilder & 105bdd1243dSDimitry Andric addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) { 106bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 107bdd1243dSDimitry Andric return *this; 108bdd1243dSDimitry Andric QualType Ty = Record->getASTContext().VoidPtrTy; 109bdd1243dSDimitry Andric if (Template) { 110bdd1243dSDimitry Andric if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>( 111bdd1243dSDimitry Andric Template->getTemplateParameters()->getParam(0))) 112bdd1243dSDimitry Andric Ty = Record->getASTContext().getPointerType( 113bdd1243dSDimitry Andric QualType(TTD->getTypeForDecl(), 0)); 114bdd1243dSDimitry Andric } 115bdd1243dSDimitry Andric return addMemberVariable("h", Ty, Access); 116bdd1243dSDimitry Andric } 117bdd1243dSDimitry Andric 118*0fca6ea1SDimitry Andric BuiltinTypeDeclBuilder &annotateHLSLResource(ResourceClass RC, 1195f757f3fSDimitry Andric ResourceKind RK, bool IsROV) { 120bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 121bdd1243dSDimitry Andric return *this; 122*0fca6ea1SDimitry Andric Record->addAttr( 123*0fca6ea1SDimitry Andric HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC)); 124*0fca6ea1SDimitry Andric Record->addAttr( 125*0fca6ea1SDimitry Andric HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK, IsROV)); 126bdd1243dSDimitry Andric return *this; 127bdd1243dSDimitry Andric } 128bdd1243dSDimitry Andric 129bdd1243dSDimitry Andric static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, 130bdd1243dSDimitry Andric StringRef Name) { 131bdd1243dSDimitry Andric IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); 132bdd1243dSDimitry Andric DeclarationNameInfo NameInfo = 133bdd1243dSDimitry Andric DeclarationNameInfo(DeclarationName(&II), SourceLocation()); 134bdd1243dSDimitry Andric LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); 135*0fca6ea1SDimitry Andric // AllowBuiltinCreation is false but LookupDirect will create 136*0fca6ea1SDimitry Andric // the builtin when searching the global scope anyways... 137*0fca6ea1SDimitry Andric S.LookupName(R, S.getCurScope()); 138*0fca6ea1SDimitry Andric // FIXME: If the builtin function was user-declared in global scope, 139*0fca6ea1SDimitry Andric // this assert *will* fail. Should this call LookupBuiltin instead? 140bdd1243dSDimitry Andric assert(R.isSingleResult() && 141bdd1243dSDimitry Andric "Since this is a builtin it should always resolve!"); 142bdd1243dSDimitry Andric auto *VD = cast<ValueDecl>(R.getFoundDecl()); 143bdd1243dSDimitry Andric QualType Ty = VD->getType(); 144bdd1243dSDimitry Andric return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(), 145bdd1243dSDimitry Andric VD, false, NameInfo, Ty, VK_PRValue); 146bdd1243dSDimitry Andric } 147bdd1243dSDimitry Andric 148bdd1243dSDimitry Andric static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) { 149bdd1243dSDimitry Andric return IntegerLiteral::Create( 150bdd1243dSDimitry Andric AST, 151bdd1243dSDimitry Andric llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy), 152bdd1243dSDimitry Andric static_cast<uint8_t>(RC)), 153bdd1243dSDimitry Andric AST.UnsignedCharTy, SourceLocation()); 154bdd1243dSDimitry Andric } 155bdd1243dSDimitry Andric 156bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S, 157bdd1243dSDimitry Andric ResourceClass RC) { 158bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 159bdd1243dSDimitry Andric return *this; 160bdd1243dSDimitry Andric ASTContext &AST = Record->getASTContext(); 161bdd1243dSDimitry Andric 162bdd1243dSDimitry Andric QualType ConstructorType = 163bdd1243dSDimitry Andric AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo()); 164bdd1243dSDimitry Andric 165bdd1243dSDimitry Andric CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); 166bdd1243dSDimitry Andric DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy); 167bdd1243dSDimitry Andric CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( 168bdd1243dSDimitry Andric AST, Record, SourceLocation(), 169bdd1243dSDimitry Andric DeclarationNameInfo(Name, SourceLocation()), ConstructorType, 170bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()), 171bdd1243dSDimitry Andric ExplicitSpecifier(), false, true, false, 172bdd1243dSDimitry Andric ConstexprSpecKind::Unspecified); 173bdd1243dSDimitry Andric 174bdd1243dSDimitry Andric DeclRefExpr *Fn = 175bdd1243dSDimitry Andric lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle"); 176bdd1243dSDimitry Andric Expr *RCExpr = emitResourceClassExpr(AST, RC); 177bdd1243dSDimitry Andric Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, 178bdd1243dSDimitry Andric SourceLocation(), FPOptionsOverride()); 179bdd1243dSDimitry Andric 1805f757f3fSDimitry Andric CXXThisExpr *This = CXXThisExpr::Create( 1815f757f3fSDimitry Andric AST, SourceLocation(), Constructor->getFunctionObjectParameterType(), 1825f757f3fSDimitry Andric true); 183bdd1243dSDimitry Andric Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"], 184bdd1243dSDimitry Andric Fields["h"]->getType(), VK_LValue, 185bdd1243dSDimitry Andric OK_Ordinary); 186bdd1243dSDimitry Andric 187bdd1243dSDimitry Andric // If the handle isn't a void pointer, cast the builtin result to the 188bdd1243dSDimitry Andric // correct type. 189bdd1243dSDimitry Andric if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) { 190bdd1243dSDimitry Andric Call = CXXStaticCastExpr::Create( 191bdd1243dSDimitry Andric AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr, 192bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()), 193bdd1243dSDimitry Andric FPOptionsOverride(), SourceLocation(), SourceLocation(), 194bdd1243dSDimitry Andric SourceRange()); 195bdd1243dSDimitry Andric } 196bdd1243dSDimitry Andric 197bdd1243dSDimitry Andric BinaryOperator *Assign = BinaryOperator::Create( 198bdd1243dSDimitry Andric AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary, 199bdd1243dSDimitry Andric SourceLocation(), FPOptionsOverride()); 200bdd1243dSDimitry Andric 201bdd1243dSDimitry Andric Constructor->setBody( 202bdd1243dSDimitry Andric CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(), 203bdd1243dSDimitry Andric SourceLocation(), SourceLocation())); 204bdd1243dSDimitry Andric Constructor->setAccess(AccessSpecifier::AS_public); 205bdd1243dSDimitry Andric Record->addDecl(Constructor); 206bdd1243dSDimitry Andric return *this; 207bdd1243dSDimitry Andric } 208bdd1243dSDimitry Andric 209bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &addArraySubscriptOperators() { 210bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 211bdd1243dSDimitry Andric return *this; 212bdd1243dSDimitry Andric addArraySubscriptOperator(true); 213bdd1243dSDimitry Andric addArraySubscriptOperator(false); 214bdd1243dSDimitry Andric return *this; 215bdd1243dSDimitry Andric } 216bdd1243dSDimitry Andric 217bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) { 218bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 219bdd1243dSDimitry Andric return *this; 220bdd1243dSDimitry Andric assert(Fields.count("h") > 0 && 221bdd1243dSDimitry Andric "Subscript operator must be added after the handle."); 222bdd1243dSDimitry Andric 223bdd1243dSDimitry Andric FieldDecl *Handle = Fields["h"]; 224bdd1243dSDimitry Andric ASTContext &AST = Record->getASTContext(); 225bdd1243dSDimitry Andric 226bdd1243dSDimitry Andric assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy && 227bdd1243dSDimitry Andric "Not yet supported for void pointer handles."); 228bdd1243dSDimitry Andric 229bdd1243dSDimitry Andric QualType ElemTy = 230bdd1243dSDimitry Andric QualType(Handle->getType()->getPointeeOrArrayElementType(), 0); 231bdd1243dSDimitry Andric QualType ReturnTy = ElemTy; 232bdd1243dSDimitry Andric 233bdd1243dSDimitry Andric FunctionProtoType::ExtProtoInfo ExtInfo; 234bdd1243dSDimitry Andric 235bdd1243dSDimitry Andric // Subscript operators return references to elements, const makes the 236bdd1243dSDimitry Andric // reference and method const so that the underlying data is not mutable. 237bdd1243dSDimitry Andric ReturnTy = AST.getLValueReferenceType(ReturnTy); 238bdd1243dSDimitry Andric if (IsConst) { 239bdd1243dSDimitry Andric ExtInfo.TypeQuals.addConst(); 240bdd1243dSDimitry Andric ReturnTy.addConst(); 241bdd1243dSDimitry Andric } 242bdd1243dSDimitry Andric 243bdd1243dSDimitry Andric QualType MethodTy = 244bdd1243dSDimitry Andric AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo); 245bdd1243dSDimitry Andric auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation()); 246bdd1243dSDimitry Andric auto *MethodDecl = CXXMethodDecl::Create( 247bdd1243dSDimitry Andric AST, Record, SourceLocation(), 248bdd1243dSDimitry Andric DeclarationNameInfo( 249bdd1243dSDimitry Andric AST.DeclarationNames.getCXXOperatorName(OO_Subscript), 250bdd1243dSDimitry Andric SourceLocation()), 251bdd1243dSDimitry Andric MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified, 252bdd1243dSDimitry Andric SourceLocation()); 253bdd1243dSDimitry Andric 254bdd1243dSDimitry Andric IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier); 255bdd1243dSDimitry Andric auto *IdxParam = ParmVarDecl::Create( 256bdd1243dSDimitry Andric AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(), 257bdd1243dSDimitry Andric &II, AST.UnsignedIntTy, 258bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()), 259bdd1243dSDimitry Andric SC_None, nullptr); 260bdd1243dSDimitry Andric MethodDecl->setParams({IdxParam}); 261bdd1243dSDimitry Andric 262bdd1243dSDimitry Andric // Also add the parameter to the function prototype. 263bdd1243dSDimitry Andric auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>(); 264bdd1243dSDimitry Andric FnProtoLoc.setParam(0, IdxParam); 265bdd1243dSDimitry Andric 2665f757f3fSDimitry Andric auto *This = 2675f757f3fSDimitry Andric CXXThisExpr::Create(AST, SourceLocation(), 2685f757f3fSDimitry Andric MethodDecl->getFunctionObjectParameterType(), true); 269bdd1243dSDimitry Andric auto *HandleAccess = MemberExpr::CreateImplicit( 270bdd1243dSDimitry Andric AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary); 271bdd1243dSDimitry Andric 272bdd1243dSDimitry Andric auto *IndexExpr = DeclRefExpr::Create( 273bdd1243dSDimitry Andric AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false, 274bdd1243dSDimitry Andric DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()), 275bdd1243dSDimitry Andric AST.UnsignedIntTy, VK_PRValue); 276bdd1243dSDimitry Andric 277bdd1243dSDimitry Andric auto *Array = 278bdd1243dSDimitry Andric new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue, 279bdd1243dSDimitry Andric OK_Ordinary, SourceLocation()); 280bdd1243dSDimitry Andric 281bdd1243dSDimitry Andric auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr); 282bdd1243dSDimitry Andric 283bdd1243dSDimitry Andric MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(), 284bdd1243dSDimitry Andric SourceLocation(), 285bdd1243dSDimitry Andric SourceLocation())); 286bdd1243dSDimitry Andric MethodDecl->setLexicalDeclContext(Record); 287bdd1243dSDimitry Andric MethodDecl->setAccess(AccessSpecifier::AS_public); 288bdd1243dSDimitry Andric MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit( 28906c3fb27SDimitry Andric AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline)); 290bdd1243dSDimitry Andric Record->addDecl(MethodDecl); 291bdd1243dSDimitry Andric 292bdd1243dSDimitry Andric return *this; 293bdd1243dSDimitry Andric } 294bdd1243dSDimitry Andric 295bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &startDefinition() { 296bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 297bdd1243dSDimitry Andric return *this; 298bdd1243dSDimitry Andric Record->startDefinition(); 299bdd1243dSDimitry Andric return *this; 300bdd1243dSDimitry Andric } 301bdd1243dSDimitry Andric 302bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &completeDefinition() { 303bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 304bdd1243dSDimitry Andric return *this; 305bdd1243dSDimitry Andric assert(Record->isBeingDefined() && 306bdd1243dSDimitry Andric "Definition must be started before completing it."); 307bdd1243dSDimitry Andric 308bdd1243dSDimitry Andric Record->completeDefinition(); 309bdd1243dSDimitry Andric return *this; 310bdd1243dSDimitry Andric } 311bdd1243dSDimitry Andric 312*0fca6ea1SDimitry Andric TemplateParameterListBuilder addTemplateArgumentList(Sema &S); 313*0fca6ea1SDimitry Andric BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S, 314*0fca6ea1SDimitry Andric ArrayRef<StringRef> Names); 315bdd1243dSDimitry Andric }; 316bdd1243dSDimitry Andric 317bdd1243dSDimitry Andric struct TemplateParameterListBuilder { 318bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &Builder; 319*0fca6ea1SDimitry Andric Sema &S; 320bdd1243dSDimitry Andric llvm::SmallVector<NamedDecl *> Params; 321bdd1243dSDimitry Andric 322*0fca6ea1SDimitry Andric TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB) 323*0fca6ea1SDimitry Andric : Builder(RB), S(S) {} 324bdd1243dSDimitry Andric 325bdd1243dSDimitry Andric ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } 326bdd1243dSDimitry Andric 327bdd1243dSDimitry Andric TemplateParameterListBuilder & 328bdd1243dSDimitry Andric addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) { 329bdd1243dSDimitry Andric if (Builder.Record->isCompleteDefinition()) 330bdd1243dSDimitry Andric return *this; 331bdd1243dSDimitry Andric unsigned Position = static_cast<unsigned>(Params.size()); 332bdd1243dSDimitry Andric auto *Decl = TemplateTypeParmDecl::Create( 333*0fca6ea1SDimitry Andric S.Context, Builder.Record->getDeclContext(), SourceLocation(), 334bdd1243dSDimitry Andric SourceLocation(), /* TemplateDepth */ 0, Position, 335*0fca6ea1SDimitry Andric &S.Context.Idents.get(Name, tok::TokenKind::identifier), 336*0fca6ea1SDimitry Andric /* Typename */ false, 337bdd1243dSDimitry Andric /* ParameterPack */ false); 338bdd1243dSDimitry Andric if (!DefaultValue.isNull()) 339*0fca6ea1SDimitry Andric Decl->setDefaultArgument( 340*0fca6ea1SDimitry Andric S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(), 341*0fca6ea1SDimitry Andric SourceLocation())); 342bdd1243dSDimitry Andric 343bdd1243dSDimitry Andric Params.emplace_back(Decl); 344bdd1243dSDimitry Andric return *this; 345bdd1243dSDimitry Andric } 346bdd1243dSDimitry Andric 347bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &finalizeTemplateArgs() { 348bdd1243dSDimitry Andric if (Params.empty()) 349bdd1243dSDimitry Andric return Builder; 350*0fca6ea1SDimitry Andric auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(), 351*0fca6ea1SDimitry Andric SourceLocation(), Params, 352*0fca6ea1SDimitry Andric SourceLocation(), nullptr); 353bdd1243dSDimitry Andric Builder.Template = ClassTemplateDecl::Create( 354*0fca6ea1SDimitry Andric S.Context, Builder.Record->getDeclContext(), SourceLocation(), 355bdd1243dSDimitry Andric DeclarationName(Builder.Record->getIdentifier()), ParamList, 356bdd1243dSDimitry Andric Builder.Record); 357bdd1243dSDimitry Andric Builder.Record->setDescribedClassTemplate(Builder.Template); 358bdd1243dSDimitry Andric Builder.Template->setImplicit(true); 359bdd1243dSDimitry Andric Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext()); 360bdd1243dSDimitry Andric // NOTE: setPreviousDecl before addDecl so new decl replace old decl when 361bdd1243dSDimitry Andric // make visible. 362bdd1243dSDimitry Andric Builder.Template->setPreviousDecl(Builder.PrevTemplate); 363bdd1243dSDimitry Andric Builder.Record->getDeclContext()->addDecl(Builder.Template); 364bdd1243dSDimitry Andric Params.clear(); 365bdd1243dSDimitry Andric 366bdd1243dSDimitry Andric QualType T = Builder.Template->getInjectedClassNameSpecialization(); 367*0fca6ea1SDimitry Andric T = S.Context.getInjectedClassNameType(Builder.Record, T); 368bdd1243dSDimitry Andric 369bdd1243dSDimitry Andric return Builder; 370bdd1243dSDimitry Andric } 371bdd1243dSDimitry Andric }; 3725f757f3fSDimitry Andric } // namespace 373bdd1243dSDimitry Andric 374*0fca6ea1SDimitry Andric TemplateParameterListBuilder 375*0fca6ea1SDimitry Andric BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) { 376*0fca6ea1SDimitry Andric return TemplateParameterListBuilder(S, *this); 377bdd1243dSDimitry Andric } 3785f757f3fSDimitry Andric 3795f757f3fSDimitry Andric BuiltinTypeDeclBuilder & 380*0fca6ea1SDimitry Andric BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S, 381*0fca6ea1SDimitry Andric ArrayRef<StringRef> Names) { 382*0fca6ea1SDimitry Andric TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S); 3835f757f3fSDimitry Andric for (StringRef Name : Names) 3845f757f3fSDimitry Andric Builder.addTypeParameter(Name); 3855f757f3fSDimitry Andric return Builder.finalizeTemplateArgs(); 3865f757f3fSDimitry Andric } 387753f127fSDimitry Andric 388753f127fSDimitry Andric HLSLExternalSemaSource::~HLSLExternalSemaSource() {} 389753f127fSDimitry Andric 390753f127fSDimitry Andric void HLSLExternalSemaSource::InitializeSema(Sema &S) { 391753f127fSDimitry Andric SemaPtr = &S; 392753f127fSDimitry Andric ASTContext &AST = SemaPtr->getASTContext(); 393bdd1243dSDimitry Andric // If the translation unit has external storage force external decls to load. 394bdd1243dSDimitry Andric if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage()) 395bdd1243dSDimitry Andric (void)AST.getTranslationUnitDecl()->decls_begin(); 396bdd1243dSDimitry Andric 397753f127fSDimitry Andric IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier); 398bdd1243dSDimitry Andric LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName); 399bdd1243dSDimitry Andric NamespaceDecl *PrevDecl = nullptr; 400bdd1243dSDimitry Andric if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl())) 401bdd1243dSDimitry Andric PrevDecl = Result.getAsSingle<NamespaceDecl>(); 402bdd1243dSDimitry Andric HLSLNamespace = NamespaceDecl::Create( 403bdd1243dSDimitry Andric AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(), 404bdd1243dSDimitry Andric SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false); 405753f127fSDimitry Andric HLSLNamespace->setImplicit(true); 406bdd1243dSDimitry Andric HLSLNamespace->setHasExternalLexicalStorage(); 407753f127fSDimitry Andric AST.getTranslationUnitDecl()->addDecl(HLSLNamespace); 408bdd1243dSDimitry Andric 409bdd1243dSDimitry Andric // Force external decls in the HLSL namespace to load from the PCH. 410bdd1243dSDimitry Andric (void)HLSLNamespace->getCanonicalDecl()->decls_begin(); 411bdd1243dSDimitry Andric defineTrivialHLSLTypes(); 4125f757f3fSDimitry Andric defineHLSLTypesWithForwardDeclarations(); 413753f127fSDimitry Andric 414753f127fSDimitry Andric // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's 415753f127fSDimitry Andric // built in types inside a namespace, but we are planning to change that in 416753f127fSDimitry Andric // the near future. In order to be source compatible older versions of HLSL 417753f127fSDimitry Andric // will need to implicitly use the hlsl namespace. For now in clang everything 418753f127fSDimitry Andric // will get added to the namespace, and we can remove the using directive for 419753f127fSDimitry Andric // future language versions to match HLSL's evolution. 420753f127fSDimitry Andric auto *UsingDecl = UsingDirectiveDecl::Create( 421753f127fSDimitry Andric AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), 422753f127fSDimitry Andric NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace, 423753f127fSDimitry Andric AST.getTranslationUnitDecl()); 424753f127fSDimitry Andric 425753f127fSDimitry Andric AST.getTranslationUnitDecl()->addDecl(UsingDecl); 426753f127fSDimitry Andric } 427753f127fSDimitry Andric 428753f127fSDimitry Andric void HLSLExternalSemaSource::defineHLSLVectorAlias() { 429753f127fSDimitry Andric ASTContext &AST = SemaPtr->getASTContext(); 430753f127fSDimitry Andric 431753f127fSDimitry Andric llvm::SmallVector<NamedDecl *> TemplateParams; 432753f127fSDimitry Andric 433753f127fSDimitry Andric auto *TypeParam = TemplateTypeParmDecl::Create( 434753f127fSDimitry Andric AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0, 435753f127fSDimitry Andric &AST.Idents.get("element", tok::TokenKind::identifier), false, false); 436*0fca6ea1SDimitry Andric TypeParam->setDefaultArgument( 437*0fca6ea1SDimitry Andric AST, SemaPtr->getTrivialTemplateArgumentLoc( 438*0fca6ea1SDimitry Andric TemplateArgument(AST.FloatTy), QualType(), SourceLocation())); 439753f127fSDimitry Andric 440753f127fSDimitry Andric TemplateParams.emplace_back(TypeParam); 441753f127fSDimitry Andric 442753f127fSDimitry Andric auto *SizeParam = NonTypeTemplateParmDecl::Create( 443753f127fSDimitry Andric AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1, 444753f127fSDimitry Andric &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy, 445753f127fSDimitry Andric false, AST.getTrivialTypeSourceInfo(AST.IntTy)); 446*0fca6ea1SDimitry Andric llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4); 447*0fca6ea1SDimitry Andric TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy, 448*0fca6ea1SDimitry Andric /*IsDefaulted=*/true); 449*0fca6ea1SDimitry Andric SizeParam->setDefaultArgument( 450*0fca6ea1SDimitry Andric AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy, 451*0fca6ea1SDimitry Andric SourceLocation(), SizeParam)); 452753f127fSDimitry Andric TemplateParams.emplace_back(SizeParam); 453753f127fSDimitry Andric 454753f127fSDimitry Andric auto *ParamList = 455753f127fSDimitry Andric TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), 456753f127fSDimitry Andric TemplateParams, SourceLocation(), nullptr); 457753f127fSDimitry Andric 458753f127fSDimitry Andric IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier); 459753f127fSDimitry Andric 460753f127fSDimitry Andric QualType AliasType = AST.getDependentSizedExtVectorType( 461753f127fSDimitry Andric AST.getTemplateTypeParmType(0, 0, false, TypeParam), 462753f127fSDimitry Andric DeclRefExpr::Create( 463753f127fSDimitry Andric AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false, 464753f127fSDimitry Andric DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()), 465753f127fSDimitry Andric AST.IntTy, VK_LValue), 466753f127fSDimitry Andric SourceLocation()); 467753f127fSDimitry Andric 468753f127fSDimitry Andric auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(), 469753f127fSDimitry Andric SourceLocation(), &II, 470753f127fSDimitry Andric AST.getTrivialTypeSourceInfo(AliasType)); 471753f127fSDimitry Andric Record->setImplicit(true); 472753f127fSDimitry Andric 473753f127fSDimitry Andric auto *Template = 474753f127fSDimitry Andric TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(), 475753f127fSDimitry Andric Record->getIdentifier(), ParamList, Record); 476753f127fSDimitry Andric 477753f127fSDimitry Andric Record->setDescribedAliasTemplate(Template); 478753f127fSDimitry Andric Template->setImplicit(true); 479753f127fSDimitry Andric Template->setLexicalDeclContext(Record->getDeclContext()); 480753f127fSDimitry Andric HLSLNamespace->addDecl(Template); 481753f127fSDimitry Andric } 482bdd1243dSDimitry Andric 483bdd1243dSDimitry Andric void HLSLExternalSemaSource::defineTrivialHLSLTypes() { 484bdd1243dSDimitry Andric defineHLSLVectorAlias(); 485bdd1243dSDimitry Andric } 486bdd1243dSDimitry Andric 4875f757f3fSDimitry Andric /// Set up common members and attributes for buffer types 4885f757f3fSDimitry Andric static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, 4895f757f3fSDimitry Andric ResourceClass RC, ResourceKind RK, 4905f757f3fSDimitry Andric bool IsROV) { 4915f757f3fSDimitry Andric return BuiltinTypeDeclBuilder(Decl) 4925f757f3fSDimitry Andric .addHandleMember() 4935f757f3fSDimitry Andric .addDefaultHandleConstructor(S, RC) 494*0fca6ea1SDimitry Andric .annotateHLSLResource(RC, RK, IsROV); 4955f757f3fSDimitry Andric } 4965f757f3fSDimitry Andric 4975f757f3fSDimitry Andric void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { 498bdd1243dSDimitry Andric CXXRecordDecl *Decl; 499bdd1243dSDimitry Andric Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") 500*0fca6ea1SDimitry Andric .addSimpleTemplateParams(*SemaPtr, {"element_type"}) 501bdd1243dSDimitry Andric .Record; 5025f757f3fSDimitry Andric onCompletion(Decl, [this](CXXRecordDecl *Decl) { 5035f757f3fSDimitry Andric setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, 5045f757f3fSDimitry Andric ResourceKind::TypedBuffer, /*IsROV=*/false) 5055f757f3fSDimitry Andric .addArraySubscriptOperators() 5065f757f3fSDimitry Andric .completeDefinition(); 5075f757f3fSDimitry Andric }); 5085f757f3fSDimitry Andric 5095f757f3fSDimitry Andric Decl = 5105f757f3fSDimitry Andric BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer") 511*0fca6ea1SDimitry Andric .addSimpleTemplateParams(*SemaPtr, {"element_type"}) 5125f757f3fSDimitry Andric .Record; 5135f757f3fSDimitry Andric onCompletion(Decl, [this](CXXRecordDecl *Decl) { 5145f757f3fSDimitry Andric setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, 5155f757f3fSDimitry Andric ResourceKind::TypedBuffer, /*IsROV=*/true) 5165f757f3fSDimitry Andric .addArraySubscriptOperators() 5175f757f3fSDimitry Andric .completeDefinition(); 5185f757f3fSDimitry Andric }); 5195f757f3fSDimitry Andric } 5205f757f3fSDimitry Andric 5215f757f3fSDimitry Andric void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record, 5225f757f3fSDimitry Andric CompletionFunction Fn) { 5235f757f3fSDimitry Andric Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn)); 524bdd1243dSDimitry Andric } 525bdd1243dSDimitry Andric 526bdd1243dSDimitry Andric void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) { 527bdd1243dSDimitry Andric if (!isa<CXXRecordDecl>(Tag)) 528bdd1243dSDimitry Andric return; 529bdd1243dSDimitry Andric auto Record = cast<CXXRecordDecl>(Tag); 530bdd1243dSDimitry Andric 531bdd1243dSDimitry Andric // If this is a specialization, we need to get the underlying templated 532bdd1243dSDimitry Andric // declaration and complete that. 533bdd1243dSDimitry Andric if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record)) 534bdd1243dSDimitry Andric Record = TDecl->getSpecializedTemplate()->getTemplatedDecl(); 535bdd1243dSDimitry Andric Record = Record->getCanonicalDecl(); 536bdd1243dSDimitry Andric auto It = Completions.find(Record); 537bdd1243dSDimitry Andric if (It == Completions.end()) 538bdd1243dSDimitry Andric return; 539bdd1243dSDimitry Andric It->second(Record); 540bdd1243dSDimitry Andric } 541