Refactor redeclarable template declarations

This patch refactors much of the common code in ClassTemplateDecl and
FunctionTemplateDecl into a common base class RedeclarableTemplateDecl
together with support functions in a template class RedeclarableTemplate.

The patch also includes similar refactoring for these classes' PCH
reader and writer implementations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109754 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 22b297d..de17568 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -84,6 +84,29 @@
 }
 
 //===----------------------------------------------------------------------===//
+// RedeclarableTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() {
+  // Find the first declaration of this function template.
+  RedeclarableTemplateDecl *First = getCanonicalDecl();
+
+  if (First->CommonOrPrev.isNull()) {
+    CommonBase *CommonPtr = First->newCommon();
+    First->CommonOrPrev = CommonPtr;
+  }
+  return First->CommonOrPrev.get<CommonBase*>();
+}
+
+
+RedeclarableTemplateDecl *RedeclarableTemplateDecl::getCanonicalDeclImpl() {
+  RedeclarableTemplateDecl *Tmpl = this;
+  while (Tmpl->getPreviousDeclaration())
+    Tmpl = Tmpl->getPreviousDeclaration();
+  return Tmpl;
+}
+
+//===----------------------------------------------------------------------===//
 // FunctionTemplateDecl Implementation
 //===----------------------------------------------------------------------===//
 
@@ -100,6 +123,12 @@
   return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
 }
 
+RedeclarableTemplateDecl::CommonBase *FunctionTemplateDecl::newCommon() {
+  Common *CommonPtr = new (getASTContext()) Common;
+  getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
+  return CommonPtr;
+}
+
 FunctionDecl *
 FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
                                          unsigned NumArgs, void *&InsertPos) {
@@ -110,27 +139,6 @@
   return Info ? Info->Function->getMostRecentDeclaration() : 0;
 }
 
-FunctionTemplateDecl *FunctionTemplateDecl::getCanonicalDecl() {
-  FunctionTemplateDecl *FunTmpl = this;
-  while (FunTmpl->getPreviousDeclaration())
-    FunTmpl = FunTmpl->getPreviousDeclaration();
-  return FunTmpl;
-}
-
-FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
-  // Find the first declaration of this function template.
-  FunctionTemplateDecl *First = this;
-  while (First->getPreviousDeclaration())
-    First = First->getPreviousDeclaration();
-
-  if (First->CommonOrPrev.isNull()) {
-    Common *CommonPtr = new (getASTContext()) Common;
-    getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
-    First->CommonOrPrev = CommonPtr;
-  }
-  return First->CommonOrPrev.get<Common*>();
-}
-
 //===----------------------------------------------------------------------===//
 // ClassTemplateDecl Implementation
 //===----------------------------------------------------------------------===//
@@ -139,13 +147,6 @@
   static_cast<Common *>(Ptr)->~Common();
 }
 
-ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() {
-  ClassTemplateDecl *Template = this;
-  while (Template->getPreviousDeclaration())
-    Template = Template->getPreviousDeclaration();
-  return Template;
-}
-
 ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
                                              DeclContext *DC,
                                              SourceLocation L,
@@ -158,6 +159,12 @@
   return New;
 }
 
+RedeclarableTemplateDecl::CommonBase *ClassTemplateDecl::newCommon() {
+  Common *CommonPtr = new (getASTContext()) Common;
+  getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
+  return CommonPtr;
+}
+
 ClassTemplateSpecializationDecl *
 ClassTemplateDecl::findSpecialization(const TemplateArgument *Args,
                                       unsigned NumArgs, void *&InsertPos) {
@@ -263,20 +270,6 @@
   return CommonPtr->InjectedClassNameType;
 }
 
-ClassTemplateDecl::Common *ClassTemplateDecl::getCommonPtr() {
-  // Find the first declaration of this function template.
-  ClassTemplateDecl *First = this;
-  while (First->getPreviousDeclaration())
-    First = First->getPreviousDeclaration();
-
-  if (First->CommonOrPrev.isNull()) {
-    Common *CommonPtr = new (getASTContext()) Common;
-    getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
-    First->CommonOrPrev = CommonPtr;
-  }
-  return First->CommonOrPrev.get<Common*>();
-}
-
 //===----------------------------------------------------------------------===//
 // TemplateTypeParm Allocation/Deallocation Method Implementations
 //===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index fe2947d..94485d2 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -78,6 +78,7 @@
     void VisitParmVarDecl(ParmVarDecl *PD);
     void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
     void VisitTemplateDecl(TemplateDecl *D);
+    void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
     void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
@@ -895,14 +896,32 @@
   D->init(TemplatedDecl, TemplateParams);
 }
 
-void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+void PCHDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   VisitTemplateDecl(D);
 
   D->IdentifierNamespace = Record[Idx++];
