diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 6b7cc86fefa8f..2d3e1088557ab 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -67,45 +67,50 @@ struct TemplateParameterListBuilder { BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr); }; -// Builder for methods of builtin types. Allows adding methods to builtin types -// using the builder pattern like this: +// Builder for methods or constructors of builtin types. Allows creating methods +// or constructors of builtin types using the builder pattern like this: // // BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType) // .addParam("param_name", Type, InOutModifier) // .callBuiltin("builtin_name", BuiltinParams...) -// .finalizeMethod(); +// .finalize(); // -// The builder needs to have all of the method parameters before it can create -// a CXXMethodDecl. It collects them in addParam calls and when a first -// method that builds the body is called or when access to 'this` is needed it -// creates the CXXMethodDecl and ParmVarDecls instances. These can then be -// referenced from the body building methods. Destructor or an explicit call to -// finalizeMethod() will complete the method definition. +// The builder needs to have all of the parameters before it can create +// a CXXMethodDecl or CXXConstructorDecl. It collects them in addParam calls and +// when a first method that builds the body is called or when access to 'this` +// is needed it creates the CXXMethodDecl/CXXConstructorDecl and ParmVarDecls +// instances. These can then be referenced from the body building methods. +// Destructor or an explicit call to finalize() will complete the method +// definition. // // The callBuiltin helper method accepts constants via `Expr *` or placeholder // value arguments to indicate which function arguments to forward to the // builtin. // // If the method that is being built has a non-void return type the -// finalizeMethod will create a return statent with the value of the last -// statement (unless the last statement is already a ReturnStmt). +// finalize() will create a return statement with the value of the last +// statement (unless the last statement is already a ReturnStmt or the return +// value is void). struct BuiltinTypeMethodBuilder { private: - struct MethodParam { + struct Param { const IdentifierInfo &NameII; QualType Ty; HLSLParamModifierAttr::Spelling Modifier; - MethodParam(const IdentifierInfo &NameII, QualType Ty, - HLSLParamModifierAttr::Spelling Modifier) + Param(const IdentifierInfo &NameII, QualType Ty, + HLSLParamModifierAttr::Spelling Modifier) : NameII(NameII), Ty(Ty), Modifier(Modifier) {} }; BuiltinTypeDeclBuilder &DeclBuilder; - DeclarationNameInfo NameInfo; + DeclarationName Name; QualType ReturnTy; + // method or constructor declaration + // (CXXConstructorDecl derives from CXXMethodDecl) CXXMethodDecl *Method; bool IsConst; - llvm::SmallVector Params; + bool IsCtor; + llvm::SmallVector Params; llvm::SmallVector StmtsList; // Argument placeholders, inspired by std::placeholder. These are the indices @@ -124,15 +129,17 @@ struct BuiltinTypeMethodBuilder { friend BuiltinTypeDeclBuilder; BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name, - QualType ReturnTy, bool IsConst = false) - : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())), - ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {} - - BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name, - QualType ReturnTy, bool IsConst = false); + QualType ReturnTy, bool IsConst = false, + bool IsCtor = false) + : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr), + IsConst(IsConst), IsCtor(IsCtor) {} + + BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr, + QualType ReturnTy, bool IsConst = false, + bool IsCtor = false); BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete; - ~BuiltinTypeMethodBuilder() { finalizeMethod(); } + ~BuiltinTypeMethodBuilder() { finalize(); } BuiltinTypeMethodBuilder & operator=(const BuiltinTypeMethodBuilder &Other) = delete; @@ -146,11 +153,18 @@ struct BuiltinTypeMethodBuilder { template BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template BuiltinTypeMethodBuilder &dereference(T Ptr); - BuiltinTypeDeclBuilder &finalizeMethod(); + BuiltinTypeDeclBuilder &finalize(); Expr *getResourceHandleExpr(); private: - void createMethodDecl(); + void createDecl(); + + // Makes sure the declaration is created; should be called before any + // statement added to the body or when access to 'this' is needed. + void ensureCompleteDecl() { + if (!Method) + createDecl(); + } }; TemplateParameterListBuilder::~TemplateParameterListBuilder() { @@ -325,13 +339,24 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) { } BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, - StringRef Name, + StringRef NameStr, QualType ReturnTy, - bool IsConst) - : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) { - const IdentifierInfo &II = - DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier); - NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation()); + bool IsConst, bool IsCtor) + : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst), + IsCtor(IsCtor) { + + assert((!NameStr.empty() || IsCtor) && "method needs a name"); + assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const"); + + ASTContext &AST = DB.SemaRef.getASTContext(); + if (IsCtor) { + Name = AST.DeclarationNames.getCXXConstructorName( + DB.Record->getTypeForDecl()->getCanonicalTypeUnqualified()); + } else { + const IdentifierInfo &II = + AST.Idents.get(NameStr, tok::TokenKind::identifier); + Name = DeclarationName(&II); + } } BuiltinTypeMethodBuilder & @@ -344,33 +369,41 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty, return *this; } -void BuiltinTypeMethodBuilder::createMethodDecl() { - assert(Method == nullptr && "Method already created"); +void BuiltinTypeMethodBuilder::createDecl() { + assert(Method == nullptr && "Method or constructor is already created"); - // create method type + // create method or constructor type ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); SmallVector ParamTypes; - for (MethodParam &MP : Params) + for (Param &MP : Params) ParamTypes.emplace_back(MP.Ty); FunctionProtoType::ExtProtoInfo ExtInfo; if (IsConst) ExtInfo.TypeQuals.addConst(); - QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo); - - // create method decl - auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation()); - Method = CXXMethodDecl::Create( - AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo, - SC_None, false, false, ConstexprSpecKind::Unspecified, SourceLocation()); + QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo); + + // create method or constructor decl + auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation()); + DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation()); + if (IsCtor) + Method = CXXConstructorDecl::Create( + AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, + ExplicitSpecifier(), false, true, false, + ConstexprSpecKind::Unspecified); + else + Method = + CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(), + NameInfo, FuncTy, TSInfo, SC_None, false, false, + ConstexprSpecKind::Unspecified, SourceLocation()); // create params & set them to the function prototype SmallVector ParmDecls; auto FnProtoLoc = Method->getTypeSourceInfo()->getTypeLoc().getAs(); for (int I = 0, E = Params.size(); I != E; I++) { - MethodParam &MP = Params[I]; + Param &MP = Params[I]; ParmVarDecl *Parm = ParmVarDecl::Create( AST, Method->getDeclContext(), SourceLocation(), SourceLocation(), &MP.NameII, MP.Ty, @@ -388,10 +421,7 @@ void BuiltinTypeMethodBuilder::createMethodDecl() { } Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() { - // The first statement added to a method or access to 'this' creates the - // declaration. - if (!Method) - createMethodDecl(); + ensureCompleteDecl(); ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); CXXThisExpr *This = CXXThisExpr::Create( @@ -409,10 +439,7 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, std::array Args{ convertPlaceholder(std::forward(ArgSpecs))...}; - // The first statement added to a method or access to 'this` creates the - // declaration. - if (!Method) - createMethodDecl(); + ensureCompleteDecl(); ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName); @@ -453,11 +480,11 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) { return *this; } -BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalizeMethod() { +BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() { assert(!DeclBuilder.Record->isCompleteDefinition() && "record is already complete"); - assert(Method != nullptr && - "method decl not created; are you missing a call to build the body?"); + + ensureCompleteDecl(); if (!Method->hasBody()) { ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); @@ -599,27 +626,18 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember( return *this; } +// Adds default constructor to the resource class: +// Resource::Resource() BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() { if (Record->isCompleteDefinition()) return *this; - ASTContext &AST = Record->getASTContext(); - QualType ConstructorType = - AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo()); - - CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); - DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy); - CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( - AST, Record, SourceLocation(), - DeclarationNameInfo(Name, SourceLocation()), ConstructorType, - AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()), - ExplicitSpecifier(), false, true, false, ConstexprSpecKind::Unspecified); - - Constructor->setBody(CompoundStmt::Create( - AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation())); - Constructor->setAccess(AccessSpecifier::AS_public); - Record->addDecl(Constructor); - return *this; + // FIXME: initialize handle to poison value; this can be added after + // resource constructor from binding is implemented, otherwise the handle + // value will get overwritten. + return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy, + false, true) + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() { @@ -713,7 +731,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() { SemaRef.getASTContext().UnsignedIntTy) .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(), PH::Handle, getConstantIntExpr(1)) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() { @@ -722,7 +740,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() { SemaRef.getASTContext().UnsignedIntTy) .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(), PH::Handle, getConstantIntExpr(-1)) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder & @@ -746,7 +764,7 @@ BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name, .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle, PH::_0) .dereference(PH::LastStmt) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() { @@ -761,7 +779,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() { AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt) .dereference(PH::LastStmt) .assign(PH::LastStmt, PH::_0) - .finalizeMethod(); + .finalize(); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { @@ -774,7 +792,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { .callBuiltin("__builtin_hlsl_resource_getpointer", AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt) .dereference(PH::LastStmt) - .finalizeMethod(); + .finalize(); } } // namespace hlsl