Skip to content

[Serialization] Support loading template specializations lazily #119333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 11, 2024

Conversation

ChuanqiXu9
Copy link
Member

@ChuanqiXu9 ChuanqiXu9 commented Dec 10, 2024

Reland #83237


(Original comments)

Currently all the specializations of a template (including instantiation, specialization and partial specializations) will be loaded at once if we want to instantiate another instance for the template, or find instantiation for the template, or just want to complete the redecl chain.

This means basically we need to load every specializations for the template once the template declaration got loaded. This is bad since when we load a specialization, we need to load all of its template arguments. Then we have to deserialize a lot of unnecessary declarations.

For example,

// M.cppm
export module M;
export template <class T>
class A {};

export class ShouldNotBeLoaded {};

export class Temp {
   A<ShouldNotBeLoaded> AS;
};

// use.cpp
import M;
A<int> a;

We have a specialization A<ShouldNotBeLoaded> in M.cppm and we instantiate the template A in use.cpp. Then we will deserialize ShouldNotBeLoaded surprisingly when compiling use.cpp. And this patch tries to avoid that.

Given that the templates are heavily used in C++, this is a pain point for the performance.

This patch adds MultiOnDiskHashTable for specializations in the ASTReader. Then we will only deserialize the specializations with the same template arguments. We made that by using ODRHash for the template arguments as the key of the hash table.

To review this patch, I think ASTReaderDecl::AddLazySpecializations may be a good entry point.

@ChuanqiXu9 ChuanqiXu9 added clang:modules C++20 modules and Clang Header Modules skip-precommit-approval PR for CI feedback, not intended for review labels Dec 10, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category lldb clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:openmp OpenMP related changes to Clang labels Dec 10, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 10, 2024

@llvm/pr-subscribers-lldb
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-modules

Author: Chuanqi Xu (ChuanqiXu9)

Changes

Reland #83237


Currently all the specializations of a template (including instantiation, specialization and partial specializations) will be loaded at once if we want to instantiate another instance for the template, or find instantiation for the template, or just want to complete the redecl chain.

This means basically we need to load every specializations for the template once the template declaration got loaded. This is bad since when we load a specialization, we need to load all of its template arguments. Then we have to deserialize a lot of unnecessary declarations.

For example,

// M.cppm
export module M;
export template &lt;class T&gt;
class A {};

export class ShouldNotBeLoaded {};

export class Temp {
   A&lt;ShouldNotBeLoaded&gt; AS;
};

// use.cpp
import M;
A&lt;int&gt; a;

We should a specialization A&lt;ShouldNotBeLoaded&gt; in M.cppm and we instantiate the template A in use.cpp. Then we will deserialize ShouldNotBeLoaded surprisingly when compiling use.cpp. And this patch tries to avoid that.

Given that the templates are heavily used in C++, this is a pain point for the performance.

This patch adds MultiOnDiskHashTable for specializations in the ASTReader. Then we will only deserialize the specializations with the same template arguments. We made that by using ODRHash for the template arguments as the key of the hash table.

To review this patch, I think ASTReaderDecl::AddLazySpecializations may be a good entry point.


Patch is 95.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/119333.diff

29 Files Affected:

  • (modified) clang/include/clang/AST/DeclTemplate.h (+13-10)
  • (modified) clang/include/clang/AST/ExternalASTSource.h (+15)
  • (modified) clang/include/clang/Sema/MultiplexExternalSemaSource.h (+6)
  • (modified) clang/include/clang/Serialization/ASTBitCodes.h (+13)
  • (modified) clang/include/clang/Serialization/ASTReader.h (+45-3)
  • (modified) clang/include/clang/Serialization/ASTWriter.h (+17)
  • (modified) clang/lib/AST/DeclTemplate.cpp (+77-31)
  • (modified) clang/lib/AST/ExternalASTSource.cpp (+9)
  • (modified) clang/lib/AST/ODRHash.cpp (+14-9)
  • (modified) clang/lib/Sema/MultiplexExternalSemaSource.cpp (+17)
  • (modified) clang/lib/Serialization/ASTCommon.h (-1)
  • (modified) clang/lib/Serialization/ASTReader.cpp (+228-9)
  • (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+43-61)
  • (modified) clang/lib/Serialization/ASTReaderInternals.h (+82)
  • (modified) clang/lib/Serialization/ASTWriter.cpp (+206-3)
  • (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+79-31)
  • (modified) clang/lib/Serialization/CMakeLists.txt (+1)
  • (added) clang/lib/Serialization/TemplateArgumentHasher.cpp (+409)
  • (added) clang/lib/Serialization/TemplateArgumentHasher.h (+34)
  • (modified) clang/test/Modules/cxx-templates.cpp (+4-4)
  • (modified) clang/test/Modules/odr_hash.cpp (+2-2)
  • (added) clang/test/Modules/recursive-instantiations.cppm (+40)
  • (modified) clang/test/OpenMP/target_parallel_ast_print.cpp (-4)
  • (modified) clang/test/OpenMP/target_teams_ast_print.cpp (-4)
  • (modified) clang/test/OpenMP/task_ast_print.cpp (-4)
  • (modified) clang/test/OpenMP/teams_ast_print.cpp (-4)
  • (modified) clang/unittests/Serialization/CMakeLists.txt (+1)
  • (added) clang/unittests/Serialization/LoadSpecLazilyTest.cpp (+262)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h (+28)
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index e4bf54c3d77b7f..dd92d40b804232 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -735,6 +735,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   }
 
   void anchor() override;