-  ClassTemplateDecl *PrevDecl =
-      cast_or_null<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]));
-  D->setPreviousDeclaration(PrevDecl);
+  RedeclarableTemplateDecl *PrevDecl =
+      cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]));
+  assert((PrevDecl == 0 || PrevDecl->getKind() == D->getKind()) &&
+         "PrevDecl kind mismatch");
+  if (PrevDecl)
+    D->CommonOrPrev = PrevDecl;
   if (PrevDecl == 0) {
+    if (RedeclarableTemplateDecl *RTD
+          = cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
+      assert(RTD->getKind() == D->getKind() &&
+             "InstantiatedFromMemberTemplate kind mismatch");
+      D->setInstantiatedFromMemberTemplateImpl(RTD);
+      if (Record[Idx++])
+        D->setMemberSpecialization();
+    }
+  }
+}
+
+void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+  VisitRedeclarableTemplateDecl(D);
+
+  if (D->getPreviousDeclaration() == 0) {
     // This ClassTemplateDecl owns a CommonPtr; read it.
 
     // FoldingSets are filled in VisitClassTemplateSpecializationDecl.
@@ -916,13 +935,6 @@
                                                  Reader.GetDecl(Record[Idx++]));
 
     // InjectedClassNameType is computed.
-
-    if (ClassTemplateDecl *CTD
-          = cast_or_null<ClassTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
-      D->setInstantiatedFromMemberTemplate(CTD);
-      if (Record[Idx++])
-        D->setMemberSpecialization();
-    }
   }
 }
 
@@ -993,13 +1005,9 @@
 }
 
 void PCHDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
-  VisitTemplateDecl(D);
+  VisitRedeclarableTemplateDecl(D);
 
-  D->IdentifierNamespace = Record[Idx++];
-  FunctionTemplateDecl *PrevDecl =
-      cast_or_null<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]));
-  D->setPreviousDeclaration(PrevDecl);
-  if (PrevDecl == 0) {
+  if (D->getPreviousDeclaration() == 0) {
     // This FunctionTemplateDecl owns a CommonPtr; read it.
 
     // Read the function specialization declarations.
@@ -1008,13 +1016,6 @@
     unsigned NumSpecs = Record[Idx++];
     while (NumSpecs--)
       Reader.GetDecl(Record[Idx++]);
-
-    if (FunctionTemplateDecl *CTD
-          = cast_or_null<FunctionTemplateDecl>(Reader.GetDecl(Record[Idx++]))) {
-      D->setInstantiatedFromMemberTemplate(CTD);
-      if (Record[Idx++])
-        D->setMemberSpecialization();
-    }
   }
 }
 
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 06266d2..3ac4958 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -76,6 +76,7 @@
     void VisitParmVarDecl(ParmVarDecl *D);
     void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
     void VisitTemplateDecl(TemplateDecl *D);
+    void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
     void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
@@ -839,15 +840,25 @@
   Writer.AddTemplateParameterList(D->getTemplateParameters(), Record);
 }
 
-void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+void PCHDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   VisitTemplateDecl(D);
 
   Record.push_back(D->getIdentifierNamespace());
   Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
   if (D->getPreviousDeclaration() == 0) {
-    // This ClassTemplateDecl owns the CommonPtr; write it.
+    // This TemplateDecl owns the CommonPtr; write it.
     assert(D->isCanonicalDecl());
 
+    Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
+    if (D->getInstantiatedFromMemberTemplate())
+      Record.push_back(D->isMemberSpecialization());
+  }
+}
+
+void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+  VisitRedeclarableTemplateDecl(D);
+
+  if (D->getPreviousDeclaration() == 0) {
     typedef llvm::FoldingSet<ClassTemplateSpecializationDecl> CTSDSetTy;
     CTSDSetTy &CTSDSet = D->getSpecializations();
     Record.push_back(CTSDSet.size());
@@ -865,10 +876,6 @@
     }
 
     // InjectedClassNameType is computed, no need to write it.
-
-    Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
-    if (D->getInstantiatedFromMemberTemplate())
-      Record.push_back(D->isMemberSpecialization());
   }
   Code = pch::DECL_CLASS_TEMPLATE;
 }
@@ -929,10 +936,8 @@
 }
 
 void PCHDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
-  VisitTemplateDecl(D);
+  VisitRedeclarableTemplateDecl(D);
 
-  Record.push_back(D->getIdentifierNamespace());
-  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
   if (D->getPreviousDeclaration() == 0) {
     // This FunctionTemplateDecl owns the CommonPtr; write it.
 
@@ -945,10 +950,6 @@
              "Expected only canonical decls in set");
       Writer.AddDeclRef(I->Function, Record);
     }
-
-    Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record);
-    if (D->getInstantiatedFromMemberTemplate())
-      Record.push_back(D->isMemberSpecialization());
   }
   Code = pch::DECL_FUNCTION_TEMPLATE;
 }