add option to instantiate templates already in the PCH
authorLuboš Luňák <l.lunak@centrum.cz>
Sun, 19 Apr 2020 15:49:47 +0000 (17:49 +0200)
committerLuboš Luňák <l.lunak@centrum.cz>
Sun, 21 Jun 2020 15:05:52 +0000 (17:05 +0200)
Add -fpch-instantiate-templates which makes template instantiations be
performed already in the PCH instead of it being done in every single
file that uses the PCH (but every single file will still do it as well
in order to handle its own instantiations). I can see 20-30% build
time saved with the few tests I've tried.

The change may reorder compiler output and also generated code, but
should be generally safe and produce functionally identical code.
There are some rare cases that do not compile with it,
such as test/PCH/pch-instantiate-templates-forward-decl.cpp. If
template instantiation bailed out instead of reporting the error,
these instantiations could even be postponed, which would make them
work.

Enable this by default for clang-cl. MSVC creates PCHs by compiling
them using an empty .cpp file, which means templates are instantiated
while building the PCH and so the .h needs to be self-contained,
making test/PCH/pch-instantiate-templates-forward-decl.cpp to fail
with MSVC anyway. So the option being enabled for clang-cl matches this.

Differential Revision: https://reviews.llvm.org/D69585

54 files changed:
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Driver/Options.td
clang/include/clang/Sema/Sema.h
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/PCH/crash-12631281.cpp
clang/test/PCH/cxx-alias-decl.cpp
clang/test/PCH/cxx-dependent-sized-ext-vector.cpp
clang/test/PCH/cxx-explicit-specifier.cpp
clang/test/PCH/cxx-exprs.cpp
clang/test/PCH/cxx-friends.cpp
clang/test/PCH/cxx-member-init.cpp
clang/test/PCH/cxx-ms-function-specialization-class-scope.cpp
clang/test/PCH/cxx-static_assert.cpp
clang/test/PCH/cxx-templates.cpp
clang/test/PCH/cxx-variadic-templates-with-default-params.cpp
clang/test/PCH/cxx-variadic-templates.cpp
clang/test/PCH/cxx0x-default-delete.cpp
clang/test/PCH/cxx11-constexpr.cpp
clang/test/PCH/cxx11-enum-template.cpp
clang/test/PCH/cxx11-exception-spec.cpp
clang/test/PCH/cxx11-inheriting-ctors.cpp
clang/test/PCH/cxx11-user-defined-literals.cpp
clang/test/PCH/cxx1y-decltype-auto.cpp
clang/test/PCH/cxx1y-deduced-return-type.cpp
clang/test/PCH/cxx1y-default-initializer.cpp
clang/test/PCH/cxx1y-init-captures.cpp
clang/test/PCH/cxx1y-variable-templates.cpp
clang/test/PCH/cxx1z-aligned-alloc.cpp
clang/test/PCH/cxx1z-decomposition.cpp
clang/test/PCH/cxx1z-using-declaration.cpp
clang/test/PCH/cxx2a-bitfield-init.cpp
clang/test/PCH/cxx2a-concept-specialization-expr.cpp
clang/test/PCH/cxx2a-constraints.cpp
clang/test/PCH/cxx2a-defaulted-comparison.cpp
clang/test/PCH/cxx2a-requires-expr.cpp
clang/test/PCH/cxx2a-template-lambdas.cpp
clang/test/PCH/delayed-pch-instantiate.cpp [new file with mode: 0644]
clang/test/PCH/friend-template.cpp
clang/test/PCH/implicitly-deleted.cpp
clang/test/PCH/late-parsed-instantiations.cpp
clang/test/PCH/local_static.cpp
clang/test/PCH/macro-undef.cpp
clang/test/PCH/make-integer-seq.cpp
clang/test/PCH/ms-if-exists.cpp
clang/test/PCH/pch-instantiate-templates-forward-decl.cpp [new file with mode: 0644]
clang/test/PCH/pch-instantiate-templates.cpp [new file with mode: 0644]
clang/test/PCH/pr18806.cpp
clang/test/PCH/pragma-diag-section.cpp
clang/test/PCH/rdar10830559.cpp
clang/test/PCH/specialization-after-instantiation.cpp [new file with mode: 0644]
clang/test/PCH/type_pack_element.cpp

