Implement support for semantic checking and template instantiation of
class template partial specializations of member templates. Also,
fixes a silly little bug in the marking of "used" template parameters
in member templates. Fixes PR5236.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85447 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 710e7d3..66ee818 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2869,6 +2869,7 @@
   
   void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
                                   bool OnlyDeduced,
+                                  unsigned Depth,
                                   llvm::SmallVectorImpl<bool> &Used);
   void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
                                      llvm::SmallVectorImpl<bool> &Deduced);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 638e00c..36a158d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2880,8 +2880,6 @@
                                                   Converted.flatSize());
 
     // Create a new class template partial specialization declaration node.
-    TemplateParameterList *TemplateParams
-      = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
     ClassTemplatePartialSpecializationDecl *PrevPartial
       = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
     ClassTemplatePartialSpecializationDecl *Partial
@@ -2901,6 +2899,11 @@
     }
     Specialization = Partial;
 
+    // If we are providing an explicit specialization of a member class 
+    // template specialization, make a note of that.
+    if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+      PrevPartial->setMemberSpecialization();
+    
     // Check that all of the template parameters of the class template
     // partial specialization are deducible from the template
     // arguments. If not, this class template partial specialization
@@ -2908,6 +2911,7 @@
     llvm::SmallVector<bool, 8> DeducibleParams;
     DeducibleParams.resize(TemplateParams->size());
     MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, 
+                               TemplateParams->getDepth(),
                                DeducibleParams);
     unsigned NumNonDeducible = 0;
     for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index a7ca8e8..14373de 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1690,6 +1690,7 @@
 static void
 MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
                            bool OnlyDeduced,
+                           unsigned Level,
                            llvm::SmallVectorImpl<bool> &Deduced);
   
 /// \brief Determine whether the function template \p FT1 is at least as
@@ -1782,18 +1783,22 @@
   case TPOC_Call: {
     unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
     for (unsigned I = 0; I != NumParams; ++I)
-      ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+      ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, 
+                                   TemplateParams->getDepth(),
                                    UsedParameters);
     break;
   }
     
   case TPOC_Conversion:
-    ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+    ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, 
+                                 TemplateParams->getDepth(),
                                  UsedParameters);
     break;
     
   case TPOC_Other:
-    ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters);
+    ::MarkUsedTemplateParameters(S, FD2->getType(), false, 
+                                 TemplateParams->getDepth(),
+                                 UsedParameters);
     break;
   }
   
@@ -2065,6 +2070,7 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            const TemplateArgument &TemplateArg,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used);
 
 /// \brief Mark the template parameters that are used by the given
@@ -2073,6 +2079,7 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            const Expr *E,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to 
   // find other occurrences of template parameters.
@@ -2085,7 +2092,8 @@
   if (!NTTP)
     return;
 
-  Used[NTTP->getIndex()] = true;
+  if (NTTP->getDepth() == Depth)
+    Used[NTTP->getIndex()] = true;
 }
 
 /// \brief Mark the template parameters that are used by the given
@@ -2094,13 +2102,15 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            NestedNameSpecifier *NNS,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   if (!NNS)
     return;
   
-  MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used);
+  MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth,
+                             Used);
   MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), 
-                             OnlyDeduced, Used);
+                             OnlyDeduced, Depth, Used);
 }
   
 /// \brief Mark the template parameters that are used by the given
@@ -2109,16 +2119,20 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            TemplateName Name,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
     if (TemplateTemplateParmDecl *TTP
-        = dyn_cast<TemplateTemplateParmDecl>(Template))
-      Used[TTP->getIndex()] = true;
+          = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+      if (TTP->getDepth() == Depth)
+        Used[TTP->getIndex()] = true;
+    }
     return;
   }
   
   if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
-    MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used);
+    MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, 
+                               Depth, Used);
 }
 
 /// \brief Mark the template parameters that are used by the given
@@ -2126,6 +2140,7 @@
 static void
 MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   if (T.isNull())
     return;
@@ -2140,6 +2155,7 @@
     MarkUsedTemplateParameters(SemaRef,
                                cast<PointerType>(T)->getPointeeType(),
                                OnlyDeduced,
+                               Depth,
                                Used);
     break;
 
