From 4adbc6d947b09a46e4eb4733a39af8cc2fced451 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 26 Jun 2009 00:10:03 +0000 Subject: [PATCH] Implicit instantiation for function template specializations. For a FunctionDecl that has been instantiated due to template argument deduction, we now store the primary template from which it was instantiated and the deduced template arguments. From this information, we can instantiate the body of the function template. llvm-svn: 74232 --- clang/include/clang/AST/Decl.h | 73 ++++++++++++++++--- clang/include/clang/AST/DeclTemplate.h | 2 +- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/AST/Decl.cpp | 18 +++++ clang/lib/Sema/SemaExpr.cpp | 11 ++- clang/lib/Sema/SemaTemplateDeduction.cpp | 4 + clang/lib/Sema/SemaTemplateInstantiate.cpp | 15 +++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 9 ++- .../SemaTemplate/implicit-instantiation-1.cpp | 11 ++- 9 files changed, 124 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index f594db27bc8f..ed2c790af688 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -25,7 +25,8 @@ class FunctionTemplateDecl; class Stmt; class CompoundStmt; class StringLiteral; - +class TemplateArgumentList; + /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { TranslationUnitDecl() @@ -614,10 +615,17 @@ public: None, Extern, Static, PrivateExtern }; private: + /// \brief Provides information about a function template specialization, + /// which is a FunctionDecl that has been explicitly specialization or + /// instantiated from a function template. + struct TemplateSpecializationInfo { + FunctionTemplateDecl *Template; + const TemplateArgumentList *TemplateArguments; + }; + /// ParamInfo - new[]'d array of pointers to VarDecls for the formal /// parameters of this function. This is null if a prototype or if there are - /// no formals. TODO: we could allocate this space immediately after the - /// FunctionDecl object to save an allocation like FunctionType does. + /// no formals. ParmVarDecl **ParamInfo; LazyDeclStmtPtr Body; @@ -664,8 +672,12 @@ private: /// 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; + /// For function template specializations, this will be a + /// FunctionTemplateSpecializationInfo, which contains information about + /// the template being specialized and the template arguments involved in + /// that specialization. + llvm::PointerUnion3 TemplateOrSpecialization; protected: FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, @@ -678,7 +690,7 @@ protected: SClass(S), IsInline(isInline), C99InlineDefinition(false), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL), - EndRangeLoc(L), TemplateOrInstantiation() {} + EndRangeLoc(L), TemplateOrSpecialization() {} virtual ~FunctionDecl() {} virtual void Destroy(ASTContext& C); @@ -887,13 +899,13 @@ public: /// X::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberFunction(). FunctionDecl *getInstantiatedFromMemberFunction() const { - return TemplateOrInstantiation.dyn_cast(); + return TemplateOrSpecialization.dyn_cast(); } /// \brief Specify that this record is an instantiation of the /// member function RD. void setInstantiationOfMemberFunction(FunctionDecl *RD) { - TemplateOrInstantiation = RD; + TemplateOrSpecialization = RD; } /// \brief Retrieves the function template that is described by this @@ -909,13 +921,54 @@ public: /// getDescribedFunctionTemplate() retrieves the /// FunctionTemplateDecl from a FunctionDecl. FunctionTemplateDecl *getDescribedFunctionTemplate() const { - return TemplateOrInstantiation.dyn_cast(); + return TemplateOrSpecialization.dyn_cast(); } void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { - TemplateOrInstantiation = Template; + TemplateOrSpecialization = Template; } + /// \brief Retrieve the primary template that this function template + /// specialization either specializes or was instantiated from. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + FunctionTemplateDecl *getPrimaryTemplate() const { + if (TemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast()) { + return Info->Template; + } + return 0; + } + + /// \brief Retrieve the template arguments used to produce this function + /// template specialization from the primary template. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + const TemplateArgumentList *getTemplateSpecializationArgs() const { + if (TemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast()) { + return Info->TemplateArguments; + } + return 0; + } + + + /// \brief Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param Context the AST context in which this function resides. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + void setFunctionTemplateSpecialization(ASTContext &Context, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index c64c974183c4..57d645b740c8 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -153,7 +153,7 @@ protected: NamedDecl *TemplatedDecl; TemplateParameterList* TemplateParams; }; - + /// Declaration of a template function. class FunctionTemplateDecl : public TemplateDecl { protected: diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 927f6b95f3cb..5343cebea76e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -821,6 +821,9 @@ def note_template_member_class_here : Note< "in instantiation of member class %0 requested here">; def note_template_member_function_here : Note< "in instantiation of member function %q0 requested here">; +def note_function_template_spec_here : Note< + "in instantiation of function template specialization %q0 requested here">; + def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; def note_partial_spec_deduct_instantiation_here : Note< diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index e48ba156c9ed..4fbf2f6f48eb 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -359,6 +359,10 @@ void FunctionDecl::Destroy(ASTContext& C) { C.Deallocate(ParamInfo); + if (TemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast()) + C.Deallocate(Info); + Decl::Destroy(C); } @@ -555,6 +559,20 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { return OO_None; } +void +FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs) { + TemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast(); + if (!Info) + Info = new (Context) TemplateSpecializationInfo; + + Info->Template = Template; + Info->TemplateArguments = TemplateArgs; + TemplateOrSpecialization = Info; +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 44b6802c1000..a01fbb1e66bf 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5566,12 +5566,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } } if (FunctionDecl *Function = dyn_cast(D)) { - // Implicit instantiation of function templates + // Implicit instantiation of function templates and member functions of + // class templates. if (!Function->getBody(Context)) { - if (Function->getInstantiatedFromMemberFunction()) + // FIXME: distinguish between implicit instantiations of function + // templates and explicit specializations (the latter don't get + // instantiated, naturally). + if (Function->getInstantiatedFromMemberFunction() || + Function->getPrimaryTemplate()) PendingImplicitInstantiations.push(std::make_pair(Function, Loc)); - - // FIXME: check for function template specializations. } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1d7e03eda3a6..03466f02a24b 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -870,6 +870,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (!Specialization || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; + // Turn the specialization into an actual function template specialization. + Specialization->setFunctionTemplateSpecialization(Context, + FunctionTemplate, + Info.take()); return TDK_Success; } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 0f677488c773..5e4fde7af99c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -29,10 +29,18 @@ using namespace clang; /// instantiate the given declaration. const TemplateArgumentList & Sema::getTemplateInstantiationArgs(NamedDecl *D) { + // Template arguments for a class template specialization. if (ClassTemplateSpecializationDecl *Spec = dyn_cast(D)) return Spec->getTemplateArgs(); + // Template arguments for a function template specialization. + if (FunctionDecl *Function = dyn_cast(D)) + if (const TemplateArgumentList *TemplateArgs + = Function->getTemplateSpecializationArgs()) + return *TemplateArgs; + + // Template arguments for a member of a class template specialization. DeclContext *EnclosingTemplateCtx = D->getDeclContext(); while (!isa(EnclosingTemplateCtx)) { assert(!EnclosingTemplateCtx->isFileContext() && @@ -158,8 +166,11 @@ void Sema::PrintInstantiationStack() { << Active->InstantiationRange; } else { FunctionDecl *Function = cast(D); - unsigned DiagID = diag::note_template_member_function_here; - // FIXME: check for a function template + unsigned DiagID; + if (Function->getPrimaryTemplate()) + DiagID = diag::note_function_template_spec_here; + else + DiagID = diag::note_template_member_function_here; Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), DiagID) << Function diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 95655d85c334..a05095fa57a6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -645,16 +645,17 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, /// function. void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function) { - // FIXME: make this work for function template specializations, too. - if (Function->isInvalidDecl()) return; assert(!Function->getBody(Context) && "Already instantiated!"); // Find the function body that we'll be substituting. - const FunctionDecl *PatternDecl - = Function->getInstantiatedFromMemberFunction(); + const FunctionDecl *PatternDecl = 0; + if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) + PatternDecl = Primary->getTemplatedDecl(); + else + PatternDecl = Function->getInstantiatedFromMemberFunction(); Stmt *Pattern = 0; if (PatternDecl) Pattern = PatternDecl->getBody(Context, PatternDecl); diff --git a/clang/test/SemaTemplate/implicit-instantiation-1.cpp b/clang/test/SemaTemplate/implicit-instantiation-1.cpp index eecaf2f6c799..b8f9622001e1 100644 --- a/clang/test/SemaTemplate/implicit-instantiation-1.cpp +++ b/clang/test/SemaTemplate/implicit-instantiation-1.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template struct X { T f(T x, U y) { return x + y; } @@ -14,3 +13,13 @@ void test(X *xii, X *xpi, X *xip) { (void)xip->g(2, 0); // okay: does not instantiate } +template +T add(T t, U u) { + return t + u; // expected-error{{invalid operands}} +} + +void test_add(char *cp, int i, int *ip) { + char* cp2 = add(cp, i); + add(cp, cp); // expected-note{{instantiation of}} + (void)sizeof(add(ip, ip)); +} \ No newline at end of file