[clang] a45f713 - add option to instantiate templates already in the PCH

Luboš Luňák via cfe-commits cfe-commits at lists.llvm.org
Sun Jun 21 08:06:10 PDT 2020


Author: Luboš Luňák
Date: 2020-06-21T17:05:52+02:00
New Revision: a45f713c673001abb4fe0612b909c698073eb356

URL: https://github.com/llvm/llvm-project/commit/a45f713c673001abb4fe0612b909c698073eb356
DIFF: https://github.com/llvm/llvm-project/commit/a45f713c673001abb4fe0612b909c698073eb356.diff

LOG: add option to instantiate templates already in the PCH

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

Added: 
    clang/test/PCH/delayed-pch-instantiate.cpp
    clang/test/PCH/pch-instantiate-templates-forward-decl.cpp
    clang/test/PCH/pch-instantiate-templates.cpp
    clang/test/PCH/specialization-after-instantiation.cpp

Modified: 
    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/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/pr18806.cpp
    clang/test/PCH/pragma-diag-section.cpp
    clang/test/PCH/rdar10830559.cpp
    clang/test/PCH/type_pack_element.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 9236327f688f..bc0c17a14789 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -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")

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7c362d72361f..8ad582c84c60 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -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]>,

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 85c5ab476b5f..8c8e981e6065 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8804,9 +8804,17 @@ class Sema final {
       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:

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 70d0fe0021a9..aa18727671be 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -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);

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index f322cc7b3a3b..1cd483081dc2 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -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);
 

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 49fbde85cdfb..fc3fb524c8f4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1010,6 +1010,11 @@ void Sema::ActOnEndOfTranslationUnit() {
                                  LateParsedInstantiations.begin(),
                                  LateParsedInstantiations.end());
     LateParsedInstantiations.clear();
+
+    if (LangOpts.PCHInstantiateTemplates) {
+      llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
+      PerformPendingInstantiations();
+    }
   }
 
   DiagnoseUnterminatedPragmaPack();

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7d0777cce6ae..1fff6b8b951e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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,

diff  --git a/clang/test/PCH/crash-12631281.cpp b/clang/test/PCH/crash-12631281.cpp
index f309bcaaccc1..f7bf65e2054d 100644
--- a/clang/test/PCH/crash-12631281.cpp
+++ b/clang/test/PCH/crash-12631281.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx-alias-decl.cpp b/clang/test/PCH/cxx-alias-decl.cpp
index 872658f7edfa..2fdf40c0ae83 100644
--- a/clang/test/PCH/cxx-alias-decl.cpp
+++ b/clang/test/PCH/cxx-alias-decl.cpp
@@ -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;
 

diff  --git a/clang/test/PCH/cxx-dependent-sized-ext-vector.cpp b/clang/test/PCH/cxx-dependent-sized-ext-vector.cpp
index 29c06f7cc797..93fb56161dfc 100644
--- a/clang/test/PCH/cxx-dependent-sized-ext-vector.cpp
+++ b/clang/test/PCH/cxx-dependent-sized-ext-vector.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx-explicit-specifier.cpp b/clang/test/PCH/cxx-explicit-specifier.cpp
index 9c7b0560e5bf..ede0730f7c13 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -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 {};

