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/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 66aa363..e9bcc04 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1669,9 +1669,10 @@
                                           const TemplateArgument *Args,
                                           unsigned NumArgs,
                                           QualType Canon) {
-  if (Canon.isNull()) {
-    // Build the canonical template specialization type, since no type
-    // was provided.
+  if (!Canon.isNull())
+    Canon = getCanonicalType(Canon);
+  else {
+    // Build the canonical template specialization type.
     TemplateName CanonTemplate = getCanonicalTemplateName(Template);
     llvm::SmallVector<TemplateArgument, 4> CanonArgs;
     CanonArgs.reserve(NumArgs);
@@ -1695,16 +1696,16 @@
                            8);
       Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, 
                                                   CanonArgs.data(), NumArgs,
-                                                  QualType());
+                                                  Canon);
       Types.push_back(Spec);
       TemplateSpecializationTypes.InsertNode(Spec, InsertPos);      
     }
     
-    Canon = QualType(Spec, 0);
+    if (Canon.isNull())
+      Canon = QualType(Spec, 0);
     assert(Canon->isDependentType() && 
            "Non-dependent template-id type must have a canonical type");
-  } else
-    Canon = getCanonicalType(Canon);
+  }
 
   // Allocate the (non-canonical) template specialization type, but don't
   // try to unique it: these types typically have location information that
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 4677d17..6b3ea43 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -161,6 +161,21 @@
   C.Deallocate((void*)this);
 }
 
+ClassTemplatePartialSpecializationDecl *
+ClassTemplateDecl::findPartialSpecialization(QualType T) {
+  ASTContext &Context = getASTContext();
+  typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+    partial_spec_iterator;
+  for (partial_spec_iterator P = getPartialSpecializations().begin(),
+                          PEnd = getPartialSpecializations().end();
+       P != PEnd; ++P) {
+    if (Context.hasSameType(Context.getTypeDeclType(&*P), T))
+      return &*P;
+  }
+  
+  return 0;
+}
+
 QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
   if (!CommonPtr->InjectedClassNameType.isNull())
     return CommonPtr->InjectedClassNameType;
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();