+
 protected:
   template <typename EntryType> struct SpecEntryTraits {
     using DeclType = EntryType;
@@ -775,13 +776,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
     return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
   }
 
-  void loadLazySpecializationsImpl() const;
+  void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
+
+  bool loadLazySpecializationsImpl(llvm::ArrayRef<TemplateArgument> Args,
+                                   TemplateParameterList *TPL = nullptr) 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);
@@ -796,13 +806,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
     /// was explicitly specialized.
     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.
-    GlobalDeclID *LazySpecializations = nullptr;
   };
 
   /// Pointer to the common data shared by all declarations of this
@@ -2283,7 +2286,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
   friend class TemplateDeclInstantiator;
 
   /// Load any lazily-loaded specializations from the external source.
-  void LoadLazySpecializations() const;
+  void LoadLazySpecializations(bool OnlyPartial = false) const;
 
   /// Get the underlying class declarations of the template.
   CXXRecordDecl *getTemplatedDecl() const {
@@ -3033,7 +3036,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
   friend class ASTDeclWriter;
 
   /// Load any lazily-loaded specializations from the external source.
-  void LoadLazySpecializations() const;
+  void LoadLazySpecializations(bool OnlyPartial = false) const;
 
   /// Get the underlying variable declarations of the template.
   VarDecl *getTemplatedDecl() const {
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 582ed7c65f58ca..9f968ba05b4466 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -152,6 +152,21 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
   virtual bool
   FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
 
+  /// 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.
+  ///
+  /// 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.
+  ///
+  /// Return true if any new specializations get loaded. Return false otherwise.
+  virtual bool
+  LoadExternalSpecializations(const Decl *D,
+                              ArrayRef<TemplateArgument> TemplateArgs);
+
   /// Ensures that the table of all visible declarations inside this
   /// context is up to date.
   ///
diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
index 3d1906d8699265..0c92c52854c9e7 100644
--- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -97,6 +97,12 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
   bool FindExternalVisibleDeclsByName(const DeclContext *DC,
                                       DeclarationName Name) override;
 
+  bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
+
+  bool
+  LoadExternalSpecializations(const Decl *D,
+                              ArrayRef<TemplateArgument> TemplateArgs) override;
+
   /// Ensures that the table of all visible declarations inside this
   /// context is up to date.
   void completeVisibleDeclsMap(const DeclContext *DC) override;
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index fd834c14ce790f..af0e08d800bf28 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -733,6 +733,13 @@ enum ASTRecordTypes {
   /// Record code for Sema's vector of functions/blocks with effects to
   /// be verified.
   DECLS_WITH_EFFECTS_TO_VERIFY = 72,
+
+  /// Record code for updated specialization
+  UPDATE_SPECIALIZATION = 73,
+
+  CXX_ADDED_TEMPLATE_SPECIALIZATION = 74,
+
+  CXX_ADDED_TEMPLATE_PARTIAL_SPECIALIZATION = 75,
 };
 
 /// Record types used within a source manager block.
@@ -1502,6 +1509,12 @@ enum DeclCode {
   /// An ImplicitConceptSpecializationDecl record.
   DECL_IMPLICIT_CONCEPT_SPECIALIZATION,
 
+  // A decls specilization record.
+  DECL_SPECIALIZATIONS,
+
+  // A decls specilization record.
+  DECL_PARTIAL_SPECIALIZATIONS,
+
   DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
 };
 
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index f739fe688c110d..f91052be5e1291 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -354,6 +354,9 @@ class ASTIdentifierLookupTrait;
 /// The on-disk hash table(s) used for DeclContext name lookup.
 struct DeclContextLookupTable;
 
+/// The on-disk hash table(s) used for specialization decls.
+struct LazySpecializationInfoLookupTable;
+
 } // namespace reader
 
 } // namespace serialization
