]> granicus.if.org Git - clang/commitdiff
[modules] Be sure to emit local specializations of imported templates, even if
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 6 Oct 2016 20:30:51 +0000 (20:30 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 6 Oct 2016 20:30:51 +0000 (20:30 +0000)
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

include/clang/Serialization/ASTWriter.h
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/merge-template-specializations/a.h [new file with mode: 0644]
test/Modules/Inputs/merge-template-specializations/b.h [new file with mode: 0644]
test/Modules/Inputs/merge-template-specializations/c.h [new file with mode: 0644]
test/Modules/Inputs/merge-template-specializations/module.modulemap [new file with mode: 0644]
test/Modules/cxx-templates.cpp
test/Modules/merge-template-specializations.cpp [new file with mode: 0644]

index f247855f69150b6a8a541fd01023074a41122198..e83dfe2536d3821049a462deea6ae2edb86e2549 100644 (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,
index fff824e4373a3fbdc69e61384ac4f57a87251060..cfe04433cfddca463bdba5139d601785a535b503 100644 (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);
+}
diff --git a/test/Modules/Inputs/merge-template-specializations/a.h b/test/Modules/Inputs/merge-template-specializations/a.h
new file mode 100644 (file)
index 0000000..fb05647
--- /dev/null
@@ -0,0 +1 @@
+template<unsigned> 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 (file)
index 0000000..96ce2bb
--- /dev/null
@@ -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 (file)
index 0000000..100463a
--- /dev/null
@@ -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 (file)
index 0000000..77e0a89
--- /dev/null
@@ -0,0 +1,3 @@
+module a { header "a.h" export * }
+module b { header "b.h" export * }
+module c { header "c.h" export * }
index 12dfdd0546eb0725290c8559322b6c8f6b09e753..c2d38497dd7b0ce0205e6936bc04ca47bd93134a 100644 (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:        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 (file)
index 0000000..25db93f
--- /dev/null
@@ -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;