From: Douglas Gregor Date: Thu, 14 May 2009 21:06:31 +0000 (+0000) Subject: Link FunctionDecls instantiated from the member functions of a class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1eee0e753fb390b04848846e837714ec774b7bfd;p=clang Link FunctionDecls instantiated from the member functions of a class template to the FunctionDecls from which they were instantiated. This is a necessary first step to support instantiation of the definitions of such functions, but by itself does essentially nothing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71792 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 79d04b338e..b2f18a73c5 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -20,6 +20,7 @@ namespace clang { class Expr; +class FunctionTemplateDecl; class Stmt; class CompoundStmt; class StringLiteral; @@ -524,6 +525,18 @@ private: // Move to DeclGroup when it is implemented. SourceLocation TypeSpecStartLoc; + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For function + /// declarations that describe a function template, this will be a + /// pointer to a FunctionTemplateDecl. For member functions + /// of class template specializations, this will be the + /// FunctionDecl from which the member function was instantiated. + llvm::PointerUnion + TemplateOrInstantiation; + protected: FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, @@ -534,7 +547,8 @@ protected: ParamInfo(0), Body(), PreviousDeclaration(0), SClass(S), IsInline(isInline), C99InlineDefinition(false), IsVirtual(false), IsPure(false), InheritedPrototype(false), - HasPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL) {} + HasPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL), + TemplateOrInstantiation() {} virtual ~FunctionDecl() {} virtual void Destroy(ASTContext& C); @@ -711,6 +725,57 @@ public: OverloadedOperatorKind getOverloadedOperator() const; + /// \brief If this function is an instantiation of a member function + /// of a class template specialization, retrieves the function from + /// which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// functions of class templates and for instantiations of function + /// templates. For example, given: + /// + /// \code + /// template + /// struct X { + /// void f(T); + /// }; + /// \endcode + /// + /// The declaration for X::f is a (non-templated) FunctionDecl + /// whose parent is the class template specialization X. For + /// this declaration, getInstantiatedFromFunction() will return + /// the FunctionDecl X::A. When a complete definition of + /// X::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberFunction(). + FunctionDecl *getInstantiatedFromMemberFunction() const { + return TemplateOrInstantiation.dyn_cast(); + } + + /// \brief Specify that this record is an instantiation of the + /// member function RD. + void setInstantiationOfMemberFunction(FunctionDecl *RD) { + TemplateOrInstantiation = RD; + } + + /// \brief Retrieves the function template that is described by this + /// function declaration. + /// + /// Every function template is represented as a FunctionTemplateDecl + /// and a FunctionDecl (or something derived from FunctionDecl). The + /// former contains template properties (such as the template + /// parameter lists) while the latter contains the actual + /// description of the template's + /// contents. FunctionTemplateDecl::getTemplatedDecl() retrieves the + /// FunctionDecl that describes the function template, + /// getDescribedFunctionTemplate() retrieves the + /// FunctionTemplateDecl from a FunctionDecl. + FunctionTemplateDecl *getDescribedFunctionTemplate() const { + return TemplateOrInstantiation.dyn_cast(); + } + + void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { + TemplateOrInstantiation = Template; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index f8e92bd407..d7f268fc6a 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -236,15 +236,16 @@ class CXXRecordDecl : public RecordDecl { /// CXXConversionDecl. OverloadedFunctionDecl Conversions; - /// \brief The template or declaration that is declaration is - /// instantiated from. + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. /// /// For non-templates, this value will be NULL. For record /// declarations that describe a class template, this will be a /// pointer to a ClassTemplateDecl. For member /// classes of class template specializations, this will be the /// RecordDecl from which the member class was instantiated. - llvm::PointerUnionTemplateOrInstantiation; + llvm::PointerUnion + TemplateOrInstantiation; protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 3db00ec1b7..9dd1565890 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -155,6 +155,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setHasPrototype(Record[Idx++]); FD->setDeleted(Record[Idx++]); FD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: C++ TemplateOrInstantiation unsigned NumParams = Record[Idx++]; llvm::SmallVector Params; Params.reserve(NumParams); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 799c77b03f..96045f94c5 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -155,6 +155,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->hasPrototype() && !D->inheritedPrototype()); Record.push_back(D->isDeleted()); Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record); + // FIXME: C++ TemplateOrInstantiation Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 92d253d3ba..6ae6b2240b 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -80,8 +80,8 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; QualType T = D->getUnderlyingType(); if (T->isDependentType()) { - T = SemaRef.InstantiateType(T, TemplateArgs, D->getLocation(), - D->getDeclName()); + T = SemaRef.InstantiateType(T, TemplateArgs, + D->getLocation(), D->getDeclName()); if (T.isNull()) { Invalid = true; T = SemaRef.Context.IntTy; @@ -139,8 +139,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; QualType T = D->getType(); if (T->isDependentType()) { - T = SemaRef.InstantiateType(T, TemplateArgs, D->getLocation(), - D->getDeclName()); + T = SemaRef.InstantiateType(T, TemplateArgs, + D->getLocation(), D->getDeclName()); if (!T.isNull() && T->isFunctionType()) { // C++ [temp.arg.type]p3: // If a declaration acquires a function type through a type @@ -290,6 +290,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), D->getDeclName(), T, D->isStatic(), D->isInline()); + Method->setInstantiationOfMemberFunction(D); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -333,6 +334,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), Name, T, D->isExplicit(), D->isInline(), false); + Constructor->setInstantiationOfMemberFunction(D); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -375,6 +377,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { D->getLocation(), SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy), T, D->isInline(), false); + Destructor->setInstantiationOfMemberFunction(D); if (InitMethodInstantiation(Destructor, D)) Destructor->setInvalidDecl(); @@ -404,6 +407,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { D->getLocation(), SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy), T, D->isInline(), D->isExplicit()); + Conversion->setInstantiationOfMemberFunction(D); if (InitMethodInstantiation(Conversion, D)) Conversion->setInvalidDecl(); @@ -513,7 +517,7 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType(); assert(Proto && "Missing prototype?"); QualType ResultType - = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs, + = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs, D->getLocation(), D->getDeclName()); if (ResultType.isNull()) return QualType(); @@ -557,7 +561,19 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, /// \param Function the already-instantiated declaration of a /// function. void Sema::InstantiateFunctionDefinition(FunctionDecl *Function) { - // FIXME: Implement this! + // FIXME: make this work for function template specializations, too. + + // Find the function body that we'll be substituting. + const FunctionDecl *PatternDecl + = Function->getInstantiatedFromMemberFunction(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(Context, PatternDecl); + + if (!Pattern) + return; + + // FIXME: instantiate the pattern } /// \brief Instantiate the definition of the given variable from its diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp index aa898dd056..ea1e0af21a 100644 --- a/test/SemaTemplate/instantiate-expr-2.cpp +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -120,3 +120,16 @@ namespace N7 { typedef Cond::Type Type; } +#if 0 +// FIXME: Unable to handle general declaration references at this point. +template struct IntegralConstant { }; + +template +struct X0 { + void f(T x, IntegralConstant); +}; + +void test_X0(X0 x, IntegralConstant ic) { + x.f(ic); +} +#endif