[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
Sat Apr 6 23:02:40 PDT 2024


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

>From 40012e175a6ab3420e2dcaa64538b210173d6950 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/2] [Serialization] Code cleanups and polish 83233

---
 clang/include/clang/AST/DeclTemplate.h        | 40 ++-------
 clang/include/clang/AST/ExternalASTSource.h   |  4 +-
 .../clang/Sema/MultiplexExternalSemaSource.h  |  2 +-
 .../include/clang/Serialization/ASTBitCodes.h |  2 +-
 clang/include/clang/Serialization/ASTReader.h |  2 +-
 clang/lib/AST/DeclTemplate.cpp                | 85 +++++++++----------
 clang/lib/AST/ExternalASTSource.cpp           |  6 +-
 .../lib/Sema/MultiplexExternalSemaSource.cpp  |  7 +-
 clang/lib/Serialization/ASTCommon.h           |  1 -
 clang/lib/Serialization/ASTReader.cpp         | 17 ++--
 clang/lib/Serialization/ASTReaderDecl.cpp     | 76 +----------------
 clang/lib/Serialization/ASTReaderInternals.h  |  1 -
 clang/lib/Serialization/ASTWriter.cpp         | 26 +-----
 clang/lib/Serialization/ASTWriterDecl.cpp     | 52 +-----------
 14 files changed, 87 insertions(+), 234 deletions(-)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 51caef54baac26..870c0d1bdd4610 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -256,8 +256,8 @@ 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 stable hash for the given arguments across compiler invocations.
+  static unsigned ComputeStableHash(ArrayRef<TemplateArgument> Args);
 
   /// Create a new template argument list that copies the given set of
   /// template arguments.
@@ -733,25 +733,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   }
 
   void anchor() override;
-  struct LazySpecializationInfo {
-    uint32_t DeclID = ~0U;
-    unsigned ODRHash = ~0U;
-    bool IsPartial = false;
-    LazySpecializationInfo(uint32_t 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 {
@@ -795,16 +776,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);
@@ -820,13 +805,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 af476aa8c57824..769abf44ecd430 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -157,7 +157,9 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
 
   /// 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 f09f037da0556a..2ac8f606ae9574 100644
--- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -99,7 +99,7 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
 
   void 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 20ae6d4bbbcb3f..00992a8d60a880 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -699,7 +699,7 @@ enum ASTRecordTypes {
   /// recorded in a preamble.
   PP_ASSUME_NONNULL_LOC = 67,
 
-  UPDATE_SPECIALIZATION = 68,
+  CXX_ADDED_TEMPLATE_SPECIALIZATION = 68,
 };
 
 /// 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 5640e1eed00388..3608faebe362d9 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2006,7 +2006,7 @@ class ASTReader
 
   void 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 7b98b046d00725..0051841420ae9b 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -342,60 +342,24 @@ 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;
-    for (uint32_t I = 0, N = Specs[0].DeclID; 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");
-
-  uint32_t ID = LazySpecInfo.DeclID;
-  assert(ID && "Loading already loaded specialization!");
-  // Note that we loaded the specialization.
-  LazySpecInfo.DeclID = 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;
-
-  ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(), Args);
-  return;
+    return false;
 
-  CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
-  if (auto *Specs = CommonBasePtr->LazySpecializations) {
-    unsigned Hash = TemplateArgumentList::ComputeODRHash(Args);
-    for (uint32_t I = 0, N = Specs[0].DeclID; 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)...,
@@ -404,6 +368,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,
@@ -939,7 +921,20 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
   return new (Mem) TemplateArgumentList(Args);
 }
 
-unsigned TemplateArgumentList::ComputeODRHash(ArrayRef<TemplateArgument> Args) {
+unsigned
+TemplateArgumentList::ComputeStableHash(ArrayRef<TemplateArgument> Args) {
+  // FIXME: 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.
   ODRHash Hasher;
   for (TemplateArgument TA : Args)
     Hasher.AddTemplateArgument(TA);
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 14a41651360b67..88c524ecd102b7 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -102,8 +102,10 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
 
 void ExternalASTSource::LoadExternalSpecializations(const Decl *D, bool) {}
 
-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/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 397c2b215d2c6d..16484649159b5d 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -121,10 +121,13 @@ void MultiplexExternalSemaSource::LoadExternalSpecializations(
     Sources[i]->LoadExternalSpecializations(D, OnlyPartial);
 }
 
-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 296642e3674a49..485809f234113f 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 79312737c53971..82c7e13eb91cf8 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3501,7 +3501,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
       break;
     }
 
-    case UPDATE_SPECIALIZATION: {
+    case CXX_ADDED_TEMPLATE_SPECIALIZATION: {
       unsigned Idx = 0;
       serialization::DeclID ID = ReadDeclID(F, Record, Idx);
       auto *Data = (const unsigned char *)Blob.data();
@@ -7974,23 +7974,30 @@ void ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) {
       GetDecl(Info.ID);
 }
 
-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 = TemplateArgumentList::ComputeStableHash(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 1ce850faa89c54..2bb9194ae70dd9 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -88,8 +88,6 @@ namespace clang {
     const SourceLocation ThisDeclLoc;
 
     using RecordData = ASTReader::RecordData;
-    using LazySpecializationInfo =
-        RedeclarableTemplateDecl::LazySpecializationInfo;
 
     TypeID DeferredTypeID = 0;
     unsigned AnonymousDeclNumber = 0;
@@ -136,18 +134,6 @@ namespace clang {
       return Record.readString();
     }
 
-    LazySpecializationInfo ReadLazySpecializationInfo() {
-      DeclID 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();
     }
@@ -274,29 +260,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);
-        llvm::sort(IDs);
-        IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
-      }
-      auto *Result = new (C) LazySpecializationInfo[1 + IDs.size()];
-      *Result = IDs.size();
-      std::copy(IDs.begin(), IDs.end(), Result + 1);
-
-      LazySpecializations = Result;
-    }
-
     template <typename DeclT>
     static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
     static Decl *getMostRecentDeclImpl(...);
@@ -328,7 +291,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);
   }
 }