diff  --git a/clang/test/PCH/cxx-exprs.cpp b/clang/test/PCH/cxx-exprs.cpp
index e02bb0aa056f..2551d362a277 100644
--- a/clang/test/PCH/cxx-exprs.cpp
+++ b/clang/test/PCH/cxx-exprs.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx-friends.cpp b/clang/test/PCH/cxx-friends.cpp
index 9c75f92f34d6..d1610beccf5a 100644
--- a/clang/test/PCH/cxx-friends.cpp
+++ b/clang/test/PCH/cxx-friends.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx-member-init.cpp b/clang/test/PCH/cxx-member-init.cpp
index 78fd74425b84..1bced567b9de 100644
--- a/clang/test/PCH/cxx-member-init.cpp
+++ b/clang/test/PCH/cxx-member-init.cpp
@@ -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 {

diff  --git a/clang/test/PCH/cxx-ms-function-specialization-class-scope.cpp b/clang/test/PCH/cxx-ms-function-specialization-class-scope.cpp
index f97a8d183c7a..af1f5ac39b26 100644
--- a/clang/test/PCH/cxx-ms-function-specialization-class-scope.cpp
+++ b/clang/test/PCH/cxx-ms-function-specialization-class-scope.cpp
@@ -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
 
 

diff  --git a/clang/test/PCH/cxx-static_assert.cpp b/clang/test/PCH/cxx-static_assert.cpp
index be6c0ab2a76b..4946b76381d9 100644
--- a/clang/test/PCH/cxx-static_assert.cpp
+++ b/clang/test/PCH/cxx-static_assert.cpp
@@ -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 at 12 {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
+// expected-error at 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;
 

diff  --git a/clang/test/PCH/cxx-templates.cpp b/clang/test/PCH/cxx-templates.cpp
index cd2787d90359..3e1c3cee79a3 100644
--- a/clang/test/PCH/cxx-templates.cpp
+++ b/clang/test/PCH/cxx-templates.cpp
@@ -17,6 +17,11 @@
 // 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
 

diff  --git a/clang/test/PCH/cxx-variadic-templates-with-default-params.cpp b/clang/test/PCH/cxx-variadic-templates-with-default-params.cpp
index 2c1482091db3..dfa10df99fe7 100644
--- a/clang/test/PCH/cxx-variadic-templates-with-default-params.cpp
+++ b/clang/test/PCH/cxx-variadic-templates-with-default-params.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx-variadic-templates.cpp b/clang/test/PCH/cxx-variadic-templates.cpp
index dc00758aa520..87b101d73c14 100644
--- a/clang/test/PCH/cxx-variadic-templates.cpp
+++ b/clang/test/PCH/cxx-variadic-templates.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx0x-default-delete.cpp b/clang/test/PCH/cxx0x-default-delete.cpp
index 230f6a614715..bca4607d33a7 100644
--- a/clang/test/PCH/cxx0x-default-delete.cpp
+++ b/clang/test/PCH/cxx0x-default-delete.cpp
@@ -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 at 12{{deleted here}}
+  f.bar(); // expected-error{{deleted function}} expected-note at 15{{deleted here}}
 }
 
-baz bz; // expected-error{{deleted function}} expected-note at 16{{deleted here}}
-quux qx; // expected-error{{private destructor}} expected-note at 20{{private here}}
+baz bz; // expected-error{{deleted function}} expected-note at 19{{deleted here}}
+quux qx; // expected-error{{private destructor}} expected-note at 23{{private here}}
 
 struct B { A a; };
 struct C { mutable A a; };

diff  --git a/clang/test/PCH/cxx11-constexpr.cpp b/clang/test/PCH/cxx11-constexpr.cpp
index 8b722ce98095..b315b477dbf1 100644
--- a/clang/test/PCH/cxx11-constexpr.cpp
+++ b/clang/test/PCH/cxx11-constexpr.cpp
@@ -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 at 13 {{not an aggregate and has no constexpr constructors}}
+// expected-note at 16 {{not an aggregate and has no constexpr constructors}}
 constexpr B b; // expected-error {{constant expression}} expected-note {{non-constexpr}}
-               // expected-note at 9 {{here}}
+               // expected-note at 12 {{here}}
 
 static_assert(plus_seven(3) == 10, "");
 

diff  --git a/clang/test/PCH/cxx11-enum-template.cpp b/clang/test/PCH/cxx11-enum-template.cpp
index ca70601da77c..52c47811a984 100644
--- a/clang/test/PCH/cxx11-enum-template.cpp
+++ b/clang/test/PCH/cxx11-enum-template.cpp
@@ -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 at 10 {{conversion from 'double' to 'int'}} expected-note {{here}}
+int k3 = (int)decltype(c)::e; // expected-error at 13 {{conversion from 'double' to 'int'}} expected-note {{here}}
 int k4 = (int)S<char>::E::e;
 
 #endif

diff  --git a/clang/test/PCH/cxx11-exception-spec.cpp b/clang/test/PCH/cxx11-exception-spec.cpp
index 8c7388a767b3..3341e29711c8 100644
--- a/clang/test/PCH/cxx11-exception-spec.cpp
+++ b/clang/test/PCH/cxx11-exception-spec.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx11-inheriting-ctors.cpp b/clang/test/PCH/cxx11-inheriting-ctors.cpp
index bf9a2b7609df..6229fb40f7a5 100644
--- a/clang/test/PCH/cxx11-inheriting-ctors.cpp
+++ b/clang/test/PCH/cxx11-inheriting-ctors.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx11-user-defined-literals.cpp b/clang/test/PCH/cxx11-user-defined-literals.cpp
index 7ad17f55d712..cf3dc8cf5a17 100644
--- a/clang/test/PCH/cxx11-user-defined-literals.cpp
+++ b/clang/test/PCH/cxx11-user-defined-literals.cpp
@@ -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 at 11 {{substitution failure}}
+                // expected-note at 14 {{substitution failure}}
 
 #endif

diff  --git a/clang/test/PCH/cxx1y-decltype-auto.cpp b/clang/test/PCH/cxx1y-decltype-auto.cpp
index a1c9339cb669..8a85283cac75 100644
--- a/clang/test/PCH/cxx1y-decltype-auto.cpp
+++ b/clang/test/PCH/cxx1y-decltype-auto.cpp
@@ -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 at 12 {{non-const reference cannot bind to bit-field 'x'}}
+// expected-error at 15 {{non-const reference cannot bind to bit-field 'x'}}
 template void f(Z); // expected-note {{in instantiation of}}
 
 #endif

diff  --git a/clang/test/PCH/cxx1y-deduced-return-type.cpp b/clang/test/PCH/cxx1y-deduced-return-type.cpp
index a61dda21e7f9..186224986645 100644
--- a/clang/test/PCH/cxx1y-deduced-return-type.cpp
+++ b/clang/test/PCH/cxx1y-deduced-return-type.cpp
@@ -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)

