[llvm-branch-commits] [clang] [Serialization] Code cleanups and polish 83233 (PR #83237)

Chuanqi Xu via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Sep 24 03:25:07 PDT 2024


https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/83237

>From f2e53e44eebab4720a1dbade24fcb14d698fb03f Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Wed, 28 Feb 2024 11:41:53 +0800
Subject: [PATCH 1/7] [Serialization] Code cleanups and polish 83233

---
 clang/include/clang/AST/DeclTemplate.h        |  39 +-
 clang/include/clang/AST/ExternalASTSource.h   |   8 +-
 .../clang/Sema/MultiplexExternalSemaSource.h  |   4 +-
 .../include/clang/Serialization/ASTBitCodes.h |   2 +-
 clang/include/clang/Serialization/ASTReader.h |   4 +-
 clang/lib/AST/DeclTemplate.cpp                |  85 ++--
 clang/lib/AST/ExternalASTSource.cpp           |  10 +-
 clang/lib/AST/ODRHash.cpp                     |  10 -
 .../lib/Sema/MultiplexExternalSemaSource.cpp  |  13 +-
 clang/lib/Serialization/ASTCommon.h           |   1 -
 clang/lib/Serialization/ASTReader.cpp         |  42 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |  76 +---
 clang/lib/Serialization/ASTReaderInternals.h  |   1 -
 clang/lib/Serialization/ASTWriter.cpp         |  27 +-
 clang/lib/Serialization/ASTWriterDecl.cpp     |  52 +--
 clang/lib/Serialization/CMakeLists.txt        |   1 +
 .../Serialization/TemplateArgumentHasher.cpp  | 423 ++++++++++++++++++
 .../Serialization/TemplateArgumentHasher.h    |  34 ++
 clang/test/Modules/cxx-templates.cpp          |   8 +-
 .../Modules/recursive-instantiations.cppm     |  40 ++
 .../test/OpenMP/target_parallel_ast_print.cpp |   4 -
 clang/test/OpenMP/target_teams_ast_print.cpp  |   4 -
 clang/test/OpenMP/task_ast_print.cpp          |   4 -
 clang/test/OpenMP/teams_ast_print.cpp         |   4 -
 24 files changed, 610 insertions(+), 286 deletions(-)
 create mode 100644 clang/lib/Serialization/TemplateArgumentHasher.cpp
 create mode 100644 clang/lib/Serialization/TemplateArgumentHasher.h
 create mode 100644 clang/test/Modules/recursive-instantiations.cppm

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 44f840d297465d..7406252363d223 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -256,9 +256,6 @@ class TemplateArgumentList final
   TemplateArgumentList(const TemplateArgumentList &) = delete;
   TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
 
-  /// Create hash for the given arguments.
-  static unsigned ComputeODRHash(ArrayRef<TemplateArgument> Args);
-
   /// Create a new template argument list that copies the given set of
   /// template arguments.
   static TemplateArgumentList *CreateCopy(ASTContext &Context,
@@ -732,25 +729,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   }
 
   void anchor() override;
-  struct LazySpecializationInfo {
-    GlobalDeclID DeclID = GlobalDeclID();
-    unsigned ODRHash = ~0U;
-    bool IsPartial = false;
-    LazySpecializationInfo(GlobalDeclID ID, unsigned Hash = ~0U,
-                           bool Partial = false)
-        : DeclID(ID), ODRHash(Hash), IsPartial(Partial) {}
-    LazySpecializationInfo() {}
-    bool operator<(const LazySpecializationInfo &Other) const {
-      return DeclID < Other.DeclID;
-    }
-    bool operator==(const LazySpecializationInfo &Other) const {
-      assert((DeclID != Other.DeclID || ODRHash == Other.ODRHash) &&
-             "Hashes differ!");
-      assert((DeclID != Other.DeclID || IsPartial == Other.IsPartial) &&
-             "Both must be the same kinds!");
-      return DeclID == Other.DeclID;
-    }
-  };
 
 protected:
   template <typename EntryType> struct SpecEntryTraits {
@@ -794,16 +772,20 @@ class RedeclarableTemplateDecl : public TemplateDecl,
 
   void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
 
-  void loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
+  bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
                                    TemplateParameterList *TPL = nullptr) const;
 
-  Decl *loadLazySpecializationImpl(LazySpecializationInfo &LazySpecInfo) const;
-
   template <class EntryType, typename ...ProfileArguments>
   typename SpecEntryTraits<EntryType>::DeclType*
   findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
                          void *&InsertPos, ProfileArguments &&...ProfileArgs);
 
+  template <class EntryType, typename... ProfileArguments>
+  typename SpecEntryTraits<EntryType>::DeclType *
+  findSpecializationLocally(llvm::FoldingSetVector<EntryType> &Specs,
+                            void *&InsertPos,
+                            ProfileArguments &&...ProfileArgs);
+
   template <class Derived, class EntryType>
   void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
                              EntryType *Entry, void *InsertPos);
@@ -819,13 +801,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
     llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
       InstantiatedFromMember;
 
-    /// If non-null, points to an array of specializations (including
-    /// partial specializations) known only by their external declaration IDs.
-    ///
-    /// The first value in the array is the number of specializations/partial
-    /// specializations that follow.
-    LazySpecializationInfo *LazySpecializations = nullptr;
-
     /// The set of "injected" template arguments used within this
     /// template.
     ///
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 24c4490d160f3f..2b73b543fabb3b 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -153,11 +153,15 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
   /// Load all the external specializations for the Decl \param D if \param
   /// OnlyPartial is false. Otherwise, load all the external **partial**
   /// specializations for the \param D.
-  virtual void LoadExternalSpecializations(const Decl *D, bool OnlyPartial);
+  ///
+  /// Return true if any new specializations get loaded. Return false otherwise.
+  virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial);
 
   /// Load all the specializations for the Decl \param D with the same template
   /// args specified by \param TemplateArgs.
-  virtual void
+  ///
+  /// Return true if any new specializations get loaded. Return false otherwise.
+  virtual bool
   LoadExternalSpecializations(const Decl *D,
                               ArrayRef<TemplateArgument> TemplateArgs);
 
diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
index f81b70daa4b3d0..da13bef15de0ea 100644
--- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -97,9 +97,9 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
   bool FindExternalVisibleDeclsByName(const DeclContext *DC,
                                       DeclarationName Name) override;
 
-  void LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
+  bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
 
-  void
+  bool
   LoadExternalSpecializations(const Decl *D,
                               ArrayRef<TemplateArgument> TemplateArgs) override;
 
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index eefc0e5218d7d3..c7c1fdaf03ef4b 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -726,7 +726,7 @@ enum ASTRecordTypes {
   VTABLES_TO_EMIT = 70,
 
   /// Record code for updated specialization
-  UPDATE_SPECIALIZATION = 71,
+  CXX_ADDED_TEMPLATE_SPECIALIZATION = 71,
 };
 
 /// Record types used within a source manager block.
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 0356fd14d9fd61..bb87998aba3844 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2008,9 +2008,9 @@ class ASTReader
                                       unsigned BlockID,
                                       uint64_t *StartOfBlockOffset = nullptr);
 
-  void LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
+  bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
 
-  void
+  bool
   LoadExternalSpecializations(const Decl *D,
                               ArrayRef<TemplateArgument> TemplateArgs) override;
 
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 1c81218626fdfb..419b2e7c18e48c 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -342,63 +342,30 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
   ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
                                               OnlyPartial);
   return;
-
-  // Grab the most recent declaration to ensure we've loaded any lazy
-  // redeclarations of this template.
-  CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
-  if (auto *Specs = CommonBasePtr->LazySpecializations) {
-    if (!OnlyPartial)
-      CommonBasePtr->LazySpecializations = nullptr;
-    unsigned N = Specs[0].DeclID.getRawValue();
-    for (unsigned I = 0; I != N; ++I) {
-      // Skip over already loaded specializations.
-      if (!Specs[I + 1].ODRHash)
-        continue;
-      if (!OnlyPartial || Specs[I + 1].IsPartial)
-        (void)loadLazySpecializationImpl(Specs[I + 1]);
-    }
-  }
-}
-
-Decl *RedeclarableTemplateDecl::loadLazySpecializationImpl(
-    LazySpecializationInfo &LazySpecInfo) const {
-  llvm_unreachable("We don't use LazySpecializationInfo any more");
-
-  GlobalDeclID ID = LazySpecInfo.DeclID;
-  assert(ID.isValid() && "Loading already loaded specialization!");
-  // Note that we loaded the specialization.
-  LazySpecInfo.DeclID = GlobalDeclID();
-  LazySpecInfo.ODRHash = LazySpecInfo.IsPartial = 0;
-  return getASTContext().getExternalSource()->GetExternalDecl(ID);
 }
 
