diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index e77c5e41fbf4..f2ffccd7e095 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -27,6 +27,7 @@ class Stmt; class CompoundStmt; class StringLiteral; class TemplateArgumentList; +class MemberSpecializationInfo; class FunctionTemplateSpecializationInfo; class TypeLoc; @@ -830,14 +831,15 @@ private: /// 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. + /// of class template specializations, this will be a MemberSpecializationInfo + /// pointer containing information about the specialization. /// 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 + llvm::PointerUnion3 TemplateOrSpecialization; protected: @@ -1063,15 +1065,12 @@ public: /// 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 TemplateOrSpecialization.dyn_cast(); - } + FunctionDecl *getInstantiatedFromMemberFunction() const; /// \brief Specify that this record is an instantiation of the - /// member function RD. - void setInstantiationOfMemberFunction(FunctionDecl *RD) { - TemplateOrSpecialization = RD; - } + /// member function FD. + void setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK); /// \brief Retrieves the function template that is described by this /// function declaration. diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 5d3e8eab4357..3f6f782c29ec 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -548,6 +548,33 @@ public: } }; +/// \brief Provides information a specialization of a member of a class +/// template, which may be a member function, static data member, or +/// member class. +class MemberSpecializationInfo { + NamedDecl *InstantiatedFrom; + TemplateSpecializationKind TSK; + +public: + explicit + MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK) + : InstantiatedFrom(IF), TSK(TSK) { } + + /// \brief Retrieve the member declaration from which this member was + /// instantiated. + NamedDecl *getInstantiatedFrom() const { return InstantiatedFrom; } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return TSK; + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + this->TSK = TSK; + } +}; + /// Declaration of a template function. class FunctionTemplateDecl : public TemplateDecl { protected: diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index fe32c396c587..a5c9fa4bac87 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -410,6 +410,16 @@ void FunctionDecl::Destroy(ASTContext& C) { for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) (*I)->Destroy(C); + FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast(); + if (FTSInfo) + C.Deallocate(FTSInfo); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast(); + if (MSInfo) + C.Deallocate(MSInfo); + C.Deallocate(ParamInfo); Decl::Destroy(C); @@ -670,6 +680,24 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { return OO_None; } +FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { + if (MemberSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast()) + return cast(Info->getInstantiatedFrom()); + + return 0; +} + +void +FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); + MemberSpecializationInfo *Info + = new (getASTContext()) MemberSpecializationInfo(FD, TSK); + TemplateOrSpecialization = Info; +} + FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization @@ -727,32 +755,30 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. - FunctionTemplateSpecializationInfo *Info + FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast(); - if (Info) - return Info->getTemplateSpecializationKind(); + if (FTSInfo) + return FTSInfo->getTemplateSpecializationKind(); - if (!getInstantiatedFromMemberFunction()) - return TSK_Undeclared; - - // Find the class template specialization corresponding to this instantiation - // of a member function. - const DeclContext *Parent = getDeclContext(); - while (Parent && !isa(Parent)) - Parent = Parent->getParent(); - - if (!Parent) - return TSK_Undeclared; - - return cast(Parent)->getSpecializationKind(); + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast(); + if (MSInfo) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; } void FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { - FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast(); - assert(Info && "Not a function template specialization"); - Info->setTemplateSpecializationKind(TSK); + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + FTSInfo->setTemplateSpecializationKind(TSK); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast()) + MSInfo->setTemplateSpecializationKind(TSK); + else + assert(false && "Function cannot have a template specialization kind"); } bool FunctionDecl::isOutOfLine() const { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f3cd2e41fbd3..339a084d7afb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3171,10 +3171,13 @@ Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD, Instantiation, FD->getLocation(), false, TSK_ExplicitSpecialization)) return true; + + // FIXME: Check for specialization-after-instantiation errors and such. - // FIXME: Mark the new declaration as a member function specialization. - // We may also want to mark the original instantiation as having been - // explicitly specialized. + // Note that this function is an explicit instantiation of a member function. + Instantiation->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + FD->setInstantiationOfMemberFunction(FunctionInTemplate, + TSK_ExplicitSpecialization); // Save the caller the trouble of having to figure out which declaration // this specialization matches. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 9c96b33cd0e3..e0ffca9d2d12 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -977,6 +977,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, DEnd = Instantiation->decls_end(); D != DEnd; ++D) { if (FunctionDecl *Function = dyn_cast(*D)) { + if (Function->getInstantiatedFromMemberFunction()) + Function->setTemplateSpecializationKind(TSK); if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration) InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast(*D)) { @@ -984,14 +986,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, TSK != TSK_ExplicitInstantiationDeclaration) InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); } else if (CXXRecordDecl *Record = dyn_cast(*D)) { - if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) { - assert(Record->getInstantiatedFromMemberClass() && - "Missing instantiated-from-template information"); + if (Record->isInjectedClassName()) + continue; + + assert(Record->getInstantiatedFromMemberClass() && + "Missing instantiated-from-template information"); + if (!Record->getDefinition(Context)) InstantiateClass(PointOfInstantiation, Record, Record->getInstantiatedFromMemberClass(), TemplateArgs, TSK); - } + else + InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, + TSK); } } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index fa303659412c..fcacb4a3f000 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -522,7 +522,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { if (!Owner->isDependentContext()) DC->makeDeclVisibleInContext(Function, /* Recoverable = */ false); - Function->setInstantiationOfMemberFunction(D); + Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } if (InitFunctionInstantiation(Function, D)) @@ -637,7 +637,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (!FunctionTemplate) - Method->setInstantiationOfMemberFunction(D); + Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical diff --git a/clang/test/SemaTemplate/extern-templates.cpp b/clang/test/SemaTemplate/extern-templates.cpp index 6bdf283391f2..7154c7e32f9c 100644 --- a/clang/test/SemaTemplate/extern-templates.cpp +++ b/clang/test/SemaTemplate/extern-templates.cpp @@ -31,11 +31,11 @@ void test_intptr(X0 xi, X0::Inner xii) { // FIXME: we would like the notes to point to the explicit instantiation at the // bottom. -extern template class X0; // expected-note{{instantiation}} +extern template class X0; // expected-note 2{{instantiation}} void test_longptr(X0 xl, X0::Inner xli) { xl.f(0); - xli.g(0); // expected-note{{instantiation}} + xli.g(0); } template class X0;