diff  --git a/clang/test/PCH/cxx1y-default-initializer.cpp b/clang/test/PCH/cxx1y-default-initializer.cpp
index acb6337dea68..a971ba6477d7 100644
--- a/clang/test/PCH/cxx1y-default-initializer.cpp
+++ b/clang/test/PCH/cxx1y-default-initializer.cpp
@@ -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
 

diff  --git a/clang/test/PCH/cxx1y-init-captures.cpp b/clang/test/PCH/cxx1y-init-captures.cpp
index 3c8fc149d84b..7f8a9fa4b3c1 100644
--- a/clang/test/PCH/cxx1y-init-captures.cpp
+++ b/clang/test/PCH/cxx1y-init-captures.cpp
@@ -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 at 15 {{lvalue of type 'const char *const'}}
+  // expected-error at 18 {{lvalue of type 'const char *const'}}
   f("foo"); // expected-note {{here}}
 }
 

diff  --git a/clang/test/PCH/cxx1y-variable-templates.cpp b/clang/test/PCH/cxx1y-variable-templates.cpp
index 29b66a11e8ce..faa9b3df22c1 100644
--- a/clang/test/PCH/cxx1y-variable-templates.cpp
+++ b/clang/test/PCH/cxx1y-variable-templates.cpp
@@ -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 
diff erent type: 'T' vs 'float'}}  // expected-note at 42 {{previous declaration is here}}
-    template<typename T> extern float err1; // expected-error {{redeclaration of 'err1' with a 
diff erent type: 'float' vs 'T'}} // expected-note at 43 {{previous declaration is here}}
+    template<typename T> extern T err0; // expected-error {{redeclaration of 'err0' with a 
diff erent type: 'T' vs 'float'}}  // expected-note at 46 {{previous declaration is here}}
+    template<typename T> extern float err1; // expected-error {{redeclaration of 'err1' with a 
diff erent type: 'float' vs 'T'}} // expected-note at 47 {{previous declaration is here}}
 #endif
     template<typename T> extern T def;
   }

diff  --git a/clang/test/PCH/cxx1z-aligned-alloc.cpp b/clang/test/PCH/cxx1z-aligned-alloc.cpp
index c49b910e852f..c1becbde3bf2 100644
--- a/clang/test/PCH/cxx1z-aligned-alloc.cpp
+++ b/clang/test/PCH/cxx1z-aligned-alloc.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp
index e033577162a6..2f817b4280de 100644
--- a/clang/test/PCH/cxx1z-decomposition.cpp
+++ b/clang/test/PCH/cxx1z-decomposition.cpp
@@ -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 at 12 {{cannot decompose non-class, non-array type 'const int'}}
+// expected-error at 15 {{cannot decompose non-class, non-array type 'const int'}}
 int z = decomp(10); // expected-note {{instantiation of}}
 
 #endif

