Index: include/clang/Serialization/ASTReader.h =================================================================== --- include/clang/Serialization/ASTReader.h +++ include/clang/Serialization/ASTReader.h @@ -16,6 +16,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileSystemOptions.h" @@ -547,6 +548,9 @@ llvm::DenseMap PendingVisibleUpdates; + llvm::SmallVector PendingLazySpecializationIDs; + + /// \brief The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet PendingDefinitions; @@ -1280,6 +1284,37 @@ RecordLocation DeclCursorForID(serialization::DeclID ID, SourceLocation &Location); void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); + template + void AddLazySpecializations(T *D, + SmallVectorImpl& IDs) { + if (IDs.empty()) + return; + + // FIXME: A hack to access the protected getCommonPtr. This is because + // AddLazySpecializations should be called in the ASTReader which is not a + // friend of Class,Function,VarTemplateDecl. + struct CommonPtrAccessor : public T { + static uint32_t *&getLazySpecializations(T *D) { + return ((CommonPtrAccessor*)D)->getCommonPtr()->LazySpecializations; + } + }; + ASTContext &C = getContext(); + + auto *&LazySpecializations = CommonPtrAccessor::getLazySpecializations(D); + + if (auto &Old = LazySpecializations) { + IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); + std::sort(IDs.begin(), IDs.end()); + IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); + } + + auto *Result = new (C) serialization::DeclID[1 + IDs.size()]; + *Result = IDs.size(); + std::copy(IDs.begin(), IDs.end(), Result + 1); + + LazySpecializations = Result; + } + void loadPendingDeclChain(Decl *D, uint64_t LocalOffset); void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D, unsigned PreviousGeneration = 0); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1951,21 +1951,6 @@ return Redecl; } -static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old, - SmallVectorImpl &IDs) { - assert(!IDs.empty() && "no IDs to add to list"); - if (Old) { - IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]); - std::sort(IDs.begin(), IDs.end()); - IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end()); - } - - auto *Result = new (Context) DeclID[1 + IDs.size()]; - *Result = IDs.size(); - std::copy(IDs.begin(), IDs.end(), Result + 1); - return Result; -} - void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); @@ -1974,12 +1959,7 @@ // the specializations. SmallVector SpecIDs; ReadDeclIDList(SpecIDs); - - if (!SpecIDs.empty()) { - auto *CommonPtr = D->getCommonPtr(); - CommonPtr->LazySpecializations = newDeclIDList( - Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); - } + Reader.AddLazySpecializations(D, SpecIDs); } if (D->getTemplatedDecl()->TemplateOrInstantiation) { @@ -2006,12 +1986,7 @@ // the specializations. SmallVector SpecIDs; ReadDeclIDList(SpecIDs); - - if (!SpecIDs.empty()) { - auto *CommonPtr = D->getCommonPtr(); - CommonPtr->LazySpecializations = newDeclIDList( - Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); - } + Reader.AddLazySpecializations(D, SpecIDs); } } @@ -2117,12 +2092,7 @@ // This FunctionTemplateDecl owns a CommonPtr; read it. SmallVector SpecIDs; ReadDeclIDList(SpecIDs); - - if (!SpecIDs.empty()) { - auto *CommonPtr = D->getCommonPtr(); - CommonPtr->LazySpecializations = newDeclIDList( - Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs); - } + Reader.AddLazySpecializations(D, SpecIDs); } } @@ -3697,6 +3667,17 @@ } } } + // Add the lazy specializations to the template. + assert((PendingLazySpecializationIDs.empty() || isa(D) || + isa(D) || isa(D)) && + "Must not have pending specializations"); + if (auto *CTD = dyn_cast(D)) + AddLazySpecializations(CTD, PendingLazySpecializationIDs); + else if (auto *FTD = dyn_cast(D)) + AddLazySpecializations(FTD, PendingLazySpecializationIDs); + else if (auto *VTD = dyn_cast(D)) + AddLazySpecializations(VTD, PendingLazySpecializationIDs); + PendingLazySpecializationIDs.clear(); // Load the pending visible updates for this decl context, if it has any. auto I = PendingVisibleUpdates.find(ID); @@ -3909,8 +3890,8 @@ } case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: - // It will be added to the template's specializations set when loaded. - (void)Record.readDecl(); + // It will be added to the template's lazy specialization set. + Reader.PendingLazySpecializationIDs.push_back(ReadDeclID()); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { Index: test/Modules/Inputs/lazy-template-specializations/A.h =================================================================== --- /dev/null +++ test/Modules/Inputs/lazy-template-specializations/A.h @@ -0,0 +1,3 @@ +#include "B.h" +int i; + Index: test/Modules/Inputs/lazy-template-specializations/B.h =================================================================== --- /dev/null +++ test/Modules/Inputs/lazy-template-specializations/B.h @@ -0,0 +1,4 @@ +namespace N { + template struct S { int a; }; + template <> struct S { double b; }; +} Index: test/Modules/Inputs/lazy-template-specializations/module.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/lazy-template-specializations/module.modulemap @@ -0,0 +1,9 @@ +module A { + header "A.h" + export * +} + +module B { + header "B.h" + export * +} Index: test/Modules/lazy-template-specializations.cpp =================================================================== --- /dev/null +++ test/Modules/lazy-template-specializations.cpp @@ -0,0 +1,10 @@ +// RUN: rm -fr %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ +// RUN: -I %S/Inputs/lazy-template-specializations -std=c++11 \ +// RUN: -error-on-deserialized-decl S -Rmodule-build %s + + +#include "A.h" + +namespace N { +}