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