-void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
+bool RedeclarableTemplateDecl::loadLazySpecializationsImpl(
     ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
   auto *ExternalSource = getASTContext().getExternalSource();
   if (!ExternalSource)
-    return;
+    return false;
 
-  ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), Args);
-  return;
+  // If TPL is not null, it implies that we're loading specializations for
+  // partial templates. We need to load all specializations in such cases.
+  if (TPL)
+    return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
+                                                       /*OnlyPartial=*/false);
 
-  CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
-  if (auto *Specs = CommonBasePtr->LazySpecializations) {
-    unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
-    unsigned N = Specs[0].DeclID.getRawValue();
-    for (unsigned I = 0; I != N; ++I)
-      if (Specs[I+1].ODRHash && Specs[I+1].ODRHash == Hash)
-        (void)loadLazySpecializationImpl(Specs[I+1]);
-  }
+  return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
+                                                     Args);
 }
 
-template<class EntryType, typename... ProfileArguments>
+template <class EntryType, typename... ProfileArguments>
 typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
-RedeclarableTemplateDecl::findSpecializationImpl(
+RedeclarableTemplateDecl::findSpecializationLocally(
     llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
-    ProfileArguments&&... ProfileArgs) {
-  using SETraits = SpecEntryTraits<EntryType>;
-
-  loadLazySpecializationsImpl(std::forward<ProfileArguments>(ProfileArgs)...);
+    ProfileArguments &&...ProfileArgs) {
+  using SETraits = RedeclarableTemplateDecl::SpecEntryTraits<EntryType>;
 
   llvm::FoldingSetNodeID ID;
   EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
@@ -407,6 +374,24 @@ RedeclarableTemplateDecl::findSpecializationImpl(
   return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr;
 }
 
+template <class EntryType, typename... ProfileArguments>
+typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType *
+RedeclarableTemplateDecl::findSpecializationImpl(
+    llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos,
+    ProfileArguments &&...ProfileArgs) {
+
+  if (auto *Found = findSpecializationLocally(
+          Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...))
+    return Found;
+
+  if (!loadLazySpecializationsImpl(
+          std::forward<ProfileArguments>(ProfileArgs)...))
+    return nullptr;
+
+  return findSpecializationLocally(
+      Specs, InsertPos, std::forward<ProfileArguments>(ProfileArgs)...);
+}
+
 template<class Derived, class EntryType>
 void RedeclarableTemplateDecl::addSpecializationImpl(
     llvm::FoldingSetVector<EntryType> &Specializations, EntryType *Entry,
@@ -955,14 +940,6 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
   return new (Mem) TemplateArgumentList(Args);
 }
 
-unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
-  ODRHash Hasher;
-  for (TemplateArgument TA : Args)
-    Hasher.AddTemplateArgument(TA);
-
-  return Hasher.CalculateHash();
-}
-
 FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
     ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
     TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 122014bfeb2321..0eeb549d8cabf3 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -98,10 +98,14 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
   return false;
 }
 
-void ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {}
+bool ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {
+  return false;
+}
 
-void ExternalASTSource::LoadExternalSpecializations(
-    const Decl *D, ArrayRef<TemplateArgument>) {}
+bool ExternalASTSource::LoadExternalSpecializations(
+    const Decl *D, ArrayRef<TemplateArgument>) {
+  return false;
+}
 
 void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {}
 
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 7b361c958c54fe..8e91add1d5875d 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -816,16 +816,6 @@ void ODRHash::AddDecl(const Decl *D) {
 
   AddDeclarationName(ND->getDeclName());
 
-  const auto *Specialization =
-            dyn_cast<ClassTemplateSpecializationDecl>(D);
-  AddBoolean(Specialization);
-  if (Specialization) {
-    const TemplateArgumentList &List = Specialization->getTemplateArgs();
-    ID.AddInteger(List.size());
-    for (const TemplateArgument &TA : List.asArray())
-      AddTemplateArgument(TA);
-  }
-
   // If this was a specialization we should take into account its template
   // arguments. This helps to reduce collisions coming when visiting template
   // specialization types (eg. when processing type template arguments).
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 8b1642cf88a12d..2e98f7ef9519cf 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -115,16 +115,21 @@ FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
   return AnyDeclsFound;
 }
 
-void MultiplexExternalSemaSource::LoadExternalSpecializations(
+bool MultiplexExternalSemaSource::LoadExternalSpecializations(
     const Decl *D, bool OnlyPartial) {
+  bool Loaded = false;
   for (size_t i = 0; i < Sources.size(); ++i)
-    Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
+    Loaded |= Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
+  return Loaded;
 }
 
-void MultiplexExternalSemaSource::LoadExternalSpecializations(
+bool MultiplexExternalSemaSource::LoadExternalSpecializations(
     const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
+  bool AnyNewSpecsLoaded = false;
   for (size_t i = 0; i < Sources.size(); ++i)
-    Sources[i]->LoadExternalSpecializations(D, TemplateArgs);
+    AnyNewSpecsLoaded |=
+        Sources[i]->LoadExternalSpecializations(D, TemplateArgs);
+  return AnyNewSpecsLoaded;
 }
 
 void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h
index 0230908d3e0528..0cef55c53ffcba 100644
--- a/clang/lib/Serialization/ASTCommon.h
+++ b/clang/lib/Serialization/ASTCommon.h
@@ -23,7 +23,6 @@ namespace serialization {
 
 enum DeclUpdateKind {
   UPD_CXX_ADDED_IMPLICIT_MEMBER,
-  UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
   UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
   UPD_CXX_ADDED_FUNCTION_DEFINITION,
   UPD_CXX_ADDED_VAR_DEFINITION,
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 2a5216ab036344..f75d8fc4676b32 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -12,6 +12,7 @@
 
 #include "ASTCommon.h"
 #include "ASTReaderInternals.h"
+#include "TemplateArgumentHasher.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTMutationListener.h"
@@ -3521,7 +3522,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
       break;
     }
 
-    case UPDATE_SPECIALIZATION: {
+    case CXX_ADDED_TEMPLATE_SPECIALIZATION: {
       unsigned Idx = 0;
       GlobalDeclID ID = ReadDeclID(F, Record, Idx);
       auto *Data = (const unsigned char *)Blob.data();
@@ -7694,8 +7695,13 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
     }
   }
 
-  if (Template)
-    Template->loadLazySpecializationsImpl(Args);
+  if (Template) {
+    // For partitial specialization, load all the specializations for safety.
+    if (isa<ClassTemplatePartialSpecializationDecl, VarTemplatePartialSpecializationDecl>(D))
+      Template->loadLazySpecializationsImpl();
+    else
+      Template->loadLazySpecializationsImpl(Args);
+  }
 }
 
 CXXCtorInitializer **
@@ -8011,12 +8017,12 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
   return ReadStmtFromStream(*Loc.F);
 }
 
-void ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
+bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
   assert(D);
 
   auto It = SpecializationsLookups.find(D);
   if (It == SpecializationsLookups.end())
-    return;
+    return false;
 
   // Get Decl may violate the iterator from SpecializationsLookups so we store
   // the DeclIDs in ahead.
@@ -8027,30 +8033,44 @@ void ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
   // the lookup table.
   if (!OnlyPartial)
     SpecializationsLookups.erase(It);
-
+  
+  bool NewSpecsFound = false;
   Deserializing LookupResults(this);
   for (auto &Info : Infos)
-    if (!OnlyPartial || Info.IsPartial)
+    if (!OnlyPartial || Info.IsPartial) {
+      if (GetExistingDecl(Info.ID))
+        continue;
+      NewSpecsFound = true;
       GetDecl(Info.ID);
+    }
+
+  return NewSpecsFound;
 }
 
