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 65*5f757f3fSDimitry Andric Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace, 66*5f757f3fSDimitry Andric SourceLocation(), SourceLocation(), &II, 67*5f757f3fSDimitry 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*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder &annotateResourceClass(ResourceClass RC, 119*5f757f3fSDimitry Andric ResourceKind RK, bool IsROV) { 120bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 121bdd1243dSDimitry Andric return *this; 122*5f757f3fSDimitry Andric Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(), 123*5f757f3fSDimitry Andric RC, RK, IsROV)); 124bdd1243dSDimitry Andric return *this; 125bdd1243dSDimitry Andric } 126bdd1243dSDimitry Andric 127bdd1243dSDimitry Andric static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, 128bdd1243dSDimitry Andric StringRef Name) { 129bdd1243dSDimitry Andric CXXScopeSpec SS; 130bdd1243dSDimitry Andric IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); 131bdd1243dSDimitry Andric DeclarationNameInfo NameInfo = 132bdd1243dSDimitry Andric DeclarationNameInfo(DeclarationName(&II), SourceLocation()); 133bdd1243dSDimitry Andric LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); 134bdd1243dSDimitry Andric S.LookupParsedName(R, S.getCurScope(), &SS, false); 135bdd1243dSDimitry Andric assert(R.isSingleResult() && 136bdd1243dSDimitry Andric "Since this is a builtin it should always resolve!"); 137bdd1243dSDimitry Andric auto *VD = cast<ValueDecl>(R.getFoundDecl()); 138bdd1243dSDimitry Andric QualType Ty = VD->getType(); 139bdd1243dSDimitry Andric return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(), 140bdd1243dSDimitry Andric VD, false, NameInfo, Ty, VK_PRValue); 141bdd1243dSDimitry Andric } 142bdd1243dSDimitry Andric 143bdd1243dSDimitry Andric static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) { 144bdd1243dSDimitry Andric return IntegerLiteral::Create( 145bdd1243dSDimitry Andric AST, 146bdd1243dSDimitry Andric llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy), 147bdd1243dSDimitry Andric static_cast<uint8_t>(RC)), 148bdd1243dSDimitry Andric AST.UnsignedCharTy, SourceLocation()); 149bdd1243dSDimitry Andric } 150bdd1243dSDimitry Andric 151bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S, 152bdd1243dSDimitry Andric ResourceClass RC) { 153bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 154bdd1243dSDimitry Andric return *this; 155bdd1243dSDimitry Andric ASTContext &AST = Record->getASTContext(); 156bdd1243dSDimitry Andric 157bdd1243dSDimitry Andric QualType ConstructorType = 158bdd1243dSDimitry Andric AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo()); 159bdd1243dSDimitry Andric 160bdd1243dSDimitry Andric CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); 161bdd1243dSDimitry Andric DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy); 162bdd1243dSDimitry Andric CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( 163bdd1243dSDimitry Andric AST, Record, SourceLocation(), 164bdd1243dSDimitry Andric DeclarationNameInfo(Name, SourceLocation()), ConstructorType, 165bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()), 166bdd1243dSDimitry Andric ExplicitSpecifier(), false, true, false, 167bdd1243dSDimitry Andric ConstexprSpecKind::Unspecified); 168bdd1243dSDimitry Andric 169bdd1243dSDimitry Andric DeclRefExpr *Fn = 170bdd1243dSDimitry Andric lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle"); 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric Expr *RCExpr = emitResourceClassExpr(AST, RC); 173bdd1243dSDimitry Andric Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, 174bdd1243dSDimitry Andric SourceLocation(), FPOptionsOverride()); 175bdd1243dSDimitry Andric 176*5f757f3fSDimitry Andric CXXThisExpr *This = CXXThisExpr::Create( 177*5f757f3fSDimitry Andric AST, SourceLocation(), Constructor->getFunctionObjectParameterType(), 178*5f757f3fSDimitry Andric true); 179bdd1243dSDimitry Andric Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"], 180bdd1243dSDimitry Andric Fields["h"]->getType(), VK_LValue, 181bdd1243dSDimitry Andric OK_Ordinary); 182bdd1243dSDimitry Andric 183bdd1243dSDimitry Andric // If the handle isn't a void pointer, cast the builtin result to the 184bdd1243dSDimitry Andric // correct type. 185bdd1243dSDimitry Andric if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) { 186bdd1243dSDimitry Andric Call = CXXStaticCastExpr::Create( 187bdd1243dSDimitry Andric AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr, 188bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()), 189bdd1243dSDimitry Andric FPOptionsOverride(), SourceLocation(), SourceLocation(), 190bdd1243dSDimitry Andric SourceRange()); 191bdd1243dSDimitry Andric } 192bdd1243dSDimitry Andric 193bdd1243dSDimitry Andric BinaryOperator *Assign = BinaryOperator::Create( 194bdd1243dSDimitry Andric AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary, 195bdd1243dSDimitry Andric SourceLocation(), FPOptionsOverride()); 196bdd1243dSDimitry Andric 197bdd1243dSDimitry Andric Constructor->setBody( 198bdd1243dSDimitry Andric CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(), 199bdd1243dSDimitry Andric SourceLocation(), SourceLocation())); 200bdd1243dSDimitry Andric Constructor->setAccess(AccessSpecifier::AS_public); 201bdd1243dSDimitry Andric Record->addDecl(Constructor); 202bdd1243dSDimitry Andric return *this; 203bdd1243dSDimitry Andric } 204bdd1243dSDimitry Andric 205bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &addArraySubscriptOperators() { 206bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 207bdd1243dSDimitry Andric return *this; 208bdd1243dSDimitry Andric addArraySubscriptOperator(true); 209bdd1243dSDimitry Andric addArraySubscriptOperator(false); 210bdd1243dSDimitry Andric return *this; 211bdd1243dSDimitry Andric } 212bdd1243dSDimitry Andric 213bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) { 214bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 215bdd1243dSDimitry Andric return *this; 216bdd1243dSDimitry Andric assert(Fields.count("h") > 0 && 217bdd1243dSDimitry Andric "Subscript operator must be added after the handle."); 218bdd1243dSDimitry Andric 219bdd1243dSDimitry Andric FieldDecl *Handle = Fields["h"]; 220bdd1243dSDimitry Andric ASTContext &AST = Record->getASTContext(); 221bdd1243dSDimitry Andric 222bdd1243dSDimitry Andric assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy && 223bdd1243dSDimitry Andric "Not yet supported for void pointer handles."); 224bdd1243dSDimitry Andric 225bdd1243dSDimitry Andric QualType ElemTy = 226bdd1243dSDimitry Andric QualType(Handle->getType()->getPointeeOrArrayElementType(), 0); 227bdd1243dSDimitry Andric QualType ReturnTy = ElemTy; 228bdd1243dSDimitry Andric 229bdd1243dSDimitry Andric FunctionProtoType::ExtProtoInfo ExtInfo; 230bdd1243dSDimitry Andric 231bdd1243dSDimitry Andric // Subscript operators return references to elements, const makes the 232bdd1243dSDimitry Andric // reference and method const so that the underlying data is not mutable. 233bdd1243dSDimitry Andric ReturnTy = AST.getLValueReferenceType(ReturnTy); 234bdd1243dSDimitry Andric if (IsConst) { 235bdd1243dSDimitry Andric ExtInfo.TypeQuals.addConst(); 236bdd1243dSDimitry Andric ReturnTy.addConst(); 237bdd1243dSDimitry Andric } 238bdd1243dSDimitry Andric 239bdd1243dSDimitry Andric QualType MethodTy = 240bdd1243dSDimitry Andric AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo); 241bdd1243dSDimitry Andric auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation()); 242bdd1243dSDimitry Andric auto *MethodDecl = CXXMethodDecl::Create( 243bdd1243dSDimitry Andric AST, Record, SourceLocation(), 244bdd1243dSDimitry Andric DeclarationNameInfo( 245bdd1243dSDimitry Andric AST.DeclarationNames.getCXXOperatorName(OO_Subscript), 246bdd1243dSDimitry Andric SourceLocation()), 247bdd1243dSDimitry Andric MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified, 248bdd1243dSDimitry Andric SourceLocation()); 249bdd1243dSDimitry Andric 250bdd1243dSDimitry Andric IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier); 251bdd1243dSDimitry Andric auto *IdxParam = ParmVarDecl::Create( 252bdd1243dSDimitry Andric AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(), 253bdd1243dSDimitry Andric &II, AST.UnsignedIntTy, 254bdd1243dSDimitry Andric AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()), 255bdd1243dSDimitry Andric SC_None, nullptr); 256bdd1243dSDimitry Andric MethodDecl->setParams({IdxParam}); 257bdd1243dSDimitry Andric 258bdd1243dSDimitry Andric // Also add the parameter to the function prototype. 259bdd1243dSDimitry Andric auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>(); 260bdd1243dSDimitry Andric FnProtoLoc.setParam(0, IdxParam); 261bdd1243dSDimitry Andric 262*5f757f3fSDimitry Andric auto *This = 263*5f757f3fSDimitry Andric CXXThisExpr::Create(AST, SourceLocation(), 264*5f757f3fSDimitry Andric MethodDecl->getFunctionObjectParameterType(), true); 265bdd1243dSDimitry Andric auto *HandleAccess = MemberExpr::CreateImplicit( 266bdd1243dSDimitry Andric AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary); 267bdd1243dSDimitry Andric 268bdd1243dSDimitry Andric auto *IndexExpr = DeclRefExpr::Create( 269bdd1243dSDimitry Andric AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false, 270bdd1243dSDimitry Andric DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()), 271bdd1243dSDimitry Andric AST.UnsignedIntTy, VK_PRValue); 272bdd1243dSDimitry Andric 273bdd1243dSDimitry Andric auto *Array = 274bdd1243dSDimitry Andric new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue, 275bdd1243dSDimitry Andric OK_Ordinary, SourceLocation()); 276bdd1243dSDimitry Andric 277bdd1243dSDimitry Andric auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr); 278bdd1243dSDimitry Andric 279bdd1243dSDimitry Andric MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(), 280bdd1243dSDimitry Andric SourceLocation(), 281bdd1243dSDimitry Andric SourceLocation())); 282bdd1243dSDimitry Andric MethodDecl->setLexicalDeclContext(Record); 283bdd1243dSDimitry Andric MethodDecl->setAccess(AccessSpecifier::AS_public); 284bdd1243dSDimitry Andric MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit( 28506c3fb27SDimitry Andric AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline)); 286bdd1243dSDimitry Andric Record->addDecl(MethodDecl); 287bdd1243dSDimitry Andric 288bdd1243dSDimitry Andric return *this; 289bdd1243dSDimitry Andric } 290bdd1243dSDimitry Andric 291bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &startDefinition() { 292bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 293bdd1243dSDimitry Andric return *this; 294bdd1243dSDimitry Andric Record->startDefinition(); 295bdd1243dSDimitry Andric return *this; 296bdd1243dSDimitry Andric } 297bdd1243dSDimitry Andric 298bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &completeDefinition() { 299bdd1243dSDimitry Andric if (Record->isCompleteDefinition()) 300bdd1243dSDimitry Andric return *this; 301bdd1243dSDimitry Andric assert(Record->isBeingDefined() && 302bdd1243dSDimitry Andric "Definition must be started before completing it."); 303bdd1243dSDimitry Andric 304bdd1243dSDimitry Andric Record->completeDefinition(); 305bdd1243dSDimitry Andric return *this; 306bdd1243dSDimitry Andric } 307bdd1243dSDimitry Andric 308bdd1243dSDimitry Andric TemplateParameterListBuilder addTemplateArgumentList(); 309*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef<StringRef> Names); 310bdd1243dSDimitry Andric }; 311bdd1243dSDimitry Andric 312bdd1243dSDimitry Andric struct TemplateParameterListBuilder { 313bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &Builder; 314bdd1243dSDimitry Andric ASTContext &AST; 315bdd1243dSDimitry Andric llvm::SmallVector<NamedDecl *> Params; 316bdd1243dSDimitry Andric 317bdd1243dSDimitry Andric TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) 318bdd1243dSDimitry Andric : Builder(RB), AST(RB.Record->getASTContext()) {} 319bdd1243dSDimitry Andric 320bdd1243dSDimitry Andric ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } 321bdd1243dSDimitry Andric 322bdd1243dSDimitry Andric TemplateParameterListBuilder & 323bdd1243dSDimitry Andric addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) { 324bdd1243dSDimitry Andric if (Builder.Record->isCompleteDefinition()) 325bdd1243dSDimitry Andric return *this; 326bdd1243dSDimitry Andric unsigned Position = static_cast<unsigned>(Params.size()); 327bdd1243dSDimitry Andric auto *Decl = TemplateTypeParmDecl::Create( 328bdd1243dSDimitry Andric AST, Builder.Record->getDeclContext(), SourceLocation(), 329bdd1243dSDimitry Andric SourceLocation(), /* TemplateDepth */ 0, Position, 330bdd1243dSDimitry Andric &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false, 331bdd1243dSDimitry Andric /* ParameterPack */ false); 332bdd1243dSDimitry Andric if (!DefaultValue.isNull()) 333bdd1243dSDimitry Andric Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue)); 334bdd1243dSDimitry Andric 335bdd1243dSDimitry Andric Params.emplace_back(Decl); 336bdd1243dSDimitry Andric return *this; 337bdd1243dSDimitry Andric } 338bdd1243dSDimitry Andric 339bdd1243dSDimitry Andric BuiltinTypeDeclBuilder &finalizeTemplateArgs() { 340bdd1243dSDimitry Andric if (Params.empty()) 341bdd1243dSDimitry Andric return Builder; 342bdd1243dSDimitry Andric auto *ParamList = 343bdd1243dSDimitry Andric TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), 344bdd1243dSDimitry Andric Params, SourceLocation(), nullptr); 345bdd1243dSDimitry Andric Builder.Template = ClassTemplateDecl::Create( 346bdd1243dSDimitry Andric AST, Builder.Record->getDeclContext(), SourceLocation(), 347bdd1243dSDimitry Andric DeclarationName(Builder.Record->getIdentifier()), ParamList, 348bdd1243dSDimitry Andric Builder.Record); 349bdd1243dSDimitry Andric Builder.Record->setDescribedClassTemplate(Builder.Template); 350bdd1243dSDimitry Andric Builder.Template->setImplicit(true); 351bdd1243dSDimitry Andric Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext()); 352bdd1243dSDimitry Andric // NOTE: setPreviousDecl before addDecl so new decl replace old decl when 353bdd1243dSDimitry Andric // make visible. 354bdd1243dSDimitry Andric Builder.Template->setPreviousDecl(Builder.PrevTemplate); 355bdd1243dSDimitry Andric Builder.Record->getDeclContext()->addDecl(Builder.Template); 356bdd1243dSDimitry Andric Params.clear(); 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric QualType T = Builder.Template->getInjectedClassNameSpecialization(); 359bdd1243dSDimitry Andric T = AST.getInjectedClassNameType(Builder.Record, T); 360bdd1243dSDimitry Andric 361bdd1243dSDimitry Andric return Builder; 362bdd1243dSDimitry Andric } 363bdd1243dSDimitry Andric }; 364*5f757f3fSDimitry Andric } // namespace 365bdd1243dSDimitry Andric 366bdd1243dSDimitry Andric TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() { 367bdd1243dSDimitry Andric return TemplateParameterListBuilder(*this); 368bdd1243dSDimitry Andric } 369*5f757f3fSDimitry Andric 370*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder & 371*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names) { 372*5f757f3fSDimitry Andric TemplateParameterListBuilder Builder = this->addTemplateArgumentList(); 373*5f757f3fSDimitry Andric for (StringRef Name : Names) 374*5f757f3fSDimitry Andric Builder.addTypeParameter(Name); 375*5f757f3fSDimitry Andric return Builder.finalizeTemplateArgs(); 376*5f757f3fSDimitry Andric } 377753f127fSDimitry Andric 378753f127fSDimitry Andric HLSLExternalSemaSource::~HLSLExternalSemaSource() {} 379753f127fSDimitry Andric 380753f127fSDimitry Andric void HLSLExternalSemaSource::InitializeSema(Sema &S) { 381753f127fSDimitry Andric SemaPtr = &S; 382753f127fSDimitry Andric ASTContext &AST = SemaPtr->getASTContext(); 383bdd1243dSDimitry Andric // If the translation unit has external storage force external decls to load. 384bdd1243dSDimitry Andric if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage()) 385bdd1243dSDimitry Andric (void)AST.getTranslationUnitDecl()->decls_begin(); 386bdd1243dSDimitry Andric 387753f127fSDimitry Andric IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier); 388bdd1243dSDimitry Andric LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName); 389bdd1243dSDimitry Andric NamespaceDecl *PrevDecl = nullptr; 390bdd1243dSDimitry Andric if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl())) 391bdd1243dSDimitry Andric PrevDecl = Result.getAsSingle<NamespaceDecl>(); 392bdd1243dSDimitry Andric HLSLNamespace = NamespaceDecl::Create( 393bdd1243dSDimitry Andric AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(), 394bdd1243dSDimitry Andric SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false); 395753f127fSDimitry Andric HLSLNamespace->setImplicit(true); 396bdd1243dSDimitry Andric HLSLNamespace->setHasExternalLexicalStorage(); 397753f127fSDimitry Andric AST.getTranslationUnitDecl()->addDecl(HLSLNamespace); 398bdd1243dSDimitry Andric 399bdd1243dSDimitry Andric // Force external decls in the HLSL namespace to load from the PCH. 400bdd1243dSDimitry Andric (void)HLSLNamespace->getCanonicalDecl()->decls_begin(); 401bdd1243dSDimitry Andric defineTrivialHLSLTypes(); 402*5f757f3fSDimitry Andric defineHLSLTypesWithForwardDeclarations(); 403753f127fSDimitry Andric 404753f127fSDimitry Andric // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's 405753f127fSDimitry Andric // built in types inside a namespace, but we are planning to change that in 406753f127fSDimitry Andric // the near future. In order to be source compatible older versions of HLSL 407753f127fSDimitry Andric // will need to implicitly use the hlsl namespace. For now in clang everything 408753f127fSDimitry Andric // will get added to the namespace, and we can remove the using directive for 409753f127fSDimitry Andric // future language versions to match HLSL's evolution. 410753f127fSDimitry Andric auto *UsingDecl = UsingDirectiveDecl::Create( 411753f127fSDimitry Andric AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), 412753f127fSDimitry Andric NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace, 413753f127fSDimitry Andric AST.getTranslationUnitDecl()); 414753f127fSDimitry Andric 415753f127fSDimitry Andric AST.getTranslationUnitDecl()->addDecl(UsingDecl); 416753f127fSDimitry Andric } 417753f127fSDimitry Andric 418753f127fSDimitry Andric void HLSLExternalSemaSource::defineHLSLVectorAlias() { 419753f127fSDimitry Andric ASTContext &AST = SemaPtr->getASTContext(); 420753f127fSDimitry Andric 421753f127fSDimitry Andric llvm::SmallVector<NamedDecl *> TemplateParams; 422753f127fSDimitry Andric 423753f127fSDimitry Andric auto *TypeParam = TemplateTypeParmDecl::Create( 424753f127fSDimitry Andric AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0, 425753f127fSDimitry Andric &AST.Idents.get("element", tok::TokenKind::identifier), false, false); 426753f127fSDimitry Andric TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy)); 427753f127fSDimitry Andric 428753f127fSDimitry Andric TemplateParams.emplace_back(TypeParam); 429753f127fSDimitry Andric 430753f127fSDimitry Andric auto *SizeParam = NonTypeTemplateParmDecl::Create( 431753f127fSDimitry Andric AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1, 432753f127fSDimitry Andric &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy, 433753f127fSDimitry Andric false, AST.getTrivialTypeSourceInfo(AST.IntTy)); 434753f127fSDimitry Andric Expr *LiteralExpr = 435753f127fSDimitry Andric IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4), 436753f127fSDimitry Andric AST.IntTy, SourceLocation()); 437753f127fSDimitry Andric SizeParam->setDefaultArgument(LiteralExpr); 438753f127fSDimitry Andric TemplateParams.emplace_back(SizeParam); 439753f127fSDimitry Andric 440753f127fSDimitry Andric auto *ParamList = 441753f127fSDimitry Andric TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), 442753f127fSDimitry Andric TemplateParams, SourceLocation(), nullptr); 443753f127fSDimitry Andric 444753f127fSDimitry Andric IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier); 445753f127fSDimitry Andric 446753f127fSDimitry Andric QualType AliasType = AST.getDependentSizedExtVectorType( 447753f127fSDimitry Andric AST.getTemplateTypeParmType(0, 0, false, TypeParam), 448753f127fSDimitry Andric DeclRefExpr::Create( 449753f127fSDimitry Andric AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false, 450753f127fSDimitry Andric DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()), 451753f127fSDimitry Andric AST.IntTy, VK_LValue), 452753f127fSDimitry Andric SourceLocation()); 453753f127fSDimitry Andric 454753f127fSDimitry Andric auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(), 455753f127fSDimitry Andric SourceLocation(), &II, 456753f127fSDimitry Andric AST.getTrivialTypeSourceInfo(AliasType)); 457753f127fSDimitry Andric Record->setImplicit(true); 458753f127fSDimitry Andric 459753f127fSDimitry Andric auto *Template = 460753f127fSDimitry Andric TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(), 461753f127fSDimitry Andric Record->getIdentifier(), ParamList, Record); 462753f127fSDimitry Andric 463753f127fSDimitry Andric Record->setDescribedAliasTemplate(Template); 464753f127fSDimitry Andric Template->setImplicit(true); 465753f127fSDimitry Andric Template->setLexicalDeclContext(Record->getDeclContext()); 466753f127fSDimitry Andric HLSLNamespace->addDecl(Template); 467753f127fSDimitry Andric } 468bdd1243dSDimitry Andric 469bdd1243dSDimitry Andric void HLSLExternalSemaSource::defineTrivialHLSLTypes() { 470bdd1243dSDimitry Andric defineHLSLVectorAlias(); 471bdd1243dSDimitry Andric 472bdd1243dSDimitry Andric ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource") 473bdd1243dSDimitry Andric .startDefinition() 474bdd1243dSDimitry Andric .addHandleMember(AccessSpecifier::AS_public) 475bdd1243dSDimitry Andric .completeDefinition() 476bdd1243dSDimitry Andric .Record; 477bdd1243dSDimitry Andric } 478bdd1243dSDimitry Andric 479*5f757f3fSDimitry Andric /// Set up common members and attributes for buffer types 480*5f757f3fSDimitry Andric static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, 481*5f757f3fSDimitry Andric ResourceClass RC, ResourceKind RK, 482*5f757f3fSDimitry Andric bool IsROV) { 483*5f757f3fSDimitry Andric return BuiltinTypeDeclBuilder(Decl) 484*5f757f3fSDimitry Andric .addHandleMember() 485*5f757f3fSDimitry Andric .addDefaultHandleConstructor(S, RC) 486*5f757f3fSDimitry Andric .annotateResourceClass(RC, RK, IsROV); 487*5f757f3fSDimitry Andric } 488*5f757f3fSDimitry Andric 489*5f757f3fSDimitry Andric void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { 490bdd1243dSDimitry Andric CXXRecordDecl *Decl; 491bdd1243dSDimitry Andric Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") 492*5f757f3fSDimitry Andric .addSimpleTemplateParams({"element_type"}) 493bdd1243dSDimitry Andric .Record; 494*5f757f3fSDimitry Andric onCompletion(Decl, [this](CXXRecordDecl *Decl) { 495*5f757f3fSDimitry Andric setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, 496*5f757f3fSDimitry Andric ResourceKind::TypedBuffer, /*IsROV=*/false) 497*5f757f3fSDimitry Andric .addArraySubscriptOperators() 498*5f757f3fSDimitry Andric .completeDefinition(); 499*5f757f3fSDimitry Andric }); 500*5f757f3fSDimitry Andric 501*5f757f3fSDimitry Andric Decl = 502*5f757f3fSDimitry Andric BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer") 503*5f757f3fSDimitry Andric .addSimpleTemplateParams({"element_type"}) 504*5f757f3fSDimitry Andric .Record; 505*5f757f3fSDimitry Andric onCompletion(Decl, [this](CXXRecordDecl *Decl) { 506*5f757f3fSDimitry Andric setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, 507*5f757f3fSDimitry Andric ResourceKind::TypedBuffer, /*IsROV=*/true) 508*5f757f3fSDimitry Andric .addArraySubscriptOperators() 509*5f757f3fSDimitry Andric .completeDefinition(); 510*5f757f3fSDimitry Andric }); 511*5f757f3fSDimitry Andric } 512*5f757f3fSDimitry Andric 513*5f757f3fSDimitry Andric void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record, 514*5f757f3fSDimitry Andric CompletionFunction Fn) { 515*5f757f3fSDimitry Andric Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn)); 516bdd1243dSDimitry Andric } 517bdd1243dSDimitry Andric 518bdd1243dSDimitry Andric void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) { 519bdd1243dSDimitry Andric if (!isa<CXXRecordDecl>(Tag)) 520bdd1243dSDimitry Andric return; 521bdd1243dSDimitry Andric auto Record = cast<CXXRecordDecl>(Tag); 522bdd1243dSDimitry Andric 523bdd1243dSDimitry Andric // If this is a specialization, we need to get the underlying templated 524bdd1243dSDimitry Andric // declaration and complete that. 525bdd1243dSDimitry Andric if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record)) 526bdd1243dSDimitry Andric Record = TDecl->getSpecializedTemplate()->getTemplatedDecl(); 527bdd1243dSDimitry Andric Record = Record->getCanonicalDecl(); 528bdd1243dSDimitry Andric auto It = Completions.find(Record); 529bdd1243dSDimitry Andric if (It == Completions.end()) 530bdd1243dSDimitry Andric return; 531bdd1243dSDimitry Andric It->second(Record); 532bdd1243dSDimitry Andric } 533