@@ -632,20 +635,40 @@ class ASTReader
   llvm::DenseMap<const DeclContext *,
                  serialization::reader::DeclContextLookupTable> Lookups;
 
+  using SpecLookupTableTy =
+      llvm::DenseMap<const Decl *,
+                     serialization::reader::LazySpecializationInfoLookupTable>;
+  /// Map from decls to specialized decls.
+  SpecLookupTableTy SpecializationsLookups;
+  /// Split partial specialization from specialization to speed up lookups.
+  SpecLookupTableTy PartialSpecializationsLookups;
+
+  bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
+                                       const Decl *D);
+  bool LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups,
+                                       const Decl *D,
+                                       ArrayRef<TemplateArgument> TemplateArgs);
+
   // Updates for visible decls can occur for other contexts than just the
   // TU, and when we read those update records, the actual context may not
   // be available yet, so have this pending map using the ID as a key. It
-  // will be realized when the context is actually loaded.
-  struct PendingVisibleUpdate {
+  // will be realized when the data is actually loaded.
+  struct UpdateData {
     ModuleFile *Mod;
     const unsigned char *Data;
   };
-  using DeclContextVisibleUpdates = SmallVector<PendingVisibleUpdate, 1>;
+  using DeclContextVisibleUpdates = SmallVector<UpdateData, 1>;
 
   /// Updates to the visible declarations of declaration contexts that
   /// haven't been loaded yet.
   llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates;
 
+  using SpecializationsUpdate = SmallVector<UpdateData, 1>;
+  using SpecializationsUpdateMap =
+      llvm::DenseMap<GlobalDeclID, SpecializationsUpdate>;
+  SpecializationsUpdateMap PendingSpecializationsUpdates;
+  SpecializationsUpdateMap PendingPartialSpecializationsUpdates;
+
   /// The set of C++ or Objective-C classes that have forward
   /// declarations that have not yet been linked to their definitions.
   llvm::SmallPtrSet<Decl *, 4> PendingDefinitions;
@@ -678,6 +701,11 @@ class ASTReader
                                      llvm::BitstreamCursor &Cursor,
                                      uint64_t Offset, GlobalDeclID ID);
 
+  bool ReadSpecializations(ModuleFile &M, llvm::BitstreamCursor &Cursor,
+                           uint64_t Offset, Decl *D, bool IsPartial);
+  void AddSpecializations(const Decl *D, const unsigned char *Data,
+                          ModuleFile &M, bool IsPartial);
+
   /// A vector containing identifiers that have already been
   /// loaded.
   ///
@@ -1419,6 +1447,14 @@ class ASTReader
   const serialization::reader::DeclContextLookupTable *
   getLoadedLookupTables(DeclContext *Primary) const;
 
+  /// Get the loaded specializations lookup tables for \p D,
+  /// if any.
+  serialization::reader::LazySpecializationInfoLookupTable *
+  getLoadedSpecializationsLookupTables(const Decl *D, bool IsPartial);
+
+  /// If we have any unloaded specialization for \p D
+  bool haveUnloadedSpecializations(const Decl *D) const;
+
 private:
   struct ImportedModule {
     ModuleFile *Mod;
@@ -2076,6 +2112,12 @@ class ASTReader
                                       unsigned BlockID,
                                       uint64_t *StartOfBlockOffset = nullptr);
 
+  bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial) override;
+
+  bool
+  LoadExternalSpecializations(const Decl *D,
+                              ArrayRef<TemplateArgument> TemplateArgs) override;
+
   /// Finds all the visible declarations with a given name.
   /// The current implementation of this method just loads the entire
   /// lookup table as unmaterialized references.
diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index e418fdea44a0a9..d98d23decbdc0d 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -423,6 +423,13 @@ class ASTWriter : public ASTDeserializationListener,
   /// Only meaningful for reduced BMI.
   DeclUpdateMap DeclUpdatesFromGMF;
 
+  /// Mapping from decl templates and its new specialization in the
+  /// current TU.
+  using SpecializationUpdateMap =
+      llvm::MapVector<const NamedDecl *, SmallVector<const Decl *>>;
+  SpecializationUpdateMap SpecializationsUpdates;
+  SpecializationUpdateMap PartialSpecializationsUpdates;
+
   using FirstLatestDeclMap = llvm::DenseMap<Decl *, Decl *>;
 
   /// Map of first declarations from a chained PCH that point to the
@@ -575,6 +582,12 @@ class ASTWriter : public ASTDeserializationListener,
 
   bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
 