-void ASTReader::LoadExternalSpecializations(
+bool ASTReader::LoadExternalSpecializations(
     const Decl *D, ArrayRef<TemplateArgument> TemplateArgs) {
   assert(D);
 
   auto It = SpecializationsLookups.find(D);
   if (It == SpecializationsLookups.end())
-    return;
+    return false;
 
   Deserializing LookupResults(this);
-  auto HashValue = TemplateArgumentList::ComputeODRHash(TemplateArgs);
+  auto HashValue = StableHashForTemplateArguments(TemplateArgs);
 
   // Get Decl may violate the iterator from SpecializationsLookups
   llvm::SmallVector<serialization::reader::LazySpecializationInfo, 8> Infos =
       It->second.Table.find(HashValue);
 
-  for (auto &Info : Infos)
+  bool NewSpecsFound = false;
+  for (auto &Info : Infos) {
+    if (GetExistingDecl(Info.ID))
+      continue;
+    NewSpecsFound = true;
     GetDecl(Info.ID);
+  }
+
+  return NewSpecsFound;
 }
 
 void ASTReader::FindExternalLexicalDecls(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 5c1ee02c561de3..9fa07137daabe6 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -89,8 +89,6 @@ namespace clang {
     const SourceLocation ThisDeclLoc;
 
     using RecordData = ASTReader::RecordData;
-    using LazySpecializationInfo =
-        RedeclarableTemplateDecl::LazySpecializationInfo;
 
     TypeID DeferredTypeID = 0;
     unsigned AnonymousDeclNumber = 0;
@@ -133,18 +131,6 @@ namespace clang {
       return Record.readString();
     }
 
-    LazySpecializationInfo ReadLazySpecializationInfo() {
-      GlobalDeclID ID = readDeclID();
-      unsigned Hash = Record.readInt();
-      bool IsPartial = Record.readInt();
-      return LazySpecializationInfo(ID, Hash, IsPartial);
-    }
-
-    void readDeclIDList(SmallVectorImpl<LazySpecializationInfo> &IDs) {
-      for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I)
-        IDs.push_back(ReadLazySpecializationInfo());
-    }
-
     Decl *readDecl() {
       return Record.readDecl();
     }
@@ -271,29 +257,6 @@ namespace clang {
         : Reader(Reader), Record(Record), Loc(Loc), ThisDeclID(thisDeclID),
           ThisDeclLoc(ThisDeclLoc) {}
 
-    template <typename T>
-    static void
-    AddLazySpecializations(T *D, SmallVectorImpl<LazySpecializationInfo> &IDs) {
-      if (IDs.empty())
-        return;
-
-      // FIXME: We should avoid this pattern of getting the ASTContext.
-      ASTContext &C = D->getASTContext();
-
-      auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;
-
-      if (auto &Old = LazySpecializations) {
-        IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0].DeclID.getRawValue());
-        llvm::sort(IDs);
-        IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
-      }
-      auto *Result = new (C) LazySpecializationInfo[1 + IDs.size()];
-      Result->DeclID = GlobalDeclID(IDs.size());
-      std::copy(IDs.begin(), IDs.end(), Result + 1);
-
-      LazySpecializations = Result;
-    }
-
     template <typename DeclT>
     static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
     static Decl *getMostRecentDeclImpl(...);
@@ -322,7 +285,7 @@ namespace clang {
     void ReadFunctionDefinition(FunctionDecl *FD);
     void Visit(Decl *D);
 
-    void UpdateDecl(Decl *D, llvm::SmallVectorImpl<LazySpecializationInfo> &);
+    void UpdateDecl(Decl *D);
 
     static void setNextObjCCategory(ObjCCategoryDecl *Cat,
                                     ObjCCategoryDecl *Next) {
@@ -2473,9 +2436,6 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   if (ThisDeclID == Redecl.getFirstID()) {
     // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
     // the specializations.
-    SmallVector<LazySpecializationInfo, 32> SpecIDs;
-    readDeclIDList(SpecIDs);
-    ASTDeclReader::AddLazySpecializations(D, SpecIDs);
     ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
   }
 
@@ -2502,9 +2462,6 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
   if (ThisDeclID == Redecl.getFirstID()) {
     // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
     // the specializations.
-    SmallVector<LazySpecializationInfo, 32> SpecIDs;
-    readDeclIDList(SpecIDs);
-    ASTDeclReader::AddLazySpecializations(D, SpecIDs);
     ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
   }
 }
@@ -2605,9 +2562,6 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
 
   if (ThisDeclID == Redecl.getFirstID()) {
     // This FunctionTemplateDecl owns a CommonPtr; read it.
-    SmallVector<LazySpecializationInfo, 32> SpecIDs;
-    readDeclIDList(SpecIDs);
-    ASTDeclReader::AddLazySpecializations(D, SpecIDs);
     ReadSpecializations(*Loc.F, D, Loc.F->DeclsCursor);
   }
 }
@@ -4268,10 +4222,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
   ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
   DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
 
-  using LazySpecializationInfo =
-      RedeclarableTemplateDecl::LazySpecializationInfo;
-  llvm::SmallVector<LazySpecializationInfo, 8> PendingLazySpecializationIDs;
-
   if (UpdI != DeclUpdateOffsets.end()) {
     auto UpdateOffsets = std::move(UpdI->second);
     DeclUpdateOffsets.erase(UpdI);
@@ -4308,7 +4258,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
 
       ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
                            SourceLocation());
-      Reader.UpdateDecl(D, PendingLazySpecializationIDs);
+      Reader.UpdateDecl(D);
 
       // We might have made this declaration interesting. If so, remember that
       // we need to hand it off to the consumer.
@@ -4318,19 +4268,6 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
       }
     }
   }
-  // Add the lazy specializations to the template.
-  assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
-          isa<FunctionTemplateDecl, VarTemplateDecl>(D)) &&
-         "Must not have pending specializations");
-  /*
-  if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
-    ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
-  else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
-    ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
-  else if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
-    ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs);
-  */
-  PendingLazySpecializationIDs.clear();
 
   // Load the pending visible updates for this decl context, if it has any.
   auto I = PendingVisibleUpdates.find(ID);
@@ -4547,9 +4484,7 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
   }
 }
 
-void ASTDeclReader::UpdateDecl(
-    Decl *D,
-    SmallVectorImpl<LazySpecializationInfo> &PendingLazySpecializationIDs) {
+void ASTDeclReader::UpdateDecl(Decl *D) {
   while (Record.getIdx() < Record.size()) {
     switch ((DeclUpdateKind)Record.readInt()) {
     case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
@@ -4560,11 +4495,6 @@ void ASTDeclReader::UpdateDecl(
       break;
     }
 
-    case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
-      // It will be added to the template's lazy specialization set.
-      PendingLazySpecializationIDs.push_back(ReadLazySpecializationInfo());
-      break;
-
     case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
       auto *Anon = readDeclAs<NamespaceDecl>();
 
diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h
index 43b8aa41f91a20..30bc8ead8b04f0 100644
--- a/clang/lib/Serialization/ASTReaderInternals.h
+++ b/clang/lib/Serialization/ASTReaderInternals.h
@@ -129,7 +129,6 @@ struct LazySpecializationInfo {
     assert(ID != Other.ID || IsPartial == Other.IsPartial);
     return ID == Other.ID;
   }
-
   // Records the size record in OnDiskHashTable.
   // sizeof() may return 8 due to align requirements.
   static constexpr unsigned Length = sizeof(DeclID) + sizeof(IsPartial);
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index aed09cd741efba..0b0c555ff1b65f 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -13,6 +13,7 @@
 #include "ASTCommon.h"
 #include "ASTReaderInternals.h"
 #include "MultiOnDiskHashTable.h"
+#include "TemplateArgumentHasher.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTUnresolvedSet.h"
 #include "clang/AST/AbstractTypeWriter.h"
@@ -4208,7 +4209,7 @@ unsigned CalculateODRHashForSpecs(const Decl *Spec) {
   else
     llvm_unreachable("New Specialization Kind?");
 
-  return TemplateArgumentList::ComputeODRHash(Args);
+  return StableHashForTemplateArguments(Args);
 }
 } // namespace
 
@@ -5870,7 +5871,7 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
 
 void ASTWriter::WriteSpecializationsUpdates() {
   auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
-  Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_SPECIALIZATION));
+  Abv->Add(llvm::BitCodeAbbrevOp(CXX_ADDED_TEMPLATE_SPECIALIZATION));
   Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
   Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
   auto UpdateSpecializationAbbrev = Stream.EmitAbbrev(std::move(Abv));
@@ -5883,7 +5884,8 @@ void ASTWriter::WriteSpecializationsUpdates() {
                                           LookupTable);
 
     // Write the lookup table
-    RecordData::value_type Record[] = {UPDATE_SPECIALIZATION, getDeclID(D).getRawValue()};
+    RecordData::value_type Record[] = {CXX_ADDED_TEMPLATE_SPECIALIZATION,
+                                       getDeclID(D).getRawValue()};
     Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
   }
 }
@@ -5920,25 +5922,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
         assert(Update.getDecl() && "no decl to add?");
         Record.AddDeclRef(Update.getDecl());
         break;
-      case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: {
-        const Decl *Spec = Update.getDecl();
-        assert(Spec && "no decl to add?");
-        Record.AddDeclRef(Spec);
-        ArrayRef<TemplateArgument> Args;
-        if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Spec))
-          Args = CTSD->getTemplateArgs().asArray();
-        else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Spec))
-          Args = VTSD->getTemplateArgs().asArray();
-        else if (auto *FD = dyn_cast<FunctionDecl>(Spec))
-          Args = FD->getTemplateSpecializationArgs()->asArray();
-        assert(Args.size());
-        Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
-        bool IsPartialSpecialization =
-            isa<ClassTemplatePartialSpecializationDecl>(Spec) ||
-            isa<VarTemplatePartialSpecializationDecl>(Spec);
-        Record.push_back(IsPartialSpecialization);
-        break;
-      }
       case UPD_CXX_ADDED_FUNCTION_DEFINITION:
       case UPD_CXX_ADDED_VAR_DEFINITION:
         break;
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index d14889271fd326..a334c459cc892c 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -216,24 +216,8 @@ namespace clang {
       llvm::MapVector<ModuleFile *, const Decl *> Firsts;
       CollectFirstDeclFromEachModule(D, /*IncludeLocal*/ true, Firsts);
 
-      for (const auto &F : Firsts) {
+      for (const auto &F : Firsts)
         SpecsInMap.push_back(F.second);
-
-        Record.AddDeclRef(F.second);
-        ArrayRef<TemplateArgument> Args;
-        if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
-          Args = CTSD->getTemplateArgs().asArray();
-        else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D))
-          Args = VTSD->getTemplateArgs().asArray();
-        else if (auto *FD = dyn_cast<FunctionDecl>(D))
-          Args = FD->getTemplateSpecializationArgs()->asArray();
-        assert(Args.size());
-        Record.push_back(TemplateArgumentList::ComputeODRHash(Args));
-        bool IsPartialSpecialization =
-            isa<ClassTemplatePartialSpecializationDecl>(D) ||
-            isa<VarTemplatePartialSpecializationDecl>(D);
-        Record.push_back(IsPartialSpecialization);
-      }
     }
 
     /// Get the specialization decl from an entry in the specialization list.
