From: Richard Smith Date: Fri, 28 Jun 2013 04:37:53 +0000 (+0000) Subject: Lazily deserialize function template specializations. This fixes a cycle in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6982bf4d77bc57a85ee173b631729fce673f16ef;p=clang Lazily deserialize function template specializations. This fixes a cycle in 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 --- diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 89c0f05a8f..14ed8a1e62 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -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 & - 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. diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index d764d2bedb..ac0d54f501 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -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 & +FunctionTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + FunctionDecl * FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, unsigned NumArgs, void *&InsertPos) { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index e93eae8112..84a8b09e4e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -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); + } } } diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp index 6da5a75cdd..433f73f12a 100644 --- a/test/PCH/cxx-templates.cpp +++ b/test/PCH/cxx-templates.cpp @@ -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