]> granicus.if.org Git - clang/commitdiff
Lazily deserialize function template specializations. This fixes a cycle in
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 28 Jun 2013 04:37:53 +0000 (04:37 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 28 Jun 2013 04:37:53 +0000 (04:37 +0000)
module deserialization / merging, and more laziness here is general goodness.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@185132 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclTemplate.h
lib/AST/DeclTemplate.cpp
lib/Serialization/ASTReaderDecl.cpp
test/PCH/cxx-templates.cpp

index 89c0f05a8f640a4ebe5d70b1269db2d28a4d7e1f..14ed8a1e62102324b967fd2ead712455712faa94 100644 (file)
@@ -743,7 +743,7 @@ protected:
   /// \brief Data that is common to all of the declarations of a given
   /// function template.
   struct Common : CommonBase {
-    Common() : InjectedArgs(0) { }
+    Common() : InjectedArgs(), LazySpecializations() { }
 
     /// \brief The function template specializations for this function
     /// template, including explicit specializations and instantiations.
@@ -757,6 +757,13 @@ protected:
     /// template, and is allocated lazily, since most function templates do not
     /// require the use of this information.
     TemplateArgument *InjectedArgs;
+
+    /// \brief If non-null, points to an array of specializations known only
+    /// by their external declaration IDs.
+    ///
+    /// The first value in the array is the number of of specializations
+    /// that follow.
+    uint32_t *LazySpecializations;
   };
 
   FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
@@ -771,12 +778,13 @@ protected:
 
   friend class FunctionDecl;
 
+  /// \brief Load any lazily-loaded specializations from the external source.
+  void LoadLazySpecializations() const;
+
   /// \brief Retrieve the set of function template specializations of this
   /// function template.
   llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
-  getSpecializations() const {
-    return getCommonPtr()->Specializations;
-  }
+  getSpecializations() const;
 
   /// \brief Add a specialization of this function template.
   ///
@@ -1822,7 +1830,7 @@ protected:
     QualType InjectedClassNameType;
 
     /// \brief If non-null, points to an array of specializations (including
-    /// partial specializations) known ownly by their external declaration IDs.
+    /// partial specializations) known only by their external declaration IDs.
     ///
     /// The first value in the array is the number of of specializations/
     /// partial specializations that follow.
index d764d2bedb1d21eec836d4a0b9a4169bf4e9a7cb..ac0d54f5011e1ae4676ace2f5c80a404140c37df 100644 (file)
@@ -245,6 +245,23 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const {
   return CommonPtr;
 }
 
+void FunctionTemplateDecl::LoadLazySpecializations() const {
+  Common *CommonPtr = getCommonPtr();
+  if (CommonPtr->LazySpecializations) {
+    ASTContext &Context = getASTContext();
+    uint32_t *Specs = CommonPtr->LazySpecializations;
+    CommonPtr->LazySpecializations = 0;
+    for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+      (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+  }
+}
+
+llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
+FunctionTemplateDecl::getSpecializations() const {
+  LoadLazySpecializations();
+  return getCommonPtr()->Specializations;
+}
+
 FunctionDecl *
 FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
                                          unsigned NumArgs, void *&InsertPos) {
index e93eae81127813c944b10ca1732feb38c1d8a40e..84a8b09e4e5951458c768094e42f86f79f7a0d7e 100644 (file)
@@ -606,11 +606,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
       FunctionTemplateSpecializationInfo::Profile(ID, TemplArgs.data(),
                                                   TemplArgs.size(), C);
       void *InsertPos = 0;
-      CanonTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+      FunctionTemplateDecl::Common *CommonPtr = CanonTemplate->getCommonPtr();
+      CommonPtr->Specializations.FindNodeOrInsertPos(ID, InsertPos);
       if (InsertPos)
-        CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos);
-      else
-        assert(0 && "Another specialization already inserted!");
+        CommonPtr->Specializations.InsertNode(FTInfo, InsertPos);
+      else {
+        assert(Reader.getContext().getLangOpts().Modules &&
+               "already deserialized this template specialization");
+        // FIXME: This specialization is a redeclaration of one from another
+        // module. Merge it.
+      }
     }
     break;
   }
@@ -1508,12 +1513,17 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
   if (ThisDeclID == Redecl.getFirstID()) {
     // This FunctionTemplateDecl owns a CommonPtr; read it.
 
-    // Read the function specialization declarations.
-    // FunctionTemplateDecl's FunctionTemplateSpecializationInfos are filled
-    // when reading the specialized FunctionDecl.
-    unsigned NumSpecs = Record[Idx++];
-    while (NumSpecs--)
-      (void)ReadDecl(Record, Idx);
+    // Read the function specialization declaration IDs. The specializations
+    // themselves will be loaded if they're needed.
+    if (unsigned NumSpecs = Record[Idx++]) {
+      // FIXME: Append specializations!
+      FunctionTemplateDecl::Common *CommonPtr = D->getCommonPtr();
+      CommonPtr->LazySpecializations = new (Reader.getContext())
+          serialization::DeclID[NumSpecs + 1];
+      CommonPtr->LazySpecializations[0] = NumSpecs;
+      for (unsigned I = 0; I != NumSpecs; ++I)
+        CommonPtr->LazySpecializations[I + 1] = ReadDeclID(Record, Idx);
+    }
   }
 }
 
index 6da5a75cdddf544d9abe5a3fc252e80521c8ae1b..433f73f12a27deccf6fabc81b9fc75616240a42b 100644 (file)
@@ -7,6 +7,11 @@
 // RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump  -o -
 // RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize | FileCheck %s
 
+// Test with modules.
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump  -o -
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize | FileCheck %s
+
 // expected-no-diagnostics
 
 // CHECK: define weak_odr void @_ZN2S4IiE1mEv