Support out-of-line definitions of the members of class template
partial specializations.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77606 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index a5a2030..1580e72 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -55,14 +55,23 @@
         if (ClassTemplateDecl *ClassTemplate 
               = dyn_cast_or_null<ClassTemplateDecl>(
                             SpecType->getTemplateName().getAsTemplateDecl())) {
+          QualType ContextType
+            = Context.getCanonicalType(QualType(SpecType, 0));
+
           // If the type of the nested name specifier is the same as the
           // injected class name of the named class template, we're entering
           // into that class template definition.
           QualType Injected = ClassTemplate->getInjectedClassNameType(Context);
-          if (Context.hasSameType(Injected, QualType(SpecType, 0)))
+          if (Context.hasSameType(Injected, ContextType))
             return ClassTemplate->getTemplatedDecl();
                 
-          // FIXME: Class template partial specializations
+          // If the type of the nested name specifier is the same as the
+          // type of one of the class template's class template partial
+          // specializations, we're entering into the definition of that
+          // class template partial specialization.
+          if (ClassTemplatePartialSpecializationDecl *PartialSpec
+                = ClassTemplate->findPartialSpecialization(ContextType))
+            return PartialSpec;
         }
       }
       
@@ -195,6 +204,7 @@
       if (T == Context.getCanonicalType(InjectedClassName))
         return Template->getTemplatedDecl();
     }
+    // FIXME: check for class template partial specializations
   }
 
   return 0;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 425b502..4264f32 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -815,6 +815,8 @@
           = cast<ClassTemplateSpecializationDecl>(Record->getDecl());
         // If the nested name specifier refers to an explicit specialization,
         // we don't need a template<> header.
+        // FIXME: revisit this approach once we cope with specialization 
+        // properly.
         if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization)
           continue;
       }
@@ -836,7 +838,8 @@
   unsigned Idx = 0;
   for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
        Idx != NumTemplateIds; ++Idx) {
-    bool DependentTemplateId = TemplateIdsInSpecifier[Idx]->isDependentType();
+    QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0);
+    bool DependentTemplateId = TemplateId->isDependentType();
     if (Idx >= NumParamLists) {
       // We have a template-id without a corresponding template parameter
       // list.
@@ -844,7 +847,7 @@
         // FIXME: the location information here isn't great. 
         Diag(SS.getRange().getBegin(), 
              diag::err_template_spec_needs_template_parameters)
-          << QualType(TemplateIdsInSpecifier[Idx], 0)
+          << TemplateId
           << SS.getRange();
       } else {
         Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
@@ -856,11 +859,32 @@
     }
     
     // Check the template parameter list against its corresponding template-id.
-    TemplateDecl *Template 
-      = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
-    TemplateParameterListsAreEqual(ParamLists[Idx], 
-                                   Template->getTemplateParameters(),
-                                   true);
+    if (DependentTemplateId) {
+      TemplateDecl *Template 
+        = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
+
+      if (ClassTemplateDecl *ClassTemplate 
+            = dyn_cast<ClassTemplateDecl>(Template)) {
+        TemplateParameterList *ExpectedTemplateParams = 0;
+        // Is this template-id naming the primary template?
+        if (Context.hasSameType(TemplateId,
+                             ClassTemplate->getInjectedClassNameType(Context)))
+          ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
+        // ... or a partial specialization?
+        else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+                   = ClassTemplate->findPartialSpecialization(TemplateId))
+          ExpectedTemplateParams = PartialSpec->getTemplateParameters();
+
+        if (ExpectedTemplateParams)
+          TemplateParameterListsAreEqual(ParamLists[Idx], 
+                                         ExpectedTemplateParams,
+                                         true);
+      } 
+    } else if (ParamLists[Idx]->size() > 0)
+      Diag(ParamLists[Idx]->getTemplateLoc(), 
+           diag::err_template_param_list_matches_nontemplate)
+        << TemplateId
+        << ParamLists[Idx]->getSourceRange();
   }
   
   // If there were at least as many template-ids as there were template
@@ -2493,6 +2517,8 @@
                                             /*ExplicitInstantiation=*/false))
     return true;
 
+  // The canonical type
+  QualType CanonType;
   if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
     // Since the only prior class template specialization with these
     // arguments was referenced but not declared, reuse that
@@ -2501,7 +2527,15 @@
     Specialization = PrevDecl;
     Specialization->setLocation(TemplateNameLoc);
     PrevDecl = 0;
+    CanonType = Context.getTypeDeclType(Specialization);
   } else if (isPartialSpecialization) {
+    // Build the canonical type that describes the converted template
+    // arguments of the class template partial specialization.
+    CanonType = Context.getTemplateSpecializationType(
+                                                  TemplateName(ClassTemplate),
+                                                  Converted.getFlatArguments(),
+                                                  Converted.flatSize());
+
     // Create a new class template partial specialization declaration node.
     TemplateParameterList *TemplateParams 
       = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
@@ -2554,7 +2588,6 @@
         }
       }
     }
-
   } else {
     // Create a new class template specialization declaration node for
     // this explicit specialization.
@@ -2573,6 +2606,8 @@
       ClassTemplate->getSpecializations().InsertNode(Specialization, 
                                                      InsertPos);
     }
+
+    CanonType = Context.getTypeDeclType(Specialization);
   }
 
   // Note that this is an explicit specialization.
@@ -2603,7 +2638,7 @@
     = Context.getTemplateSpecializationType(Name, 
                                             TemplateArgs.data(),
                                             TemplateArgs.size(),
-                                  Context.getTypeDeclType(Specialization));
+                                            CanonType);
   Specialization->setTypeAsWritten(WrittenTy);
   TemplateArgsIn.release();