+  void GenerateSpecializationInfoLookupTable(
+      const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
+      llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);
+  uint64_t WriteSpecializationInfoLookupTable(
+      const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
+      bool IsPartial);
   void GenerateNameLookupTable(ASTContext &Context, const DeclContext *DC,
                                llvm::SmallVectorImpl<char> &LookupTable);
   uint64_t WriteDeclContextLexicalBlock(ASTContext &Context,
@@ -590,6 +603,7 @@ class ASTWriter : public ASTDeserializationListener,
   void WriteDeclAndTypes(ASTContext &Context);
   void PrepareWritingSpecialDecls(Sema &SemaRef);
   void WriteSpecialDeclRecords(Sema &SemaRef);
+  void WriteSpecializationsUpdates(bool IsPartial);
   void WriteDeclUpdatesBlocks(ASTContext &Context,
                               RecordDataImpl &OffsetsRecord);
   void WriteDeclContextVisibleUpdate(ASTContext &Context,
@@ -619,6 +633,9 @@ class ASTWriter : public ASTDeserializationListener,
   unsigned DeclEnumAbbrev = 0;
   unsigned DeclObjCIvarAbbrev = 0;
   unsigned DeclCXXMethodAbbrev = 0;
+  unsigned DeclSpecializationsAbbrev = 0;
+  unsigned DeclPartialSpecializationsAbbrev = 0;
+
   unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
   unsigned DeclTemplateCXXMethodAbbrev = 0;
   unsigned DeclMemberSpecializedCXXMethodAbbrev = 0;
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 1da3f26bf23cd5..40ee3753c24227 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -16,7 +16,9 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/ODRHash.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
@@ -348,26 +350,39 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
   return Common;
 }
 
-void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
-  // Grab the most recent declaration to ensure we've loaded any lazy
-  // redeclarations of this template.
-  CommonBase *CommonBasePtr = getMostRecentDecl()->getCommonPtr();
-  if (CommonBasePtr->LazySpecializations) {
-    ASTContext &Context = getASTContext();
-    GlobalDeclID *Specs = CommonBasePtr->LazySpecializations;
-    CommonBasePtr->LazySpecializations = nullptr;
-    unsigned SpecSize = (*Specs++).getRawValue();
-    for (unsigned I = 0; I != SpecSize; ++I)
-      (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
-  }
+void RedeclarableTemplateDecl::loadLazySpecializationsImpl(
+    bool OnlyPartial /*=false*/) const {
+  auto *ExternalSource = getASTContext().getExternalSource();
+  if (!ExternalSource)
+    return;
+
+  ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
+                                              OnlyPartial);
+  return;
 }
 
-template<class EntryType, typename... ProfileArguments>
+bool RedeclarableTemplateDecl::loadLazySpecializationsImpl(
+    ArrayRef<TemplateArgument> Args, TemplateParameterList *TPL) const {
+  auto *ExternalSource = getASTContext().getExternalSource();
+  if (!ExternalSource)
+    return false;
+
+  // 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);
+
+  return ExternalSource->LoadExternalSpecializations(this->getCanonicalDecl(),
+                                                     Args);
+}
+
+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>;
+    ProfileArguments &&...ProfileArgs) {
+  using SETraits = RedeclarableTemplateDecl::SpecEntryTraits<EntryType>;
 
   llvm::FoldingSetNodeID ID;
   EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)...,
@@ -376,6 +391,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,
@@ -384,10 +417,14 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
 
   if (InsertPos) {
 #ifndef NDEBUG
+    auto Args = SETraits::getTemplateArgs(Entry);
+    // Due to hash collisions, it can happen that we load another template
+    // specialization with the same hash. This is fine, as long as the next
+    // call to findSpecializationImpl does not find a matching Decl for the
+    // template arguments.
+    loadLazySpecializationsImpl(Args);
     void *CorrectInsertPos;
-    assert(!findSpecializationImpl(Specializations,
-                                   CorrectInsertPos,
-                                   SETraits::getTemplateArgs(Entry)) &&
+    assert(!findSpecializationImpl(Specializations, CorrectInsertPos, Args) &&
            InsertPos == CorrectInsertPos &&
            "given incorrect InsertPos for specialization");
 #endif
@@ -445,12 +482,14 @@ FunctionTemplateDecl::getSpecializations() const {
 FunctionDecl *
 FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                          void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
+  auto *Common = getCommonPtr();
+  return findSpecializationImpl(Common->Specializations, InsertPos, Args);
 }
 
 void FunctionTemplateDecl::addSpecialization(
       FunctionTemplateSpecializationInfo *Info, void *InsertPos) {
-  addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info,
+  auto *Common = getCommonPtr();
+  addSpecializationImpl<FunctionTemplateDecl>(Common->Specializations, Info,
                                               InsertPos);
 }
 
@@ -510,8 +549,9 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
                                        DeclarationName(), nullptr, nullptr);
 }
 