index 9236327..bc0c17a 100644 (file)
@@ -165,6 +165,7 @@ BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 2, CMK_None,
 BENIGN_LANGOPT(CompilingPCH, 1, 0, "building a pch")
 BENIGN_LANGOPT(BuildingPCHWithObjectFile, 1, 0, "building a pch which has a corresponding object file")
 BENIGN_LANGOPT(CacheGeneratedPCH, 1, 0, "cache generated PCH files in memory")
+BENIGN_LANGOPT(PCHInstantiateTemplates, 1, 0, "instantiate templates while building a PCH")
 COMPATIBLE_LANGOPT(ModulesDeclUse    , 1, 0, "require declaration of module uses")
 BENIGN_LANGOPT(ModulesSearchAll  , 1, 1, "searching even non-imported modules to find unresolved references")
 COMPATIBLE_LANGOPT(ModulesStrictDeclUse, 1, 0, "requiring declaration of module uses and all headers to be in modules")
index 7c362d7..8ad582c 100644 (file)
@@ -1420,6 +1420,13 @@ def fpch_validate_input_files_content:
 def fno_pch_validate_input_files_content:
   Flag <["-"], "fno_pch-validate-input-files-content">,
   Group<f_Group>, Flags<[DriverOption]>;
+def fpch_instantiate_templates:
+  Flag <["-"], "fpch-instantiate-templates">,
+  Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Instantiate templates already while building a PCH">;
+def fno_pch_instantiate_templates:
+  Flag <["-"], "fno-pch-instantiate-templates">,
+  Group<f_Group>, Flags<[CC1Option]>;
 
 def fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
   Flags<[DriverOption, CC1Option]>,
index 85c5ab4..8c8e981 100644 (file)
@@ -8804,9 +8804,17 @@ public:
       S.VTableUses.swap(SavedVTableUses);
 
       // Restore the set of pending implicit instantiations.
-      assert(S.PendingInstantiations.empty() &&
-             "PendingInstantiations should be empty before it is discarded.");
-      S.PendingInstantiations.swap(SavedPendingInstantiations);
+      if (S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) {
+        assert(S.PendingInstantiations.empty() &&
+               "PendingInstantiations should be empty before it is discarded.");
+        S.PendingInstantiations.swap(SavedPendingInstantiations);
+      } else {
+        // Template instantiations in the PCH may be delayed until the TU.
+        S.PendingInstantiations.swap(SavedPendingInstantiations);
+        S.PendingInstantiations.insert(S.PendingInstantiations.end(),
+                                       SavedPendingInstantiations.begin(),
+                                       SavedPendingInstantiations.end());
+      }
     }
 
   private:
index 70d0fe0..aa18727 100644 (file)
@@ -1241,6 +1241,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
     if (YcArg && JA.getKind() >= Action::PrecompileJobClass &&
         JA.getKind() <= Action::AssembleJobClass) {
       CmdArgs.push_back(Args.MakeArgString("-building-pch-with-obj"));
+      CmdArgs.push_back(Args.MakeArgString("-fpch-instantiate-templates"));
     }
     if (YcArg || YuArg) {
       StringRef ThroughHeader = YcArg ? YcArg->getValue() : YuArg->getValue();
@@ -5633,6 +5634,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
                    options::OPT_fno_pch_validate_input_files_content, false))
     CmdArgs.push_back("-fvalidate-ast-input-files-content");
+  if (Args.hasFlag(options::OPT_fpch_instantiate_templates,
+                   options::OPT_fno_pch_instantiate_templates, false))
+    CmdArgs.push_back("-fpch-instantiate-templates");
 
   Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
                   options::OPT_fno_experimental_new_pass_manager);
index f322cc7..1cd4830 100644 (file)
@@ -3370,6 +3370,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
 
   Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers);
   Opts.BuildingPCHWithObjectFile = Args.hasArg(OPT_building_pch_with_obj);
+  Opts.PCHInstantiateTemplates = Args.hasArg(OPT_fpch_instantiate_templates);
 
   Opts.MatrixTypes = Args.hasArg(OPT_fenable_matrix);
 
index 49fbde8..fc3fb52 100644 (file)
@@ -1010,6 +1010,11 @@ void Sema::ActOnEndOfTranslationUnit() {
                                  LateParsedInstantiations.begin(),
                                  LateParsedInstantiations.end());
     LateParsedInstantiations.clear();
+
+    if (LangOpts.PCHInstantiateTemplates) {
+      llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
+      PerformPendingInstantiations();
+    }
   }
 
   DiagnoseUnterminatedPragmaPack();