@@ -260,22 +244,12 @@ namespace clang {
       // If we have any lazy specializations, and the external AST source is
       // our chained AST reader, we can just write out the DeclIDs. Otherwise,
       // we need to resolve them to actual declarations.
-      if (Writer.Chain != Writer.Context->getExternalSource() &&
-          Common->LazySpecializations) {
+      if (Writer.Chain != Writer.Context->getExternalSource() && Writer.Chain &&
+          Writer.Chain->getLoadedSpecializationsLookupTables(D)) {
         D->LoadLazySpecializations();
-        assert(!Common->LazySpecializations);
+        assert(!Writer.Chain->getLoadedSpecializationsLookupTables(D));
       }
 
-      using LazySpecializationInfo =
-          RedeclarableTemplateDecl::LazySpecializationInfo;
-      ArrayRef<LazySpecializationInfo> LazySpecializations;
-      if (auto *LS = Common->LazySpecializations)
-        LazySpecializations = llvm::ArrayRef(LS + 1, LS[0].DeclID.getRawValue());
-
-      // Add a slot to the record for the number of specializations.
-      unsigned I = Record.size();
-      Record.push_back(0);
-
       // AddFirstDeclFromEachModule might trigger deserialization, invalidating
       // *Specializations iterators.
       llvm::SmallVector<const Decl*, 16> Specs;
@@ -291,21 +265,6 @@ namespace clang {
         AddFirstSpecializationDeclFromEachModule(D, SpecsInOnDiskMap);
       }
 
-      // We don't need to insert LazySpecializations to SpecsInOnDiskMap,
-      // since we'll handle that in GenerateSpecializationInfoLookupTable.
-      for (auto &SpecInfo : LazySpecializations) {
-        Record.push_back(SpecInfo.DeclID.getRawValue());
-        Record.push_back(SpecInfo.ODRHash);
-        Record.push_back(SpecInfo.IsPartial);
-      }
-
-      // Update the size entry we added earlier. We linerized the
-      // LazySpecializationInfo members and we need to adjust the size as we
-      // will read them always together.
-      assert((Record.size() - I - 1) % 3 == 0 &&
-             "Must be divisible by LazySpecializationInfo count!");
-      Record[I] = (Record.size() - I - 1) / 3;
-
       Record.AddOffset(
           Writer.WriteSpecializationInfoLookupTable(D, SpecsInOnDiskMap));
     }
@@ -328,9 +287,6 @@ namespace clang {
       if (Writer.getFirstLocalDecl(Specialization) != Specialization)
         return;
 
-      Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate(
-          UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization));
-
       Writer.SpecializationsUpdates[cast<NamedDecl>(Template)].push_back(
           cast<NamedDecl>(Specialization));
     }
diff --git a/clang/lib/Serialization/CMakeLists.txt b/clang/lib/Serialization/CMakeLists.txt
index 5a4b3a58e9c45e..59a95546ec57dc 100644
--- a/clang/lib/Serialization/CMakeLists.txt
+++ b/clang/lib/Serialization/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangSerialization
   ModuleFileExtension.cpp
   ModuleManager.cpp
   PCHContainerOperations.cpp
+  TemplateArgumentHasher.cpp
 
   ADDITIONAL_HEADERS
   ASTCommon.h