-void ClassTemplateDecl::LoadLazySpecializations() const {
-  loadLazySpecializationsImpl();
+void ClassTemplateDecl::LoadLazySpecializations(
+    bool OnlyPartial /*=false*/) const {
+  loadLazySpecializationsImpl(OnlyPartial);
 }
 
 llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
@@ -522,7 +562,7 @@ ClassTemplateDecl::getSpecializations() const {
 
 llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
 ClassTemplateDecl::getPartialSpecializations() const {
-  LoadLazySpecializations();
+  LoadLazySpecializations(/*PartialOnly = */ true);
   return getCommonPtr()->PartialSpecializations;
 }
 
@@ -536,12 +576,15 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
 ClassTemplateSpecializationDecl *
 ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                       void *&InsertPos) {
-  return findSpecializationImpl(getSpecializations(), InsertPos, Args);
+  auto *Common = getCommonPtr();
+  return findSpecializationImpl(Common->Specializations, InsertPos, Args);
 }
 
 void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
                                           void *InsertPos) {
-  addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos);
+  auto *Common = getCommonPtr();
+  addSpecializationImpl<ClassTemplateDecl>(Common->Specializations, D,
+                                           InsertPos);
 }
 
 ClassTemplatePartialSpecializationDecl *
@@ -1259,8 +1302,9 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
                                      DeclarationName(), nullptr, nullptr);
 }
 
-void VarTemplateDecl::LoadLaz...
[truncated]

Currently all the specializations of a template (including
instantiation, specialization and partial specializations)  will be
loaded at once if we want to instantiate another instance for the
template, or find instantiation for the template, or just want to
complete the redecl chain.

This means basically we need to load every specializations for the
template once the template declaration got loaded. This is bad since
when we load a specialization, we need to load all of its template
arguments. Then we have to deserialize a lot of unnecessary
declarations.

For example,

```
// M.cppm
export module M;
export template <class T>
class A {};

export class ShouldNotBeLoaded {};

export class Temp {
   A<ShouldNotBeLoaded> AS;
};

// use.cpp
import M;
A<int> a;
```

We should a specialization ` A<ShouldNotBeLoaded>` in `M.cppm` and we
instantiate the template `A` in `use.cpp`. Then we will deserialize
`ShouldNotBeLoaded` surprisingly when compiling `use.cpp`. And this
patch tries to avoid that.

Given that the templates are heavily used in C++, this is a pain point
for the performance.

This patch adds MultiOnDiskHashTable for specializations in the
ASTReader. Then we will only deserialize the specializations with the
same template arguments. We made that by using ODRHash for the template
arguments as the key of the hash table.

To review this patch, I think `ASTReaderDecl::AddLazySpecializations`
may be a good entry point.
@h-vetinari
Copy link
Contributor

I think the title of the commit ("Support load lazy specialization lazily") is hard to parse and somewhat redundant. Perhaps the following would be better (IIUC): "Support loading template specializations lazily"

Also "We should a specialization A<ShouldNotBeLoaded> in M.cppm [...]" in the body of the commit message is hard to parse. Perhaps what was meant was "We have a specialization [...]"?

@ChuanqiXu9 ChuanqiXu9 changed the title [Serialization] Support load lazy specialization lazily [Serialization] Support loading template specializations lazily Dec 10, 2024
@ChuanqiXu9
Copy link
Member Author

I think the title of the commit ("Support load lazy specialization lazily") is hard to parse and somewhat redundant. Perhaps the following would be better (IIUC): "Support loading template specializations lazily"

Also "We should a specialization A<ShouldNotBeLoaded> in M.cppm [...]" in the body of the commit message is hard to parse. Perhaps what was meant was "We have a specialization [...]"?

Nice catch. Thanks.

Copy link
Contributor

@vgvassilev vgvassilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if relands require reviews but lgtm!

@ChuanqiXu9
Copy link
Member Author

Thanks. Given the change in lldb is trivial, I'd like to land it to see what happens.

@ChuanqiXu9 ChuanqiXu9 merged commit 20e9049 into llvm:main Dec 11, 2024
8 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 11, 2024

LLVM Buildbot has detected a new failure on builder lldb-aarch64-windows running on linaro-armv8-windows-msvc-05 while building clang,lldb at step 4 "build".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/141/builds/4612

