Class template partial specializations can be declared anywhere that
its definition may be defined, including in a class.

Also, put in an assertion when trying to instantiate a class template
partial specialization of a member template, which is not yet
implemented.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83469 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 1addd16..9d7dd0a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2434,11 +2434,19 @@
     return true;
   }
   
+  // FIXME: For everything except class template partial specializations,
+  // complain if the explicit specialization/instantiation occurs at class 
+  // scope.
+
+  // C++ [temp.class.spec]p6:
+  //   A class template partial specialization may be declared or redeclared
+  //   in any namespace scope in which its definition may be defined (14.5.1 
+  //   and 14.5.2).  
   bool ComplainedAboutScope = false;
-  DeclContext *SpecializedContext
+  DeclContext *SpecializedContext 
     = Specialized->getDeclContext()->getEnclosingNamespaceContext();
+  DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
   if (TSK == TSK_ExplicitSpecialization) {
-    DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
     if ((!PrevDecl || 
          getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
          getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
@@ -2468,8 +2476,8 @@
   // specializations of function templates, static data members, and member
   // functions, so we skip the check here for those kinds of entities.
   // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
-  // Should we refactor the check, so that it occurs later?
-  if (!ComplainedAboutScope && !S.CurContext->Encloses(SpecializedContext) &&
+  // Should we refactor that check, so that it occurs later?
+  if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) &&
       ((TSK == TSK_ExplicitSpecialization &&
         !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
           isa<FunctionDecl>(Specialized))) || 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 53252ec..fa30365 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -57,6 +57,8 @@
     ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
     Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
     Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+    Decl *VisitClassTemplatePartialSpecializationDecl(
+                                    ClassTemplatePartialSpecializationDecl *D);
     Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
     Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
     Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
@@ -401,6 +403,13 @@
 }
 
 Decl *
+TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
+                                   ClassTemplatePartialSpecializationDecl *D) {
+  assert(false &&"Partial specializations of member templates are unsupported");
+  return 0;
+}
+
+Decl *
 TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
   // FIXME: Dig out the out-of-line definition of this function template?
 
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
new file mode 100644
index 0000000..afe6ab2
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+  template<typename U> struct Inner0 {
+    static const unsigned value = 0;
+  };
+  
+  template<typename U> struct Inner0<U*> { 
+    static const unsigned value = 1;
+  };
+};
+
+template<typename T> template<typename U>
+struct X0<T>::Inner0<const U*> {
+  static const unsigned value = 2;
+};
+
+// FIXME: Test instantiation of these partial specializations (once they are
+// implemented).