]> granicus.if.org Git - clang/commitdiff
Permit explicit specialization of member functions of class templates
authorDouglas Gregor <dgregor@apple.com>
Mon, 12 Oct 2009 22:27:17 +0000 (22:27 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 12 Oct 2009 22:27:17 +0000 (22:27 +0000)
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

lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp [new file with mode: 0644]

index d29b84b308281bf2ec5e9b6849b887a68b3b34f8..998abb34037fe08dde9398007e2ea0bf3ca0ccca 100644 (file)
@@ -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));
index 503d318c4c5ec74f8e6e2aa9c645592a771d38fc..916e44329471b96981fe5cbde19eaa884006dd7a 100644 (file)
@@ -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 (file)
index 0000000..ce40afd
--- /dev/null
@@ -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) { }