diff --git a/clang/lib/Serialization/TemplateArgumentHasher.cpp b/clang/lib/Serialization/TemplateArgumentHasher.cpp
new file mode 100644
index 00000000000000..de0d8633a5c54e
--- /dev/null
+++ b/clang/lib/Serialization/TemplateArgumentHasher.cpp
@@ -0,0 +1,423 @@
+//===- TemplateArgumentHasher.cpp - Hash Template Arguments -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TemplateArgumentHasher.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/FoldingSet.h"
+
+using namespace clang;
+
+namespace {
+
+class TemplateArgumentHasher {
+  // If we bail out during the process of calculating hash values for
+  // template arguments for any reason. We're allowed to do it since
+  // TemplateArgumentHasher are only required to give the same hash value
+  // for the same template arguments, but not required to give different
+  // hash value for different template arguments.
+  //
+  // So in the worst case, it is still a valid implementation to give all
+  // inputs the same BailedOutValue as output.
+  bool BailedOut = false;
+  static constexpr unsigned BailedOutValue = 0x12345678;
+
+  llvm::FoldingSetNodeID ID;
+public:
+  TemplateArgumentHasher() = default;
+
+  void AddTemplateArgument(TemplateArgument TA);
+
+  void AddInteger(unsigned V) {
+    ID.AddInteger(V);
+  }
+
+  unsigned getValue() {
+    if (BailedOut)
+      return BailedOutValue;
+    
+    return ID.computeStableHash();
+  }
+
+  void setBailedOut() { BailedOut = true; }
+
+  void AddType(const Type *T);
+  void AddQualType(QualType T);
+  void AddDecl(const Decl *D);
+  void AddStructuralValue(const APValue &);
+  void AddTemplateName(TemplateName Name);
+  void AddDeclarationName(DeclarationName Name);
+  void AddIdentifierInfo(const IdentifierInfo *II);
+};
+
+void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) {
+  const auto Kind = TA.getKind();
+  AddInteger(Kind);
+
+  switch (Kind) {
+    case TemplateArgument::Null:
+      llvm_unreachable("Expected valid TemplateArgument");
+    case TemplateArgument::Type:
+      AddQualType(TA.getAsType());
+      break;
+    case TemplateArgument::Declaration:
+      AddDecl(TA.getAsDecl());
+      break;
+    case TemplateArgument::NullPtr:
+      ID.AddPointer(nullptr);
+      break;
+    case TemplateArgument::Integral: {
+      // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
+      // any builtin integral type, so we use the hash of APSInt instead.
+      TA.getAsIntegral().Profile(ID);
+      break;
+    }
+    case TemplateArgument::StructuralValue:
+      AddQualType(TA.getStructuralValueType());
+      AddStructuralValue(TA.getAsStructuralValue());
+      break;
+    case TemplateArgument::Template:
+    case TemplateArgument::TemplateExpansion:
+      AddTemplateName(TA.getAsTemplateOrTemplatePattern());
+      break;
+    case TemplateArgument::Expression:
+      // If we meet expression in template argument, it implies
+      // that the template is still dependent. It is meaningless
+      // to get a stable hash for the template. Bail out simply.
+      BailedOut = true;
+      break;
+    case TemplateArgument::Pack:
+      AddInteger(TA.pack_size());
+      for (auto SubTA : TA.pack_elements()) {
+        AddTemplateArgument(SubTA);
+      }
+      break;
+  }
+}
+
+void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) {
+  auto Kind = Value.getKind();
+  AddInteger(Kind);
+
+  // 'APValue::Profile' uses pointer values to make hash for LValue and
+  // MemberPointer, but they differ from one compiler invocation to another.
+  // It may be difficult to handle such cases. Bail out simply.
+
+  if (Kind == APValue::LValue || Kind == APValue::MemberPointer) {
+    BailedOut = true;
+    return;
+  }
+
+  Value.Profile(ID);
+}
+
+void TemplateArgumentHasher::AddTemplateName(TemplateName Name) {
+  switch (Name.getKind()) {
+  case TemplateName::Template:
+    AddDecl(Name.getAsTemplateDecl());
+    break;
+  case TemplateName::QualifiedTemplate: {
+    QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
+    AddTemplateName(QTN->getUnderlyingTemplate());
+    break;
+  }
+  case TemplateName::OverloadedTemplate:
+  case TemplateName::AssumedTemplate:
+  case TemplateName::DependentTemplate:
+  case TemplateName::SubstTemplateTemplateParm:
+  case TemplateName::SubstTemplateTemplateParmPack:
+    BailedOut = true;
+    break;
+  case TemplateName::UsingTemplate:
+    UsingShadowDecl *USD = Name.getAsUsingShadowDecl();
+    if (USD)
+      AddDecl(USD->getTargetDecl());
+    else
+      BailedOut = true;
+    break;
+  }
+}
+
+void TemplateArgumentHasher::AddIdentifierInfo(const IdentifierInfo *II) {
+  assert(II && "Expecting non-null pointer.");
+  ID.AddString(II->getName());
+}
+
+void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) {
+  if (Name.isEmpty())
+    return;
+
+  switch(Name.getNameKind()) {
+  case DeclarationName::Identifier:
+    AddIdentifierInfo(Name.getAsIdentifierInfo());
+    break;
+  case DeclarationName::ObjCZeroArgSelector:
+  case DeclarationName::ObjCOneArgSelector:
+  case DeclarationName::ObjCMultiArgSelector:
+    BailedOut = true;
+    break;
+  case DeclarationName::CXXConstructorName:
+  case DeclarationName::CXXDestructorName:
+    AddQualType(Name.getCXXNameType());
+    break;
+  case DeclarationName::CXXOperatorName:
+    AddInteger(Name.getCXXOverloadedOperator());
+    break;
+  case DeclarationName::CXXLiteralOperatorName:
+    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
+    break;
+  case DeclarationName::CXXConversionFunctionName:
+    AddQualType(Name.getCXXNameType());
+    break;
+  case DeclarationName::CXXUsingDirective:
+    break;
+  case DeclarationName::CXXDeductionGuideName: {
+    if (auto *Template = Name.getCXXDeductionGuideTemplate())
+      AddDecl(Template);
+  }
+  }
+}
+
+void TemplateArgumentHasher::AddDecl(const Decl *D) {
+  const NamedDecl *ND = dyn_cast<NamedDecl>(D);
+  if (!ND) {
+    BailedOut = true;
+    return;
+  }
+
+  AddDeclarationName(ND->getDeclName());
+}
+
+void TemplateArgumentHasher::AddQualType(QualType T) {
+  if (T.isNull()) {
+    BailedOut = true;
+    return;
+  }
+  SplitQualType split = T.split();
+  AddInteger(split.Quals.getAsOpaqueValue());
+  AddType(split.Ty);
+}
+
+// Process a Type pointer.  Add* methods call back into TemplateArgumentHasher
+// while Visit* methods process the relevant parts of the Type.
+// Any unhandled type will make the hash computation bail out.
+class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
+  typedef TypeVisitor<TypeVisitorHelper> Inherited;
+  llvm::FoldingSetNodeID &ID;
+  TemplateArgumentHasher &Hash;
+
+public:
+  TypeVisitorHelper(llvm::FoldingSetNodeID &ID, TemplateArgumentHasher &Hash)
+      : ID(ID), Hash(Hash) {}
+
+  void AddDecl(const Decl *D) {
+    if (D)
+      Hash.AddDecl(D);
+    else
+      Hash.AddInteger(0);
+  }
+
+  void AddQualType(QualType T) {
+    Hash.AddQualType(T);
+  }
+
+  void AddType(const Type *T) {
+    if (T)
+      Hash.AddType(T);
+    else
+      Hash.AddInteger(0);
+  }
+
+  void VisitQualifiers(Qualifiers Quals) {
+    Hash.AddInteger(Quals.getAsOpaqueValue());
+  }
+
+  void Visit(const Type *T) {
+    Inherited::Visit(T);
+  }
+
+  // Unhandled types. Bail out simply.
+  void VisitType(const Type *T) {
+    Hash.setBailedOut();
+  }
+
+  void VisitAdjustedType(const AdjustedType *T) {
+    AddQualType(T->getOriginalType());
+  }
+
+  void VisitDecayedType(const DecayedType *T) {
+    // getDecayedType and getPointeeType are derived from getAdjustedType
+    // and don't need to be separately processed.
+    VisitAdjustedType(T);
+  }
+
+  void VisitArrayType(const ArrayType *T) {
+    AddQualType(T->getElementType());
+    Hash.AddInteger(llvm::to_underlying(T->getSizeModifier()));
+    VisitQualifiers(T->getIndexTypeQualifiers());
+  }
+  void VisitConstantArrayType(const ConstantArrayType *T) {
+    T->getSize().Profile(ID);
+    VisitArrayType(T);
+  }
+
+  void VisitAttributedType(const AttributedType *T) {
+    Hash.AddInteger(T->getAttrKind());
+    AddQualType(T->getModifiedType());
+  }
+
+  void VisitBuiltinType(const BuiltinType *T) {
+    Hash.AddInteger(T->getKind());
+  }
+
+  void VisitComplexType(const ComplexType *T) {
+    AddQualType(T->getElementType());
+  }
+
+  void VisitDecltypeType(const DecltypeType *T) {
+    AddQualType(T->getUnderlyingType());
+  }
+
+  void VisitDeducedType(const DeducedType *T) {
+    AddQualType(T->getDeducedType());
+  }
+
+  void VisitAutoType(const AutoType *T) {
+    VisitDeducedType(T);
+  }
+
+  void VisitDeducedTemplateSpecializationType(
+      const DeducedTemplateSpecializationType *T) {
+    Hash.AddTemplateName(T->getTemplateName());
+    VisitDeducedType(T);
+  }
+
+  void VisitFunctionType(const FunctionType *T) {
+    AddQualType(T->getReturnType());
+    T->getExtInfo().Profile(ID);
+    Hash.AddInteger(T->isConst());
+    Hash.AddInteger(T->isVolatile());
+    Hash.AddInteger(T->isRestrict());
+  }
+
+  void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+    VisitFunctionType(T);
+  }
+
+  void VisitFunctionProtoType(const FunctionProtoType *T) {
+    Hash.AddInteger(T->getNumParams());
+    for (auto ParamType : T->getParamTypes())
+      AddQualType(ParamType);
+
+    VisitFunctionType(T);
+  }
+
+  void VisitMemberPointerType(const MemberPointerType *T) {
+    AddQualType(T->getPointeeType());
+    AddType(T->getClass());
+  }
+
+  void VisitPackExpansionType(const PackExpansionType *T) {
+    AddQualType(T->getPattern());
+  }
+
+  void VisitParenType(const ParenType *T) {
+    AddQualType(T->getInnerType());
+  }
+
+  void VisitPointerType(const PointerType *T) {
+    AddQualType(T->getPointeeType());
+  }
+
+  void VisitReferenceType(const ReferenceType *T) {
+    AddQualType(T->getPointeeTypeAsWritten());
+  }
+
+  void VisitLValueReferenceType(const LValueReferenceType *T) {
+    VisitReferenceType(T);
+  }
+
+  void VisitRValueReferenceType(const RValueReferenceType *T) {
+    VisitReferenceType(T);
+  }
+
+  void
+  VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
+    AddDecl(T->getAssociatedDecl());
+    Hash.AddTemplateArgument(T->getArgumentPack());
+  }
+
+  void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+    AddDecl(T->getAssociatedDecl());
+    AddQualType(T->getReplacementType());
+  }
+
+  void VisitTagType(const TagType *T) {
+    AddDecl(T->getDecl());
+  }
+
+  void VisitRecordType(const RecordType *T) { VisitTagType(T); }
+  void VisitEnumType(const EnumType *T) { VisitTagType(T); }
+
+  void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+    Hash.AddInteger(T->template_arguments().size());
+    for (const auto &TA : T->template_arguments()) {
+      Hash.AddTemplateArgument(TA);
+    }
+    Hash.AddTemplateName(T->getTemplateName());
+  }
+
+  void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+    Hash.AddInteger(T->getDepth());
+    Hash.AddInteger(T->getIndex());
+    Hash.AddInteger(T->isParameterPack());
+  }
+
+  void VisitTypedefType(const TypedefType *T) {
+    AddDecl(T->getDecl());
+  }
+
+  void VisitElaboratedType(const ElaboratedType *T) {
+    AddQualType(T->getNamedType());
+  }
+
+  void VisitUnaryTransformType(const UnaryTransformType *T) {
+    AddQualType(T->getUnderlyingType());
+    AddQualType(T->getBaseType());
+  }
+
+  void VisitVectorType(const VectorType *T) {
+    AddQualType(T->getElementType());
+    Hash.AddInteger(T->getNumElements());
+    Hash.AddInteger(llvm::to_underlying(T->getVectorKind()));
+  }
+
+  void VisitExtVectorType(const ExtVectorType * T) {
+    VisitVectorType(T);
+  }
+};
+
+void TemplateArgumentHasher::AddType(const Type *T) {
+  assert(T && "Expecting non-null pointer.");
+  TypeVisitorHelper(ID, *this).Visit(T);
+}
+
+}
+
+unsigned clang::serialization::StableHashForTemplateArguments(llvm::ArrayRef<TemplateArgument> Args) {
+  TemplateArgumentHasher Hasher;
+  Hasher.AddInteger(Args.size());
+  for (TemplateArgument Arg : Args)
+    Hasher.AddTemplateArgument(Arg);
+  return Hasher.getValue();
+}
diff --git a/clang/lib/Serialization/TemplateArgumentHasher.h b/clang/lib/Serialization/TemplateArgumentHasher.h
new file mode 100644
index 00000000000000..8ead99556be5f2
--- /dev/null
+++ b/clang/lib/Serialization/TemplateArgumentHasher.h
@@ -0,0 +1,34 @@
+//===- TemplateArgumentHasher.h - Hash Template Arguments -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/TemplateBase.h"
+
+namespace clang {
+namespace serialization {
+
+/// Calculate a stable hash value for template arguments. We guarantee that
+/// the same template arguments must have the same hashed values. But we don't
+/// guarantee that the template arguments with the same hashed value are the
+/// same template arguments.
+///
+/// ODR hashing may not be the best mechanism to hash the template
+/// arguments. ODR hashing is (or perhaps, should be) about determining whether
+/// two things are spelled the same way and have the same meaning (as required
+/// by the C++ ODR), whereas what we want here is whether they have the same
+/// meaning regardless of spelling. Maybe we can get away with reusing ODR
+/// hashing anyway, on the basis that any canonical, non-dependent template
+/// argument should have the same (invented) spelling in every translation
+/// unit, but it is not sure that's true in all cases. There may still be cases
+/// where the canonical type includes some aspect of "whatever we saw first",
+/// in which case the ODR hash can differ across translation units for
+/// non-dependent, canonical template arguments that are spelled differently
+/// but have the same meaning. But it is not easy to raise examples.
+unsigned StableHashForTemplateArguments(llvm::ArrayRef<TemplateArgument> Args);
+
+}
+}
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index e10ba7c2ac3ef2..b7d5741e69af61 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -251,7 +251,7 @@ namespace Std {
 
 // CHECK-DUMP:      ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}>  col:{{.*}} in cxx_templates_common SomeTemplate
 // CHECK-DUMP:        ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
-// CHECK-DUMP-NEXT:     TemplateArgument type 'char[1]'
+// CHECK-DUMP-NEXT:     TemplateArgument type 'char[2]'
 // CHECK-DUMP:        ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
 // CHECK-DUMP-NEXT:     DefinitionData
 // CHECK-DUMP-NEXT:       DefaultConstructor
@@ -260,9 +260,9 @@ namespace Std {
 // CHECK-DUMP-NEXT:       CopyAssignment
 // CHECK-DUMP-NEXT:       MoveAssignment
 // CHECK-DUMP-NEXT:       Destructor
-// CHECK-DUMP-NEXT:     TemplateArgument type 'char[1]'
-// CHECK-DUMP:        ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
 // CHECK-DUMP-NEXT:     TemplateArgument type 'char[2]'
+// CHECK-DUMP:        ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
+// CHECK-DUMP-NEXT:     TemplateArgument type 'char[1]'
 // CHECK-DUMP:        ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
 // CHECK-DUMP-NEXT:     DefinitionData
 // CHECK-DUMP-NEXT:       DefaultConstructor
@@ -271,4 +271,4 @@ namespace Std {
 // CHECK-DUMP-NEXT:       CopyAssignment
 // CHECK-DUMP-NEXT:       MoveAssignment
 // CHECK-DUMP-NEXT:       Destructor
-// CHECK-DUMP-NEXT:     TemplateArgument type 'char[2]'
+// CHECK-DUMP-NEXT:     TemplateArgument type 'char[1]'
diff --git a/clang/test/Modules/recursive-instantiations.cppm b/clang/test/Modules/recursive-instantiations.cppm
new file mode 100644
index 00000000000000..d5854b0e647e37
--- /dev/null
+++ b/clang/test/Modules/recursive-instantiations.cppm
@@ -0,0 +1,40 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/type_traits.cppm -emit-module-interface -o %t/type_traits.pcm
+// RUN: %clang_cc1 -std=c++20 %t/test.cpp -fprebuilt-module-path=%t -verify
+
+//--- type_traits.cppm
+export module type_traits;
+
+export template <typename T>
+constexpr bool is_pod_v = __is_pod(T);
+
+//--- test.cpp
+// expected-no-diagnostics
+import type_traits;
+// Base is either void or wrapper<T>.
+template <class Base> struct wrapper : Base {};
+template <> struct wrapper<void> {};
+
+// wrap<0>::type<T> is wrapper<T>, wrap<1>::type<T> is wrapper<wrapper<T>>,
+// and so on.
+template <int N>
+struct wrap {
+  template <class Base>
+  using type = wrapper<typename wrap<N-1>::template type<Base>>;
+};
+
+template <>
+struct wrap<0> {
+  template <class Base>
+  using type = wrapper<Base>;
+};
+
+inline constexpr int kMaxRank = 40;
+template <int N, class Base = void>
+using rank = typename wrap<N>::template type<Base>;
+using rank_selector_t = rank<kMaxRank>;
+
+static_assert(is_pod_v<rank_selector_t>, "Must be POD");
diff --git a/clang/test/OpenMP/target_parallel_ast_print.cpp b/clang/test/OpenMP/target_parallel_ast_print.cpp
index 7e27ac7b92ca4a..3ee98bc525c1bd 100644
--- a/clang/test/OpenMP/target_parallel_ast_print.cpp
+++ b/clang/test/OpenMP/target_parallel_ast_print.cpp
@@ -38,10 +38,6 @@ struct S {
 // CHECK:        static int TS;
 // CHECK-NEXT:   #pragma omp threadprivate(S<int>::TS)
 // CHECK-NEXT: }
-// CHECK:      template<> struct S<char> {
-// CHECK:        static char TS;
-// CHECK-NEXT:   #pragma omp threadprivate(S<char>::TS)
-// CHECK-NEXT: }
 
 template <typename T, int C>
 T tmain(T argc, T *argv) {
diff --git a/clang/test/OpenMP/target_teams_ast_print.cpp b/clang/test/OpenMP/target_teams_ast_print.cpp
index 2ff34e4498bfe1..358200bd57c182 100644
--- a/clang/test/OpenMP/target_teams_ast_print.cpp
+++ b/clang/test/OpenMP/target_teams_ast_print.cpp
@@ -40,10 +40,6 @@ struct S {
 // CHECK:        static int TS;
 // CHECK-NEXT:   #pragma omp threadprivate(S<int>::TS)
 // CHECK-NEXT: }
-// CHECK:      template<> struct S<long> {
-// CHECK:        static long TS;
-// CHECK-NEXT:   #pragma omp threadprivate(S<long>::TS)
-// CHECK-NEXT: }
 
 template <typename T, int C>
 T tmain(T argc, T *argv) {
diff --git a/clang/test/OpenMP/task_ast_print.cpp b/clang/test/OpenMP/task_ast_print.cpp
index 2a6b8908a1e2dc..30fb7ab75cc87a 100644
--- a/clang/test/OpenMP/task_ast_print.cpp
+++ b/clang/test/OpenMP/task_ast_print.cpp
@@ -87,10 +87,6 @@ struct S {
 // CHECK:        static int TS;
 // CHECK-NEXT:   #pragma omp threadprivate(S<int>::TS)
 // CHECK-NEXT: }
-// CHECK:      template<> struct S<long> {
-// CHECK:        static long TS;
-// CHECK-NEXT:   #pragma omp threadprivate(S<long>::TS)
-// CHECK-NEXT: }
 
 template <typename T, int C>
 T tmain(T argc, T *argv) {
diff --git a/clang/test/OpenMP/teams_ast_print.cpp b/clang/test/OpenMP/teams_ast_print.cpp
index 0087f71ac9f742..597a9b2bdbdc5d 100644
--- a/clang/test/OpenMP/teams_ast_print.cpp
+++ b/clang/test/OpenMP/teams_ast_print.cpp
@@ -27,10 +27,6 @@ struct S {
 // CHECK:        static int TS;
 // CHECK-NEXT:   #pragma omp threadprivate(S<int>::TS)
 // CHECK-NEXT: }
-// CHECK:      template<> struct S<long> {
-// CHECK:        static long TS;
-// CHECK-NEXT:   #pragma omp threadprivate(S<long>::TS)
-// CHECK-NEXT: }
 
 template <typename T, int C>
 T tmain(T argc, T *argv) {

>From e883be85e91243137ca4c44a8b78f4617f9dba54 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Wed, 10 Jul 2024 17:52:56 +0800
Subject: [PATCH 2/7] fmt

---
 clang/lib/Serialization/ASTReader.cpp         |   5 +-
 .../Serialization/TemplateArgumentHasher.cpp  | 122 ++++++++----------
 .../Serialization/TemplateArgumentHasher.h    |   4 +-
 3 files changed, 57 insertions(+), 74 deletions(-)

diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f75d8fc4676b32..bd0ebda69b0d8a 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7697,7 +7697,8 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
 
   if (Template) {
     // For partitial specialization, load all the specializations for safety.
-    if (isa<ClassTemplatePartialSpecializationDecl, VarTemplatePartialSpecializationDecl>(D))
+    if (isa<ClassTemplatePartialSpecializationDecl,
+            VarTemplatePartialSpecializationDecl>(D))
       Template->loadLazySpecializationsImpl();
     else
       Template->loadLazySpecializationsImpl(Args);
@@ -8033,7 +8034,7 @@ bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
   // the lookup table.
   if (!OnlyPartial)
     SpecializationsLookups.erase(It);
-  
+
   bool NewSpecsFound = false;
   Deserializing LookupResults(this);
   for (auto &Info : Infos)
diff --git a/clang/lib/Serialization/TemplateArgumentHasher.cpp b/clang/lib/Serialization/TemplateArgumentHasher.cpp
index de0d8633a5c54e..ab7ea262cddf61 100644
--- a/clang/lib/Serialization/TemplateArgumentHasher.cpp
+++ b/clang/lib/Serialization/TemplateArgumentHasher.cpp
@@ -33,19 +33,18 @@ class TemplateArgumentHasher {
   static constexpr unsigned BailedOutValue = 0x12345678;
 
   llvm::FoldingSetNodeID ID;
+
 public:
   TemplateArgumentHasher() = default;
 
   void AddTemplateArgument(TemplateArgument TA);
 
-  void AddInteger(unsigned V) {
-    ID.AddInteger(V);
-  }
+  void AddInteger(unsigned V) { ID.AddInteger(V); }
 
   unsigned getValue() {
     if (BailedOut)
       return BailedOutValue;
-    
+
     return ID.computeStableHash();
   }
 
@@ -65,43 +64,43 @@ void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) {
   AddInteger(Kind);
 
   switch (Kind) {
-    case TemplateArgument::Null:
-      llvm_unreachable("Expected valid TemplateArgument");
-    case TemplateArgument::Type:
-      AddQualType(TA.getAsType());
-      break;
-    case TemplateArgument::Declaration:
-      AddDecl(TA.getAsDecl());
-      break;
-    case TemplateArgument::NullPtr:
-      ID.AddPointer(nullptr);
-      break;
-    case TemplateArgument::Integral: {
-      // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
-      // any builtin integral type, so we use the hash of APSInt instead.
-      TA.getAsIntegral().Profile(ID);
-      break;
+  case TemplateArgument::Null:
+    llvm_unreachable("Expected valid TemplateArgument");
+  case TemplateArgument::Type:
+    AddQualType(TA.getAsType());
+    break;
+  case TemplateArgument::Declaration:
+    AddDecl(TA.getAsDecl());
+    break;
+  case TemplateArgument::NullPtr:
+    ID.AddPointer(nullptr);
+    break;
+  case TemplateArgument::Integral: {
+    // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
+    // any builtin integral type, so we use the hash of APSInt instead.
+    TA.getAsIntegral().Profile(ID);
+    break;
+  }
+  case TemplateArgument::StructuralValue:
+    AddQualType(TA.getStructuralValueType());
+    AddStructuralValue(TA.getAsStructuralValue());
+    break;
+  case TemplateArgument::Template:
+  case TemplateArgument::TemplateExpansion:
+    AddTemplateName(TA.getAsTemplateOrTemplatePattern());
+    break;
+  case TemplateArgument::Expression:
+    // If we meet expression in template argument, it implies
+    // that the template is still dependent. It is meaningless
+    // to get a stable hash for the template. Bail out simply.
+    BailedOut = true;
+    break;
+  case TemplateArgument::Pack:
+    AddInteger(TA.pack_size());
+    for (auto SubTA : TA.pack_elements()) {
+      AddTemplateArgument(SubTA);
     }
-    case TemplateArgument::StructuralValue:
-      AddQualType(TA.getStructuralValueType());
-      AddStructuralValue(TA.getAsStructuralValue());
-      break;
-    case TemplateArgument::Template:
-    case TemplateArgument::TemplateExpansion:
-      AddTemplateName(TA.getAsTemplateOrTemplatePattern());
-      break;
-    case TemplateArgument::Expression:
-      // If we meet expression in template argument, it implies
-      // that the template is still dependent. It is meaningless
-      // to get a stable hash for the template. Bail out simply.
-      BailedOut = true;
-      break;
-    case TemplateArgument::Pack:
-      AddInteger(TA.pack_size());
-      for (auto SubTA : TA.pack_elements()) {
-        AddTemplateArgument(SubTA);
-      }
-      break;
+    break;
   }
 }
 
@@ -157,7 +156,7 @@ void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) {
   if (Name.isEmpty())
     return;
 
-  switch(Name.getNameKind()) {
+  switch (Name.getNameKind()) {
   case DeclarationName::Identifier:
     AddIdentifierInfo(Name.getAsIdentifierInfo());
     break;
@@ -227,9 +226,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
       Hash.AddInteger(0);
   }
 
-  void AddQualType(QualType T) {
-    Hash.AddQualType(T);
-  }
+  void AddQualType(QualType T) { Hash.AddQualType(T); }
 
   void AddType(const Type *T) {
     if (T)
@@ -242,14 +239,10 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     Hash.AddInteger(Quals.getAsOpaqueValue());
   }
 
-  void Visit(const Type *T) {
-    Inherited::Visit(T);
-  }
+  void Visit(const Type *T) { Inherited::Visit(T); }
 
   // Unhandled types. Bail out simply.
-  void VisitType(const Type *T) {
-    Hash.setBailedOut();
-  }
+  void VisitType(const Type *T) { Hash.setBailedOut(); }
 
   void VisitAdjustedType(const AdjustedType *T) {
     AddQualType(T->getOriginalType());
@@ -276,9 +269,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     AddQualType(T->getModifiedType());
   }
 
-  void VisitBuiltinType(const BuiltinType *T) {
-    Hash.AddInteger(T->getKind());
-  }
+  void VisitBuiltinType(const BuiltinType *T) { Hash.AddInteger(T->getKind()); }
 
   void VisitComplexType(const ComplexType *T) {
     AddQualType(T->getElementType());
@@ -292,9 +283,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     AddQualType(T->getDeducedType());
   }
 
-  void VisitAutoType(const AutoType *T) {
-    VisitDeducedType(T);
-  }
+  void VisitAutoType(const AutoType *T) { VisitDeducedType(T); }
 
   void VisitDeducedTemplateSpecializationType(
       const DeducedTemplateSpecializationType *T) {
@@ -331,9 +320,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     AddQualType(T->getPattern());
   }
 
-  void VisitParenType(const ParenType *T) {
-    AddQualType(T->getInnerType());
-  }
+  void VisitParenType(const ParenType *T) { AddQualType(T->getInnerType()); }
 
   void VisitPointerType(const PointerType *T) {
     AddQualType(T->getPointeeType());
@@ -362,9 +349,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     AddQualType(T->getReplacementType());
   }
 
-  void VisitTagType(const TagType *T) {
-    AddDecl(T->getDecl());
-  }
+  void VisitTagType(const TagType *T) { AddDecl(T->getDecl()); }
 
   void VisitRecordType(const RecordType *T) { VisitTagType(T); }
   void VisitEnumType(const EnumType *T) { VisitTagType(T); }
@@ -383,9 +368,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     Hash.AddInteger(T->isParameterPack());
   }
 
-  void VisitTypedefType(const TypedefType *T) {
-    AddDecl(T->getDecl());
-  }
+  void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); }
 
   void VisitElaboratedType(const ElaboratedType *T) {
     AddQualType(T->getNamedType());
@@ -402,9 +385,7 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> {
     Hash.AddInteger(llvm::to_underlying(T->getVectorKind()));
   }
 
-  void VisitExtVectorType(const ExtVectorType * T) {
-    VisitVectorType(T);
-  }
+  void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); }
 };
 
 void TemplateArgumentHasher::AddType(const Type *T) {
@@ -412,9 +393,10 @@ void TemplateArgumentHasher::AddType(const Type *T) {
   TypeVisitorHelper(ID, *this).Visit(T);
 }
 
-}
+} // namespace
 
-unsigned clang::serialization::StableHashForTemplateArguments(llvm::ArrayRef<TemplateArgument> Args) {
+unsigned clang::serialization::StableHashForTemplateArguments(
+    llvm::ArrayRef<TemplateArgument> Args) {
   TemplateArgumentHasher Hasher;
   Hasher.AddInteger(Args.size());
   for (TemplateArgument Arg : Args)
diff --git a/clang/lib/Serialization/TemplateArgumentHasher.h b/clang/lib/Serialization/TemplateArgumentHasher.h
index 8ead99556be5f2..f23f1318afbbf4 100644
--- a/clang/lib/Serialization/TemplateArgumentHasher.h
+++ b/clang/lib/Serialization/TemplateArgumentHasher.h
@@ -30,5 +30,5 @@ namespace serialization {
 /// but have the same meaning. But it is not easy to raise examples.
 unsigned StableHashForTemplateArguments(llvm::ArrayRef<TemplateArgument> Args);
 
-}
-}
+} // namespace serialization
+} // namespace clang

>From 61c451d2cce4d9b613de93aedd3f3fd4dcc296ee Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Tue, 27 Aug 2024 13:37:34 +0800
Subject: [PATCH 3/7] load specializations before writing specialization decls

---
 clang/lib/Serialization/ASTWriterDecl.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index a334c459cc892c..bdcf26ccd67e5f 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1759,6 +1759,12 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
 
 void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
                                            ClassTemplateSpecializationDecl *D) {
+  // FIXME: We need to load the "logical" first declaration before writing
+  // the Redeclarable part. But it may be too expensive to load all the
+  // specializations. Maybe we can find a way to load the "logical" first
+  // declaration only. Or we should try to solve this on the reader side.
+  D->getSpecializedTemplate()->specializations();
+
   RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
 
   VisitCXXRecordDecl(D);
@@ -1827,6 +1833,12 @@ void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
 
 void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
     VarTemplateSpecializationDecl *D) {
+  // FIXME: We need to load the "logical" first declaration before writing
+  // the Redeclarable part. But it may be too expensive to load all the
+  // specializations. Maybe we can find a way to load the "logical" first
+  // declaration only. Or we should try to solve this on the reader side.
+  D->getSpecializedTemplate()->specializations();
+
   RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
 
   llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>

>From 965ed85055aca6123f1b0b060fd2ef5c9bbfd9fe Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Tue, 27 Aug 2024 13:38:52 +0800
Subject: [PATCH 4/7] address comments

---
 clang/lib/Serialization/ASTReaderInternals.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h
index 30bc8ead8b04f0..0611255b7858d8 100644
--- a/clang/lib/Serialization/ASTReaderInternals.h
+++ b/clang/lib/Serialization/ASTReaderInternals.h
@@ -125,7 +125,7 @@ struct LazySpecializationInfo {
   // Whether or not this specialization is partial.
   bool IsPartial;
 
-  bool operator==(const LazySpecializationInfo &Other) {
+  bool operator==(const LazySpecializationInfo &Other) const {
     assert(ID != Other.ID || IsPartial == Other.IsPartial);
     return ID == Other.ID;
   }

>From 88c9d8c05b97ad0c7cc1521ff9ba171504da1531 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Wed, 28 Aug 2024 14:26:23 +0800
Subject: [PATCH 5/7] Revert "load specializations before writing
 specialization decls"

This reverts commit 61c451d2cce4d9b613de93aedd3f3fd4dcc296ee.
---
 clang/lib/Serialization/ASTWriterDecl.cpp | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index bdcf26ccd67e5f..a334c459cc892c 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1759,12 +1759,6 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
 
 void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
                                            ClassTemplateSpecializationDecl *D) {
-  // FIXME: We need to load the "logical" first declaration before writing
-  // the Redeclarable part. But it may be too expensive to load all the
-  // specializations. Maybe we can find a way to load the "logical" first
-  // declaration only. Or we should try to solve this on the reader side.
-  D->getSpecializedTemplate()->specializations();
-
   RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
 
   VisitCXXRecordDecl(D);
@@ -1833,12 +1827,6 @@ void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) {
 
 void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
     VarTemplateSpecializationDecl *D) {
-  // FIXME: We need to load the "logical" first declaration before writing
-  // the Redeclarable part. But it may be too expensive to load all the
-  // specializations. Maybe we can find a way to load the "logical" first
-  // declaration only. Or we should try to solve this on the reader side.
-  D->getSpecializedTemplate()->specializations();
-
   RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
 
   llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>

>From 89a8d1bfc0c40a2afe5276858b4a2961c62c5e4e Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Wed, 28 Aug 2024 15:45:02 +0800
Subject: [PATCH 6/7] Do not omit data from imported modules with same key

---
 clang/lib/Serialization/ASTWriter.cpp          | 6 +++++-
 clang/lib/Serialization/MultiOnDiskHashTable.h | 4 ++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 0b0c555ff1b65f..e07cc2697fb545 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4245,7 +4245,11 @@ void ASTWriter::GenerateSpecializationInfoLookupTable(
 
   auto *Lookups =
       Chain ? Chain->getLoadedSpecializationsLookupTables(D) : nullptr;
-  Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);
+  // We can't OmitDataWithSameKeyInBase since the lazy load specialization
+  // mechanism assumes that different specializations can share the same
+  // hash key.
+  Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr,
+                 /*OmitDataWithSameKeyInBase=*/false);
 }
 
 uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
diff --git a/clang/lib/Serialization/MultiOnDiskHashTable.h b/clang/lib/Serialization/MultiOnDiskHashTable.h
index a0d75ec3a9e76e..76910f4d1e21b9 100644
--- a/clang/lib/Serialization/MultiOnDiskHashTable.h
+++ b/clang/lib/Serialization/MultiOnDiskHashTable.h
@@ -306,7 +306,7 @@ class MultiOnDiskHashTableGenerator {
   }
 
   void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info,
-            const BaseTable *Base) {
+            const BaseTable *Base, bool OmitDataWithSameKeyInBase = true) {
     using namespace llvm::support;
 
     llvm::raw_svector_ostream OutStream(Out);
@@ -326,7 +326,7 @@ class MultiOnDiskHashTableGenerator {
 
         // Add all merged entries from Base to the generator.
         for (auto &KV : Merged->Data) {
-          if (!Gen.contains(KV.first, Info))
+          if (!OmitDataWithSameKeyInBase || !Gen.contains(KV.first, Info))
             Gen.insert(KV.first, Info.ImportData(KV.second), Info);
         }
       } else {

>From 201865d57a2ebbb1a4a133eedcd0bd428853a530 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Tue, 24 Sep 2024 18:24:35 +0800
Subject: [PATCH 7/7] Handle merging spec info manually

---
 clang/lib/Serialization/ASTWriter.cpp         | 28 +++++++++++++------
 .../lib/Serialization/MultiOnDiskHashTable.h  |  4 +--
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index e07cc2697fb545..d5511d8d0ebd09 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4131,7 +4131,7 @@ class LazySpecializationInfoLookupTrait {
   explicit LazySpecializationInfoLookupTrait(ASTWriter &Writer)
       : Writer(Writer) {}
 
-  template <typename Col> data_type getData(Col &&C) {
+  template <typename Col, typename Col2> data_type getData(Col &&C, Col2 &ExistingInfo) {
     unsigned Start = Specs.size();
     for (auto *D : C) {
       bool IsPartial = isa<ClassTemplatePartialSpecializationDecl,
@@ -4141,6 +4141,8 @@ class LazySpecializationInfoLookupTrait {
       Specs.push_back({GlobalDeclID(Writer.GetDeclRef(ND).getRawValue()),
                        IsPartial});
     }
+    for (const serialization::reader::LazySpecializationInfo &Info : ExistingInfo)
+      Specs.push_back(Info);
     return std::make_pair(Start, Specs.size());
   }
 
@@ -4240,16 +4242,24 @@ void ASTWriter::GenerateSpecializationInfoLookupTable(
     Iter->second.push_back(cast<NamedDecl>(Specialization));
   }
 
-  for (auto Iter : SpecializationMaps)
-    Generator.insert(Iter.first, Trait.getData(Iter.second), Trait);
-
   auto *Lookups =
       Chain ? Chain->getLoadedSpecializationsLookupTables(D) : nullptr;
-  // We can't OmitDataWithSameKeyInBase since the lazy load specialization
-  // mechanism assumes that different specializations can share the same
-  // hash key.
-  Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr,
-                 /*OmitDataWithSameKeyInBase=*/false);
+
+  for (auto &[HashValue, Specs] : SpecializationMaps) {
+    SmallVector<serialization::reader::LazySpecializationInfo, 16> ExisitingSpecs;
+    // We have to merge the lookup table manually here. We can't depend on the merge mechanism
+    // offered by clang::serialization::MultiOnDiskHashTableGenerator since that generator
+    // assumes the we'll get the same value with the same key.
+    // And also underlying llvm::OnDiskChainedHashTableGenerator assumes that we won't insert
+    // the values with the same key twice.
+    // So we have to merge the lookup table here manually.
+    if (Lookups)
+      ExisitingSpecs = Lookups->Table.find(HashValue);
+
+    Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait);
+  }
+
+  Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);
 }
 
 uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
diff --git a/clang/lib/Serialization/MultiOnDiskHashTable.h b/clang/lib/Serialization/MultiOnDiskHashTable.h
index 76910f4d1e21b9..a0d75ec3a9e76e 100644
--- a/clang/lib/Serialization/MultiOnDiskHashTable.h
+++ b/clang/lib/Serialization/MultiOnDiskHashTable.h
@@ -306,7 +306,7 @@ class MultiOnDiskHashTableGenerator {
   }
 
   void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info,
-            const BaseTable *Base, bool OmitDataWithSameKeyInBase = true) {
+            const BaseTable *Base) {
     using namespace llvm::support;
 
     llvm::raw_svector_ostream OutStream(Out);
@@ -326,7 +326,7 @@ class MultiOnDiskHashTableGenerator {
 
         // Add all merged entries from Base to the generator.
         for (auto &KV : Merged->Data) {
-          if (!OmitDataWithSameKeyInBase || !Gen.contains(KV.first, Info))
+          if (!Gen.contains(KV.first, Info))
             Gen.insert(KV.first, Info.ImportData(KV.second), Info);
         }
       } else {



More information about the llvm-branch-commits mailing list