@@ -2147,6 +2163,7 @@
     MarkUsedTemplateParameters(SemaRef,
                                cast<BlockPointerType>(T)->getPointeeType(),
                                OnlyDeduced,
+                               Depth,
                                Used);
     break;
 
@@ -2155,69 +2172,74 @@
     MarkUsedTemplateParameters(SemaRef,
                                cast<ReferenceType>(T)->getPointeeType(),
                                OnlyDeduced,
+                               Depth,
                                Used);
     break;
 
   case Type::MemberPointer: {
     const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
     MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     break;
   }
 
   case Type::DependentSizedArray:
     MarkUsedTemplateParameters(SemaRef,
                                cast<DependentSizedArrayType>(T)->getSizeExpr(),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     // Fall through to check the element type
 
   case Type::ConstantArray:
   case Type::IncompleteArray:
     MarkUsedTemplateParameters(SemaRef,
                                cast<ArrayType>(T)->getElementType(),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     break;
 
   case Type::Vector:
   case Type::ExtVector:
     MarkUsedTemplateParameters(SemaRef,
                                cast<VectorType>(T)->getElementType(),
-                               OnlyDeduced, Used);
+                               OnlyDeduced, Depth, Used);
     break;
 
   case Type::DependentSizedExtVector: {
     const DependentSizedExtVectorType *VecType
       = cast<DependentSizedExtVectorType>(T);
     MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, 
-                               Used);
+                               Depth, Used);
     break;
   }
 
   case Type::FunctionProto: {
     const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
     MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
       MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
-                                 Used);
+                                 Depth, Used);
     break;
   }
 
-  case Type::TemplateTypeParm:
-    Used[cast<TemplateTypeParmType>(T)->getIndex()] = true;
+  case Type::TemplateTypeParm: {
+    const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(T);
+    if (TTP->getDepth() == Depth)
+      Used[TTP->getIndex()] = true;
     break;
+  }
 
   case Type::TemplateSpecialization: {
     const TemplateSpecializationType *Spec
       = cast<TemplateSpecializationType>(T);
     MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
-      MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used);
+      MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+                                 Used);
     break;
   }
 
@@ -2225,14 +2247,14 @@
     if (!OnlyDeduced)
       MarkUsedTemplateParameters(SemaRef, 
                                  cast<ComplexType>(T)->getElementType(),
-                                 OnlyDeduced, Used);
+                                 OnlyDeduced, Depth, Used);
     break;
 
   case Type::Typename:
     if (!OnlyDeduced)
       MarkUsedTemplateParameters(SemaRef,
                                  cast<TypenameType>(T)->getQualifier(),
-                                 OnlyDeduced, Used);
+                                 OnlyDeduced, Depth, Used);
     break;
 
   // None of these types have any template parameters in them.
@@ -2259,6 +2281,7 @@
 MarkUsedTemplateParameters(Sema &SemaRef,
                            const TemplateArgument &TemplateArg,
                            bool OnlyDeduced,
+                           unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
   switch (TemplateArg.getKind()) {
   case TemplateArgument::Null:
@@ -2267,25 +2290,27 @@
 
   case TemplateArgument::Type:
     MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
-                               Used);
+                               Depth, Used);
     break;
 
   case TemplateArgument::Declaration:
     if (TemplateTemplateParmDecl *TTP
-        = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
-      Used[TTP->getIndex()] = true;
+          = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) {
+      if (TTP->getDepth() == Depth)
+        Used[TTP->getIndex()] = true;
+    }
     break;
 
   case TemplateArgument::Expression:
     MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, 
-                               Used);
+                               Depth, Used);
     break;
       
   case TemplateArgument::Pack:
     for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
                                       PEnd = TemplateArg.pack_end();
          P != PEnd; ++P)
-      MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used);
+      MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used);
     break;
   }
 }
@@ -2301,10 +2326,11 @@
 /// deduced.
 void
 Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
-                                 bool OnlyDeduced,
+                                 bool OnlyDeduced, unsigned Depth,
                                  llvm::SmallVectorImpl<bool> &Used) {
   for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
-    ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used);
+    ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, 
+                                 Depth, Used);
 }
 
 /// \brief Marks all of the template parameters that will be deduced by a
@@ -2319,5 +2345,5 @@
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
   for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
     ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