diff  --git a/clang/test/PCH/cxx1z-using-declaration.cpp b/clang/test/PCH/cxx1z-using-declaration.cpp
index a185ff174046..dd0e59f516f6 100644
--- a/clang/test/PCH/cxx1z-using-declaration.cpp
+++ b/clang/test/PCH/cxx1z-using-declaration.cpp
@@ -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 at 13 {{no match}}
-  // expected-note at 16 {{candidate}}
-  // expected-note at 17 {{candidate}}
-  // expected-note at 18 {{candidate}}
+  // expected-error at 16 {{no match}}
+  // expected-note at 19 {{candidate}}
+  // expected-note at 20 {{candidate}}
+  // expected-note at 21 {{candidate}}
   a.g(0, 0, 0); // expected-note {{instantiation of}}
 }
 

diff  --git a/clang/test/PCH/cxx2a-bitfield-init.cpp b/clang/test/PCH/cxx2a-bitfield-init.cpp
index 344f3cb9129d..ab7c3cea8b48 100644
--- a/clang/test/PCH/cxx2a-bitfield-init.cpp
+++ b/clang/test/PCH/cxx2a-bitfield-init.cpp
@@ -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

diff  --git a/clang/test/PCH/cxx2a-concept-specialization-expr.cpp b/clang/test/PCH/cxx2a-concept-specialization-expr.cpp
index 6227d57c872f..386fee2cb898 100644
--- a/clang/test/PCH/cxx2a-concept-specialization-expr.cpp
+++ b/clang/test/PCH/cxx2a-concept-specialization-expr.cpp
@@ -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/cxx2a-constraints.cpp b/clang/test/PCH/cxx2a-constraints.cpp
index 593d962ea101..d8b79337c8f1 100644
--- a/clang/test/PCH/cxx2a-constraints.cpp
+++ b/clang/test/PCH/cxx2a-constraints.cpp
@@ -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/cxx2a-defaulted-comparison.cpp b/clang/test/PCH/cxx2a-defaulted-comparison.cpp
index 4fb0b83b2648..8fea0fb02847 100644
--- a/clang/test/PCH/cxx2a-defaulted-comparison.cpp
+++ b/clang/test/PCH/cxx2a-defaulted-comparison.cpp
@@ -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
 

diff  --git a/clang/test/PCH/cxx2a-requires-expr.cpp b/clang/test/PCH/cxx2a-requires-expr.cpp
index 5548db4ccf92..d958f3a14704 100644
--- a/clang/test/PCH/cxx2a-requires-expr.cpp
+++ b/clang/test/PCH/cxx2a-requires-expr.cpp
@@ -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;
 

diff  --git a/clang/test/PCH/cxx2a-template-lambdas.cpp b/clang/test/PCH/cxx2a-template-lambdas.cpp
index c9d923f98c01..c11de0aa8481 100644
--- a/clang/test/PCH/cxx2a-template-lambdas.cpp
+++ b/clang/test/PCH/cxx2a-template-lambdas.cpp
@@ -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
index 000000000000..cf7a9f2d4a86
--- /dev/null
+++ b/clang/test/PCH/delayed-pch-instantiate.cpp
@@ -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

diff  --git a/clang/test/PCH/friend-template.cpp b/clang/test/PCH/friend-template.cpp
index 989819b64fbe..a608879ee97f 100644
--- a/clang/test/PCH/friend-template.cpp
+++ b/clang/test/PCH/friend-template.cpp
@@ -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

diff  --git a/clang/test/PCH/implicitly-deleted.cpp b/clang/test/PCH/implicitly-deleted.cpp
index 5238fd3d93ce..669bdac16980 100644
--- a/clang/test/PCH/implicitly-deleted.cpp
+++ b/clang/test/PCH/implicitly-deleted.cpp
@@ -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;

diff  --git a/clang/test/PCH/late-parsed-instantiations.cpp b/clang/test/PCH/late-parsed-instantiations.cpp
index cbcc063e581c..7a787810a87f 100644
--- a/clang/test/PCH/late-parsed-instantiations.cpp
+++ b/clang/test/PCH/late-parsed-instantiations.cpp
@@ -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

diff  --git a/clang/test/PCH/local_static.cpp b/clang/test/PCH/local_static.cpp
index b4131bffde22..d198d84e0b98 100644
--- a/clang/test/PCH/local_static.cpp
+++ b/clang/test/PCH/local_static.cpp
@@ -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;

