From: Richard Smith Date: Thu, 6 Oct 2016 20:30:51 +0000 (+0000) Subject: [modules] Be sure to emit local specializations of imported templates, even if X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=18a60c7f6bcb33fc30a0f223ec1369f7551040fe;p=clang [modules] Be sure to emit local specializations of imported templates, even if the resulting specialization is not referenced by the rest of the AST. This both avoids performing unnecessary reinstantiations in downstream users of the AST file and fixes a bug (breaking modules self-host right now) where we would sometimes fail to emit a definition of a class template specialization if we imported just a declaration of it from elsewhere (see new testcase for reduced example). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@283489 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index f247855f69..e83dfe2536 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -373,9 +373,10 @@ private: /// it. llvm::SmallSetVector UpdatedDeclContexts; - /// \brief Keeps track of visible decls that were added in DeclContexts - /// coming from another AST file. - SmallVector UpdatingVisibleDecls; + /// \brief Keeps track of declarations that we must emit, even though we're + /// not guaranteed to be able to find them by walking the AST starting at the + /// translation unit. + SmallVector DeclsToEmitEvenIfUnreferenced; /// \brief The set of Objective-C class that have categories we /// should serialize. @@ -667,6 +668,14 @@ private: void CompletedTagDefinition(const TagDecl *D) override; void AddedVisibleDecl(const DeclContext *DC, const Decl *D) override; void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) override; + void AddedCXXTemplateSpecialization( + const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D) override; + void AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, + const VarTemplateSpecializationDecl *D) override; + void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) override; void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; void ResolvedOperatorDelete(const CXXDestructorDecl *DD, diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index fff824e437..cfe04433cf 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4472,8 +4472,9 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, Number.second)); // Make sure visible decls, added to DeclContexts previously loaded from - // an AST file, are registered for serialization. - for (const auto *I : UpdatingVisibleDecls) { + // an AST file, are registered for serialization. Likewise for template + // specializations added to imported templates. + for (const auto *I : DeclsToEmitEvenIfUnreferenced) { GetDeclRef(I); } @@ -5818,9 +5819,9 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { // that we write out all of its lookup results so we don't get a nasty // surprise when we try to emit its lookup table. for (auto *Child : DC->decls()) - UpdatingVisibleDecls.push_back(Child); + DeclsToEmitEvenIfUnreferenced.push_back(Child); } - UpdatingVisibleDecls.push_back(D); + DeclsToEmitEvenIfUnreferenced.push_back(D); } void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { @@ -5989,3 +5990,39 @@ void ASTWriter::AddedAttributeToRecord(const Attr *Attr, return; DeclUpdates[Record].push_back(DeclUpdate(UPD_ADDED_ATTR_TO_RECORD, Attr)); } + +void ASTWriter::AddedCXXTemplateSpecialization( + const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + + if (!TD->getFirstDecl()->isFromASTFile()) + return; + if (Chain && Chain->isProcessingUpdateRecords()) + return; + + DeclsToEmitEvenIfUnreferenced.push_back(D); +} + +void ASTWriter::AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + + if (!TD->getFirstDecl()->isFromASTFile()) + return; + if (Chain && Chain->isProcessingUpdateRecords()) + return; + + DeclsToEmitEvenIfUnreferenced.push_back(D); +} + +void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + + if (!TD->getFirstDecl()->isFromASTFile()) + return; + if (Chain && Chain->isProcessingUpdateRecords()) + return; + + DeclsToEmitEvenIfUnreferenced.push_back(D); +} diff --git a/test/Modules/Inputs/merge-template-specializations/a.h b/test/Modules/Inputs/merge-template-specializations/a.h new file mode 100644 index 0000000000..fb05647c0a --- /dev/null +++ b/test/Modules/Inputs/merge-template-specializations/a.h @@ -0,0 +1 @@ +template class SmallString {}; diff --git a/test/Modules/Inputs/merge-template-specializations/b.h b/test/Modules/Inputs/merge-template-specializations/b.h new file mode 100644 index 0000000000..96ce2bb1d8 --- /dev/null +++ b/test/Modules/Inputs/merge-template-specializations/b.h @@ -0,0 +1,2 @@ +#include "a.h" +void f(SmallString<256>&); diff --git a/test/Modules/Inputs/merge-template-specializations/c.h b/test/Modules/Inputs/merge-template-specializations/c.h new file mode 100644 index 0000000000..100463a2f7 --- /dev/null +++ b/test/Modules/Inputs/merge-template-specializations/c.h @@ -0,0 +1,3 @@ +#include "a.h" +struct X { SmallString<256> ss; }; +#include "b.h" diff --git a/test/Modules/Inputs/merge-template-specializations/module.modulemap b/test/Modules/Inputs/merge-template-specializations/module.modulemap new file mode 100644 index 0000000000..77e0a89e39 --- /dev/null +++ b/test/Modules/Inputs/merge-template-specializations/module.modulemap @@ -0,0 +1,3 @@ +module a { header "a.h" export * } +module b { header "b.h" export * } +module c { header "c.h" export * } diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index 12dfdd0546..c2d38497dd 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -249,10 +249,10 @@ namespace Std { // CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate -// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition -// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' -// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition // CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate +// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' +// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition +// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' diff --git a/test/Modules/merge-template-specializations.cpp b/test/Modules/merge-template-specializations.cpp new file mode 100644 index 0000000000..25db93fbbb --- /dev/null +++ b/test/Modules/merge-template-specializations.cpp @@ -0,0 +1,5 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -fmodules-local-submodule-visibility -I%S/Inputs/merge-template-specializations -std=c++11 -verify %s +// expected-no-diagnostics +#include "c.h" +X x;