Improve checking for specializations of member classes of class
templates, and keep track of how those member classes were
instantiated or specialized. 

Make sure that we don't try to instantiate an explicitly-specialized
member class of a class template, when that explicit specialization
was a declaration rather than a definition.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83547 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 7408f2f..2d35117 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -437,6 +437,53 @@
   Conversions.addOverload(ConvDecl);
 }
 
+CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
+  if (MemberSpecializationInfo *MSInfo
+        = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>())
+    return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
+  
+  return 0;
+}
+
+void 
+CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
+                                             TemplateSpecializationKind TSK) {
+  assert(TemplateOrInstantiation.isNull() && 
+         "Previous template or instantiation?");
+  assert(!isa<ClassTemplateSpecializationDecl>(this));
+  TemplateOrInstantiation 
+    = new (getASTContext()) MemberSpecializationInfo(RD, TSK);
+}
+
+TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() {
+  if (ClassTemplateSpecializationDecl *Spec
+        = dyn_cast<ClassTemplateSpecializationDecl>(this))
+    return Spec->getSpecializationKind();
+  
+  if (MemberSpecializationInfo *MSInfo
+      = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>())
+    return MSInfo->getTemplateSpecializationKind();
+  
+  return TSK_Undeclared;
+}
+
+void 
+CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+  if (ClassTemplateSpecializationDecl *Spec
+      = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
+    Spec->setSpecializationKind(TSK);
+    return;
+  }
+  
+  if (MemberSpecializationInfo *MSInfo
+        = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>()) {
+    MSInfo->setTemplateSpecializationKind(TSK);
+    return;
+  }
+  
+  assert(false && "Not a class template or member class specialization");
+}
+
 CXXConstructorDecl *
 CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
   QualType ClassType = Context.getTypeDeclType(this);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2070335..267eea8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4161,11 +4161,14 @@
         TemplateParameterLists.release();
         return Result.get();
       } else {
-        // FIXME: diagnose the extraneous 'template<>', once we recover
-        // slightly better in ParseTemplate.cpp from bogus template
-        // parameters.
+        // The "template<>" header is extraneous.
+        Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
+          << ElaboratedType::getNameForTagKind(Kind) << Name;
+        isExplicitSpecialization = true;
       }
     }
+             
+    TemplateParameterLists.release();
   }
 
   DeclContext *SearchDC = CurContext;
@@ -4493,6 +4496,11 @@
     }
   }
 
+  // If this is a specialization of a member class (of a class template),
+  // check the specialization.
+  if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl))
+    Invalid = true;
+      
   if (Invalid)
     New->setInvalidDecl();
 
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5c6ec00..219d731 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2360,15 +2360,13 @@
   if (!D)
     return TSK_Undeclared;
   
-  if (ClassTemplateSpecializationDecl *CTS 
-        = dyn_cast<ClassTemplateSpecializationDecl>(D))
-    return CTS->getSpecializationKind();
+  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+    return Record->getTemplateSpecializationKind();
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
     return Function->getTemplateSpecializationKind();
   if (VarDecl *Var = dyn_cast<VarDecl>(D))
     return Var->getTemplateSpecializationKind();
   
-  // FIXME: member classes of class templates!
   return TSK_Undeclared;
 }
 
@@ -3192,23 +3190,46 @@
   // FIXME: Check for specialization-after-instantiation errors and such.
   
   // Note that this is an explicit instantiation of a member.