diff  --git a/clang/test/PCH/macro-undef.cpp b/clang/test/PCH/macro-undef.cpp
index bfe87d12b208..4ec935d15edc 100644
--- a/clang/test/PCH/macro-undef.cpp
+++ b/clang/test/PCH/macro-undef.cpp
@@ -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 at 12 {{uninitialized}}
-// expected-note at 11 {{initialize}}
-// CHECK: fix-it:"{{.*}}":{11:10-11:10}:" = NULL"
+// expected-warning at 16 {{uninitialized}}
+// expected-note at 15 {{initialize}}
+// CHECK: fix-it:"{{.*}}":{15:10-15:10}:" = NULL"
 
-// expected-warning at 18 {{uninitialized}}
-// expected-note at 17 {{initialize}}
-// CHECK: fix-it:"{{.*}}":{17:10-17:10}:" = 0"
+// expected-warning at 22 {{uninitialized}}
+// expected-note at 21 {{initialize}}
+// CHECK: fix-it:"{{.*}}":{21:10-21:10}:" = 0"
 
 int main() {
   f<int>(); // expected-note {{instantiation}}

diff  --git a/clang/test/PCH/make-integer-seq.cpp b/clang/test/PCH/make-integer-seq.cpp
index 3622c33449d3..a52349cb7c96 100644
--- a/clang/test/PCH/make-integer-seq.cpp
+++ b/clang/test/PCH/make-integer-seq.cpp
@@ -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);

diff  --git a/clang/test/PCH/ms-if-exists.cpp b/clang/test/PCH/ms-if-exists.cpp
index be29ac62ef24..c875b1db7245 100644
--- a/clang/test/PCH/ms-if-exists.cpp
+++ b/clang/test/PCH/ms-if-exists.cpp
@@ -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 at 14{{no viable conversion from 'HasFoo' to 'int *'}}
+                         // expected-error at 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
index 000000000000..a7b418df1fa4
--- /dev/null
+++ b/clang/test/PCH/pch-instantiate-templates-forward-decl.cpp
@@ -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 at 20 {{variable has incomplete type}}
+// expected-note at 17 {{in instantiation of function template specialization}}
+// expected-note at 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
index 000000000000..20aadf83bdb8
--- /dev/null
+++ b/clang/test/PCH/pch-instantiate-templates.cpp
@@ -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 at 18 {{cannot initialize return object}}
+// expected-note at 22 {{in instantiation of member function}}

diff  --git a/clang/test/PCH/pr18806.cpp b/clang/test/PCH/pr18806.cpp
index c28320db9561..28ceb82ca5a5 100644
--- a/clang/test/PCH/pr18806.cpp
+++ b/clang/test/PCH/pr18806.cpp
@@ -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

diff  --git a/clang/test/PCH/pragma-diag-section.cpp b/clang/test/PCH/pragma-diag-section.cpp
index eea6bd73f546..7f72f3ce679a 100644
--- a/clang/test/PCH/pragma-diag-section.cpp
+++ b/clang/test/PCH/pragma-diag-section.cpp
@@ -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 at 41 {{in instantiation of member function}} \
-                  expected-note at 28 {{initialize the variable 'a' to silence}}
+                  expected-note at 44 {{in instantiation of member function}} \
+                  expected-note at 31 {{initialize the variable 'a' to silence}}
     }
 };
 

diff  --git a/clang/test/PCH/rdar10830559.cpp b/clang/test/PCH/rdar10830559.cpp
index aa19da43a34e..0144f34cbba8 100644
--- a/clang/test/PCH/rdar10830559.cpp
+++ b/clang/test/PCH/rdar10830559.cpp
@@ -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
index 000000000000..a10a075f095f
--- /dev/null
+++ b/clang/test/PCH/specialization-after-instantiation.cpp
@@ -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 at 20 {{implicit instantiation first required here}}
+  return 10;
+}
+
+#endif // BODY

diff  --git a/clang/test/PCH/type_pack_element.cpp b/clang/test/PCH/type_pack_element.cpp
index c4ed6c81e2e9..9d1106bfe705 100644
--- a/clang/test/PCH/type_pack_element.cpp
+++ b/clang/test/PCH/type_pack_element.cpp
@@ -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 { };
 


        


More information about the cfe-commits mailing list