aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-10-12 22:27:17 +0000
committerDouglas Gregor <dgregor@apple.com>2009-10-12 22:27:17 +0000
commit37d68185088947322a97eabdc1c0714b0debd929 (patch)
treeb826d6a61322d0940063c360274397974d3ce2f1
parent2d15215844eaf6391ad566c44dcf420c18c6b773 (diff)
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
-rw-r--r--lib/Sema/SemaDecl.cpp14
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp4
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp26
3 files changed, 40 insertions, 4 deletions
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<FunctionTemplateDecl>(OldDecl))
+ = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
- else {
+ FunctionTemplateDecl *NewTemplateDecl
+ = NewFD->getDescribedFunctionTemplate();
+ assert(NewTemplateDecl && "Template/non-template mismatch");
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
+ Method->setAccess(OldTemplateDecl->getAccess());
+ NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
+ }
+ } else {
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
NewFD->setAccess(OldDecl->getAccess());
NewFD->setPreviousDeclaration(cast<FunctionDecl>(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<class T> struct A {
+ void f(T);
+ template<class X1> void g1(T, X1);
+ template<class X2> void g2(T, X2);
+ void h(T) { }
+};
+
+// specialization
+template<> void A<int>::f(int);
+
+// out of class member template definition
+template<class T> template<class X1> void A<T>::g1(T, X1) { }
+
+// member template specialization
+template<> template<class X1> void A<int>::g1(int, X1);
+
+// member template specialization
+template<> template<>
+ void A<int>::g1(int, char); // X1 deduced as char
+
+template<> template<>
+ void A<int>::g2<char>(int, char); // X2 specified as char
+ // member specialization even if defined in class definition
+
+template<> void A<int>::h(int) { }