Here is the relevant piece of the build log for the reference
Step 4 (build) failure: build (failure)
...
756.483 [4392/10/2097] Linking CXX static library lib\LLVMRuntimeDyld.lib
756.943 [4391/10/2098] Building CXX object lib\ProfileData\Coverage\CMakeFiles\LLVMCoverage.dir\CoverageMapping.cpp.obj
757.033 [4390/10/2099] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\TemplateArgumentHasher.cpp.obj
757.048 [4389/10/2100] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ModuleManager.cpp.obj
757.298 [4388/10/2101] Building CXX object lib\ProfileData\Coverage\CMakeFiles\LLVMCoverage.dir\CoverageMappingWriter.cpp.obj
757.317 [4387/10/2102] Building CXX object lib\ProfileData\Coverage\CMakeFiles\LLVMCoverage.dir\CoverageMappingReader.cpp.obj
757.326 [4386/10/2103] Linking CXX static library lib\LLVMPasses.lib
757.577 [4385/10/2104] Linking CXX static library lib\clangParse.lib
757.712 [4384/10/2105] Building CXX object tools\clang\lib\Rewrite\CMakeFiles\obj.clangRewrite.dir\Rewriter.cpp.obj
757.756 [4383/10/2106] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriter.cpp.obj
FAILED: tools/clang/lib/Serialization/CMakeFiles/obj.clangSerialization.dir/ASTWriter.cpp.obj 
ccache C:\Users\tcwg\scoop\apps\llvm\current\bin\clang-cl.exe  /nologo -TP -DCLANG_BUILD_STATIC -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\clang\lib\Serialization -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\lib\Serialization -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\clang\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\llvm\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:__cplusplus /Oi /Brepro /bigobj /permissive- -Werror=unguarded-availability-new /W4  -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported /Gw /O2 /Ob2 /DNDEBUG -std:c++17 -MD  /EHs-c- /GR- /showIncludes /Fotools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriter.cpp.obj /Fdtools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ -c -- C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\lib\Serialization\ASTWriter.cpp
C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\lib\Serialization\ASTWriter.cpp(4331,38): error: non-constant-expression cannot be narrowed from type 'clang::serialization::DeclCode' to 'RecordData::value_type' (aka 'unsigned long long') in initializer list [-Wc++11-narrowing]
 4331 |   RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 4332 |                                                : DECL_SPECIALIZATIONS};
      |                                                ~~~~~~~~~~~~~~~~~~~~~~
C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\lib\Serialization\ASTWriter.cpp(4331,38): note: insert an explicit cast to silence this issue
 4331 |   RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                      static_cast<value_type>(
 4332 |                                                : DECL_SPECIALIZATIONS};
      |                                                ~~~~~~~~~~~~~~~~~~~~~~
      |                                                                      )
C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\lib\Serialization\ASTWriter.cpp(6068,40): error: non-constant-expression cannot be narrowed from type 'clang::serialization::ASTRecordTypes' to 'RecordData::value_type' (aka 'unsigned long long') in initializer list [-Wc++11-narrowing]
 6068 |     RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
      |                                        ^~~~~~~~~~
C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\clang\lib\Serialization\ASTWriter.cpp(6068,40): note: insert an explicit cast to silence this issue
 6068 |     RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
      |                                        ^~~~~~~~~~
      |                                        static_cast<value_type>( )
2 errors generated.
757.823 [4383/9/2107] Building CXX object tools\clang\lib\Rewrite\CMakeFiles\obj.clangRewrite.dir\TokenRewriter.cpp.obj
757.921 [4383/8/2108] Linking CXX static library lib\clangDriver.lib
758.476 [4383/7/2109] Building CXX object tools\clang\lib\Rewrite\CMakeFiles\obj.clangRewrite.dir\HTMLRewrite.cpp.obj
760.493 [4383/6/2110] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriterStmt.cpp.obj
760.743 [4383/5/2111] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTReaderStmt.cpp.obj
761.750 [4383/4/2112] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriterDecl.cpp.obj
768.173 [4383/3/2113] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTReaderDecl.cpp.obj
773.797 [4383/2/2114] Building CXX object lib\LTO\CMakeFiles\LLVMLTO.dir\LTO.cpp.obj
789.791 [4383/1/2115] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTReader.cpp.obj
ninja: build stopped: subcommand failed.

@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 11, 2024

LLVM Buildbot has detected a new failure on builder clang-arm64-windows-msvc running on linaro-armv8-windows-msvc-04 while building clang,lldb at step 4 "build stage 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/161/builds/3610