@@ -4218,10 +4172,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);
@@ -4259,7 +4209,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.
@@ -4271,19 +4221,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);
@@ -4501,9 +4438,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: {
@@ -4514,11 +4449,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 7febf0f489c327..792f128be89753 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 = 5;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 01352e38e6bfa4..c980b4a323b2a1 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4060,7 +4060,7 @@ unsigned CalculateODRHashForSpecs(const Decl *Spec) {
   else
     llvm_unreachable("New Specialization Kind?");
 
-  return TemplateArgumentList::ComputeODRHash(Args);
+  return TemplateArgumentList::ComputeStableHash(Args);
 }
 } // namespace
 
@@ -5478,7 +5478,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));
@@ -5491,7 +5491,8 @@ void ASTWriter::WriteSpecializationsUpdates() {
                                           LookupTable);
 
     // Write the lookup table
-    RecordData::value_type Record[] = {UPDATE_SPECIALIZATION, getDeclID(D)};
+    RecordData::value_type Record[] = {CXX_ADDED_TEMPLATE_SPECIALIZATION,
+                                       getDeclID(D)};
     Stream.EmitRecordWithBlob(UpdateSpecializationAbbrev, Record, LookupTable);
   }
 }
@@ -5528,25 +5529,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
         assert(Update.getDecl() && "no decl to add?");
         Record.push_back(GetDeclRef(Update.getDecl()));
         break;
-      case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: {
-        const Decl *Spec = Update.getDecl();
-        assert(Spec && "no decl to add?");
-        Record.push_back(GetDeclRef(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 6a23bb543a0090..ec2163b5283ae4 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -217,24 +217,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.
@@ -261,22 +245,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);
-
-      // 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;
@@ -292,21 +266,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);
-        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));
     }
@@ -329,9 +288,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));
     }

>From 859705c8c7bd6e0b2b7bb500fa5e1794b9f3f335 Mon Sep 17 00:00:00 2001
From: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
Date: Sun, 7 Apr 2024 13:58:37 +0800
Subject: [PATCH 2/2] Avoid computing ODR Hash duplicatly

---
 clang/lib/AST/ODRHash.cpp                     | 10 -----
 .../Modules/recursive-instantiations.cppm     | 40 +++++++++++++++++++
 2 files changed, 40 insertions(+), 10 deletions(-)
 create mode 100644 clang/test/Modules/recursive-instantiations.cppm

diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index b59da315dac105..f4ee8d9d998fe3 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -803,16 +803,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/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");



More information about the llvm-branch-commits mailing list