-                                 true, Deduced);
+                                 true, TemplateParams->getDepth(), Deduced);
 }
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 1493013..794ec2a 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -981,61 +981,72 @@
     }
   }
 
-  if (Matched.size() == 1) {
-    //   -- If exactly one matching specialization is found, the
-    //      instantiation is generated from that specialization.
-    Pattern = Matched[0].first;
-    ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second);
-  } else if (Matched.size() > 1) {
-    //   -- If more than one matching specialization is found, the
-    //      partial order rules (14.5.4.2) are used to determine
-    //      whether one of the specializations is more specialized
-    //      than the others. If none of the specializations is more
-    //      specialized than all of the other matching
-    //      specializations, then the use of the class template is
-    //      ambiguous and the program is ill-formed.
+  if (Matched.size() >= 1) {
     llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
-    for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
-                                                  PEnd = Matched.end();
-         P != PEnd; ++P) {
-      if (getMoreSpecializedPartialSpecialization(P->first, Best->first) 
-            == P->first)
-        Best = P;
-    }
-    
-    // Determine if the best partial specialization is more specialized than
-    // the others.
-    bool Ambiguous = false;
-    for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
-                                                  PEnd = Matched.end();
-         P != PEnd; ++P) {
-      if (P != Best &&
-          getMoreSpecializedPartialSpecialization(P->first, Best->first)
-            != Best->first) {
-        Ambiguous = true;
-        break;
+    if (Matched.size() == 1) {
+      //   -- If exactly one matching specialization is found, the
+      //      instantiation is generated from that specialization.
+      // We don't need to do anything for this.
+    } else {
+      //   -- If more than one matching specialization is found, the
+      //      partial order rules (14.5.4.2) are used to determine
+      //      whether one of the specializations is more specialized
+      //      than the others. If none of the specializations is more
+      //      specialized than all of the other matching
+      //      specializations, then the use of the class template is
+      //      ambiguous and the program is ill-formed.
+      for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+                                                    PEnd = Matched.end();
+           P != PEnd; ++P) {
+        if (getMoreSpecializedPartialSpecialization(P->first, Best->first) 
+              == P->first)
+          Best = P;
       }
-    }
-     
-    if (Ambiguous) {
-      // Partial ordering did not produce a clear winner. Complain.
-      ClassTemplateSpec->setInvalidDecl();
-      Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
-        << ClassTemplateSpec;
       
-      // Print the matching partial specializations.
+      // Determine if the best partial specialization is more specialized than
+      // the others.
+      bool Ambiguous = false;
       for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
                                                     PEnd = Matched.end();
-           P != PEnd; ++P)
-        Diag(P->first->getLocation(), diag::note_partial_spec_match)
-          << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
-                                             *P->second);
+           P != PEnd; ++P) {
+        if (P != Best &&
+            getMoreSpecializedPartialSpecialization(P->first, Best->first)
+              != Best->first) {
+          Ambiguous = true;
+          break;
+        }
+      }
+       
+      if (Ambiguous) {
+        // Partial ordering did not produce a clear winner. Complain.
+        ClassTemplateSpec->setInvalidDecl();
+        Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+          << ClassTemplateSpec;
+        
+        // Print the matching partial specializations.
+        for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+                                                      PEnd = Matched.end();
+             P != PEnd; ++P)
+          Diag(P->first->getLocation(), diag::note_partial_spec_match)
+            << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
+                                               *P->second);
 
-      return true;
+        return true;
+      }
     }
     
     // Instantiate using the best class template partial specialization.
-    Pattern = Best->first;
+    ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first;
+    while (OrigPartialSpec->getInstantiatedFromMember()) {
+      // If we've found an explicit specialization of this class template,
+      // stop here and use that as the pattern.
+      if (OrigPartialSpec->isMemberSpecialization())
+        break;
+      
+      OrigPartialSpec = OrigPartialSpec->getInstantiatedFromMember();
+    }
+    
+    Pattern = OrigPartialSpec;
     ClassTemplateSpec->setInstantiationOf(Best->first, Best->second);
   } else {
     //   -- If no matches are found, the instantiation is generated
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 17b99bc..50b0fb8 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -82,6 +82,10 @@
 
     TemplateParameterList *
       SubstTemplateParams(TemplateParameterList *List);
+      
+    bool InstantiateClassTemplatePartialSpecialization(
+                                              ClassTemplateDecl *ClassTemplate,
+                           ClassTemplatePartialSpecializationDecl *PartialSpec);
   };
 }
 