Here is the relevant piece of the build log for the reference
Step 4 (build stage 1) failure: 'ninja' (failure)
...
[3247/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DebugHandlerBase.cpp.obj
[3248/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DebugLocStream.cpp.obj
[3249/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DIE.cpp.obj
[3250/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DIEHash.cpp.obj
[3251/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DwarfCFIException.cpp.obj
[3252/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DwarfCompileUnit.cpp.obj
[3253/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DwarfDebug.cpp.obj
[3254/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DwarfExpression.cpp.obj
[3255/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DwarfFile.cpp.obj
[3256/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriter.cpp.obj
FAILED: tools/clang/lib/Serialization/CMakeFiles/obj.clangSerialization.dir/ASTWriter.cpp.obj 
ccache C:\Users\tcwg\scoop\apps\llvm\current\bin\clang-cl.exe  /nologo -TP -DCLANG_BUILD_STATIC -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -IC:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\stage1\tools\clang\lib\Serialization -IC:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\lib\Serialization -IC:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\include -IC:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\stage1\tools\clang\include -IC:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\stage1\include -IC:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\llvm\include /DWIN32 /D_WINDOWS   /Zc:inline /Zc:__cplusplus /Oi /Brepro /bigobj /permissive- -Werror=unguarded-availability-new /W4  -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported /Gw /O2 /Ob2  -std:c++17 -MD  /EHs-c- /GR- -UNDEBUG /showIncludes /Fotools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriter.cpp.obj /Fdtools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ -c -- C:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\lib\Serialization\ASTWriter.cpp
C:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\lib\Serialization\ASTWriter.cpp(4331,38): error: non-constant-expression cannot be narrowed from type 'clang::serialization::DeclCode' to 'RecordData::value_type' (aka 'unsigned long long') in initializer list [-Wc++11-narrowing]
 4331 |   RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 4332 |                                                : DECL_SPECIALIZATIONS};
      |                                                ~~~~~~~~~~~~~~~~~~~~~~
C:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\lib\Serialization\ASTWriter.cpp(4331,38): note: insert an explicit cast to silence this issue
 4331 |   RecordData::value_type Record[] = {IsPartial ? DECL_PARTIAL_SPECIALIZATIONS
      |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                      static_cast<value_type>(
 4332 |                                                : DECL_SPECIALIZATIONS};
      |                                                ~~~~~~~~~~~~~~~~~~~~~~
      |                                                                      )
C:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\lib\Serialization\ASTWriter.cpp(6068,40): error: non-constant-expression cannot be narrowed from type 'clang::serialization::ASTRecordTypes' to 'RecordData::value_type' (aka 'unsigned long long') in initializer list [-Wc++11-narrowing]
 6068 |     RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
      |                                        ^~~~~~~~~~
C:\Users\tcwg\llvm-worker\clang-arm64-windows-msvc\llvm\clang\lib\Serialization\ASTWriter.cpp(6068,40): note: insert an explicit cast to silence this issue
 6068 |     RecordData::value_type Record[] = {RecordType, getDeclID(D).getRawValue()};
      |                                        ^~~~~~~~~~
      |                                        static_cast<value_type>( )
2 errors generated.
[3257/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\TemplateArgumentHasher.cpp.obj
[3258/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\DwarfStringPool.cpp.obj
[3259/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ModuleManager.cpp.obj
[3260/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTReaderStmt.cpp.obj
[3261/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriterDecl.cpp.obj
[3262/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTWriterStmt.cpp.obj
[3263/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTReaderDecl.cpp.obj
[3264/9149] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\AsmPrinter.cpp.obj
[3265/9149] Building CXX object tools\clang\lib\Serialization\CMakeFiles\obj.clangSerialization.dir\ASTReader.cpp.obj
ninja: build stopped: subcommand failed.

@vgvassilev
Copy link
Contributor

@ChuanqiXu9, can we insert a fix for windows?

@hahnjo
Copy link
Member

hahnjo commented Dec 11, 2024

I believe 30ea0f0 already addresses the cast. The bots are just slow...

@ilya-biryukov
Copy link
Contributor

@ChuanqiXu9 the added test fails under ASAN that reports memory leaks:

$ cmake -G Ninja -DLLVM_USE_SANITIZER=Address -DCMAKE_CXX_COMPILER=clang -DCMAKE_C_COMPILER=clang ../
$ ninja SerializationTests
$ ./tools/clang/unittests/Serialization/SerializationTests

produces

==4100640==ERROR: LeakSanitizer: detected memory leaks

Indirect leak of 32776 byte(s) in 1 object(s) allocated from:
    #0 0x559f90ba330c in calloc (/usr/local/google/home/ibiryukov/code/llvm-project/build-asan/tools/clang/unittests/Serialization/SerializationTests+0x174d30c) (BuildId: 4baf7bfc387b0be3)
    #1 0x559f910585eb in safe_calloc /usr/local/google/home/ibiryukov/code/llvm-project/llvm/include/llvm/Support/MemAlloc.h:40:18
    #2 0x559f910585eb in AllocateBuckets /usr/local/google/home/ibiryukov/code/llvm-project/llvm/lib/Support/FoldingSet.cpp:173:40
    #3 0x559f910585eb in llvm::FoldingSetBase::FoldingSetBase(unsigned int) /usr/local/google/home/ibiryukov/code/llvm-project/llvm/lib/Support/FoldingSet.cpp:187:13
    #4 0x559f90f34503 in FoldingSetImpl /usr/local/google/home/ibiryukov/code/llvm-project/llvm/include/llvm/ADT/FoldingSet.h:454:9
    #5 0x559f90f34503 in ContextualFoldingSet /usr/local/google/home/ibiryukov/code/llvm-project/llvm/include/llvm/ADT/FoldingSet.h:636:9
    #6 0x559f90f34503 in clang::ASTContext::ASTContext(clang::LangOptions&, clang::SourceManager&, clang::IdentifierTable&, clang::SelectorTable&, clang::Builtin::Context&, clang::TranslationUnitKind) /usr/local/google/home/ibiryukov/code/llvm-project/clang/lib/AST/ASTContext.cpp:920:7
    #7 0x559f92667204 in clang::CompilerInstance::createASTContext() /usr/local/google/home/ibiryukov/code/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:553:23
    #8 0x559f928ad79a in clang::FrontendAction::BeginSourceFile(clang::CompilerInstance&, clang::FrontendInputFile const&) /usr/local/google/home/ibiryukov/code/llvm-project/clang/lib/Frontend/FrontendAction.cpp:948:10
    #9 0x559f9266fb7d in clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) /usr/local/google/home/ibiryukov/code/llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1061:13
    #10 0x559f90c13901 in (anonymous namespace)::LoadSpecLazilyTest::GenerateModuleInterface[abi:cxx11](llvm::StringRef, llvm::StringRef) /usr/local/google/home/ibiryukov/code/llvm-project/clang/unittests/Serialization/LoadSpecLazilyTest.cpp:86:5
    #11 0x559f90c18b8b in (anonymous namespace)::LoadSpecLazilyTest_ChainedTest2_Test::TestBody() /usr/local/google/home/ibiryukov/code/llvm-project/clang/unittests/Serialization/LoadSpecLazilyTest.cpp:227:3
    #12 0x559f90e46395 in HandleExceptionsInMethodIfSupported<testing::Test, void> /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc
    #13 0x559f90e46395 in testing::Test::Run() /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc:2687:5
    #14 0x559f90e48ae2 in testing::TestInfo::Run() /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc:2836:11
    #15 0x559f90e4ad74 in testing::TestSuite::Run() /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc:3015:30
    #16 0x559f90e82ee8 in testing::internal::UnitTestImpl::RunAllTests() /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc:5920:44
    #17 0x559f90e811c7 in HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc
    #18 0x559f90e811c7 in testing::UnitTest::Run() /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/src/gtest.cc:5484:10
    #19 0x559f90e08bfa in RUN_ALL_TESTS /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h:2317:73
    #20 0x559f90e08bfa in main /usr/local/google/home/ibiryukov/code/llvm-project/third-party/unittest/UnitTestMain/TestMain.cpp:55:10
    #21 0x7f0546213c89 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
...
SUMMARY: AddressSanitizer: 488922 byte(s) leaked in 529 allocation(s).

Maybe revert the change or is there a simple fix forward?

@ilya-biryukov
Copy link
Contributor

Ah, it's DisableFree again. I'll send a fix.

@ilya-biryukov
Copy link
Contributor

Fixed by 7f43120.

@@ -1502,6 +1509,12 @@ enum DeclCode {
/// An ImplicitConceptSpecializationDecl record.
DECL_IMPLICIT_CONCEPT_SPECIALIZATION,

// A decls specilization record.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note specialization is misspelled in this comment and the one below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// A decls specilization record.
DECL_PARTIAL_SPECIALIZATIONS,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DECL_LAST also needs to be updated her.e

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this! Done in 366dadd

swift-ci pushed a commit to swiftlang/llvm-project that referenced this pull request Feb 25, 2025
Address post commit review at
llvm#119333 (review)

(cherry picked from commit 366dadd)
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Feb 25, 2025
Address post commit review at
llvm/llvm-project#119333 (review)

(cherry picked from commit 366dadd)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:openmp OpenMP related changes to Clang clang Clang issues not falling into any other category lldb skip-precommit-approval PR for CI feedback, not intended for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants