From: Douglas Gregor Date: Mon, 12 Oct 2009 22:27:17 +0000 (+0000) Subject: Permit explicit specialization of member functions of class templates X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=37d68185088947322a97eabdc1c0714b0debd929;p=clang Permit explicit specialization of member functions of class templates that are declarations (rather than definitions). Also, be sure to set the access specifiers properly when instantiating the declarations of member function templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83911 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d29b84b308..998abb3403 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2810,7 +2810,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // function templates or member functions of class templates, per // C++ [temp.expl.spec]p2. if (!IsFunctionDefinition && !isFriend && - NewFD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { + !isFunctionTemplateSpecialization && !isExplicitSpecialization) { Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); @@ -2979,9 +2979,17 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, return NewFD->setInvalidDecl(); if (FunctionTemplateDecl *OldTemplateDecl - = dyn_cast(OldDecl)) + = dyn_cast(OldDecl)) { NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); - else { + FunctionTemplateDecl *NewTemplateDecl + = NewFD->getDescribedFunctionTemplate(); + assert(NewTemplateDecl && "Template/non-template mismatch"); + if (CXXMethodDecl *Method + = dyn_cast(NewTemplateDecl->getTemplatedDecl())) { + Method->setAccess(OldTemplateDecl->getAccess()); + NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); + } + } else { if (isa(NewFD)) // Set access for out-of-line definitions NewFD->setAccess(OldDecl->getAccess()); NewFD->setPreviousDeclaration(cast(OldDecl)); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 503d318c4c..916e443294 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -431,7 +431,9 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Link the instantiated function template declaration to the function // template from which it was instantiated. - FunctionTemplateDecl *InstTemplate = InstMethod->getDescribedFunctionTemplate(); + FunctionTemplateDecl *InstTemplate + = InstMethod->getDescribedFunctionTemplate(); + InstTemplate->setAccess(D->getAccess()); assert(InstTemplate && "VisitCXXMethodDecl didn't create a template!"); InstTemplate->setInstantiatedFromMemberTemplate(D); Owner->addDecl(InstTemplate); diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp new file mode 100644 index 0000000000..ce40afd402 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp @@ -0,0 +1,26 @@ +// RUN: clang-cc -fsyntax-only %s +template struct A { + void f(T); + template void g1(T, X1); + template void g2(T, X2); + void h(T) { } +}; + +// specialization +template<> void A::f(int); + +// out of class member template definition +template template void A::g1(T, X1) { } + +// member template specialization +template<> template void A::g1(int, X1); + +// member template specialization +template<> template<> + void A::g1(int, char); // X1 deduced as char + +template<> template<> + void A::g2(int, char); // X2 specified as char + // member specialization even if defined in class definition + +template<> void A::h(int) { }