@@ -389,6 +393,21 @@
   return 0;
 }
 
+namespace {
+  class SortDeclByLocation {
+    SourceManager &SourceMgr;
+    
+  public:
+    explicit SortDeclByLocation(SourceManager &SourceMgr) 
+      : SourceMgr(SourceMgr) { }
+    
+    bool operator()(const Decl *X, const Decl *Y) const {
+      return SourceMgr.isBeforeInTranslationUnit(X->getLocation(),
+                                                 Y->getLocation());
+    }
+  };
+}
+
 Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   TemplateParameterList *TempParams = D->getTemplateParameters();
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -413,13 +432,52 @@
   SemaRef.Context.getTypeDeclType(RecordInst);
   
   Owner->addDecl(Inst);
+  
+  // First, we sort the partial specializations by location, so 
+  // that we instantiate them in the order they were declared.
+  llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+         P = D->getPartialSpecializations().begin(), 
+         PEnd = D->getPartialSpecializations().end();
+       P != PEnd; ++P)
+    PartialSpecs.push_back(&*P);
+  std::sort(PartialSpecs.begin(), PartialSpecs.end(),
+            SortDeclByLocation(SemaRef.SourceMgr));
+  
+  // Instantiate all of the partial specializations of this member class 
+  // template.
+  for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
+    InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
+  
   return Inst;
 }
 
 Decl *
 TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
                                    ClassTemplatePartialSpecializationDecl *D) {
-  assert(false &&"Partial specializations of member templates are unsupported");
+  ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
+  
+  // Lookup the already-instantiated declaration in the instantiation
+  // of the class template and return that.
+  DeclContext::lookup_result Found
+    = Owner->lookup(ClassTemplate->getDeclName());
+  if (Found.first == Found.second)
+    return 0;
+  
+  ClassTemplateDecl *InstClassTemplate
+    = dyn_cast<ClassTemplateDecl>(*Found.first);
+  if (!InstClassTemplate)
+    return 0;
+  
+  Decl *DCanon = D->getCanonicalDecl();
+  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+            P = InstClassTemplate->getPartialSpecializations().begin(),
+         PEnd = InstClassTemplate->getPartialSpecializations().end();
+       P != PEnd; ++P) {
+    if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+      return &*P;
+  }
+  
   return 0;
 }
 
@@ -431,7 +489,7 @@
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
   if (!InstParams)
     return NULL;
-
+  
   FunctionDecl *Instantiated = 0;
   if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
     Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, 
@@ -945,6 +1003,130 @@
   return InstL;
 }
 