index 7d0777c..1fff6b8 100644 (file)
@@ -5926,6 +5926,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
 /// Performs template instantiation for all implicit template
 /// instantiations we have seen until this point.
 void Sema::PerformPendingInstantiations(bool LocalOnly) {
+  std::deque<PendingImplicitInstantiation> delayedPCHInstantiations;
   while (!PendingLocalImplicitInstantiations.empty() ||
          (!LocalOnly && !PendingInstantiations.empty())) {
     PendingImplicitInstantiation Inst;
@@ -5956,6 +5957,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
         if (Function->isDefined())
           Function->setInstantiationIsPending(false);
       }
+      // Definition of a PCH-ed template declaration may be available only in the TU.
+      if (!LocalOnly && LangOpts.PCHInstantiateTemplates &&
+          TUKind == TU_Prefix && Function->instantiationIsPending())
+        delayedPCHInstantiations.push_back(Inst);
       continue;
     }
 
@@ -6001,6 +6006,9 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
     InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
                                   DefinitionRequired, true);
   }
+
+  if (!LocalOnly && LangOpts.PCHInstantiateTemplates)
+    PendingInstantiations.swap(delayedPCHInstantiations);
 }
 
 void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
index f309bca..f7bf65e 100644 (file)
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 %s -emit-pch -o %t.pch
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -include-pch %t.pch -verify
+
+// RUN: %clang_cc1 -std=c++11 %s -emit-pch -fpch-instantiate-templates -o %t.pch
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -include-pch %t.pch -verify
+
 // expected-no-diagnostics
 
 // rdar://12631281
index 872658f..2fdf40c 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -o %t %S/cxx-alias-decl.h
 // RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t -fsyntax-only -emit-llvm -o - %s 
 
+// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -fpch-instantiate-templates -o %t %S/cxx-alias-decl.h
+// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
 template struct T<S>;
 C<A>::A<char> a;
 
index 29c06f7..93fb561 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -emit-pch %s -o %t
 // RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -std=c++11 -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+
 #ifndef HEADER_INCLUDED
 
 #define HEADER_INCLUDED
index 9c7b056..ede0730 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t-cxx2a
 // RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
 
+// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t-cxx2a
+// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
+
 #ifndef USE_PCH
 namespace inheriting_constructor {
   struct S {};
index e02bb0a..2551d36 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
 // RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s 
 
+// RUN: %clang_cc1 -std=c++11 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
+
 // expected-no-diagnostics
 
 #ifndef HEADER
index 9c75f92..d1610be 100644 (file)
@@ -5,6 +5,10 @@
 // RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h
 // RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize
 
+// Test with pch and template instantiation in the pch.
+// RUN: %clang_cc1 -x c++-header -emit-pch -fpch-instantiate-templates -o %t %S/cxx-friends.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize
+
 // Test with modules.
 // RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-friends.h -fmodules
 // RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s -error-on-deserialized-decl doNotDeserialize -fmodules
index 78fd744..1bced56 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -emit-pch -o %t %s
 // RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s 
 
+// RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
 #ifdef HEADER
 int n;
 struct S {
index f97a8d1..af1f5ac 100644 (file)
@@ -1,6 +1,9 @@
 // REQUIRES: x86-registered-target
 // RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown  -x c++-header -emit-pch -o %t %S/cxx-ms-function-specialization-class-scope.h
 // RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s 
+
+// RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown  -x c++-header -emit-pch -fpch-instantiate-templates -o %t %S/cxx-ms-function-specialization-class-scope.h
+// RUN: %clang_cc1 -fms-extensions -triple i386-unknown-unknown -include-pch %t -fsyntax-only -verify %s 
 // expected-no-diagnostics
 
 
index be6c0ab..4946b76 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
 // RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
 
+// RUN: %clang_cc1 -std=c++11 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
+
 #ifndef HEADER
 #define HEADER
 
@@ -14,7 +17,7 @@ template<int N> struct T {
 
 #else
 
-// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
+// expected-error@15 {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
 T<2> t2;
 
index cd2787d..3e1c3ce 100644 (file)
 // RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s
 // RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
 
+// Test with pch and template instantiation in the pch.
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fpch-instantiate-templates -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
+
 // CHECK: define weak_odr {{.*}}void @_ZN2S4IiE1mEv
 // CHECK: define linkonce_odr {{.*}}void @_ZN2S3IiE1mEv
 
index 2c14820..dfa10df 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -std=c++11 -x c++-header -emit-pch -o %t %s
 // RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
 
+// RUN: %clang_cc1 -std=c++11 -x c++-header -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -fsyntax-only -verify %s
+
 // expected-no-diagnostics
 
 // PR25271: Ensure that default template arguments prior to a parameter pack
index dc00758..87b101d 100644 (file)
@@ -7,6 +7,10 @@
 // RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s -ast-dump  -o -
 // RUN: %clang_cc1 -std=c++11 -include-pch %t %s -emit-llvm -o - | FileCheck %s
 
+// RUN: %clang_cc1 -std=c++11 -x c++-header -emit-pch -fpch-instantiate-templates -o %t %S/cxx-variadic-templates.h
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s -ast-dump  -o -
+// RUN: %clang_cc1 -std=c++11 -include-pch %t %s -emit-llvm -o - | FileCheck %s
+
 // expected-no-diagnostics
 
 // CHECK: allocate_shared
index 230f6a6..bca4607 100644 (file)
@@ -4,6 +4,9 @@
 // RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %s
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -include-pch %t %s
 
+// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -include-pch %t %s
+
 #ifndef PASS1
 #define PASS1
 
@@ -30,11 +33,11 @@ struct A {
 foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}}
 foo f;
 void fn() {
-  f.bar(); // expected-error{{deleted function}} expected-note@12{{deleted here}}
+  f.bar(); // expected-error{{deleted function}} expected-note@15{{deleted here}}
 }
 
-baz bz; // expected-error{{deleted function}} expected-note@16{{deleted here}}
-quux qx; // expected-error{{private destructor}} expected-note@20{{private here}}
+baz bz; // expected-error{{deleted function}} expected-note@19{{deleted here}}
+quux qx; // expected-error{{private destructor}} expected-note@23{{private here}}
 
 struct B { A a; };
 struct C { mutable A a; };
index 8b722ce..b315b47 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
 #ifndef HEADER_INCLUDED
 
 #define HEADER_INCLUDED
@@ -31,9 +34,9 @@ constexpr T plus_seven(T other) {
 
 static_assert(D(4).k == 9, "");
 constexpr int f(C c) { return 0; } // expected-error {{not a literal type}}
-// expected-note@13 {{not an aggregate and has no constexpr constructors}}
+// expected-note@16 {{not an aggregate and has no constexpr constructors}}
 constexpr B b; // expected-error {{constant expression}} expected-note {{non-constexpr}}
-               // expected-note@9 {{here}}
+               // expected-note@12 {{here}}
 
 static_assert(plus_seven(3) == 10, "");
 
index ca70601..52c4781 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
 #ifndef HEADER_INCLUDED
 
 #define HEADER_INCLUDED
@@ -20,7 +23,7 @@ template struct S<char>;
 
 int k1 = (int)S<int>::E::e;
 int k2 = (int)decltype(b)::e;
-int k3 = (int)decltype(c)::e; // expected-error@10 {{conversion from 'double' to 'int'}} expected-note {{here}}
+int k3 = (int)decltype(c)::e; // expected-error@13 {{conversion from 'double' to 'int'}} expected-note {{here}}
 int k4 = (int)S<char>::E::e;
 
 #endif
index 8c7388a..3341e29 100644 (file)
@@ -2,6 +2,12 @@
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.1 -emit-pch %s -o %t.2
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.2 -verify %s
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.2 -emit-llvm-only %s
+
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch -fpch-instantiate-templates %s -o %t.1
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.1 -emit-pch -fpch-instantiate-templates %s -o %t.2
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.2 -verify %s
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t.2 -emit-llvm-only %s
+
 // expected-no-diagnostics
 
 #ifndef PHASE1_DONE
index bf9a2b7..6229fb4 100644 (file)
@@ -4,10 +4,17 @@
 // RxN: %clang_cc1 -std=c++11 -emit-pch -o %t.12 -include %s %s
 // RxN: %clang_cc1 -std=c++11 -include-pch %t.12 -verify %s
 //
+// RxN: %clang_cc1 -std=c++11 -emit-pch -fpch-instantiate-templates -o %t.12 -include %s %s
+// RxN: %clang_cc1 -std=c++11 -include-pch %t.12 -verify %s
+//
 // Emit with definitions in update records:
 // RxN: %clang_cc1 -std=c++11 -emit-pch -o %t.1 %s
 // RxN: %clang_cc1 -std=c++11 -include-pch %t.1 -emit-pch -o %t.2 -verify %s
 // RxN: %clang_cc1 -std=c++11 -include-pch %t.1 -include-pch %t.2 -verify %s
+//
+// RxN: %clang_cc1 -std=c++11 -emit-pch -fpch-instantiate-templates -o %t.1 %s
+// RxN: %clang_cc1 -std=c++11 -include-pch %t.1 -emit-pch -fpch-instantiate-templates -o %t.2 -verify %s
+// RxN: %clang_cc1 -std=c++11 -include-pch %t.1 -include-pch %t.2 -verify %s
 
 
 // expected-no-diagnostics
index 7ad17f5..cf3dc8c 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
 #ifndef HEADER_INCLUDED
 
 #define HEADER_INCLUDED
@@ -17,6 +20,6 @@ int k = f(0);
 int *l = f(&k);
 struct S {};
 int m = f(S()); // expected-error {{no matching}}
-                // expected-note@11 {{substitution failure}}
+                // expected-note@14 {{substitution failure}}
 
 #endif
index a1c9339..8a85283 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
+
 #ifndef HEADER_INCLUDED
 
 #define HEADER_INCLUDED
@@ -18,7 +21,7 @@ struct Z {
   int x : 5; // expected-note {{bit-field}}
 };
 
-// expected-error@12 {{non-const reference cannot bind to bit-field 'x'}}
+// expected-error@15 {{non-const reference cannot bind to bit-field 'x'}}
 template void f(Z); // expected-note {{in instantiation of}}
 
 #endif
index a61dda2..1862249 100644 (file)
@@ -6,6 +6,10 @@
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.a -emit-pch %s -o %t.b
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.b -verify %s
 
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch -fpch-instantiate-templates %s -o %t.a
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.a -emit-pch -fpch-instantiate-templates %s -o %t.b
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.b -verify %s
+
 // expected-no-diagnostics
 
 #if !defined(HEADER1)
index acb6337..a971ba6 100644 (file)
@@ -3,6 +3,10 @@
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.1 -emit-pch -o %t.2 %s
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.2 -verify %s
 
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch -fpch-instantiate-templates -o %t.1 %s
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.1 -emit-pch -fpch-instantiate-templates -o %t.2 %s
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.2 -verify %s
+
 #ifndef HEADER_1
 #define HEADER_1
 
index 3c8fc14..7f8a9fa 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s
+
 #ifndef HEADER
 #define HEADER
 
@@ -21,7 +24,7 @@ int y = counter();
 
 void g() {
   f(0); // ok
-  // expected-error@15 {{lvalue of type 'const char *const'}}
+  // expected-error@18 {{lvalue of type 'const char *const'}}
   f("foo"); // expected-note {{here}}
 }
 
index 29b66a1..faa9b3d 100644 (file)
@@ -7,6 +7,10 @@
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.a -emit-pch %s -o %t.b -DHEADER2
 // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.b -verify %s -DHEADERUSE
 
+// RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch -fpch-instantiate-templates %s -o %t.a -DHEADER1
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.a -emit-pch -fpch-instantiate-templates %s -o %t.b -DHEADER2
+// RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t.b -verify %s -DHEADERUSE
+
 #ifndef ERROR
 // expected-no-diagnostics
 #endif
@@ -89,8 +93,8 @@ namespace join {
 
   namespace diff_types {
 #ifdef ERROR
-    template<typename T> extern T err0; // expected-error {{redeclaration of 'err0' with a different type: 'T' vs 'float'}}  // expected-note@42 {{previous declaration is here}}
-    template<typename T> extern float err1; // expected-error {{redeclaration of 'err1' with a different type: 'float' vs 'T'}} // expected-note@43 {{previous declaration is here}}
+    template<typename T> extern T err0; // expected-error {{redeclaration of 'err0' with a different type: 'T' vs 'float'}}  // expected-note@46 {{previous declaration is here}}
+    template<typename T> extern float err1; // expected-error {{redeclaration of 'err1' with a different type: 'float' vs 'T'}} // expected-note@47 {{previous declaration is here}}
 #endif
     template<typename T> extern T def;
   }
index c49b910..c1becbd 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -include-pch %t -verify %s
+
 // expected-no-diagnostics
 
 #ifndef HEADER
index e033577..2f817b4 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -pedantic -std=c++1z -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic -std=c++1z -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic -std=c++1z -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic -std=c++1z -include-pch %t -verify %s
+
 #ifndef HEADER
 #define HEADER
 
@@ -26,7 +29,7 @@ int k = decomp(arr);
 
 static_assert(foo({1, 2}) == 12);
 
-// expected-error@12 {{cannot decompose non-class, non-array type 'const int'}}
+// expected-error@15 {{cannot decompose non-class, non-array type 'const int'}}
 int z = decomp(10); // expected-note {{instantiation of}}
 
 #endif
index a185ff1..dd0e59f 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -pedantic -std=c++1z -emit-pch %s -o %t
 // RUN: %clang_cc1 -pedantic -std=c++1z -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -pedantic -std=c++1z -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -pedantic -std=c++1z -include-pch %t -verify %s
+
 #ifndef HEADER
 #define HEADER
 
@@ -25,10 +28,10 @@ void test() {
   a.g();
   a.g(0);
   a.g(0, 0);
-  // expected-error@13 {{no match}}
-  // expected-note@16 {{candidate}}
-  // expected-note@17 {{candidate}}
-  // expected-note@18 {{candidate}}
+  // expected-error@16 {{no match}}
+  // expected-note@19 {{candidate}}
+  // expected-note@20 {{candidate}}
+  // expected-note@21 {{candidate}}
   a.g(0, 0, 0); // expected-note {{instantiation of}}
 }
 
index 344f3cb..ab7c3ce 100644 (file)
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -std=c++2a -include %s -verify %s
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
 // RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s -DPCH
+// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s -DPCH
 
 #ifndef HEADER
 #define HEADER
index 6227d57..386fee2 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
 // RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
+
 // expected-no-diagnostics
 
 #ifndef HEADER
index 593d962..d8b7933 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
 // RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
+
 // expected-no-diagnostics
 
 #ifndef HEADER
index 4fb0b83..8fea0fb 100644 (file)
@@ -2,6 +2,9 @@
 //
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t.pch
 // RUN: %clang_cc1 -std=c++2a -include-pch %t.pch %s -verify
+//
+// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t.pch
+// RUN: %clang_cc1 -std=c++2a -include-pch %t.pch %s -verify
 
 // expected-no-diagnostics
 
index 5548db4..d958f3a 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -emit-pch -std=c++2a -o %t %s
 // RUN: %clang_cc1 -std=c++2a -x ast -ast-print %t | FileCheck %s
 
+// RUN: %clang_cc1 -emit-pch -std=c++2a -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -std=c++2a -x ast -ast-print %t | FileCheck %s
+
 template<typename T>
 concept C = true;
 
index c9d923f..c11de0a 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
 // RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
+
 // expected-no-diagnostics
 
 #ifndef HEADER
diff --git a/clang/test/PCH/delayed-pch-instantiate.cpp b/clang/test/PCH/delayed-pch-instantiate.cpp
new file mode 100644 (file)
index 0000000..cf7a9f2
--- /dev/null
@@ -0,0 +1,30 @@
+// Test this without pch.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -DBODY %s -o - | FileCheck %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -include-pch %t -DBODY %s -o - | FileCheck %s
+
+// RUN: %clang_cc1 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -include-pch %t -DBODY %s -o - | FileCheck %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER_H
+#define HEADER_H
+struct A {
+  void foo() { bar<0>(); } // This will trigger implicit instantiation of bar<0>() in the PCH.
+  template <int N>
+  void bar();
+};
+#endif
+
+#ifdef BODY
+// But the definition is only in the source, so the instantiation must be delayed until the TU.
+template <int N>
+void A::bar() {}
+
+void test(A *a) { a->foo(); }
+#endif
+
+// CHECK: define linkonce_odr void @_ZN1A3barILi0EEEvv
index 989819b..a608879 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 -emit-pch -o %t %s
 // RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s 
 
+// RUN: %clang_cc1 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
+
 // expected-no-diagnostics
 
 #ifndef HEADER
index 5238fd3..669bdac 100644 (file)
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -x c++-header %s -emit-pch -o %t.pch
 // RUN: %clang_cc1 -std=c++11 -x c++ /dev/null -include-pch %t.pch
+
+// RUN: %clang_cc1 -std=c++11 -x c++-header %s -emit-pch -fpch-instantiate-templates -o %t.pch
+// RUN: %clang_cc1 -std=c++11 -x c++ /dev/null -include-pch %t.pch
+
 class move_only { move_only(const move_only&) = delete; move_only(move_only&&); };
 struct sb {
   move_only il;
index cbcc063..7a78781 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -emit-pch %s -o %t.pch -verify
 // RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -include-pch %t.pch %s -verify
 
+// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -emit-pch -fpch-instantiate-templates %s -o %t.pch -verify
+// RUN: %clang_cc1 -fdelayed-template-parsing -std=c++14 -include-pch %t.pch %s -verify
+
 #ifndef HEADER_INCLUDED
 
 #define HEADER_INCLUDED
index b4131bf..d198d84 100644 (file)
@@ -8,6 +8,10 @@
 // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -include-pch %t.pch -emit-llvm -o %t.pch.ll %s
 // RUN: FileCheck --input-file %t.pch.ll %s
 
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -x c++-header -emit-pch -fpch-instantiate-templates -o %t.pch %S/local_static.h
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -include-pch %t.pch -emit-llvm -o %t.pch.ll %s
+// RUN: FileCheck --input-file %t.pch.ll %s
+
 void test(Bar &b) {
   b.f<int>();
   static int s;
index bfe87d1..4ec935d 100644 (file)
@@ -2,31 +2,35 @@
 // RUN: %clang_cc1 -std=c++98 -fsyntax-only -include-pch %t %s -Wuninitialized -verify
 // RUN: %clang_cc1 -std=c++98 -fsyntax-only -include-pch %t %s -Wuninitialized -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
 
+// RUN: %clang_cc1 -std=c++98 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -include-pch %t %s -Wuninitialized -verify
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -include-pch %t %s -Wuninitialized -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
+
 #ifndef HEADER
 #define HEADER
 
 #define NULL 0
 template<typename T>
 void *f() {
-  void *p;  // @11
-  return p; // @12
+  void *p;  // @15
+  return p; // @16
 }
 #undef NULL
 template<typename T>
 void *g() {
-  void *p;  // @17
-  return p; // @18
+  void *p;  // @21
+  return p; // @22
 }
 
 #else
 
-// expected-warning@12 {{uninitialized}}
-// expected-note@11 {{initialize}}
-// CHECK: fix-it:"{{.*}}":{11:10-11:10}:" = NULL"
+// expected-warning@16 {{uninitialized}}
+// expected-note@15 {{initialize}}
+// CHECK: fix-it:"{{.*}}":{15:10-15:10}:" = NULL"
 
-// expected-warning@18 {{uninitialized}}
-// expected-note@17 {{initialize}}
-// CHECK: fix-it:"{{.*}}":{17:10-17:10}:" = 0"
+// expected-warning@22 {{uninitialized}}
+// expected-note@21 {{initialize}}
+// CHECK: fix-it:"{{.*}}":{21:10-21:10}:" = 0"
 
 int main() {
   f<int>(); // expected-note {{instantiation}}
index 3622c33..a52349c 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -o %t.pch
 // RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
 
+// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -fpch-instantiate-templates -o %t.pch
+// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
+
 template <class T, T... I>
 struct Seq {
     static constexpr T PackSize = sizeof...(I);
index be29ac6..c875b1d 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -emit-pch -o %t %s
 // RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -include-pch %t %s -verify
 
+// RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -include-pch %t %s -verify
+
 #ifndef HEADER
 #define HEADER
 template<typename T>
@@ -25,6 +28,6 @@ struct HasBar {
 };
 
 template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}}
-                         // expected-error@14{{no viable conversion from 'HasFoo' to 'int *'}}
+                         // expected-error@17{{no viable conversion from 'HasFoo' to 'int *'}}
 template void f(HasBar);
 #endif
diff --git a/clang/test/PCH/pch-instantiate-templates-forward-decl.cpp b/clang/test/PCH/pch-instantiate-templates-forward-decl.cpp
new file mode 100644 (file)
index 0000000..a7b418d
--- /dev/null
@@ -0,0 +1,30 @@
+// Test this without pch.
+// RUN: %clang_cc1 -fsyntax-only %s -DBODY
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -DBODY
+
+// Test with pch with template instantiation in the pch.
+// RUN: %clang_cc1 -emit-pch -fpch-instantiate-templates -o %t %s -verify
+
+#ifndef HEADER_H
+#define HEADER_H
+
+template <typename T>
+void f();
+struct X;            // @16
+void g() { f<X>(); } // @17 instantiation not performed yet
+
+template <typename T>
+void f() { T t; }; // @20
+
+#endif
+
+#ifdef BODY
+struct X {};
+#endif
+
+// expected-error@20 {{variable has incomplete type}}
+// expected-note@17 {{in instantiation of function template specialization}}
+// expected-note@16 {{forward declaration}}
diff --git a/clang/test/PCH/pch-instantiate-templates.cpp b/clang/test/PCH/pch-instantiate-templates.cpp
new file mode 100644 (file)
index 0000000..20aadf8
--- /dev/null
@@ -0,0 +1,28 @@
+// Test this without pch, template will be instantiated.
+// RUN: %clang_cc1 -fsyntax-only %s -verify=expected
+
+// Test with pch, template will be instantiated in the TU.
+// RUN: %clang_cc1 -emit-pch -o %t %s -verify=ok
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -verify=expected
+
+// Test with pch with template instantiation in the pch.
+// RUN: %clang_cc1 -emit-pch -fpch-instantiate-templates -o %t %s -verify=expected
+
+// ok-no-diagnostics
+
+#ifndef HEADER_H
+#define HEADER_H
+
+template <typename T>
+struct A {
+  T foo() const { return "test"; } // @18
+};
+
+double bar(A<double> *a) {
+  return a->foo(); // @22
+}
+
+#endif
+
+// expected-error@18 {{cannot initialize return object}}
+// expected-note@22 {{in instantiation of member function}}
index c28320d..28ceb82 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
 // RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
 
+// RUN: %clang_cc1 -std=c++11 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+
 // expected-no-diagnostics
 
 // Before the patch, this test triggered an assert violation in
index eea6bd7..7f72f3c 100644 (file)
@@ -5,6 +5,9 @@
 // RUN: %clang_cc1 %s -emit-pch -o %t
 // RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only -Wuninitialized
 
+// RUN: %clang_cc1 %s -emit-pch -fpch-instantiate-templates -o %t
+// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only -Wuninitialized
+
 #ifndef HEADER
 #define HEADER
 
@@ -27,8 +30,8 @@ struct TS2 {
     void m() {
       T a;
       T b = a; // expected-warning {{variable 'a' is uninitialized}} \
-                  expected-note@41 {{in instantiation of member function}} \
-                  expected-note@28 {{initialize the variable 'a' to silence}}
+                  expected-note@44 {{in instantiation of member function}} \
+                  expected-note@31 {{initialize the variable 'a' to silence}}
     }
 };
 
index aa19da4..0144f34 100644 (file)
@@ -6,6 +6,9 @@
 // RUN: %clang_cc1 -emit-pch -o %t %s
 // RUN: %clang_cc1 -include-pch %t -emit-llvm-only %t.empty.cpp 
 
+// RUN: %clang_cc1 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -include-pch %t -emit-llvm-only %t.empty.cpp
+
 // rdar://10830559
 
 //#pragma ms_struct on
diff --git a/clang/test/PCH/specialization-after-instantiation.cpp b/clang/test/PCH/specialization-after-instantiation.cpp
new file mode 100644 (file)
index 0000000..a10a075
--- /dev/null
@@ -0,0 +1,32 @@
+// Test this without pch.
+// RUN: %clang_cc1 -fsyntax-only -verify -DBODY %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify -DBODY %s
+
+// RUN: %clang_cc1 -emit-pch -fpch-instantiate-templates -o %t %s
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify -DBODY %s
+
+#ifndef HEADER_H
+#define HEADER_H
+
+template <typename T>
+struct A {
+  int foo() const;
+};
+
+int bar(A<double> *a) {
+  return a->foo();
+}
+
+#endif // HEADER_H
+
+#ifdef BODY
+
+template <>
+int A<double>::foo() const { // expected-error {{explicit specialization of 'foo' after instantiation}}  // expected-note@20 {{implicit instantiation first required here}}
+  return 10;
+}
+
+#endif // BODY
index c4ed6c8..9d1106b 100644 (file)
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -o %t.pch
 // RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
 
+// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -fpch-instantiate-templates -o %t.pch
+// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
+
 template <int i>
 struct X { };