[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).

llvm-svn: 283489
This commit is contained in:
Richard Smith 2016-10-06 20:30:51 +00:00
parent f65f56e002
commit c26d97401c
8 changed files with 71 additions and 11 deletions

View File

@ -373,9 +373,10 @@ private:
/// it.
llvm::SmallSetVector<const DeclContext *, 16> UpdatedDeclContexts;
/// \brief Keeps track of visible decls that were added in DeclContexts
/// coming from another AST file.
SmallVector<const Decl *, 16> 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<const Decl *, 16> 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,

View File

@ -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);
}

View File

@ -0,0 +1 @@
template<unsigned> class SmallString {};

View File

@ -0,0 +1,2 @@
#include "a.h"
void f(SmallString<256>&);

View File

@ -0,0 +1,3 @@
#include "a.h"
struct X { SmallString<256> ss; };
#include "b.h"

View File

@ -0,0 +1,3 @@
module a { header "a.h" export * }
module b { header "b.h" export * }
module c { header "c.h" export * }

View File

@ -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-NEXT: TemplateArgument type 'char [2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]'
// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate
// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]'
// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]'
// CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition
// CHECK-DUMP-NEXT: TemplateArgument type 'char [2]'
// CHECK-DUMP-NEXT: TemplateArgument type 'char [1]'

View File

@ -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;