+/// \brief Instantiate the declaration of a class template partial 
+/// specialization.
+///
+/// \param ClassTemplate the (instantiated) class template that is partially
+// specialized by the instantiation of \p PartialSpec.
+///
+/// \param PartialSpec the (uninstantiated) class template partial 
+/// specialization that we are instantiating.
+///
+/// \returns true if there was an error, false otherwise.
+bool 
+TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
+                                            ClassTemplateDecl *ClassTemplate,
+                          ClassTemplatePartialSpecializationDecl *PartialSpec) {
+  // Substitute into the template parameters of the class template partial
+  // specialization.
+  TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
+  TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+  if (!InstParams)
+    return true;
+  
+  // Substitute into the template arguments of the class template partial
+  // specialization.
+  const TemplateArgumentList &PartialSpecTemplateArgs 
+    = PartialSpec->getTemplateInstantiationArgs();
+  llvm::SmallVector<TemplateArgument, 4> InstTemplateArgs;
+  for (unsigned I = 0, N = PartialSpecTemplateArgs.size(); I != N; ++I) {
+    TemplateArgument Inst = SemaRef.Subst(PartialSpecTemplateArgs[I], 
+                                          TemplateArgs);
+    if (Inst.isNull())
+      return true;
+    
+    InstTemplateArgs.push_back(Inst);
+  }
+  
+
+  // Check that the template argument list is well-formed for this
+  // class template.
+  TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), 
+                                        InstTemplateArgs.size());
+  if (SemaRef.CheckTemplateArgumentList(ClassTemplate, 
+                                        PartialSpec->getLocation(),
+                                        /*FIXME:*/PartialSpec->getLocation(),
+                                        InstTemplateArgs.data(), 
+                                        InstTemplateArgs.size(),
+                                        /*FIXME:*/PartialSpec->getLocation(), 
+                                        false,
+                                        Converted))
+    return true;
+
+  // Figure out where to insert this class template partial specialization
+  // in the member template's set of class template partial specializations.
+  llvm::FoldingSetNodeID ID;
+  ClassTemplatePartialSpecializationDecl::Profile(ID,
+                                                  Converted.getFlatArguments(),
+                                                  Converted.flatSize(),
+                                                  SemaRef.Context);
+  void *InsertPos = 0;
+  ClassTemplateSpecializationDecl *PrevDecl
+    = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+                                                                     InsertPos);
+  
+  // Build the canonical type that describes the converted template
+  // arguments of the class template partial specialization.
+  QualType CanonType 
+    = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
+                                                  Converted.getFlatArguments(),
+                                                    Converted.flatSize());
+
+  // Build the fully-sugared type for this class template
+  // specialization as the user wrote in the specialization
+  // itself. This means that we'll pretty-print the type retrieved
+  // from the specialization's declaration the way that the user
+  // actually wrote the specialization, rather than formatting the
+  // name based on the "canonical" representation used to store the
+  // template arguments in the specialization.
+  QualType WrittenTy
+    = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
+                                                    InstTemplateArgs.data(),
+                                                    InstTemplateArgs.size(),
+                                                    CanonType);
+  
+  if (PrevDecl) {
+    // We've already seen a partial specialization with the same template
+    // parameters and template arguments. This can happen, for example, when
+    // substituting the outer template arguments ends up causing two
+    // class template partial specializations of a member class template
+    // to have identical forms, e.g.,
+    //
+    //   template<typename T, typename U>
+    //   struct Outer {
+    //     template<typename X, typename Y> struct Inner;
+    //     template<typename Y> struct Inner<T, Y>;
+    //     template<typename Y> struct Inner<U, Y>;
+    //   };
+    //
+    //   Outer<int, int> outer; // error: the partial specializations of Inner
+    //                          // have the same signature.
+    SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
+      << WrittenTy;
+    SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
+      << SemaRef.Context.getTypeDeclType(PrevDecl);
+    return true;
+  }
+  
+  
+  // Create the class template partial specialization declaration.
+  ClassTemplatePartialSpecializationDecl *InstPartialSpec
+    = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner, 
+                                                     PartialSpec->getLocation(), 
+                                                     InstParams,
+                                                     ClassTemplate, 
+                                                     Converted,
+                                                     0);
+  InstPartialSpec->setInstantiatedFromMember(PartialSpec);
+  InstPartialSpec->setTypeAsWritten(WrittenTy);
+  
+  // Add this partial specialization to the set of class template partial
+  // specializations.
+  ClassTemplate->getPartialSpecializations().InsertNode(InstPartialSpec,
+                                                        InsertPos);
+  return false;
+}
+
 /// \brief Does substitution on the type of the given function, including
 /// all of the function parameters.
 ///
@@ -1391,6 +1573,22 @@
   return false;
 }
 
+static bool 
+isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern,
+                  ClassTemplatePartialSpecializationDecl *Instance) {
+  Pattern 
+    = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl());
+  do {
+    Instance = cast<ClassTemplatePartialSpecializationDecl>(
+                                                Instance->getCanonicalDecl());
+    if (Pattern == Instance)
+      return true;
+    Instance = Instance->getInstantiatedFromMember();
+  } while (Instance);
+  
+  return false;
+}
+
 static bool isInstantiationOf(CXXRecordDecl *Pattern,
                               CXXRecordDecl *Instance) {
   Pattern = Pattern->getCanonicalDecl();
@@ -1481,6 +1679,11 @@
   if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
     return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
 
+  if (ClassTemplatePartialSpecializationDecl *PartialSpec
+        = dyn_cast<ClassTemplatePartialSpecializationDecl>(Other))
+    return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D),
+                             PartialSpec);
+
   if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
     if (!Field->getDeclName()) {
       // This is an unnamed field.