+  // the original declaration to note that it is an explicit specialization
+  // (if it was previously an implicit instantiation). This latter step
+  // makes bookkeeping easier.
   if (isa<FunctionDecl>(Member)) {
-    // FIXME: We're also setting the original instantiation we found to be
-    // an explicit specialization, although I'd rather not have to do this.
-    cast<FunctionDecl>(Instantiation)->setTemplateSpecializationKind(
-                                                    TSK_ExplicitSpecialization);
+    FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
+    if (InstantiationFunction->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationFunction->setTemplateSpecializationKind(
+                                                  TSK_ExplicitSpecialization);
+      InstantiationFunction->setLocation(Member->getLocation());
+    }
+    
     cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
                                         cast<CXXMethodDecl>(InstantiatedFrom),
                                                   TSK_ExplicitSpecialization);
   } else if (isa<VarDecl>(Member)) {
+    VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
+    if (InstantiationVar->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationVar->setTemplateSpecializationKind(
+                                                  TSK_ExplicitSpecialization);
+      InstantiationVar->setLocation(Member->getLocation());
+    }
+    
     Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
                                                 cast<VarDecl>(InstantiatedFrom),
                                                 TSK_ExplicitSpecialization);
   } else {
     assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
-    // FIXME: Record TSK_ExplicitSpecialization.
+    CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
+    if (InstantiationClass->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationClass->setTemplateSpecializationKind(
+                                                   TSK_ExplicitSpecialization);
+      InstantiationClass->setLocation(Member->getLocation());
+    }
+    
     cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
-                                        cast<CXXRecordDecl>(InstantiatedFrom));
+                                        cast<CXXRecordDecl>(InstantiatedFrom),
+                                                   TSK_ExplicitSpecialization);
   }
              
   // Save the caller the trouble of having to figure out which declaration
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 2f7af60..ec00d98 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -972,20 +972,30 @@
                               CXXRecordDecl *Instantiation,
                         const MultiLevelTemplateArgumentList &TemplateArgs,
                               TemplateSpecializationKind TSK) {
-  // FIXME: extern templates
   for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
                                DEnd = Instantiation->decls_end();
        D != DEnd; ++D) {
     if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
-      if (Function->getInstantiatedFromMemberFunction())
+      if (Function->getInstantiatedFromMemberFunction()) {
+        // If this member was explicitly specialized, do nothing.
+        if (Function->getTemplateSpecializationKind() ==
+              TSK_ExplicitSpecialization)
+          continue;
+        
         Function->setTemplateSpecializationKind(TSK);
-      if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
+      }
+      
+      if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition)
         InstantiateFunctionDefinition(PointOfInstantiation, Function);
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
       if (Var->isStaticDataMember()) {
+        // If this member was explicitly specialized, do nothing.
+        if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+          continue;
+        
         Var->setTemplateSpecializationKind(TSK);
         
-        if (TSK != TSK_ExplicitInstantiationDeclaration)
+        if (TSK == TSK_ExplicitInstantiationDefinition)
           InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
       }        
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
@@ -994,6 +1004,11 @@
       
       assert(Record->getInstantiatedFromMemberClass() &&
              "Missing instantiated-from-template information");
+      
+      // If this member was explicitly specialized, do nothing.
+      if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        continue;
+      
       if (!Record->getDefinition(Context))
         InstantiateClass(PointOfInstantiation, Record,
                          Record->getInstantiatedFromMemberClass(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bafcea0..b354827 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -454,7 +454,7 @@
   if (D->getAccess() != AS_none)
     Record->setAccess(D->getAccess());
   if (!D->isInjectedClassName())
-    Record->setInstantiationOfMemberClass(D);
+    Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
 
   // If the original function was part of a friend declaration,
   // inherit its namespace state.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 402bc9d..da72197 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1849,10 +1849,11 @@
                  = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
       if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
         // This record was instantiated from a class within a template.
-        return InstantiateClass(Loc, Rec, Pattern,
-                                getTemplateInstantiationArgs(Rec),
-                                TSK_ImplicitInstantiation,
-                                /*Complain=*/diag != 0);
+        if (Rec->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+          return InstantiateClass(Loc, Rec, Pattern,
+                                  getTemplateInstantiationArgs(Rec),
+                                  TSK_ImplicitInstantiation,
+                                  /*Complain=*/diag != 0);
       }
     }
   }