[llvm-branch-commits] [clang] [clang] Implement evaluation context for checking template parameters (PR #126088)

Matheus Izvekov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Feb 6 08:32:10 PST 2025


https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/126088

Instead of manually adding a note pointing to the relevant template parameter to every relevant error, which is very easy to miss, this patch adds a new instantiation context note, so that this can work using RAII magic.

This fixes a bunch of places where these notes were missing, and is more future-proof.

Some diagnostics are reworked to make better use of this note:
- Errors about missing template arguments now refer to the parameter which is missing an argument.
- Template Template parameter mismatches now refer to template parameters as parameters instead of arguments.

It's likely this will add the note to some diagnostics where the parameter is not super relevant, but this can be reworked with time and the decrease in maintenance burden makes up for it.

This bypasses the templight dumper for the new context entry, as the tests are very hard to update.

This depends on #125453, which is needed to avoid losing the context note for errors occuring during template argument deduction.

>From ad221308c153e96aad7fbdc2bebadc345152a03e Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Fri, 31 Jan 2025 17:51:18 -0300
Subject: [PATCH] [clang] Implement evaluation context for checking template
 parameters

Instead of manually adding a note pointing to the relevant template
parameter to every relevant error, which is very easy to miss,
this patch adds a new instantiation context note, so that this
can work using RAII magic.

This fixes a bunch of places where these notes were missing, and is
more future-proof.

Some diagnostics are reworked to make better use of this note:
- Errors about missing template arguments now refer to the parameter
  which is missing an argument.
- Template Template parameter mismatches now refer to template
  parameters as parameters instead of arguments.

It's likely this will add the note to some diagnostics where the
parameter is not super relevant, but this can be reworked with time
and the decrease in maintenance burden makes up for it.

This bypasses the templight dumper for the new context entry, as the
tests are very hard to update.

This depends on #125453, which is needed to avoid losing the context
note for errors occuring during template argument deduction.
---
 clang/docs/ReleaseNotes.rst                   |  10 ++
 .../clang/Basic/DiagnosticSemaKinds.td        |  10 +-
 clang/include/clang/Sema/Sema.h               |  20 ++-
 clang/lib/Frontend/FrontendActions.cpp        |  24 ++-
 clang/lib/Sema/SemaInit.cpp                   |   7 +-
 clang/lib/Sema/SemaLambda.cpp                 |   7 +-
 clang/lib/Sema/SemaLookup.cpp                 |  14 +-
 clang/lib/Sema/SemaTemplate.cpp               | 141 ++++++------------
 clang/lib/Sema/SemaTemplateDeduction.cpp      |   5 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  30 +++-
 clang/test/AST/ByteCode/cxx1z.cpp             |   2 +-
 clang/test/AST/ByteCode/cxx20.cpp             |   2 +-
 clang/test/AST/ByteCode/cxx98.cpp             |   2 +-
 .../basic.lookup/basic.lookup.unqual/p7.cpp   |   1 +
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |   2 +-
 clang/test/CXX/drs/cwg0xx.cpp                 |  10 +-
 clang/test/CXX/drs/cwg10xx.cpp                |   1 +
 clang/test/CXX/drs/cwg13xx.cpp                |   1 +
 clang/test/CXX/drs/cwg18xx.cpp                |  19 +--
 clang/test/CXX/drs/cwg1xx.cpp                 |  16 +-
 clang/test/CXX/drs/cwg20xx.cpp                |  10 +-
 clang/test/CXX/drs/cwg21xx.cpp                |   3 +-
 clang/test/CXX/drs/cwg3xx.cpp                 |   3 +
 clang/test/CXX/drs/cwg4xx.cpp                 |  11 +-
 clang/test/CXX/drs/cwg6xx.cpp                 |   5 +-
 clang/test/CXX/expr/expr.const/p3-0x.cpp      |   7 +-
 .../expr.prim.req/type-requirement.cpp        |   2 +-
 .../temp/temp.arg/temp.arg.nontype/p1-11.cpp  |   2 +-
 .../CXX/temp/temp.arg/temp.arg.nontype/p1.cpp |   7 +-
 .../CXX/temp/temp.arg/temp.arg.nontype/p5.cpp |  14 +-
 .../temp/temp.arg/temp.arg.template/p3-0x.cpp |  12 +-
 .../temp/temp.arg/temp.arg.template/p3-2a.cpp |   8 +-
 .../CXX/temp/temp.arg/temp.arg.type/p2.cpp    |  18 ++-
 .../temp/temp.decls/temp.class.spec/p8-1y.cpp |   4 +-
 .../temp.variadic/fixed-expansion.cpp         |  42 +++---
 .../multi-level-substitution.cpp              |  10 +-
 clang/test/CXX/temp/temp.deduct/p9.cpp        |   5 +-
 clang/test/CXX/temp/temp.param/p1.cpp         |   9 +-
 clang/test/CXX/temp/temp.param/p12.cpp        |   2 +-
 clang/test/CXX/temp/temp.param/p15-cxx0x.cpp  |  10 +-
 clang/test/CXX/temp/temp.param/p8-cxx20.cpp   |   2 +-
 .../temp.dep/temp.dep.constexpr/p2.cpp        |   2 +-
 .../cxx1y-variable-template-no-body.cpp       |  10 +-
 clang/test/CXX/temp/temp.spec/part.spec.cpp   |   4 +-
 .../CXX/temp/temp.spec/temp.expl.spec/p20.cpp |   8 +-
 clang/test/Misc/integer-literal-printing.cpp  |   7 +
 clang/test/Modules/missing-body-in-import.cpp |   1 +
 clang/test/Modules/template-default-args.cpp  |   4 +-
 clang/test/Parser/MicrosoftExtensions.cpp     |   2 +-
 clang/test/Parser/cxx-template-argument.cpp   |  12 +-
 .../Parser/cxx-template-template-recovery.cpp |  24 +--
 ...xx1z-class-template-argument-deduction.cpp |  10 +-
 clang/test/SemaCXX/access-base-class.cpp      |  24 +--
 clang/test/SemaCXX/alias-template.cpp         |   5 +-
 clang/test/SemaCXX/anonymous-struct.cpp       |   3 +-
 .../SemaCXX/constant-expression-cxx11.cpp     |   4 +-
 clang/test/SemaCXX/constant-expression.cpp    |   2 +-
 .../SemaCXX/cxx1z-noexcept-function-type.cpp  |   1 +
 clang/test/SemaCXX/cxx2a-consteval.cpp        |   2 +-
 clang/test/SemaCXX/cxx98-compat-flags.cpp     |   3 +-
 clang/test/SemaCXX/cxx98-compat.cpp           |  11 +-
 .../SemaCXX/implicit-member-functions.cpp     |   1 +
 clang/test/SemaCXX/lambda-expressions.cpp     |   6 +-
 clang/test/SemaCXX/make_integer_seq.cpp       |   1 +
 clang/test/SemaCXX/type-trait-common-type.cpp |   6 +-
 clang/test/SemaCXX/undefined-internal.cpp     |   6 +-
 ...ated-specializations-in-system-headers.cpp |   1 +
 clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl   |   4 +-
 .../SemaHLSL/BuiltIns/StructuredBuffers.hlsl  |  62 ++++----
 .../SemaObjCXX/parameterized_classes_subst.mm |   2 +-
 clang/test/SemaTemplate/alias-templates.cpp   |   9 +-
 clang/test/SemaTemplate/cwg2398.cpp           |  32 ++--
 clang/test/SemaTemplate/default-arguments.cpp |  23 +--
 .../instantiate-member-pointers.cpp           |  12 +-
 .../instantiate-template-template-parm.cpp    |   4 +-
 .../SemaTemplate/instantiation-default-1.cpp  |  13 +-
 .../SemaTemplate/instantiation-default-2.cpp  |   3 +-
 .../SemaTemplate/instantiation-dependence.cpp |   3 +-
 .../instantiation-depth-defarg.cpp            |   8 +-
 .../instantiation-depth-exception-spec.cpp    |   8 +-
 .../test/SemaTemplate/instantiation-depth.cpp |   6 +-
 .../ms-unqualified-base-class.cpp             |   4 +-
 clang/test/SemaTemplate/nested-template.cpp   |   4 +-
 .../SemaTemplate/partial-spec-instantiate.cpp |   3 +-
 clang/test/SemaTemplate/recovery-crash.cpp    |   3 +-
 clang/test/SemaTemplate/stack-exhaustion.cpp  |   8 +-
 clang/test/SemaTemplate/temp_arg.cpp          |  12 +-
 clang/test/SemaTemplate/temp_arg_nontype.cpp  |  20 ++-
 .../SemaTemplate/temp_arg_nontype_cxx11.cpp   |   2 +-
 .../SemaTemplate/temp_arg_nontype_cxx1z.cpp   |   8 +-
 .../SemaTemplate/temp_arg_nontype_cxx20.cpp   |  24 +--
 .../SemaTemplate/temp_arg_nontype_cxx2c.cpp   |  10 +-
 clang/test/SemaTemplate/temp_arg_template.cpp |  15 +-
 .../SemaTemplate/temp_arg_template_p0522.cpp  |  13 +-
 clang/test/SemaTemplate/temp_arg_type.cpp     |   7 +-
 95 files changed, 545 insertions(+), 447 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index dfce173d414ebb2..7e20954c65e67b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,6 +149,16 @@ Bug Fixes to C++ Support
 - Clang now prints the correct instantiation context for diagnostics suppressed
   by template argument deduction.
 
+Improvements to C++ diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Clang now more consistently adds a note pointing to the relevant template
+  parameter. Some diagnostics are reworded to better take advantage of this.
+- Template Template Parameter diagnostics now stop referring to template
+  parameters as template arguments, in some circumstances, better hiding
+  from the users template template parameter partial ordering arcana.
+
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7b3b932c482baa2..6ab26fb25d8238f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5290,10 +5290,14 @@ def err_template_missing_args : Error<
   "%select{class template|function template|variable template|alias template|"
   "template template parameter|concept|template}0 %1 requires template "
   "arguments">;
-def err_template_arg_list_different_arity : Error<
-  "%select{too few|too many}0 template arguments for "
+def err_template_param_missing_arg : Error<
+  "missing template argument for template parameter">;
+def err_template_template_param_missing_param : Error<
+  "missing template parameter to bind to template template parameter">;
+def err_template_too_many_args : Error<
+  "too many template arguments for "
   "%select{class template|function template|variable template|alias template|"
-  "template template parameter|concept|template}1 %2">;
+  "template template parameter|concept|template}0 %1">;
 def note_template_decl_here : Note<"template is declared here">;
 def note_template_decl_external : Note<
   "template declaration from hidden source: %0">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e39930c1a450343..93b1094616d6a1a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11781,7 +11781,7 @@ class Sema final : public SemaBase {
                                  bool *ConstraintsNotSatisfied = nullptr);
 
   bool CheckTemplateTypeArgument(
-      TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
+      TemplateArgumentLoc &Arg,
       SmallVectorImpl<TemplateArgument> &SugaredConverted,
       SmallVectorImpl<TemplateArgument> &CanonicalConverted);
 
@@ -11817,9 +11817,10 @@ class Sema final : public SemaBase {
                                      bool PartialOrdering,
                                      bool *StrictPackMatch);
 
+  SmallString<128> toTerseString(const NamedDecl &D) const;
+
   void NoteTemplateLocation(const NamedDecl &Decl,
                             std::optional<SourceRange> ParamRange = {});
-  void NoteTemplateParameterLocation(const NamedDecl &Decl);
 
   /// Given a non-type template argument that refers to a
   /// declaration and the type of its corresponding non-type template
@@ -12821,6 +12822,9 @@ class Sema final : public SemaBase {
 
       /// We are performing partial ordering for template template parameters.
       PartialOrderingTTP,
+
+      /// Checking a Template Parameter
+      CheckTemplateParameter,
     } Kind;
 
     /// Was the enclosing context a non-instantiation SFINAE context?
@@ -13048,6 +13052,11 @@ class Sema final : public SemaBase {
                           PartialOrderingTTP, TemplateDecl *PArg,
                           SourceRange InstantiationRange = SourceRange());
 
+    struct CheckTemplateParameter {};
+    /// \brief Note that we are checking a template parameter.
+    InstantiatingTemplate(Sema &SemaRef, CheckTemplateParameter,
+                          NamedDecl *Param);
+
     /// Note that we have finished instantiating this template.
     void Clear();
 
@@ -13081,6 +13090,13 @@ class Sema final : public SemaBase {
     InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
   };
 
+  /// For any diagnostics which occur within its scope, adds a context note
+  /// pointing to the declaration of the template parameter.
+  struct CheckTemplateParameterRAII : InstantiatingTemplate {
+    CheckTemplateParameterRAII(Sema &S, NamedDecl *Param)
+        : InstantiatingTemplate(S, CheckTemplateParameter(), Param) {}
+  };
+
   bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
                              const MultiLevelTemplateArgumentList &TemplateArgs,
                              TemplateArgumentLoc &Output,
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 1ea4a2e9e88cf59..60e103e643e273b 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -403,7 +403,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
   }
 
 private:
-  static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
+  static std::optional<std::string>
+  toString(CodeSynthesisContext::SynthesisKind Kind) {
     switch (Kind) {
     case CodeSynthesisContext::TemplateInstantiation:
       return "TemplateInstantiation";
@@ -461,8 +462,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
       return "TypeAliasTemplateInstantiation";
     case CodeSynthesisContext::PartialOrderingTTP:
       return "PartialOrderingTTP";
+    case CodeSynthesisContext::CheckTemplateParameter:
+      return std::nullopt;
     }
-    return "";
+    return std::nullopt;
   }
 
   template <bool BeginInstantiation>
@@ -470,12 +473,14 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
                                     const CodeSynthesisContext &Inst) {
     std::string YAML;
     {
+      std::optional<TemplightEntry> Entry =
+          getTemplightEntry<BeginInstantiation>(TheSema, Inst);
+      if (!Entry)
+        return;
       llvm::raw_string_ostream OS(YAML);
       llvm::yaml::Output YO(OS);
-      TemplightEntry Entry =
-          getTemplightEntry<BeginInstantiation>(TheSema, Inst);
       llvm::yaml::EmptyContext Context;
-      llvm::yaml::yamlize(YO, Entry, true, Context);
+      llvm::yaml::yamlize(YO, *Entry, true, Context);
     }
     Out << "---" << YAML << "\n";
   }
@@ -555,10 +560,13 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
   }
 
   template <bool BeginInstantiation>
-  static TemplightEntry getTemplightEntry(const Sema &TheSema,
-                                          const CodeSynthesisContext &Inst) {
+  static std::optional<TemplightEntry>
+  getTemplightEntry(const Sema &TheSema, const CodeSynthesisContext &Inst) {
     TemplightEntry Entry;
-    Entry.Kind = toString(Inst.Kind);
+    std::optional<std::string> Kind = toString(Inst.Kind);
+    if (!Kind)
+      return std::nullopt;
+    Entry.Kind = *Kind;
     Entry.Event = BeginInstantiation ? "Begin" : "End";
     llvm::raw_string_ostream OS(Entry.Name);
     printEntryName(TheSema, Inst.Entity, OS);
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index f206cd57eca898b..9281cfc950232f1 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -7246,7 +7246,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
 
 void InitializationSequence::PrintInitLocationNote(Sema &S,
                                               const InitializedEntity &Entity) {
-  if (Entity.isParamOrTemplateParamKind() && Entity.getDecl()) {
+  if (Entity.isParameterKind() && Entity.getDecl()) {
     if (Entity.getDecl()->getLocation().isInvalid())
       return;
 
@@ -7255,9 +7255,8 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
         << Entity.getDecl()->getDeclName();
     else
       S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
-  }
-  else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
-           Entity.getMethodDecl())
+  } else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
+             Entity.getMethodDecl())
     S.Diag(Entity.getMethodDecl()->getLocation(),
            diag::note_method_return_type_change)
       << Entity.getMethodDecl()->getDeclName();
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index ceb32ee15dfa39c..4d278bbc67d281a 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1506,14 +1506,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   TemplateParameterList *TemplateParams =
       getGenericLambdaTemplateParameterList(LSI, *this);
   if (TemplateParams) {
-    for (const auto *TP : TemplateParams->asArray()) {
+    for (auto *TP : TemplateParams->asArray()) {
       if (!TP->getIdentifier())
         continue;
+      CheckTemplateParameterRAII CTP(*this, TP);
       for (const auto &Capture : Intro.Captures) {
-        if (Capture.Id == TP->getIdentifier()) {
+        if (Capture.Id == TP->getIdentifier())
           Diag(Capture.Loc, diag::err_template_param_shadow) << Capture.Id;
-          NoteTemplateParameterLocation(*TP);
-        }
       }
     }
   }
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 0f5b7426e743e05..71d9add9d8c098f 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1586,9 +1586,13 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
   unsigned N = CodeSynthesisContexts.size();
   for (unsigned I = CodeSynthesisContextLookupModules.size();
        I != N; ++I) {
-    Module *M = CodeSynthesisContexts[I].Entity ?
-                getDefiningModule(*this, CodeSynthesisContexts[I].Entity) :
-                nullptr;
+    auto &Ctx = CodeSynthesisContexts[I];
+    // FIXME: Are there any other context kinds that shouldn't be looked at
+    // here?
+    if (Ctx.Kind == CodeSynthesisContext::PartialOrderingTTP ||
+        Ctx.Kind == CodeSynthesisContext::CheckTemplateParameter)
+      continue;
+    Module *M = Ctx.Entity ? getDefiningModule(*this, Ctx.Entity) : nullptr;
     if (M && !LookupModulesCache.insert(M).second)
       M = nullptr;
     CodeSynthesisContextLookupModules.push_back(M);
@@ -3709,7 +3713,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
       TemplateParameterList *Params = FD->getTemplateParameters();
       if (Params->size() == 1) {
         IsTemplate = true;
-        if (!Params->getParam(0)->isTemplateParameterPack() && !StringLit) {
+        NamedDecl *Param = Params->getParam(0);
+        if (!Param->isTemplateParameterPack() && !StringLit) {
           // Implied but not stated: user-defined integer and floating literals
           // only ever use numeric literal operator templates, not templates
           // taking a parameter of class type.
@@ -3722,6 +3727,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
         if (StringLit) {
           SFINAETrap Trap(*this);
           CheckTemplateArgumentInfo CTAI;
+          CheckTemplateParameterRAII CTP(*this, Param);
           TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
           if (CheckTemplateArgument(
                   Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9e68972b33f0a03..78093c66c1a53aa 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -869,9 +869,11 @@ void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
           ? diag::ext_template_param_shadow
           : (SupportedForCompatibility ? diag::ext_compat_template_param_shadow
                                        : diag::err_template_param_shadow);
-  const auto *ND = cast<NamedDecl>(PrevDecl);
+  auto *ND = cast<NamedDecl>(PrevDecl);
+  CheckTemplateParameterRAII CTP(*this, ND);
+  // FIXME: Don't put the name in the diagnostic, unless there is no source
+  // location.
   Diag(Loc, DiagId) << ND->getDeclName();
-  NoteTemplateParameterLocation(*ND);
 }
 
 TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) {
@@ -4824,7 +4826,7 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
 }
 
 bool Sema::CheckTemplateTypeArgument(
-    TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL,
+    TemplateArgumentLoc &AL,
     SmallVectorImpl<TemplateArgument> &SugaredConverted,
     SmallVectorImpl<TemplateArgument> &CanonicalConverted) {
   const TemplateArgument &Arg = AL.getArgument();
@@ -4880,7 +4882,6 @@ bool Sema::CheckTemplateTypeArgument(
                       ? diag::ext_ms_template_type_arg_missing_typename
                       : diag::err_template_arg_must_be_type_suggest)
             << FixItHint::CreateInsertion(Loc, "typename ");
-        NoteTemplateParameterLocation(*Param);
 
         // Recover by synthesizing a type using the location information that we
         // already have.
@@ -4918,7 +4919,6 @@ bool Sema::CheckTemplateTypeArgument(
     // is not a type.
     SourceRange SR = AL.getSourceRange();
     Diag(SR.getBegin(), diag::err_template_arg_must_be_type) << SR;
-    NoteTemplateParameterLocation(*Param);
 
     return true;
   }
@@ -5208,8 +5208,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
                                  CheckTemplateArgumentInfo &CTAI,
                                  CheckTemplateArgumentKind CTAK) {
   // Check template type parameters.
-  if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
-    return CheckTemplateTypeArgument(TTP, ArgLoc, CTAI.SugaredConverted,
+  if (isa<TemplateTypeParmDecl>(Param))
+    return CheckTemplateTypeArgument(ArgLoc, CTAI.SugaredConverted,
                                      CTAI.CanonicalConverted);
 
   const TemplateArgument &Arg = ArgLoc.getArgument();
@@ -5354,8 +5354,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
       // therefore cannot be a non-type template argument.
       Diag(ArgLoc.getLocation(), diag::err_template_arg_must_be_expr)
           << ArgLoc.getSourceRange();
-      NoteTemplateParameterLocation(*Param);
-
       return true;
 
     case TemplateArgument::Type: {
@@ -5375,7 +5373,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
         Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) << SR << T;
       else
         Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR;
-      NoteTemplateParameterLocation(*Param);
       return true;
     }
 
@@ -5466,11 +5463,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
 }
 
 /// Diagnose a missing template argument.
-template<typename TemplateParmDecl>
+template <typename TemplateParmDecl>
 static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
-                                    TemplateDecl *TD,
-                                    const TemplateParmDecl *D,
-                                    TemplateArgumentListInfo &Args) {
+                                    TemplateDecl *TD, const TemplateParmDecl *D,
+                                    TemplateArgumentListInfo &Args,
+                                    bool MatchingTTP) {
   // Dig out the most recent declaration of the template parameter; there may be
   // declarations of the template that are more recent than TD.
   D = cast<TemplateParmDecl>(cast<TemplateDecl>(TD->getMostRecentDecl())
@@ -5488,16 +5485,12 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
     return true;
   }
 
+  SourceLocation DiagLoc = Args.getRAngleLoc();
   // FIXME: If there's a more recent default argument that *is* visible,
   // diagnose that it was declared too late.
-
-  TemplateParameterList *Params = TD->getTemplateParameters();
-
-  S.Diag(Loc, diag::err_template_arg_list_different_arity)
-    << /*not enough args*/0
-    << (int)S.getTemplateNameKindForDiagnostics(TemplateName(TD))
-    << TD;
-  S.NoteTemplateLocation(*TD, Params->getSourceRange());
+  S.Diag(DiagLoc.isValid() ? DiagLoc : Loc,
+         MatchingTTP ? diag::err_template_template_param_missing_param
+                     : diag::err_template_param_missing_arg);
   return true;
 }
 
@@ -5536,6 +5529,8 @@ bool Sema::CheckTemplateArgumentList(
                                        Param = ParamBegin;
        Param != ParamEnd;
        /* increment in loop */) {
+    CheckTemplateParameterRAII CTP1(*this, *Param);
+
     if (size_t ParamIdx = Param - ParamBegin;
         DefaultArgs && ParamIdx >= DefaultArgs.StartPos) {
       // All written arguments should have been consumed by this point.
@@ -5572,11 +5567,9 @@ bool Sema::CheckTemplateArgumentList(
         continue;
       } else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
         // Not enough arguments for this parameter pack.
-        Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-          << /*not enough args*/0
-          << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
-          << Template;
-        NoteTemplateLocation(*Template, Params->getSourceRange());
+        Diag(RAngleLoc, CTAI.MatchingTTP
+                            ? diag::err_template_template_param_missing_param
+                            : diag::err_template_param_missing_arg);
         return true;
       }
     }
@@ -5589,8 +5582,10 @@ bool Sema::CheckTemplateArgumentList(
 
       if (ArgIsExpansion && CTAI.MatchingTTP) {
         SmallVector<TemplateArgument, 4> Args(ParamEnd - Param);
+        CTP1.Clear(); // Will continue processing parameters below.
         for (TemplateParameterList::iterator First = Param; Param != ParamEnd;
              ++Param) {
+          CheckTemplateParameterRAII CTP2(*this, *Param);
           TemplateArgument &Arg = Args[Param - First];
           Arg = ArgLoc.getArgument();
           if (!(*Param)->isTemplateParameterPack() ||
@@ -5631,7 +5626,6 @@ bool Sema::CheckTemplateArgumentList(
                  diag::err_template_expansion_into_fixed_list)
                 << (isa<ConceptDecl>(Template) ? 1 : 0)
                 << ArgLoc.getSourceRange();
-            NoteTemplateParameterLocation(**Param);
             return true;
           }
         }
@@ -5738,14 +5732,14 @@ bool Sema::CheckTemplateArgumentList(
       if (!HasDefaultArg) {
         if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param))
           return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
-                                         NewArgs);
+                                         NewArgs, CTAI.MatchingTTP);
         if (NonTypeTemplateParmDecl *NTTP =
                 dyn_cast<NonTypeTemplateParmDecl>(*Param))
           return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
-                                         NewArgs);
+                                         NewArgs, CTAI.MatchingTTP);
         return diagnoseMissingArgument(*this, TemplateLoc, Template,
                                        cast<TemplateTemplateParmDecl>(*Param),
-                                       NewArgs);
+                                       NewArgs, CTAI.MatchingTTP);
       }
       return true;
     }
@@ -5801,8 +5795,7 @@ bool Sema::CheckTemplateArgumentList(
   // If we have any leftover arguments, then there were too many arguments.
   // Complain and fail.
   if (ArgIdx < NumArgs) {
-    Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-        << /*too many args*/1
+    Diag(TemplateLoc, diag::err_template_too_many_args)
         << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
         << Template
         << SourceRange(NewArgs[ArgIdx].getLocation(), NewArgs.getRAngleLoc());
@@ -6227,8 +6220,6 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
       << Arg->getType() << Arg->getSourceRange();
     for (unsigned I = 0, N = Notes.size(); I != N; ++I)
       S.Diag(Notes[I].first, Notes[I].second);
-
-    S.NoteTemplateParameterLocation(*Param);
     return NPV_Error;
   }
 
@@ -6253,8 +6244,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
     // The types didn't match, but we know we got a null pointer; complain,
     // then recover as if the types were correct.
     S.Diag(Arg->getExprLoc(), diag::err_template_arg_wrongtype_null_constant)
-      << Arg->getType() << ParamType << Arg->getSourceRange();
-    S.NoteTemplateParameterLocation(*Param);
+        << Arg->getType() << ParamType << Arg->getSourceRange();
     return NPV_NullPointer;
   }
 
@@ -6263,8 +6253,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
     // We could just return NPV_NotNullPointer, but we can print a better
     // message with the information we have here.
     S.Diag(Arg->getExprLoc(), diag::err_template_arg_invalid)
-      << EvalResult.Val.getAsString(S.Context, ParamType);
-    S.NoteTemplateParameterLocation(*Param);
+        << EvalResult.Val.getAsString(S.Context, ParamType);
     return NPV_Error;
   }
 
@@ -6276,7 +6265,6 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
         << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), Code)
         << FixItHint::CreateInsertion(S.getLocForEndOfToken(Arg->getEndLoc()),
                                       ")");
-    S.NoteTemplateParameterLocation(*Param);
     return NPV_NullPointer;
   }
 
@@ -6317,7 +6305,6 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
           S.Diag(Arg->getBeginLoc(),
                  diag::err_template_arg_ref_bind_ignores_quals)
               << ParamType << Arg->getType() << Arg->getSourceRange();
-          S.NoteTemplateParameterLocation(*Param);
           return true;
         }
       }
@@ -6335,7 +6322,6 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
       else
         S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_convertible)
             << ArgIn->getType() << ParamType << Arg->getSourceRange();
-      S.NoteTemplateParameterLocation(*Param);
       return true;
     }
   }
@@ -6478,7 +6464,6 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
   if (!Entity) {
     S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
         << Arg->getSourceRange();
-    S.NoteTemplateParameterLocation(*Param);
     return true;
   }
 
@@ -6486,7 +6471,6 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
   if (isa<FieldDecl>(Entity) || isa<IndirectFieldDecl>(Entity)) {
     S.Diag(Arg->getBeginLoc(), diag::err_template_arg_field)
         << Entity << Arg->getSourceRange();
-    S.NoteTemplateParameterLocation(*Param);
     return true;
   }
 
@@ -6495,7 +6479,6 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
     if (!Method->isStatic()) {
       S.Diag(Arg->getBeginLoc(), diag::err_template_arg_method)
           << Method << Arg->getSourceRange();
-      S.NoteTemplateParameterLocation(*Param);
       return true;
     }
   }
@@ -6535,7 +6518,6 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
     if (Var->getType()->isReferenceType()) {
       S.Diag(Arg->getBeginLoc(), diag::err_template_arg_reference_var)
           << Var->getType() << Arg->getSourceRange();
-      S.NoteTemplateParameterLocation(*Param);
       return true;
     }
 
@@ -6555,15 +6537,12 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
     if (!S.Context.hasSameUnqualifiedType(Entity->getType(),
                                           ParamType.getNonReferenceType())) {
       S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
-        << ParamType;
-      S.NoteTemplateParameterLocation(*Param);
+          << ParamType;
       return true;
     }
 
     S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
-      << ParamType
-      << FixItHint::CreateRemoval(AddrOpLoc);
-    S.NoteTemplateParameterLocation(*Param);
+        << ParamType << FixItHint::CreateRemoval(AddrOpLoc);
 
     ArgType = Entity->getType();
   }
@@ -6584,15 +6563,12 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
       ArgType = S.Context.getPointerType(Entity->getType());
       if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) {
         S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of)
-          << ParamType;
-        S.NoteTemplateParameterLocation(*Param);
+            << ParamType;
         return true;
       }
 
       S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of)
-        << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&");
-
-      S.NoteTemplateParameterLocation(*Param);
+          << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&");
     }
   }
 
@@ -6708,7 +6684,6 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
     // We can't perform this conversion.
     S.Diag(ResultArg->getBeginLoc(), diag::err_template_arg_not_convertible)
         << ResultArg->getType() << ParamType << ResultArg->getSourceRange();
-    S.NoteTemplateParameterLocation(*Param);
     return true;
   }
 
@@ -6814,7 +6789,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
              diag::err_non_type_template_parm_type_deduction_failure)
             << Param->getDeclName() << Param->getType() << Arg->getType()
             << Arg->getSourceRange();
-        NoteTemplateParameterLocation(*Param);
         return ExprError();
       }
     }
@@ -6823,10 +6797,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     // declaration, but here we'll pass the argument location because that's
     // where the parameter type is deduced.
     ParamType = CheckNonTypeTemplateParameterType(ParamType, Arg->getExprLoc());
-    if (ParamType.isNull()) {
-      NoteTemplateParameterLocation(*Param);
+    if (ParamType.isNull())
       return ExprError();
-    }
   }
 
   // We should have already dropped all cv-qualifiers by now.
@@ -6858,9 +6830,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     // not the type of the template argument deduced from A, against the
     // template parameter type.
     Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
-      << Arg->getType()
-      << ParamType.getUnqualifiedType();
-    NoteTemplateParameterLocation(*Param);
+        << Arg->getType() << ParamType.getUnqualifiedType();
     return ExprError();
   }
 
@@ -6955,10 +6925,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
           Arg, ParamType,
           PartialOrderingTTP ? CCEK_InjectedTTP : CCEK_TemplateArg, Param);
       assert(!ArgResult.isUnset());
-      if (ArgResult.isInvalid()) {
-        NoteTemplateParameterLocation(*Param);
+      if (ArgResult.isInvalid())
         return ExprError();
-      }
     } else {
       ArgResult = Arg;
     }
@@ -7105,7 +7073,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     if (!ArgType->isIntegralOrEnumerationType()) {
       Diag(Arg->getBeginLoc(), diag::err_template_arg_not_integral_or_enumeral)
           << ArgType << Arg->getSourceRange();
-      NoteTemplateParameterLocation(*Param);
       return ExprError();
     } else if (!Arg->isValueDependent()) {
       class TmplArgICEDiagnoser : public VerifyICEDiagnoser {
@@ -7143,7 +7110,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
       // We can't perform this conversion.
       Diag(Arg->getBeginLoc(), diag::err_template_arg_not_convertible)
           << Arg->getType() << ParamType << Arg->getSourceRange();
-      NoteTemplateParameterLocation(*Param);
       return ExprError();
     }
 
@@ -7189,7 +7155,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
         Diag(Arg->getBeginLoc(), diag::warn_template_arg_negative)
             << toString(OldValue, 10) << toString(Value, 10) << Param->getType()
             << Arg->getSourceRange();
-        NoteTemplateParameterLocation(*Param);
       }
 
       // Complain if we overflowed the template parameter's type.
@@ -7200,12 +7165,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
         RequiredBits = OldValue.getActiveBits() + 1;
       else
         RequiredBits = OldValue.getSignificantBits();
-      if (RequiredBits > AllowedBits) {
+      if (RequiredBits > AllowedBits)
         Diag(Arg->getBeginLoc(), diag::warn_template_arg_too_large)
             << toString(OldValue, 10) << toString(Value, 10) << Param->getType()
             << Arg->getSourceRange();
-        NoteTemplateParameterLocation(*Param);
-      }
     }
 
     QualType T = ParamType->isEnumeralType() ? ParamType : IntegerType;
@@ -7330,8 +7293,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     switch (isNullPointerValueTemplateArgument(*this, Param, ParamType, Arg)) {
     case NPV_NotNullPointer:
       Diag(Arg->getExprLoc(), diag::err_template_arg_not_convertible)
-        << Arg->getType() << ParamType;
-      NoteTemplateParameterLocation(*Param);
+          << Arg->getType() << ParamType;
       return ExprError();
 
     case NPV_Error:
@@ -7429,7 +7391,6 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
     Diag(Arg.getLocation(),
          diag::err_template_template_parameter_not_at_least_as_constrained)
         << Template << Param << Arg.getSourceRange();
-    Diag(Param->getLocation(), diag::note_entity_declared_at) << Param;
     Diag(Template->getLocation(), diag::note_entity_declared_at) << Template;
     MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template,
                                                   TemplateAC);
@@ -7438,25 +7399,24 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
   return false;
 }
 
-static Sema::SemaDiagnosticBuilder noteLocation(Sema &S, const NamedDecl &Decl,
-                                                unsigned HereDiagID,
-                                                unsigned ExternalDiagID) {
-  if (Decl.getLocation().isValid())
-    return S.Diag(Decl.getLocation(), HereDiagID);
-
+SmallString<128> Sema::toTerseString(const NamedDecl &D) const {
   SmallString<128> Str;
   llvm::raw_svector_ostream Out(Str);
-  PrintingPolicy PP = S.getPrintingPolicy();
+  PrintingPolicy PP = getPrintingPolicy();
   PP.TerseOutput = 1;
-  Decl.print(Out, PP);
-  return S.Diag(Decl.getLocation(), ExternalDiagID) << Out.str();
+  D.print(Out, PP);
+  return Str;
 }
 
+// FIXME: Transform this into a context note.
 void Sema::NoteTemplateLocation(const NamedDecl &Decl,
                                 std::optional<SourceRange> ParamRange) {
+  bool HasLoc = Decl.getLocation().isValid();
   SemaDiagnosticBuilder DB =
-      noteLocation(*this, Decl, diag::note_template_decl_here,
-                   diag::note_template_decl_external);
+      Diag(Decl.getLocation(), HasLoc ? diag::note_template_decl_here
+                                      : diag::note_template_decl_external);
+  if (!HasLoc)
+    DB << toTerseString(Decl).str();
   if (ParamRange && ParamRange->isValid()) {
     assert(Decl.getLocation().isValid() &&
            "Parameter range has location when Decl does not");
@@ -7464,11 +7424,6 @@ void Sema::NoteTemplateLocation(const NamedDecl &Decl,
   }
 }
 
-void Sema::NoteTemplateParameterLocation(const NamedDecl &Decl) {
-  noteLocation(*this, Decl, diag::note_template_param_here,
-               diag::note_template_param_external);
-}
-
 ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
     const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc,
     NamedDecl *TemplateParam) {
@@ -8238,7 +8193,6 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
       S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getBeginLoc(),
              diag::err_dependent_typed_non_type_arg_in_partial_spec)
           << Param->getType();
-      S.NoteTemplateParameterLocation(*Param);
       return true;
     }
   }
@@ -8262,6 +8216,7 @@ bool Sema::CheckTemplatePartialSpecializationArgs(
     if (!Param)
       continue;
 
+    CheckTemplateParameterRAII CTP(*this, Param);
     if (CheckNonTypeTemplatePartialSpecializationArgs(*this, TemplateNameLoc,
                                                       Param, &TemplateArgs[I],
                                                       1, I >= NumExplicit))
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index eb70dd743c8be51..aa78a9054ff5b66 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3006,7 +3006,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
         // arguments).
         S.Diag(Param->getLocation(),
                diag::err_template_arg_deduced_incomplete_pack)
-          << Arg << Param;
+            << Arg
+            << Param; // FIXME: Make this diagnostic point to the argument.
         return true;
       }
       if (ConvertArg(InnerArg, SugaredPackedArgsBuilder.size()))
@@ -3072,7 +3073,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
 
   for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
     NamedDecl *Param = TemplateParams->getParam(I);
-
+    Sema::CheckTemplateParameterRAII CTP(S, Param);
     // C++0x [temp.arg.explicit]p3:
     //    A trailing template parameter pack (14.5.3) not otherwise deduced will
     //    be deduced to an empty sequence of template arguments.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index cccf2095816db14..ab91324da97e387 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -575,6 +575,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
   case BuildingDeductionGuides:
   case TypeAliasTemplateInstantiation:
   case PartialOrderingTTP:
+  case CheckTemplateParameter:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -809,7 +810,16 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
     Sema &SemaRef, SourceLocation ArgLoc, PartialOrderingTTP,
     TemplateDecl *PArg, SourceRange InstantiationRange)
     : InstantiatingTemplate(SemaRef, CodeSynthesisContext::PartialOrderingTTP,
-                            ArgLoc, InstantiationRange, PArg) {}
+                            ArgLoc, SourceRange(), PArg) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
+                                                   CheckTemplateParameter,
+                                                   NamedDecl *Param)
+    : InstantiatingTemplate(
+          SemaRef, CodeSynthesisContext::CheckTemplateParameter,
+          Param->getLocation(), Param->getSourceRange(), Param) {
+  assert(Param->isTemplateParameter());
+}
 
 void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
   Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
@@ -1251,12 +1261,18 @@ void Sema::PrintInstantiationStack(DiagFuncRef DiagFunc) {
     case CodeSynthesisContext::PartialOrderingTTP:
       DiagFunc(Active->PointOfInstantiation,
                PDiag(diag::note_template_arg_template_params_mismatch));
-      if (SourceLocation ParamLoc = Active->Entity->getLocation();
-          ParamLoc.isValid())
-        DiagFunc(ParamLoc, PDiag(diag::note_template_prev_declaration)
-                               << /*isTemplateTemplateParam=*/true
-                               << Active->InstantiationRange);
       break;
+    case CodeSynthesisContext::CheckTemplateParameter: {
+      auto &ND = *cast<NamedDecl>(Active->Entity);
+      if (SourceLocation Loc = ND.getLocation(); Loc.isValid()) {
+        DiagFunc(Loc, PDiag(diag::note_template_param_here)
+                          << ND.getSourceRange());
+        break;
+      }
+      DiagFunc(SourceLocation(), PDiag(diag::note_template_param_external)
+                                     << toTerseString(ND).str());
+      break;
+    }
     }
   }
 }
@@ -1300,6 +1316,7 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
     case CodeSynthesisContext::DefaultTemplateArgumentChecking:
     case CodeSynthesisContext::RewritingOperatorAsSpaceship:
     case CodeSynthesisContext::PartialOrderingTTP:
+    case CodeSynthesisContext::CheckTemplateParameter:
       // A default template argument instantiation and substitution into
       // template parameters with arguments for prior parameters may or may
       // not be a SFINAE context; look further up the stack.
@@ -2348,6 +2365,7 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
 ExprResult
 TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
                                           SubstNonTypeTemplateParmExpr *E) {
+  Sema::CheckTemplateParameterRAII CTP(SemaRef, E->getParameter());
   ExprResult SubstReplacement = E->getReplacement();
   if (!isa<ConstantExpr>(SubstReplacement.get()))
     SubstReplacement = TransformExpr(E->getReplacement());
diff --git a/clang/test/AST/ByteCode/cxx1z.cpp b/clang/test/AST/ByteCode/cxx1z.cpp
index 57f99235a2b2015..ca5f10f6567b4c4 100644
--- a/clang/test/AST/ByteCode/cxx1z.cpp
+++ b/clang/test/AST/ByteCode/cxx1z.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s
 // RUN: %clang_cc1 -std=c++17 -verify=ref,both %s
 
-template<typename T, T val> struct A {};
+template<typename T, T val> struct A {}; // both-note 6{{template parameter is declared here}}
 namespace Temp {
   struct S { int n; };
   constexpr S &addr(S &&s) { return s; }
diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp
index 6f65fa5c7cfd3ed..043cf94a5d8faf2 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -895,7 +895,7 @@ namespace VirtDtor {
 }
 
 namespace TemporaryInNTTP {
-  template<auto n> struct B { /* ... */ };
+  template<auto n> struct B { /* ... */ }; // both-note {{template parameter is declared here}}
   struct J1 {
     J1 *self=this;
   };
diff --git a/clang/test/AST/ByteCode/cxx98.cpp b/clang/test/AST/ByteCode/cxx98.cpp
index c17049b01c1daf0..9af668029f8a32c 100644
--- a/clang/test/AST/ByteCode/cxx98.cpp
+++ b/clang/test/AST/ByteCode/cxx98.cpp
@@ -6,7 +6,7 @@
 namespace IntOrEnum {
   const int k = 0;
   const int &p = k; // both-note {{declared here}}
-  template<int n> struct S {};
+  template<int n> struct S {}; // both-note {{template parameter is declared here}}
   S<p> s; // both-error {{not an integral constant expression}} \
           // both-note {{read of variable 'p' of non-integral, non-enumeration type 'const int &'}}
 }
diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
index 9632fda296aa171..fc4e359666ba98b 100644
--- a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
+++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
@@ -33,5 +33,6 @@ namespace test1 {
 // specifiers.
 namespace test2 {
   template <class T> struct bar {};
+  // expected-note at -1 {{template parameter is declared here}}
   template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template 'foo' requires template arguments}} expected-note {{template is declared here}}
 }
diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
index 2bceb3e267790db..57c99212f4c69a8 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
@@ -251,5 +251,5 @@ void P1957R2(void *a, int *b, Agg<int> *c, int Agg<int>::*d) {
   Agg<bool> tc = {c}; // expected-error {{cannot be narrowed}} expected-note {{}}
   Agg<bool> td = {d}; // expected-error {{cannot be narrowed}} expected-note {{}}
 }
-template<bool> struct BoolParam {};
+template<bool> struct BoolParam {}; // expected-note {{template parameter is declared here}}
 BoolParam<&P1957R2> bp; // expected-error {{not allowed in a converted constant expression}}
diff --git a/clang/test/CXX/drs/cwg0xx.cpp b/clang/test/CXX/drs/cwg0xx.cpp
index 282e71bbf3bdaab..7215a8046f27fbc 100644
--- a/clang/test/CXX/drs/cwg0xx.cpp
+++ b/clang/test/CXX/drs/cwg0xx.cpp
@@ -806,6 +806,7 @@ namespace cwg49 { // cwg49: 2.8
   // since-cxx17-error@#cwg49-c {{non-type template argument is not a constant expression}}
   //   since-cxx17-note@#cwg49-c {{read of non-constexpr variable 'q' is not allowed in a constant expression}}
   //   since-cxx17-note@#cwg49-q {{declared here}}
+  //   since-cxx17-note@#cwg49-A {{template parameter is declared here}}
 } // namespace cwg49
 
 namespace cwg50 { // cwg50: 2.7
@@ -1018,9 +1019,9 @@ namespace cwg62 { // cwg62: 2.9
   struct A {
     struct { int n; } b;
   };
-  template<typename T> struct X {};
-  template<typename T> T get() { return get<T>(); }
-  template<typename T> int take(T) { return 0; }
+  template<typename T> struct X {}; // cxx98-note 6{{template parameter is declared here}}
+  template<typename T> T get() { return get<T>(); } // cxx98-note 4{{template parameter is declared here}}
+  template<typename T> int take(T) { return 0; }    // cxx98-note 1{{template parameter is declared here}}
 
   X<A> x1;
   A a = get<A>();
@@ -1135,10 +1136,11 @@ namespace cwg69 { // cwg69: 9
   extern template void f<char>();
   // cxx98-error at -1 {{extern templates are a C++11 extension}}
   // expected-error at -2 {{explicit instantiation declaration of 'f' with internal linkage}}
-  template<void(*)()> struct Q {};
+  template<void(*)()> struct Q {}; // #cwg69-Q
   Q<&f<int> > q;
   // cxx98-error at -1 {{non-type template argument referring to function 'f<int>' with internal linkage is a C++11 extension}}
   //   cxx98-note@#cwg69-f {{non-type template argument refers to function here}}
+  //   cxx98-note@#cwg69-Q {{template parameter is declared here}}
 } // namespace cwg69
 
 namespace cwg70 { // cwg70: 2.7
diff --git a/clang/test/CXX/drs/cwg10xx.cpp b/clang/test/CXX/drs/cwg10xx.cpp
index c5b96c4ab8ffcfb..10ee50558c7e81d 100644
--- a/clang/test/CXX/drs/cwg10xx.cpp
+++ b/clang/test/CXX/drs/cwg10xx.cpp
@@ -43,6 +43,7 @@ namespace cwg1004 { // cwg1004: 5
   template<class T, template<class> class U = T::template A> struct Third { };
   // expected-error at -1 {{is a constructor name}}
   //   expected-note@#cwg1004-t {{in instantiation of default argument}}
+  //   expected-note at -3 {{template parameter is declared here}}
   Third<A<int> > t; // #cwg1004-t
 } // namespace cwg1004
 
diff --git a/clang/test/CXX/drs/cwg13xx.cpp b/clang/test/CXX/drs/cwg13xx.cpp
index 9c72fefb5b65cd1..8a9f28567369970 100644
--- a/clang/test/CXX/drs/cwg13xx.cpp
+++ b/clang/test/CXX/drs/cwg13xx.cpp
@@ -180,6 +180,7 @@ namespace cwg1315 { // cwg1315: partial
   // dependent type of T::value is not the same as 'int'.
   // A core issue will be opened to decide what is supposed to happen here.
   template <typename T, int I> struct C;
+  // expected-note at -1 {{template parameter is declared here}}
   template <typename T> struct C<T, T::value>;
   // expected-error at -1 {{type of specialized non-type template argument depends on a template parameter of the partial specialization}}
 } // namespace cwg1315
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 626473f11d3ec53..5f40fe469b01b8f 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -26,6 +26,7 @@ S<i> V; // #cwg1801-S-i
 // cxx98-14-error at -1 {{non-type template argument does not refer to any declaration}}
 //   cxx98-14-note@#cwg1801-S {{template parameter is declared here}}
 // cxx17-error@#cwg1801-S-i {{non-type template argument refers to subobject '.i'}}
+//   cxx17-note@#cwg1801-S {{template parameter is declared here}}
 } // namespace cwg1801
 
 namespace cwg1802 { // cwg1802: 3.1
@@ -381,13 +382,13 @@ struct A {
   struct B {
     void e();
   };
-  
+
   void f();
-  
+
   struct D {
     void g();
   };
-  
+
   T h();
 
   template<T U>
@@ -399,13 +400,13 @@ struct A<int> {
   struct B {
     void e();
   };
-  
+
   int f();
-  
+
   struct D {
     void g();
   };
-  
+
   template<int U>
   int i();
 };
@@ -430,11 +431,11 @@ class C {
   template<class T>
   friend void A<T>::D::g();
   // expected-warning at -1 {{dependent nested name specifier 'A<T>::D::' for friend class declaration is not supported; turning off access control for 'C'}}
-  
+
   template<class T>
   friend int *A<T*>::h();
   // expected-warning at -1 {{dependent nested name specifier 'A<T *>::' for friend class declaration is not supported; turning off access control for 'C'}}
-  
+
   template<class T>
   template<T U>
   friend T A<T>::i();
@@ -451,7 +452,7 @@ template<class T>
 void A<T>::f() { (void)c.private_int; }
 int A<int>::f() { (void)c.private_int; return 0; }
 
-// FIXME: both definition of 'D::g' are not friends, so they don't have access to 'private_int' 
+// FIXME: both definition of 'D::g' are not friends, so they don't have access to 'private_int'
 template<class T>
 void A<T>::D::g() { (void)c.private_int; }
 void A<int>::D::g() { (void)c.private_int; }
diff --git a/clang/test/CXX/drs/cwg1xx.cpp b/clang/test/CXX/drs/cwg1xx.cpp
index 15bcc20b7fa2a9d..51f320fc43cfaed 100644
--- a/clang/test/CXX/drs/cwg1xx.cpp
+++ b/clang/test/CXX/drs/cwg1xx.cpp
@@ -26,18 +26,22 @@ namespace cwg100 { // cwg100: 2.7
   // cxx98-14-error@#cwg100-a {{non-type template argument does not refer to any declaration}}
   //   cxx98-14-note@#cwg100-A {{template parameter is declared here}}
   // since-cxx17-error@#cwg100-a {{pointer to string literal is not allowed in a template argument}}
+  //   since-cxx17-note@#cwg100-A {{template parameter is declared here}}
   B<"bar"> b; // #cwg100-b
   // cxx98-14-error@#cwg100-b {{non-type template argument does not refer to any declaration}}
   //   cxx98-14-note@#cwg100-B {{template parameter is declared here}}
   // since-cxx17-error@#cwg100-b {{reference to string literal is not allowed in a template argument}}
+  //   since-cxx17-note@#cwg100-B {{template parameter is declared here}}
   C<"baz"> c; // #cwg100-c
   // cxx98-14-error@#cwg100-c {{non-type template argument does not refer to any declaration}}
   //   cxx98-14-note@#cwg100-C {{template parameter is declared here}}
   // since-cxx17-error@#cwg100-c {{pointer to subobject of string literal is not allowed in a template argument}}
+  //   since-cxx17-note@#cwg100-C {{template parameter is declared here}}
   D<*"quux"> d; // #cwg100-d
   // cxx98-14-error@#cwg100-d {{non-type template argument does not refer to any declaration}}
   //   cxx98-14-note@#cwg100-D {{template parameter is declared here}}
   // since-cxx17-error@#cwg100-d {{reference to subobject of string literal is not allowed in a template argument}}
+  //   since-cxx17-note@#cwg100-D {{template parameter is declared here}}
 } // namespace cwg100
 
 namespace cwg101 { // cwg101: 3.5
@@ -152,15 +156,17 @@ namespace cwg112 { // cwg112: 3.1
   volatile T a2[1] = {};
   const Arr a3 = {}; // #cwg112-a3
   volatile Arr a4 = {};
-  template<const volatile T*> struct X {};
+  template<const volatile T*> struct X {}; // #cwg112-X
   // FIXME: Test this somehow in C++11 and on.
   X<a1> x1;
   // cxx98-error at -1 {{non-type template argument referring to object 'a1' with internal linkage is a C++11 extension}}
   //   cxx98-note@#cwg112-a1 {{non-type template argument refers to object here}}
+  //   cxx98-note@#cwg112-X {{template parameter is declared here}}
   X<a2> x2;
   X<a3> x3;
   // cxx98-error at -1 {{non-type template argument referring to object 'a3' with internal linkage is a C++11 extension}}
   //   cxx98-note@#cwg112-a3 {{non-type template argument refers to object here}}
+  //   cxx98-note@#cwg112-X {{template parameter is declared here}}
   X<a4> x4;
 } // namespace cwg112
 
@@ -634,7 +640,7 @@ namespace example3 {
 struct Base {
 private:
   static const int i = 10; // #cwg138-ex3-Base-i
-  
+
 public:
   struct Data;
   // Elaborated type specifier is not the sole constituent of declaration,
@@ -648,7 +654,7 @@ struct Base {
   };
 };
 struct Data {
-  void f() {  
+  void f() {
     int i2 = Base::i;
     // expected-error at -1 {{'i' is a private member of 'cwg138::example3::Base'}}
     //   expected-note@#cwg138-ex3-Base-i {{declared private here}}
@@ -1309,8 +1315,8 @@ namespace cwg184 { // cwg184: 2.7
 
   template<template<typename TT> class T> void A<T>::f() { // #cwg184-T
     T<> t;
-    // expected-error at -1 {{too few template arguments for template template parameter 'T'}}
-    //   expected-note@#cwg184-T {{template is declared here}}
+    // expected-error at -1 {{missing template argument for template parameter}}
+    //   expected-note@#cwg184-T {{template parameter is declared here}}
   }
 
   template<template<typename TT = char> class T> void A<T>::g() {
diff --git a/clang/test/CXX/drs/cwg20xx.cpp b/clang/test/CXX/drs/cwg20xx.cpp
index 141a1012aef933e..fd31a51f79ec57b 100644
--- a/clang/test/CXX/drs/cwg20xx.cpp
+++ b/clang/test/CXX/drs/cwg20xx.cpp
@@ -27,7 +27,7 @@ int b = __builtin_addressof(b2)->foo;
 // cwg2009: na
 
 namespace cwg2026 { // cwg2026: 11
-  template<int> struct X {};
+  template<int> struct X {}; // #cwg2026-X
 
   const int a = a + 1; // #cwg2026-a
   // expected-warning at -1 {{variable 'a' is uninitialized when used within its own initialization}}
@@ -35,9 +35,11 @@ namespace cwg2026 { // cwg2026: 11
   // cxx98-error at -1 {{non-type template argument of type 'int' is not an integral constant expression}}
   //   cxx98-note at -2 {{initializer of 'a' is not a constant expression}}
   //   cxx98-note@#cwg2026-a {{declared here}}
+  //   cxx98-note@#cwg2026-X {{template parameter is declared here}}
   // since-cxx11-error@#cwg2026-xa {{non-type template argument is not a constant expression}}
   //   since-cxx11-note@#cwg2026-xa {{initializer of 'a' is not a constant expression}}
   //   since-cxx11-note@#cwg2026-a {{declared here}}
+  //   since-cxx11-note@#cwg2026-X {{template parameter is declared here}}
 
 #if __cplusplus >= 201103L
   constexpr int b = b;
@@ -65,9 +67,11 @@ namespace cwg2026 { // cwg2026: 11
     // cxx98-error at -1 {{non-type template argument of type 'int' is not an integral constant expression}}
     //   cxx98-note at -2 {{initializer of 'e' is not a constant expression}}
     //   cxx98-note@#cwg2026-e {{declared here}}
+    //   cxx98-note@#cwg2026-X {{template parameter is declared here}}
     // since-cxx11-error@#cwg2026-xe {{non-type template argument is not a constant expression}}
     //   since-cxx11-note@#cwg2026-xe {{initializer of 'e' is not a constant expression}}
     //   since-cxx11-note@#cwg2026-e {{declared here}}
+    //   since-cxx11-note@#cwg2026-X {{template parameter is declared here}}
 
 #if __cplusplus >= 201103L
     static constexpr int f = f;
@@ -149,7 +153,7 @@ namespace cwg2076 { // cwg2076: 13
     operator string_view() const;
   };
 
-  void foo(const string &); // #cwg2076-foo 
+  void foo(const string &); // #cwg2076-foo
   void bar(string_view); // #cwg2076-bar
 
   void func(const string &arg) {
@@ -429,7 +433,7 @@ int f()
   return 0;
 }
 } // namespace GH42233
-} // namespace cwg2091 
+} // namespace cwg2091
 
 namespace cwg2094 { // cwg2094: 5
   struct A { int n; };
diff --git a/clang/test/CXX/drs/cwg21xx.cpp b/clang/test/CXX/drs/cwg21xx.cpp
index 42a7c4d7bbdedb8..97bf32065875926 100644
--- a/clang/test/CXX/drs/cwg21xx.cpp
+++ b/clang/test/CXX/drs/cwg21xx.cpp
@@ -24,7 +24,7 @@ namespace std {
 }
 
 namespace cwg2100 { // cwg2100: 12
-  template<const int *P, bool = true> struct X {};
+  template<const int *P, bool = true> struct X {}; // #cwg2100-X
   template<typename T> struct A {
     static const int n = 1;
     int f() {
@@ -35,6 +35,7 @@ namespace cwg2100 { // cwg2100: 12
       return X<&n>::n; // ok, value-dependent
       // cxx98-14-error at -1 {{non-type template argument refers to object 'n' that does not have linkage}}
       //   cxx98-14-note@#cwg2100-n {{non-type template argument refers to object here}}
+      //   cxx98-14-note@#cwg2100-X {{template parameter is declared here}}
     }
   };
   template<const int *P> struct X<P> {
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index 6c420ecd4c91db3..415082c0fdceefa 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -318,6 +318,7 @@ namespace cwg319 { // cwg319: no
   pa parr; // ok, type has linkage despite using 'n1'
 
   template<typename> struct X {};
+  // cxx98-note at -1 2{{template parameter is declared here}}
 
   void f() {
     struct A { int n; };
@@ -997,6 +998,7 @@ namespace cwg354 { // cwg354: 3.1 c++11
   //   since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}}
   ptr_mem<(int S::*)0> m1;
   // cxx98-error at -1 {{non-type template argument is not a pointer to member constant}}
+  //   cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}}
   ptr_mem<(float S::*)0> m2; // #cwg354-m2
   // cxx98-error@#cwg354-m2 {{non-type template argument of type 'float S::*' cannot be converted to a value of type 'int S::*'}}
   //   cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}}
@@ -1503,6 +1505,7 @@ namespace cwg389 { // cwg389: no
     typedef enum {} const D; // #cwg389-D
   };
   template<typename> struct T {};
+  // cxx98-note at -1 5{{template parameter is declared here}}
 
   struct WithLinkage1 {};
   enum WithLinkage2 {};
diff --git a/clang/test/CXX/drs/cwg4xx.cpp b/clang/test/CXX/drs/cwg4xx.cpp
index 0debc104ac45b82..59979d36d37b4b2 100644
--- a/clang/test/CXX/drs/cwg4xx.cpp
+++ b/clang/test/CXX/drs/cwg4xx.cpp
@@ -43,12 +43,15 @@ namespace cwg401 { // cwg401: 2.8
   // expected-error@#cwg401-A {{'type' is a private member of 'cwg401::C'}}
   //   expected-note@#cwg402-friend-A-C {{in instantiation of default argument for 'A<C>' required here}}
   //   expected-note@#cwg402-C-type {{implicitly declared private here}}
+  //   expected-note@#cwg401-A {{template parameter is declared here}}
   // expected-error@#cwg401-A {{'type' is a protected member of 'cwg401::B'}}
   //   expected-note@#cwg402-b {{in instantiation of default argument for 'A<B>' required here}}
   //   expected-note@#cwg402-B-type {{declared protected here}}
+  //   expected-note@#cwg401-A {{template parameter is declared here}}
   // expected-error@#cwg401-A {{'type' is a private member of 'cwg401::D'}}
   //   expected-note@#cwg402-d {{in instantiation of default argument for 'A<D>' required here}}
   //   expected-note@#cwg402-D-type {{implicitly declared private here}}
+  //   expected-note@#cwg401-A {{template parameter is declared here}}
   class B {
   protected:
     typedef int type; // #cwg402-B-type
@@ -80,8 +83,9 @@ namespace cwg401 { // cwg401: 2.8
   // to not treat the default template argument as a SFINAE context in C++98.
   template<class T, class U = typename T::type> void f(T) {} // #cwg402-f
   // cxx98-error at -1 {{default template arguments for a function template are a C++11 extension}}
-  // cxx98-error at -2 {{'type' is a protected member of 'cwg401::B'}}
-  //   cxx98-note at -3 {{in instantiation of default argument for 'f<B>' required here}}
+  //   cxx98-note at -2 {{template parameter is declared here}}
+  // cxx98-error at -3 {{'type' is a protected member of 'cwg401::B'}}
+  //   cxx98-note at -4 {{in instantiation of default argument for 'f<B>' required here}}
   //   cxx98-note@#cwg402-f-b {{while substituting deduced template arguments into function template 'f' [with T = B, U = (no value)]}}
   //   cxx98-note@#cwg402-B-type {{declared protected here}}
   void g(B b) { f(b); } // #cwg402-f-b
@@ -637,6 +641,8 @@ namespace cwg431 { // cwg431: 2.8
 
 namespace cwg432 { // cwg432: 3.0
   template<typename T> struct A {};
+  // expected-note at -1    {{template parameter is declared here}}
+  // since-cxx11-note at -2 {{template parameter is declared here}}
   template<typename T> struct B : A<B> {};
   // expected-error at -1 {{use of class template 'B' requires template arguments}}
   //   expected-note at -2 {{template is declared here}}
@@ -1377,6 +1383,7 @@ namespace cwg487 { // cwg487: 2.7
 
 namespace cwg488 { // cwg488: 2.9 c++11
   template <typename T> void f(T);
+  // cxx98-note at -1 {{template parameter is declared here}}
   void f(int);
   void g() {
     // FIXME: It seems CWG thought this should be a SFINAE failure prior to
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index fb6acde459d9c4e..56db1ac52382617 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -83,6 +83,7 @@ namespace cwg603 { // cwg603: 3.1
   typedef S<'\001'> S1;
   typedef S<(1ul << __CHAR_BIT__) + 1> S1;
   // since-cxx11-error at -1 {{non-type template argument evaluates to 257, which cannot be narrowed to type 'unsigned char'}}
+  //   since-cxx11-note at -4 {{template parameter is declared here}}
 } // namespace cwg603
 
 // cwg604: na
@@ -407,7 +408,7 @@ namespace cwg638 { // cwg638: no
 
   class X {
     typedef int type;
-    template<class T> friend struct A<T>::B; 
+    template<class T> friend struct A<T>::B;
     // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
     template<class T> friend void A<T>::f();
     // expected-warning at -1 {{dependent nested name specifier 'A<T>::' for friend class declaration is not supported; turning off access control for 'X'}}
@@ -1078,7 +1079,7 @@ namespace cwg677 { // cwg677: no
   struct A {
     void *operator new(std::size_t);
     void operator delete(void*) = delete; // #cwg677-A-delete
-    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}} 
+    // cxx98-error at -1 {{deleted function definitions are a C++11 extension}}
   };
   struct B {
     void *operator new(std::size_t);
diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp
index 3eedef3cf7712f9..f40e1af14d11189 100644
--- a/clang/test/CXX/expr/expr.const/p3-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp
@@ -4,7 +4,7 @@
 // A converted constant expression of type T is a core constant expression,
 int nonconst = 8; // expected-note 3 {{here}}
 enum NonConstE : unsigned char { NCE = nonconst }; // expected-error {{enumerator value is not a constant expression}} expected-note {{read of non-const}}
-template<int = nonconst> struct NonConstT {}; // expected-error {{non-type template argument is not a constant expression}} expected-note {{read of non-const}}
+template<int = nonconst> struct NonConstT {}; // expected-error {{non-type template argument is not a constant expression}} expected-note {{read of non-const}} expected-note {{template parameter is declared here}}
 void NonConstF() {
   switch (nonconst) {
     case nonconst: // expected-error {{case value is not a constant expression}} expected-note {{read of non-const}}
@@ -66,7 +66,7 @@ enum class EEE : unsigned short {
   e = 123456, // expected-error {{enumerator value evaluates to 123456, which cannot be narrowed to type 'unsigned short'}}
   f = -3 // expected-error {{enumerator value evaluates to -3, which cannot be narrowed to type 'unsigned short'}}
 };
-template<unsigned char> using A = int; // cxx17-note 2{{template parameter is declared here}}
+template<unsigned char> using A = int; // expected-note 4{{template parameter is declared here}}
 
 using Int = A<E6>;
 using Int = A<EE::EE32>; // expected-error {{not implicitly convertible}}
@@ -79,7 +79,8 @@ using Int = A<-3>; // expected-error {{template argument evaluates to -3, which
 // integral conversions as well as boolean conversions.
 // FIXME: Per core issue 1407, this is not correct.
 template<typename T, T v> struct Val { static constexpr T value = v; };
-// cxx17-note at -1 2{{template parameter is declared here}}
+// cxx17-note at -1 1{{template parameter is declared here}}
+// expected-note at -2 2{{template parameter is declared here}}
 static_assert(Val<bool, E1>::value == 1, ""); // ok
 static_assert(Val<bool, '\0'>::value == 0, ""); // ok
 static_assert(Val<bool, U'\1'>::value == 1, ""); // ok
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
index 5433cfb21955dd8..2572e766cb263a0 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
@@ -77,7 +77,7 @@ using r2i3 = r2<int, int>; // expected-error{{constraints not satisfied for clas
 namespace ns2 {
   template<typename T, typename U> struct identity {};
 
-  template<typename... Ts> requires requires { typename identity<Ts...>; } // expected-note 2{{because 'typename identity<Ts...>' would be invalid: too few template arguments for class template 'identity'}}
+  template<typename... Ts> requires requires { typename identity<Ts...>; } // expected-note 2{{because 'typename identity<Ts...>' would be invalid: missing template argument for template parameter}}
   struct r4 {};
 
   using r4i1 = r4<int>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int>]}}
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
index 692958ef565cf48..332f69bacb69e48 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
@@ -9,7 +9,7 @@ template<int *ip> struct IP {  // expected-note 6 {{template parameter is declar
   IP<ip> *ip2;
 };
 
-template<int &ip> struct IR {};
+template<int &ip> struct IR {}; // expected-note {{template parameter is declared here}}
 
 constexpr std::nullptr_t get_nullptr() { return nullptr; }
 
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index 629000d88acc37d..e979051e234196a 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -31,16 +31,16 @@ namespace non_type_tmpl_param {
 //      omitted if the name refers to a function or array and shall be omitted
 //      if the corresopnding template-parameter is a reference; or
 namespace addr_of_obj_or_func {
-  template <int* p> struct X0 { }; // expected-note 5{{here}}
+  template <int* p> struct X0 { }; // expected-note 5{{here}} cxx17-note 2{{here}}
 #if __cplusplus >= 201103L
   // precxx17-note at -2 2{{template parameter is declared here}}
 #endif
 
-  template <int (*fp)(int)> struct X1 { }; // cxx17-note {{here}}
+  template <int (*fp)(int)> struct X1 { }; // cxx17-note {{here}} precxx17-note{{here}}
 #if __cplusplus <= 199711L
   // precxx17-note at -2 {{here}}
 #endif
-  template <int &p> struct X2 { }; // expected-note 4{{here}}
+  template <int &p> struct X2 { }; // expected-note 5{{here}}
   template <const int &p> struct X2k { }; // expected-note {{here}}
   template <int (&fp)(int)> struct X3 { }; // expected-note 4{{here}}
 
@@ -180,6 +180,7 @@ namespace addr_of_obj_or_func {
 
 namespace bad_args {
   template <int* N> struct X0 { }; // precxx17-note 4{{template parameter is declared here}}
+                                   // cxx17-note at -1 3{{template parameter is declared here}}
   int i = 42;
   X0<&i + 2> x0a; // precxx17-error{{non-type template argument does not refer to any declaration}} \
                      cxx17-error {{non-type template argument is not a constant expression}} \
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
index 034ad49d0715cab..bb7512a95ed3b66 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
@@ -48,9 +48,9 @@ namespace pointer_to_object_parameters {
     X(int, int);
     operator int() const;
   };
-  
-  template<X const *Ptr> struct A2; // expected-note 0-1{{template parameter is declared here}}
-  
+
+  template<X const *Ptr> struct A2; // expected-note 1-2{{template parameter is declared here}}
+
   X *X_ptr; // expected-note 0-1{{declared here}}
   X an_X;
   X array_of_Xs[10];
@@ -131,16 +131,16 @@ namespace reference_parameters {
     S3<vi> s3v;
     S3<cvi> s3cv;
   }
-  
+
   namespace PR6250 {
     template <typename T, const T &ref> void inc() {
       ref++; // expected-error{{read-only variable is not assignable}}
     }
-  
+
     template<typename T, const T &ref> void bind() {
       T &ref2 = ref; // expected-error{{drops 'const' qualifier}}
     }
-    
+
     int counter;
     void test() {
       inc<int, counter>(); // expected-note{{instantiation of}}
@@ -213,7 +213,7 @@ namespace reference_to_function {
 //        (13.4).
 namespace pointer_to_member_function {
   struct X { };
-  struct Y : X { 
+  struct Y : X {
     int f(int);
     int g(int);
     int g(float);
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
index 3caed045c6688b9..99031cf0395bf40 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
@@ -20,14 +20,14 @@ eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined t
 template<
   template <int ...N> // expected-error {{cannot be narrowed from type 'int' to 'short'}}
                       // expected-error at -1 {{conversion from 'int' to 'void *' is not allowed in a converted constant expression}}
-  class TT // expected-note 2{{previous template template parameter is here}}
+  class TT // expected-note 2{{template parameter is declared here}}
 > struct X0 { };
 
 template<int I, int J, int ...Rest> struct X0a;
 template<int ...Rest> struct X0b;
 template<int I, long J> struct X0c;
-template<int I, short J> struct X0d;
-template<int I, void *J> struct X0e; // expected-note{{template parameter is declared here}}
+template<int I, short J> struct X0d; // expected-note {{template parameter is declared here}}
+template<int I, void *J> struct X0e; // expected-note {{template parameter is declared here}}
 
 X0<X0a> inst_x0a;
 X0<X0b> inst_x0b;
@@ -38,14 +38,14 @@ X0<X0e> inst_x0e; // expected-note{{template template argument has different tem
 template<typename T,
          template <T ...N> // expected-error {{conversion from 'short' to 'void *' is not allowed in a converted constant expression}}
                            // expected-error at -1 {{cannot be narrowed from type 'int' to 'short'}}
-         class TT // expected-note 2{{previous template template parameter is here}}
+         class TT // expected-note 2{{template parameter is declared here}}
 > struct X1 { };
 
 template<int I, int J, int ...Rest> struct X1a;
 template<long I, long ...Rest> struct X1b;
 template<short I, short J> struct X1c;
-template<short I, long J> struct X1d;
-template<short I, void *J> struct X1e; // expected-note{{template parameter is declared here}}
+template<short I, long J> struct X1d;  // expected-note {{template parameter is declared here}}
+template<short I, void *J> struct X1e; // expected-note {{template parameter is declared here}}
 
 X1<int, X1a> inst_x1a;
 X1<long, X1b> inst_x1b;
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
index 342ffba53dbfaf1..5570a7f9d75deba 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
@@ -13,12 +13,12 @@ template<F> struct W { }; // #W
 S1<X> s11;
 S1<Y> s12;
 // expected-error at -1 {{template template argument 'Y' is more constrained than template template parameter 'P'}}
-// expected-note@#S1 {{'P' declared here}}
+// expected-note@#S1 {{template parameter is declared here}}
 // expected-note@#Y {{'Y' declared here}}
 S1<Z> s13;
 S1<W> s14;
 // expected-error at -1 {{template template argument 'W' is more constrained than template template parameter 'P'}}
-// expected-note@#S1 {{'P' declared here}}
+// expected-note@#S1 {{template parameter is declared here}}
 // expected-note@#W {{'W' declared here}}
 // expected-note@#F 1-2{{similar constraint expressions not considered equivalent}}
 // expected-note@#C 1-2{{similar constraint}}
@@ -43,12 +43,12 @@ template<template<typename T> requires C<T> class P> struct S4 { }; // #S4
 S4<X> s41;
 S4<Y> s42;
 // expected-error at -1 {{template template argument 'Y' is more constrained than template template parameter 'P'}}
-// expected-note@#S4 {{'P' declared here}}
+// expected-note@#S4 {{template parameter is declared here}}
 // expected-note@#Y {{'Y' declared here}}
 S4<Z> s43;
 S4<W> s44;
 // expected-error at -1 {{template template argument 'W' is more constrained than template template parameter 'P'}}
-// expected-note@#S4 {{'P' declared here}}
+// expected-note@#S4 {{template parameter is declared here}}
 // expected-note@#W {{'W' declared here}}
 
 template<template<typename T> requires C<T> typename U> struct S5 {
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
index 650f8585b115a87..65f3e178ac963bb 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
 template<class T> struct A {
@@ -13,7 +13,8 @@ template<typename T> struct B {
 };
 B<function> b; // expected-note{{instantiation of}}
 
-template <typename T> int f0(void *, const T&); // expected-note{{candidate template ignored: substitution failure}}
+template <typename T> // #f0-temphead
+int f0(void *, const T&); // expected-note{{candidate template ignored: substitution failure}}
 enum {e};
 // expected-note at -1 {{unnamed type used in template argument was declared here}}
 
@@ -22,6 +23,7 @@ void test_f0(int n) { // #here
 #if __cplusplus <= 199711L
   // expected-warning at -2 {{template argument uses unnamed type}}
   // expected-note at -3 {{while substituting deduced template arguments}}
+  // expected-note@#f0-temphead {{template parameter is declared here}}
 #endif
 
   int vla[n]; // expected-warning {{variable length arrays in C++ are a Clang extension}}
@@ -33,9 +35,9 @@ void test_f0(int n) { // #here
 }
 
 namespace N0 {
-  template <typename R, typename A1> void f0(R (*)(A1));
-  template <typename T> int f1(T);
-  template <typename T, typename U> int f1(T, U);
+  template <typename R, typename A1> void f0(R (*)(A1)); // #f0
+  template <typename T> int f1(T);                       // #f1-1
+  template <typename T, typename U> int f1(T, U);        // #f1-2
   enum {e1};
 #if __cplusplus <= 199711L
   // expected-note at -2 2{{unnamed type used in template argument was declared here}}
@@ -51,7 +53,7 @@ namespace N0 {
  // expected-note at -2 {{unnamed type used in template argument was declared here}}
 #endif
 
-  template<typename T> struct X;
+  template<typename T> struct X; // cxx98-note {{template parameter is declared here}}
   template<typename T> struct X<T*> { };
 
   void f() {
@@ -59,24 +61,28 @@ namespace N0 {
 #if __cplusplus <= 199711L
     // expected-warning at -2 {{template argument uses unnamed type}}
     // expected-note at -3 {{while substituting deduced template arguments}}
+    // expected-note@#f0 {{template parameter is declared here}}
 #endif
 
        &f1<__typeof__(e1)>);
 #if __cplusplus <= 199711L
  // expected-warning at -2 {{template argument uses unnamed type}}
  // expected-note at -3 {{while substituting explicitly-specified template arguments}}
+ // expected-note@#f1-1 {{template parameter is declared here}}
 #endif
 
     int (*fp1)(int, __typeof__(e2)) = f1;
 #if __cplusplus <= 199711L
     // expected-warning at -2 {{template argument uses unnamed type}}
     // expected-note at -3 {{while substituting deduced template arguments}}
+    // expected-note@#f1-2 {{template parameter is declared here}}
 #endif
 
     f1(e2);
 #if __cplusplus <= 199711L
     // expected-warning at -2 {{template argument uses unnamed type}}
     // expected-note at -3 {{while substituting deduced template arguments}}
+    // expected-note@#f1-1 {{template parameter is declared here}}
 #endif
 
     f1(e2);
diff --git a/clang/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp b/clang/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
index 388a80ee765c879..cf01e406c14ad4b 100644
--- a/clang/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
@@ -25,7 +25,7 @@ template<typename Outer> struct X {
   template<typename Inner> static int y<Outer>; // expected-error 3{{cannot be deduced}} expected-note 3{{'Inner'}}
   template<typename Inner> static int y<Inner>; // expected-error {{does not specialize}}
 
-  template<typename, int> static int z;
+  template<typename, int> static int z; // expected-note {{template parameter is declared here}}
   template<Outer N> static int z<int, N>; // expected-error {{not implicitly convertible}}
 };
 template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-error {{cannot be deduced}} expected-note {{'Inner'}}
@@ -33,4 +33,4 @@ template<typename Outer> template<typename Inner> int X<Outer>::y<Inner>; // exp
 template<> template<typename Inner> int X<int>::y<Inner>; // expected-error {{does not specialize}} expected-note {{instantiation of}}
 
 X<int> xi;
-X<int*> xf; // expected-note {{instantiation of}}
+X<int*> xf; // expected-note 2{{instantiation of}}
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
index ab4c663d24c7d5e..cab5c967b0c4f42 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
@@ -14,10 +14,10 @@ struct is_same<T, T> {
 };
 
 namespace ExpandIntoFixed {
-  template<typename T, 
-           typename U, 
-           typename V = pair<T, U>, 
-           typename W = V*> 
+  template<typename T,
+           typename U,
+           typename V = pair<T, U>,
+           typename W = V*>
   class X0 { };
 
   template<typename ...Ts>
@@ -26,24 +26,24 @@ namespace ExpandIntoFixed {
     typedef X0<Ts...> type;
   };
 
-  static_assert(is_same<X1<int, int>::type, 
+  static_assert(is_same<X1<int, int>::type,
                         X0<int, int, pair<int, int>, pair<int, int>*>>::value,
                 "fails with two default arguments");
 
-  static_assert(is_same<X1<int, int, float>::type, 
+  static_assert(is_same<X1<int, int, float>::type,
                         X0<int, int, float, float*>>::value,
                 "fails with one default argument");
 
-  static_assert(is_same<X1<int, int, float, double>::type, 
+  static_assert(is_same<X1<int, int, float, double>::type,
                         X0<int, int, float, double>>::value,
                 "fails with no default arguments");
 }
 
 namespace ExpandIntoFixedShifted {
-  template<typename T, 
-           typename U, 
-           typename V = pair<T, U>, 
-           typename W = V*> 
+  template<typename T,
+           typename U,
+           typename V = pair<T, U>,
+           typename W = V*>
   class X0 { };
 
   template<typename ...Ts>
@@ -52,15 +52,15 @@ namespace ExpandIntoFixedShifted {
     typedef X0<char, Ts...> type;
   };
 
-  static_assert(is_same<X1<int>::type, 
+  static_assert(is_same<X1<int>::type,
                         X0<char, int, pair<char, int>, pair<char, int>*>>::value,
                 "fails with two default arguments");
 
-  static_assert(is_same<X1<int, float>::type, 
+  static_assert(is_same<X1<int, float>::type,
                         X0<char, int, float, float*>>::value,
                 "fails with one default argument");
 
-  static_assert(is_same<X1<int, float, double>::type, 
+  static_assert(is_same<X1<int, float, double>::type,
                         X0<char, int, float, double>>::value,
                 "fails with no default arguments");
 }
@@ -76,11 +76,11 @@ namespace Deduction {
 }
 
 namespace PR9021a {
-  template<typename, typename> 
+  template<typename, typename>
   struct A { };
 
   template<typename ...T>
-  struct B { 
+  struct B {
     A<T...> a1;
   };
 
@@ -93,9 +93,9 @@ namespace PR9021b {
   template<class, class>
   struct t2
   {
-    
+
   };
-  
+
   template<template<class...> class M>
   struct m
   {
@@ -107,14 +107,14 @@ namespace PR9021b {
 }
 
 namespace PartialSpecialization {
-  template<typename T, typename U, typename V = U>
-  struct X0; // expected-note 2{{template is declared here}}
+  template<typename T, typename U, typename V = U> // expected-note {{template parameter is declared here}}
+  struct X0; // expected-note {{template is declared here}}
 
   template<typename ...Ts>
   struct X0<Ts...> { // expected-error {{class template partial specialization is not more specialized than the primary template}}
   };
 
-  X0<int> x0i; // expected-error{{too few template arguments for class template 'X0'}}
+  X0<int> x0i; // expected-error{{missing template argument for template parameter}}
   X0<int, float> x0if;
   X0<int, float, double> x0ifd;
 }
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 30e7c65dac91cb7..c6e6038fb6ddf56 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -48,7 +48,7 @@ namespace PacksAtDifferentLevels {
   int check1[X<short, int>::Inner<tuple<pair<short, unsigned short>,
                                         pair<int, unsigned int>,
                                         pair<long, unsigned long>>
-                                       >::value == 1? 1 : -1]; 
+                                       >::value == 1? 1 : -1];
 
   template<unsigned ...Values> struct unsigned_tuple { };
   template<typename ...Types>
@@ -99,7 +99,7 @@ namespace PacksAtDifferentLevels {
   int check5[X2<short, int>::Inner<int(pair<short, unsigned short>,
                                        pair<int, unsigned int>,
                                        pair<long, unsigned long>)
-                                     >::value == 1? 1 : -1]; 
+                                     >::value == 1? 1 : -1];
 
   template<typename T, typename U>
   struct some_function_object {
@@ -217,8 +217,8 @@ namespace ExpandingNonTypeTemplateParameters {
   template<typename ...Types>
   struct tuple_of_values {
     template<Types ...Values> // expected-error{{a non-type template parameter cannot have type 'float'}} \
-    // expected-note{{template parameter is declared here}}
-    struct apply { // expected-note 2{{template is declared here}}
+    // expected-note 2{{template parameter is declared here}}
+    struct apply { // expected-note {{template is declared here}}
       typedef tuple<value_c<Types, Values>...> type;
     };
   };
@@ -236,7 +236,7 @@ namespace ExpandingNonTypeTemplateParameters {
 
   tuple_of_values<int&, float&>::apply<i, i>::type tv2; // expected-error{{non-type template parameter of reference type 'float &' cannot bind to template argument of type 'int'}}
 
-  tuple_of_values<int&, float&>::apply<i>::type tv3; // expected-error{{too few template arguments for class template 'apply'}}
+  tuple_of_values<int&, float&>::apply<i>::type tv3; // expected-error{{missing template argument for template parameter}}
 
   tuple_of_values<int&, float&>::apply<i, f, i>::type tv4; // expected-error{{too many template arguments for class template 'apply'}}
 }
diff --git a/clang/test/CXX/temp/temp.deduct/p9.cpp b/clang/test/CXX/temp/temp.deduct/p9.cpp
index 7b661c275211b9e..5f9ea27234c81dc 100644
--- a/clang/test/CXX/temp/temp.deduct/p9.cpp
+++ b/clang/test/CXX/temp/temp.deduct/p9.cpp
@@ -15,13 +15,14 @@ void test_f() {
 }
 
 template <class T, unsigned = sizeof([]() { T::invalid; })>
+// expected-note at -1 {{template parameter is declared here}}
 void g(T);
 void g(...);
 void test_g() {
-  g(0); // expected-error at -4 {{type 'int' cannot be used prior to '::'}}
+  g(0); // expected-error at -5 {{type 'int' cannot be used prior to '::'}}
         // expected-note at -4 {{in instantiation of default argument}}
         // expected-note at -2 {{while substituting deduced template arguments}}
-        // expected-note at -7 {{while substituting into a lambda expression here}}
+        // expected-note at -8 {{while substituting into a lambda expression here}}
 }
 
 template <class T>
diff --git a/clang/test/CXX/temp/temp.param/p1.cpp b/clang/test/CXX/temp/temp.param/p1.cpp
index e9a978961769c39..e2eecdf0d455449 100644
--- a/clang/test/CXX/temp/temp.param/p1.cpp
+++ b/clang/test/CXX/temp/temp.param/p1.cpp
@@ -5,8 +5,9 @@ template<template<> class C> class D; // expected-error{{template template param
 
 
 struct A {};
-template<class M, 
-         class T = A,  // expected-note{{previous default template argument defined here}}
+template<class M,
+         class T // expected-note {{template parameter is declared here}}
+           = A,  // expected-note{{previous default template argument defined here}}
          class C> // expected-error{{template parameter missing a default argument}}
-class X0 {}; // expected-note{{template is declared here}}
-X0<int> x0; // expected-error{{too few template arguments for class template 'X0'}}
+class X0 {};
+X0<int> x0; // expected-error{{missing template argument for template parameter}}
diff --git a/clang/test/CXX/temp/temp.param/p12.cpp b/clang/test/CXX/temp/temp.param/p12.cpp
index 8317e7f24152cce..09f8325336a452c 100644
--- a/clang/test/CXX/temp/temp.param/p12.cpp
+++ b/clang/test/CXX/temp/temp.param/p12.cpp
@@ -32,7 +32,7 @@ template<int N,
   class B3n;
 
 // Check validity of default arguments
-template<template<class, int> class =// expected-note {{previous template template parameter is here}}
+template<template<class, int> class =// expected-note {{template parameter is declared here}}
            Y1> // expected-error{{too many template arguments for class template 'Y1'}}
                // expected-note at -1 {{template template argument has different template parameters than its corresponding template template parameter}}
   class C1 {};
diff --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
index 83144a494937b65..402a205f1ea63dd 100644
--- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -77,9 +77,9 @@ template<typename T> struct wrap {
 
 template<typename T> struct takedrop_impl;
 template<place...X> struct takedrop_impl<places<X...>> {
-  template<template<decltype(X)> class ...Take,
+  template<template<decltype(X)> class ...Take, // expected-note 2{{template parameter is declared here}}
            template<place      > class ...Drop>
-  struct inner { // expected-note 2{{declared}}
+  struct inner {
     typedef types<typename Take<_>::type...> take;
     typedef types<typename Drop<_>::type...> drop;
   };
@@ -87,11 +87,11 @@ template<place...X> struct takedrop_impl<places<X...>> {
 
 template<unsigned N, typename...Ts> struct take {
   using type = typename takedrop_impl<typename make_places<N>::type>::
-    template inner<wrap<Ts>::template inner...>::take; // expected-error {{too few template arguments}}
+    template inner<wrap<Ts>::template inner...>::take; // expected-error {{missing template argument}}
 };
 template<unsigned N, typename...Ts> struct drop {
   using type = typename takedrop_impl<typename make_places<N>::type>::
-    template inner<wrap<Ts>::template inner...>::drop; // expected-error {{too few template arguments}}
+    template inner<wrap<Ts>::template inner...>::drop; // expected-error {{missing template argument}}
 };
 
 using T1 = take<3, int, char, double, long>::type; // expected-note {{previous}}
@@ -118,7 +118,7 @@ using D3 = drop<5, int, char, double, long>::type; // expected-note {{in instant
 // implicitly a pack expansion.
 template<typename ...Default> struct DefArg {
   template<template<typename T = Default> class ...Classes> struct Inner { // expected-error {{default argument contains unexpanded parameter pack}} expected-note {{here}}
-    Inner(Classes<>...); // expected-error {{too few}}
+    Inner(Classes<>...); // expected-error {{missing template argument}}
   };
 };
 template<typename T> struct vector {};
diff --git a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp
index a3478c06696614f..aa1666f6306d054 100644
--- a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp
+++ b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp
@@ -59,7 +59,7 @@ namespace ConstDestruction {
     f<D{1, true}>();
   }
 
-  template<D d> struct Z {};
+  template<D d> struct Z {}; // expected-note {{template parameter is declared here}}
   Z<D{2, true}> z1;
   Z<D{2, false}> z2; // expected-error {{non-type template argument is not a constant expression}} expected-note-re {{in call to '{{.*}}.~D()'}}
 }
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp
index ecb82372bcb47f9..cb048ecdf70014f 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp
@@ -2,7 +2,7 @@
 // RUN: %clang_cc1 -std=c++11 -verify=cxx11 %s
 // cxx11-no-diagnostics
 
-template<int n> struct S;
+template<int n> struct S; // cxx98-note {{template parameter is declared here}}
 
 template<int n> struct T {
   T() {
diff --git a/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
index 741ebc5de41fccb..749b45524f9e621 100644
--- a/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
+++ b/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
@@ -3,27 +3,27 @@
 // RUN: not %clang_cc1 --std=c++1y -x c++ -fixit %t -DFIXING
 // RUN: %clang_cc1 --std=c++1y -x c++ %t -DFIXING
 
-template<typename T> 
-T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+template<typename T> // expected-note {{template parameter is declared here}}
+T pi = T(3.1415926535897932385);
 
 template int pi<int>;
 
 #ifndef FIXING
-template float pi<>; // expected-error {{too few template arguments for variable template 'pi'}}
+template float pi<>; // expected-error {{missing template argument for template parameter}}
 template double pi_var0; // expected-error {{explicit instantiation of 'pi_var0' does not refer to a function template, variable template, member function, member class, or static data member}}
 #endif
 
 // Should recover as if definition
 template double pi_var = 5; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}}
 #ifndef FIXING
-template<typename T> 
+template<typename T>
 T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}}
 
 template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \
                           expected-error{{redefinition of 'pi0' as different kind of symbol}}
 #endif
 
-template<typename T> 
+template<typename T>
 T pi1 = T(3.1415926535897932385); // expected-note 0-2 {{here}}
 
 // Should recover as if specialization
diff --git a/clang/test/CXX/temp/temp.spec/part.spec.cpp b/clang/test/CXX/temp/temp.spec/part.spec.cpp
index 4b0fdb902633a19..3923d160ef5cfd1 100644
--- a/clang/test/CXX/temp/temp.spec/part.spec.cpp
+++ b/clang/test/CXX/temp/temp.spec/part.spec.cpp
@@ -250,7 +250,7 @@ template <typename T> class PCT1 {};
 template <typename T1, typename T2> class PCT2 {};
 template <int X> class PCT3 {};
 template <void (TestClass::*)()> class PCT4 {};
-template <void (*)()> class PCT5 {};
+template <void (*)()> class PCT5 {}; // expected-note {{template parameter is declared here}}
 template <typename T> class PCT6 {
   // expected-note at +1 3{{implicitly declared private here}}
   template <typename NT> class NPCT1 {};
@@ -416,7 +416,7 @@ template <typename T1, typename T2> class PCTT1 {};
 template <typename T1, typename T2, typename T3> class PCTT2 {};
 template <typename T, int X> class PCTT3 {};
 template <typename T, void (TestClass::*)()> class PCTT4 {};
-template <typename T, void (*)()> class PCTT5 {};
+template <typename T, void (*)()> class PCTT5 {}; // expected-note {{template parameter is declared here}}
 template <typename T1, typename T2> class PCTT6 {
   template <typename NT> class NCT1 {};
   template <typename NT> class NCT2; // forward declaration
diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
index 0283dba63b110ab..63fd997add4ec6d 100644
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
@@ -2,13 +2,13 @@
 template<typename T>
 void f(T);
 
-template<typename T>
-struct A { }; // expected-note{{template is declared here}}
+template<typename T> // expected-note {{template parameter is declared here}}
+struct A { };
 
 struct X {
   template<> friend void f<int>(int); // expected-error{{in a friend}}
   template<> friend class A<int>; // expected-error{{cannot be a friend}}
-  
+
   friend void f<float>(float); // okay
   friend class A<float>; // okay
 };
@@ -18,6 +18,6 @@ struct PR41792 {
   template <> friend void f<>(int);
 
   // expected-error at +2{{template specialization declaration cannot be a friend}}
-  // expected-error at +1{{too few template arguments for class template 'A'}}
+  // expected-error at +1{{missing template argument for template parameter}}
   template <> friend class A<>;
 };
diff --git a/clang/test/Misc/integer-literal-printing.cpp b/clang/test/Misc/integer-literal-printing.cpp
index bd231a368fb703f..bc52b3f04467940 100644
--- a/clang/test/Misc/integer-literal-printing.cpp
+++ b/clang/test/Misc/integer-literal-printing.cpp
@@ -14,6 +14,7 @@ enum class boolTy : bool {
 template <boolTy T> struct Type3Helper;
 template <> struct Type3Helper<boolTy::b> { typedef boolTy Ty; };
 template <boolTy T, typename Type3Helper<T>::Ty U> struct Type3 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 // PR14386
 enum class charTy : char {
@@ -23,6 +24,7 @@ enum class charTy : char {
 template <charTy T> struct Type4Helper;
 template <> struct Type4Helper<charTy::c> { typedef charTy Ty; };
 template <charTy T, typename Type4Helper<T>::Ty U> struct Type4 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 enum class scharTy : signed char {
   c = 0,
@@ -31,6 +33,7 @@ enum class scharTy : signed char {
 template <scharTy T> struct Type5Helper;
 template <> struct Type5Helper<scharTy::c> { typedef scharTy Ty; };
 template <scharTy T, typename Type5Helper<T>::Ty U> struct Type5 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 enum class ucharTy : unsigned char {
   c = 0,
@@ -39,6 +42,7 @@ enum class ucharTy : unsigned char {
 template <ucharTy T> struct Type6Helper;
 template <> struct Type6Helper<ucharTy::c> { typedef ucharTy Ty; };
 template <ucharTy T, typename Type6Helper<T>::Ty U> struct Type6 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 enum class wcharTy : wchar_t {
   c = 0,
@@ -47,6 +51,7 @@ enum class wcharTy : wchar_t {
 template <wcharTy T> struct Type7Helper;
 template <> struct Type7Helper<wcharTy::c> { typedef wcharTy Ty; };
 template <wcharTy T, typename Type7Helper<T>::Ty U> struct Type7 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 enum class char16Ty : char16_t {
   c = 0,
@@ -55,6 +60,7 @@ enum class char16Ty : char16_t {
 template <char16Ty T> struct Type8Helper;
 template <> struct Type8Helper<char16Ty::c> { typedef char16Ty Ty; };
 template <char16Ty T, typename Type8Helper<T>::Ty U> struct Type8 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 enum class char32Ty : char16_t {
   c = 0,
@@ -63,6 +69,7 @@ enum class char32Ty : char16_t {
 template <char32Ty T> struct Type9Helper;
 template <> struct Type9Helper<char32Ty::c> { typedef char32Ty Ty; };
 template <char32Ty T, typename Type9Helper<T>::Ty U> struct Type9 {};
+// expected-note at -1 {{template parameter is declared here}}
 
 void Function() {
   Function1(Type1<-42>()); // expected-error{{no matching function for call to 'Function1'}}
diff --git a/clang/test/Modules/missing-body-in-import.cpp b/clang/test/Modules/missing-body-in-import.cpp
index b52ebba15087a3b..e25f7b592130197 100644
--- a/clang/test/Modules/missing-body-in-import.cpp
+++ b/clang/test/Modules/missing-body-in-import.cpp
@@ -29,6 +29,7 @@ export module mod2;
 import mod1;
 
 struct C: B <A{"a", "b"}> { // expected-error {{non-type template argument is not a constant expression}}
+                            // expected-note at mod1.cppm:11 {{template parameter is declared here}}
   constexpr C(int a) { }
 };
 
diff --git a/clang/test/Modules/template-default-args.cpp b/clang/test/Modules/template-default-args.cpp
index 85b2a18d9e50694..1d8de709fd59838 100644
--- a/clang/test/Modules/template-default-args.cpp
+++ b/clang/test/Modules/template-default-args.cpp
@@ -22,7 +22,7 @@ template<typename T = int> struct B;
 template<typename T = int> struct C;
 template<typename T> struct D {};
 template<typename T> struct F {};
-template<typename T> struct G {};
+template<typename T> struct G {}; // #G
 template<typename T> struct J {};
 template<typename T = int> struct J;
 struct K : J<> {};
@@ -39,8 +39,10 @@ E<> e;
 F<> f;
 G<> g; // expected-error {{missing '#include "a.h"'; default argument of 'G' must be defined before it is used}}
 // expected-note at a.h:7 {{default argument declared here is not reachable}}
+// expected-note@#G {{template parameter is declared here}}
 H<> h; // expected-error {{missing '#include "a.h"'; default argument of 'H' must be defined before it is used}}
 // expected-note at a.h:8 {{default argument declared here is not reachable}}
+// expected-note at a.h:8 {{template parameter is declared here}}
 I<> i;
 L<> *l;
 END
diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp
index 9102bca8f6bb2c9..e47b4ef78afdfcf 100644
--- a/clang/test/Parser/MicrosoftExtensions.cpp
+++ b/clang/test/Parser/MicrosoftExtensions.cpp
@@ -126,7 +126,7 @@ void template_uuid()
 }
 
 
-template <class T, const GUID* g = &__uuidof(T)> // expected-note {{template parameter is declared here}}
+template <class T, const GUID* g = &__uuidof(T)> // expected-note 2{{template parameter is declared here}}
 class COM_CLASS_TEMPLATE  { };
 
 typedef COM_CLASS_TEMPLATE<struct_with_uuid, &*&__uuidof(struct_with_uuid)> COM_TYPE_1; // expected-warning {{non-type template argument containing a dereference operation is a Microsoft extension}}
diff --git a/clang/test/Parser/cxx-template-argument.cpp b/clang/test/Parser/cxx-template-argument.cpp
index 3c2169f86d6e745..ffe53e7c6f77e27 100644
--- a/clang/test/Parser/cxx-template-argument.cpp
+++ b/clang/test/Parser/cxx-template-argument.cpp
@@ -57,9 +57,9 @@ namespace PR13210 {
 // Don't emit spurious messages
 namespace pr16225add {
 
-  template<class T1, typename T2> struct Known { }; // expected-note 3 {{template is declared here}}
+  template<class T1, typename T2> struct Known { }; // expected-note 3{{template parameter is declared here}}
   template<class T1, typename T2> struct X;
-  template<class T1, typename T2> struct ABC; // expected-note {{template is declared here}}
+  template<class T1, typename T2> struct ABC; // expected-note {{template parameter is declared here}}
   template<int N1, int N2> struct ABC2 {};
 
   template<class T1, typename T2> struct foo :
@@ -68,7 +68,7 @@ namespace pr16225add {
 
   template<class T1, typename T2> struct foo2 :
     UnknownBase<T1,T2>, // expected-error {{no template named 'UnknownBase'}}
-    Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}
+    Known<T1>  // expected-error {{missing template argument for template parameter}}
   { };
 
   template<class T1, typename T2> struct foo3 :
@@ -76,8 +76,8 @@ namespace pr16225add {
   { };
 
   template<class T1, typename T2> struct foo4 :
-    UnknownBase<T1,ABC<T2> >, // expected-error {{too few template arguments for class template 'ABC'}}
-    Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}
+    UnknownBase<T1,ABC<T2> >, // expected-error {{missing template argument for template parameter}}
+    Known<T1>  // expected-error {{missing template argument for template parameter}}
   { };
 
   template<class T1, typename T2> struct foo5 :
@@ -92,7 +92,7 @@ namespace pr16225add {
 #if __cplusplus <= 199711L
     // expected-error at -2 {{use '> >'}}
 #endif
-    Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}
+    Known<T1>  // expected-error {{missing template argument for template parameter}}
   { };
 
   template<class T1, typename T2, int N> struct foo7 :
diff --git a/clang/test/Parser/cxx-template-template-recovery.cpp b/clang/test/Parser/cxx-template-template-recovery.cpp
index 5700b160cd36403..2ece5a8ccdbea3d 100644
--- a/clang/test/Parser/cxx-template-template-recovery.cpp
+++ b/clang/test/Parser/cxx-template-template-recovery.cpp
@@ -1,33 +1,33 @@
 // RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only %s
 
 namespace a {
-  template <typename T>
-  concept C1 = true; // #C1
+  template <typename T> // #C1-T
+  concept C1 = true;
 
   template <typename T>
   auto V1 = true; // #V1
 
   namespace b {
-    template <typename T>
-    concept C2 = true; // #C2
+    template <typename T> // #C2-T
+    concept C2 = true;
     template <typename T>
     auto V2 = true; // #V2
   }
 }
 
-template <typename T>
-concept C3 = true; // #C3
+template <typename T> // #C3-T
+concept C3 = true;
 template <typename T>
 auto V3 = true; // #V3
 template <template <typename T> typename C>
 constexpr bool test = true;
 
-static_assert(test<a::C1>); // expected-error {{too few template arguments for concept 'C1'}} \
-                            // expected-note@#C1 {{here}}
-static_assert(test<a::b::C2>); // expected-error {{too few template arguments for concept 'C2'}} \
-                               // expected-note@#C2 {{here}}
-static_assert(test<C3>); // expected-error {{too few template arguments for concept 'C3'}} \
-                         // expected-note@#C3 {{here}}
+static_assert(test<a::C1>); // expected-error {{missing template argument for template parameter}} \
+                            // expected-note@#C1-T {{here}}
+static_assert(test<a::b::C2>); // expected-error {{missing template argument for template parameter}} \
+                               // expected-note@#C2-T {{here}}
+static_assert(test<C3>); // expected-error {{missing template argument for template parameter}} \
+                         // expected-note@#C3-T {{here}}
 
 static_assert(test<a::V1>); // expected-error {{use of variable template 'a::V1' requires template arguments}} \
                             // expected-note@#V1 {{here}}
diff --git a/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp b/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp
index a1594333abae739..eda8cb739f0af08 100644
--- a/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp
@@ -11,7 +11,7 @@ A(int) -> A<int>;
 // Make sure we still correctly parse cases where a template can appear without arguments.
 namespace template_template_arg {
   template<template<typename> typename> struct X {};
-  template<typename> struct Y {};
+  template<typename> struct Y {}; // expected-note 2{{template parameter is declared here}}
 
   X<A> xa;
   Y<A> ya; // expected-error {{requires template arguments}}
@@ -36,10 +36,10 @@ namespace template_template_arg {
 
 namespace template_template_arg_pack {
   template<template<typename> typename...> struct XP {};
-  template<typename...> struct YP {};
+  template<typename...> struct YP {}; // expected-note 2{{template parameter is declared here}}
 
   struct Z { template<typename T> struct Q {}; }; // expected-note 2{{here}}
-  
+
   template<typename T> using ZId = Z;
 
   template<typename ...Ts> struct A {
@@ -116,7 +116,7 @@ namespace stmt {
 }
 
 namespace expr {
-  template<typename T> struct U {};
+  template<typename T> struct U {}; // expected-note {{template parameter is declared here}}
   void j() {
     (void)typeid(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
     (void)sizeof(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
@@ -217,7 +217,7 @@ namespace typename_specifier {
 }
 
 namespace parenthesized {
-  template<typename T> struct X { X(T); };                    
+  template<typename T> struct X { X(T); };
   auto n = (X([]{}));
 }
 
diff --git a/clang/test/SemaCXX/access-base-class.cpp b/clang/test/SemaCXX/access-base-class.cpp
index 47d0f02ec545c89..7d5fe38848f95ed 100644
--- a/clang/test/SemaCXX/access-base-class.cpp
+++ b/clang/test/SemaCXX/access-base-class.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 namespace T1 {
-  
+
 class A { };
 class B : private A { }; // expected-note {{declared private here}}
 
@@ -10,7 +10,7 @@ void f(B* b) {
 
 }
 
-namespace T2 { 
+namespace T2 {
 
 class A { };
 class B : A { }; // expected-note {{implicitly declared private here}}
@@ -24,7 +24,7 @@ void f(B* b) {
 namespace T3 {
 
 class A { };
-class B : public A { }; 
+class B : public A { };
 
 void f(B* b) {
   A *a = b;
@@ -50,30 +50,30 @@ void f(D *d) {
 
 namespace T5 {
   class A {};
-    
+
   class B : private A {
     void f(B *b) {
       A *a = b;
     }
-  };    
+  };
 }
 
 namespace T6 {
   class C;
-  
+
   class A {}; // expected-note{{member is declared here}}
-  
+
   class B : private A { // expected-note {{declared private here}} expected-note {{constrained by private inheritance here}}
     void f(C* c);
   };
-  
-  class C : public B { 
+
+  class C : public B {
     void f(C *c) {
       A* a = c; // expected-error {{cannot cast 'C' to its private base class 'A'}} \
                 // expected-error {{'A' is a private member of 'T6::A'}}
     }
   };
-  
+
   void B::f(C *c) {
     A *a = c;
   }
@@ -82,7 +82,7 @@ namespace T6 {
 namespace T7 {
   class A {};
   class B : public A {};
-  class C : private B { 
+  class C : private B {
     void f(C *c) {
       A* a = c; // okay
     }
@@ -98,7 +98,7 @@ struct flag {
 template <class T>
 struct trait : flag<sizeof(T)> {}; // expected-note 2{{here}}
 
-template <class T, bool Inferred = trait<T>::value> // expected-note {{here}}
+template <class T, bool Inferred = trait<T>::value> // expected-note 2{{here}}
 struct a {};
 
 template <class T>
diff --git a/clang/test/SemaCXX/alias-template.cpp b/clang/test/SemaCXX/alias-template.cpp
index b49d36a6267e66c..90095b35a577417 100644
--- a/clang/test/SemaCXX/alias-template.cpp
+++ b/clang/test/SemaCXX/alias-template.cpp
@@ -167,7 +167,10 @@ namespace SFINAE {
     f<E>();
   }
 
-  template<typename T, typename U = EnableIf<is_enum<T>>> struct fail1 {}; // expected-note {{here}}
+  template<typename T,
+    typename U = // expected-note {{template parameter is declared here}}
+      EnableIf<is_enum<T>>> // expected-note {{in instantiation of template type alias 'EnableIf' requested here}}
+  struct fail1 {};
   template<typename T> struct fail2 : DisableIf<is_enum<T>> {}; // expected-note {{here}}
 
   fail1<int> f1; // expected-note {{here}}
diff --git a/clang/test/SemaCXX/anonymous-struct.cpp b/clang/test/SemaCXX/anonymous-struct.cpp
index 75309821998eba1..51066a4516873c5 100644
--- a/clang/test/SemaCXX/anonymous-struct.cpp
+++ b/clang/test/SemaCXX/anonymous-struct.cpp
@@ -27,7 +27,7 @@ struct E {
   };
 };
 
-template <class T> void foo(T);
+template <class T> void foo(T); // #foo
 typedef struct { // expected-error {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration after its linkage was computed; add a tag name here to establish linkage prior to definition}}
 // expected-note at -1 {{unnamed type used in template argument was declared here}}
 
@@ -36,6 +36,7 @@ typedef struct { // expected-error {{anonymous non-C-compatible type given name
 #if __cplusplus <= 199711L
     // expected-warning at -2 {{template argument uses unnamed type}}
     // expected-note at -3 {{while substituting deduced template arguments}}
+    // expected-note@#foo {{template parameter is declared here}}
 #endif
   }
 } A; // expected-note {{type is given name 'A' for linkage purposes by this typedef declaration}}
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 76e2f81947051d8..4a7f4fd9c7e505d 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -102,7 +102,7 @@ static_assert(n9 == 123, "");
 }
 
 namespace TemplateArgumentConversion {
-  template<int n> struct IntParam {};
+  template<int n> struct IntParam {}; // expected-note {{template parameter is declared here}}
 
   using IntParam0 = IntParam<0>;
   using IntParam0 = IntParam<id(0)>;
@@ -1529,7 +1529,7 @@ namespace MutableMembers {
   constexpr int mmn2 = mm.n; // expected-error {{constant expression}} expected-note {{read of mutable member 'n' is not allowed in a constant expression}}
 
   // Here's one reason why allowing this would be a disaster...
-  template<int n> struct Id { int k = n; };
+  template<int n> struct Id { int k = n; }; // expected-note {{template parameter is declared here}}
   int f() {
     constexpr MM m = { 0 };
     ++m.n;
diff --git a/clang/test/SemaCXX/constant-expression.cpp b/clang/test/SemaCXX/constant-expression.cpp
index cc041a4acd18cbb..d984ced4eae3b24 100644
--- a/clang/test/SemaCXX/constant-expression.cpp
+++ b/clang/test/SemaCXX/constant-expression.cpp
@@ -99,7 +99,7 @@ void diags(int n) {
 namespace IntOrEnum {
   const int k = 0;
   const int &p = k; // expected-note {{declared here}}
-  template<int n> struct S {};
+  template<int n> struct S {}; // expected-note {{template parameter is declared here}}
   S<p> s; // expected-error {{not an integral constant expression}} expected-note {{read of variable 'p' of non-integral, non-enumeration type 'const int &'}}
 }
 
diff --git a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp
index c8204c21523a373..6b8495e8c9d95f3 100644
--- a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp
+++ b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp
@@ -74,6 +74,7 @@ namespace DependentDefaultCtorExceptionSpec {
   };
   struct InstantiateFromAnotherClass {
     template <class B, class T = decltype(static_cast<bool (B::*)(int)>(&B::foo))> // expected-note {{in instantiation of function template specialization}}
+    // expected-note at -1 {{template parameter is declared here}}
     InstantiateFromAnotherClass(B *) {} // expected-note {{in instantiation of default argument}}
   };
   NoexceptWithThis<int> f{};
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index fef4674d178412e..931acfd86f808e2 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -201,7 +201,7 @@ struct A {
 
 using mem_ptr_type = int (A::*)(int);
 
-template<mem_ptr_type ptr>
+template<mem_ptr_type ptr> // expected-note 2{{template parameter is declared here}}
 struct C {};
 
 C<&A::f> c;
diff --git a/clang/test/SemaCXX/cxx98-compat-flags.cpp b/clang/test/SemaCXX/cxx98-compat-flags.cpp
index 6ffb3a5884d17cc..3986251357acac9 100644
--- a/clang/test/SemaCXX/cxx98-compat-flags.cpp
+++ b/clang/test/SemaCXX/cxx98-compat-flags.cpp
@@ -1,7 +1,8 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat-pedantic -verify %s
 // RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat-pedantic -Wno-bind-to-temporary-copy -Wno-unnamed-type-template-args -Wno-local-type-template-args -Wno-binary-literal -Werror %s
 
-template<typename T> int TemplateFn(T) { return 0; }
+template<typename T> // expected-note 2{{template parameter is declared here}}
+int TemplateFn(T) { return 0; }
 void LocalTemplateArg() {
   struct S {};
   TemplateFn(S()); // expected-warning {{local type 'S' as template argument is incompatible with C++98}}
diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp
index d31d95a9995f19f..99ed49481614b58 100644
--- a/clang/test/SemaCXX/cxx98-compat.cpp
+++ b/clang/test/SemaCXX/cxx98-compat.cpp
@@ -173,7 +173,8 @@ struct DelegCtor {
 
 template<int n = 0> void DefaultFuncTemplateArg(); // expected-warning {{default template arguments for a function template are incompatible with C++98}}
 
-template<typename T> int TemplateFn(T) { return 0; }
+template<typename T> // expected-note 2{{template parameter is declared here}}
+int TemplateFn(T) { return 0; }
 void LocalTemplateArg() {
   struct S {};
   TemplateFn(S()); // expected-warning {{local type 'S' as template argument is incompatible with C++98}}
@@ -188,7 +189,7 @@ int UnnamedTemplateArg = TemplateFn(obj_of_unnamed_type); // expected-warning {{
 #ifndef CXX17COMPAT
 namespace RedundantParensInAddressTemplateParam {
   int n;
-  template<int*p> struct S {};
+  template<int*p> struct S {}; // expected-note 2{{template parameter is declared here}}
   S<(&n)> s; // expected-warning {{redundant parentheses surrounding address non-type template argument are incompatible with C++98}}
   S<(((&n)))> t; // expected-warning {{redundant parentheses surrounding address non-type template argument are incompatible with C++98}}
 }
@@ -311,7 +312,7 @@ namespace LiteralUCNs {
 // template argument evaluation rules.
 #ifndef CXX17COMPAT
 namespace NonTypeTemplateArgs {
-  template<typename T, T v> struct S {};
+  template<typename T, T v> struct S {}; // expected-note 2{{template parameter is declared here}}
   const int k = 5; // expected-note {{here}}
   static void f() {} // expected-note {{here}}
   S<const int&, k> s1; // expected-warning {{non-type template argument referring to object 'k' with internal linkage is incompatible with C++98}}
@@ -320,8 +321,8 @@ namespace NonTypeTemplateArgs {
 
 namespace NullPointerTemplateArg {
   struct A {};
-  template<int*> struct X {};
-  template<int A::*> struct Y {};
+  template<int*> struct X {}; // expected-note {{template parameter is declared here}}
+  template<int A::*> struct Y {}; // expected-note {{template parameter is declared here}}
   X<(int*)0> x; // expected-warning {{use of null pointer as non-type template argument is incompatible with C++98}}
   Y<(int A::*)0> y; // expected-warning {{use of null pointer as non-type template argument is incompatible with C++98}}
 }
diff --git a/clang/test/SemaCXX/implicit-member-functions.cpp b/clang/test/SemaCXX/implicit-member-functions.cpp
index 1554b1af5d59a94..b48f93778ff81f7 100644
--- a/clang/test/SemaCXX/implicit-member-functions.cpp
+++ b/clang/test/SemaCXX/implicit-member-functions.cpp
@@ -63,6 +63,7 @@ namespace Recursion {
     template<typename T,
              typename = typename InvokeCopyConstructor<typename T::type>::type>
     // expected-note at -1 {{in instantiation of template class}}
+    // expected-note at -2 {{template parameter is declared here}}
     A(const T &);
     // expected-note at -1 {{in instantiation of default argument}}
   };
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index 2d2dde82a28e6b6..f411ef581f21604 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -442,7 +442,7 @@ struct A {
   // expected-error at -1 {{field has incomplete type 'void'}}
 };
 
-template <typename F>
+template <typename F> // cxx03-note {{template parameter is declared here}}
 void g(F f) {
   auto a = A<decltype(f())>();
   // expected-note at -1 {{in instantiation of template class 'PR20731::A<void>' requested here}}
@@ -499,12 +499,14 @@ namespace error_in_transform_prototype {
 
 namespace PR21857 {
   template<typename Fn> struct fun : Fn {
+    // cxx03-note at -1 {{template parameter is declared here}}
     fun() = default;
     using Fn::operator();
   };
   template<typename Fn> fun<Fn> wrap(Fn fn); // cxx03-warning {{template argument uses unnamed type}}
+                                             // cxx03-note at -1 {{template parameter is declared here}}
   auto x = wrap([](){}); // cxx03-warning {{template argument uses unnamed type}} cxx03-note 2 {{unnamed type used in template argument was declared here}}
-                         // cxx03-note at -1 {{while substituting deduced template arguments into function template}}
+                         // cxx03-note at -1 2{{while substituting deduced template arguments into function template}}
 }
 
 namespace PR13987 {
diff --git a/clang/test/SemaCXX/make_integer_seq.cpp b/clang/test/SemaCXX/make_integer_seq.cpp
index 71b7b8260d4abc8..3da0024b9671148 100644
--- a/clang/test/SemaCXX/make_integer_seq.cpp
+++ b/clang/test/SemaCXX/make_integer_seq.cpp
@@ -50,3 +50,4 @@ __make_integer_seq<f, int, 0> x; // expected-error{{template template parameter
 
 __make_integer_seq<__make_integer_seq, int, 10> PR28494; // expected-note{{different template parameters}}
 // expected-error at make_integer_seq.cpp:* {{template argument for template template parameter must be a class template or type alias template}}
+// expected-note@*:* 3{{template parameter from hidden source: class}}
diff --git a/clang/test/SemaCXX/type-trait-common-type.cpp b/clang/test/SemaCXX/type-trait-common-type.cpp
index 7190dcad76f1a3b..a59e0320e5306cc 100644
--- a/clang/test/SemaCXX/type-trait-common-type.cpp
+++ b/clang/test/SemaCXX/type-trait-common-type.cpp
@@ -5,10 +5,12 @@
 #  error
 #endif
 
-// expected-note@*:* {{template declaration from hidden source: template <template <class ...> class, template <class> class, class, class ...>}}
+// expected-note@*:* {{template parameter from hidden source: template <class ...> class}}
+// expected-note@*:* {{template parameter from hidden source: class ...}}
+// expected-note@*:* 2{{template parameter from hidden source: template <class ...> class}}
 
 void test() {
-  __builtin_common_type<> a; // expected-error {{too few template arguments for template '__builtin_common_type'}}
+  __builtin_common_type<> a; // expected-error {{missing template argument for template parameter}}
   __builtin_common_type<1> b; // expected-error {{template argument for template template parameter must be a class template or type alias template}}
   __builtin_common_type<int, 1> c; // expected-error {{template argument for template template parameter must be a class template or type alias template}}
 }
diff --git a/clang/test/SemaCXX/undefined-internal.cpp b/clang/test/SemaCXX/undefined-internal.cpp
index 9745f097c76b78c..7f466237370e688 100644
--- a/clang/test/SemaCXX/undefined-internal.cpp
+++ b/clang/test/SemaCXX/undefined-internal.cpp
@@ -209,9 +209,11 @@ namespace OverloadUse {
     t<f>(&n, &n); // expected-note {{used here}}
 #if __cplusplus < 201103L
     // expected-warning at -3 {{non-type template argument referring to function 'f' with internal linkage}}
-    // expected-note at -4 {{while substituting explicitly-specified template arguments}}
-    // expected-warning at -4 {{non-type template argument referring to function 'f' with internal linkage}}
+    // expected-note at -7 {{template parameter is declared here}}
     // expected-note at -5 {{while substituting explicitly-specified template arguments}}
+    // expected-warning at -5 {{non-type template argument referring to function 'f' with internal linkage}}
+    // expected-note at -9 {{template parameter is declared here}}
+    // expected-note at -7 {{while substituting explicitly-specified template arguments}}
 #endif
   }
 }
diff --git a/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp b/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp
index 79c9d339b6f2058..1fe0916b3226ce5 100644
--- a/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp
+++ b/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp
@@ -10,6 +10,7 @@ template <>
 struct [[deprecated]] traits<int> {}; // expected-note {{'traits<int>' has been explicitly marked deprecated here}}
 
 template<typename T, typename Trait = traits<T>>  // expected-warning {{'traits<int>' is deprecated}}
+                                                  // expected-note at -1 {{template parameter is declared here}}
 struct basic_string {};
 
 // should not warn, defined and used in system headers
diff --git a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
index 941e0a975d5f44d..e62cc8d24e3a762 100644
--- a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
@@ -8,7 +8,7 @@ typedef vector<double, 3> double3;
 // expected-error at +1 {{class template 'RWBuffer' requires template arguments}}
 RWBuffer BufferErr1;
 
-// expected-error at +1 {{too few template arguments for class template 'RWBuffer'}}
+// expected-error at +1 {{missing template argument for template parameter}}
 RWBuffer<> BufferErr2;
 
 // test implicit RWBuffer concept
@@ -39,7 +39,7 @@ template<typename T> struct TemplatedVector {
 
 // structs not allowed
 // expected-error at +4 {{constraints not satisfied for class template 'RWBuffer'}}
-// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class RWBuffer}}
+// expected-note@*:* {{template parameter from hidden source: typename element_type}}
 // expected-note@*:* {{because 's' does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(s)' evaluated to false}}
 RWBuffer<s> r6;
diff --git a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
index fb14429025d5a5e..d5e2142cc55d232 100644
--- a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
@@ -1,31 +1,31 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -verify %s
-
-typedef vector<float, 3> float3;
-
-StructuredBuffer<float3> Buffer;
-
-// expected-error at +2 {{class template 'StructuredBuffer' requires template arguments}}
-// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_structured_resource_element_compatible<element_type> class StructuredBuffer {}}}
-StructuredBuffer BufferErr1;
-
-// expected-error at +2 {{too few template arguments for class template 'StructuredBuffer'}}
-// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_structured_resource_element_compatible<element_type> class StructuredBuffer {}}}
-StructuredBuffer<> BufferErr2;
-
-// test elements of 0 size
-// expected-error at +3{{constraints not satisfied for class template 'StructuredBuffer' [with element_type = int[0]]}}
-// expected-note@*:*{{because 'int[0]' does not satisfy '__is_structured_resource_element_compatible'}}
-// expected-note@*:*{{because 'sizeof(int[0]) >= 1UL' (0 >= 1) evaluated to false}}
-StructuredBuffer<int[0]> BufferErr3;
-
-// In C++, empty structs do have a size of 1. So should HLSL.
-// The concept will accept empty structs as element types, despite it being unintuitive.
-struct Empty {};
-StructuredBuffer<Empty> BufferErr4;
-
-
-[numthreads(1,1,1)]
-void main() {
-  (void)Buffer.__handle; // expected-error {{'__handle' is a private member of 'hlsl::StructuredBuffer<vector<float, 3>>'}}
-  // expected-note@* {{implicitly declared private here}}
-}
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -verify %s
+
+typedef vector<float, 3> float3;
+
+StructuredBuffer<float3> Buffer;
+
+// expected-error at +2 {{class template 'StructuredBuffer' requires template arguments}}
+// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_structured_resource_element_compatible<element_type> class StructuredBuffer {}}}
+StructuredBuffer BufferErr1;
+
+// expected-error at +2 {{missing template argument for template parameter}}
+// expected-note@*:* {{template parameter from hidden source: typename element_type}}
+StructuredBuffer<> BufferErr2;
+
+// test elements of 0 size
+// expected-error at +3{{constraints not satisfied for class template 'StructuredBuffer' [with element_type = int[0]]}}
+// expected-note@*:*{{because 'int[0]' does not satisfy '__is_structured_resource_element_compatible'}}
+// expected-note@*:*{{because 'sizeof(int[0]) >= 1UL' (0 >= 1) evaluated to false}}
+StructuredBuffer<int[0]> BufferErr3;
+
+// In C++, empty structs do have a size of 1. So should HLSL.
+// The concept will accept empty structs as element types, despite it being unintuitive.
+struct Empty {};
+StructuredBuffer<Empty> BufferErr4;
+
+
+[numthreads(1,1,1)]
+void main() {
+  (void)Buffer.__handle; // expected-error {{'__handle' is a private member of 'hlsl::StructuredBuffer<vector<float, 3>>'}}
+  // expected-note@* {{implicitly declared private here}}
+}
diff --git a/clang/test/SemaObjCXX/parameterized_classes_subst.mm b/clang/test/SemaObjCXX/parameterized_classes_subst.mm
index 8aacf21faf09131..e113bea22f8a85d 100644
--- a/clang/test/SemaObjCXX/parameterized_classes_subst.mm
+++ b/clang/test/SemaObjCXX/parameterized_classes_subst.mm
@@ -408,7 +408,7 @@ void testVariadicInstantiation() {
 // --------------------------------------------------------------------------
 // Parameterized classes are not templates
 // --------------------------------------------------------------------------
-template<template<typename T, typename U> class TT>
+template<template<typename T, typename U> class TT> // expected-note {{template parameter is declared here}}
 struct AcceptsTemplateTemplate { };
 
 typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}}
diff --git a/clang/test/SemaTemplate/alias-templates.cpp b/clang/test/SemaTemplate/alias-templates.cpp
index ab5cad72faf1b79..c27b193361654aa 100644
--- a/clang/test/SemaTemplate/alias-templates.cpp
+++ b/clang/test/SemaTemplate/alias-templates.cpp
@@ -278,12 +278,12 @@ namespace PR31514 {
 namespace an_alias_template_is_not_a_class_template {
   template<typename T> using Foo = int; // expected-note 3{{here}}
   Foo x; // expected-error {{use of alias template 'Foo' requires template arguments}}
-  Foo<> y; // expected-error {{too few template arguments for alias template 'Foo'}}
+  Foo<> y; // expected-error {{missing template argument for template parameter}}
   int z = Foo(); // expected-error {{use of alias template 'Foo' requires template arguments}}
 
   template<template<typename> class Bar> void f() { // expected-note 3{{here}}
     Bar x; // expected-error {{use of template template parameter 'Bar' requires template arguments}}
-    Bar<> y; // expected-error {{too few template arguments for template template parameter 'Bar'}}
+    Bar<> y; // expected-error {{missing template argument for template parameter}}
     int z = Bar(); // expected-error {{use of template template parameter 'Bar' requires template arguments}}
   }
 }
@@ -304,11 +304,12 @@ namespace resolved_nttp {
   using TB = int (*)(int (*)[1], int (*)[2], int (*)[3]);
 
   template <typename T, int ...M> struct C {
-    template <T... N> using Fn = T(int(*...A)[N]);
+    template <T... N> // expected-note 3{{template parameter is declared here}}
+      using Fn = T(int(*...A)[N]);
     Fn<1, M..., 4> *p; // expected-error-re 3{{evaluates to {{[234]}}, which cannot be narrowed to type 'bool'}}
   };
   using TC = decltype(C<int, 2, 3>::p);
   using TC = int (*)(int (*)[1], int (*)[2], int (*)[3], int (*)[4]);
 
-  using TC2 = decltype(C<bool, 2, 3>::p); // expected-note {{instantiation of}}
+  using TC2 = decltype(C<bool, 2, 3>::p); // expected-note 3{{instantiation of}}
 }
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 51d98d4b3b20256..077ad8259fbad66 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -264,7 +264,7 @@ namespace classes {
     template<class T, class U> struct A {};
 
     template<template<class> class TT> auto f(TT<int> a) { return a; }
-    // expected-note at -1 2{{substitution failure: too few template arguments}}
+    // expected-note at -1 2{{missing template parameter}}
 
     A<int, float> v1;
     A<int, double> v2;
@@ -280,7 +280,7 @@ namespace classes {
       static constexpr auto val = E1;
     };
     template <template <class T3> class TT> void f(TT<int> v) {
-      // expected-note at -1 {{substitution failure: too few template arguments}}
+      // expected-note at -1 {{missing template parameter}}
       static_assert(v.val == 3);
     };
     void test() {
@@ -313,7 +313,7 @@ namespace classes {
     }
 
     template <template <class T2, int V3> class TT2> auto g(TT2<double, 1>) {
-      // expected-note at -1 {{too few template arguments for class template 'A'}}
+      // expected-note at -1 {{missing template parameter}}
       return f(TT2<int, 2>());
     }
 
@@ -347,9 +347,9 @@ namespace packs {
   namespace t1 {
     template<template<int, int...> class> struct A {};
     // expected-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
-    // expected-note at -2 {{previous template template parameter is here}}
+    // expected-note at -2 {{template parameter is declared here}}
 
-    template<char> struct B;
+    template<char> struct B; // expected-note {{template parameter is declared here}}
     template struct A<B>;
     // expected-note at -1 {{has different template parameters}}
   } // namespace t1
@@ -361,9 +361,9 @@ namespace packs {
   namespace t3 {
     template<template<int...> class> struct A {};
     // expected-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
-    // expected-note at -2 {{previous template template parameter is here}}
+    // expected-note at -2 {{template parameter is declared here}}
 
-    template<char> struct B;
+    template<char> struct B; // expected-note {{template parameter is declared here}}
     template struct A<B>;
     // expected-note at -1 {{has different template parameters}}
   } // namespace t3
@@ -501,7 +501,7 @@ namespace constraints {
   // expected-note at -1 {{similar constraint expressions not considered equivalent}}
 
   namespace t1 {
-    template<template<C1, class... T1s> class TT1> // expected-note {{TT1' declared here}}
+    template<template<C1, class... T1s> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
     template<D1, class T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
@@ -513,7 +513,7 @@ namespace constraints {
     template struct A<B>;
   } // namespace t2
   namespace t3 {
-    template<template<C1, class... T1s> class TT1> // expected-note {{'TT1' declared here}}
+    template<template<C1, class... T1s> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
     template<C2, class T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
@@ -521,7 +521,7 @@ namespace constraints {
   } // namespace t2
   namespace t4 {
     // FIXME: This should be accepted.
-    template<template<C1... T1s> class TT1> // expected-note {{'TT1' declared here}}
+    template<template<C1... T1s> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
     template<C1 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
@@ -529,14 +529,14 @@ namespace constraints {
   } // namespace t4
   namespace t5 {
     // FIXME: This should be accepted
-    template<template<C2... T1s> class TT1> // expected-note {{'TT1' declared here}}
+    template<template<C2... T1s> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
     template<C1 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
     // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t5
   namespace t6 {
-    template<template<C1... T1s> class TT1> // expected-note {{'TT1' declared here}}
+    template<template<C1... T1s> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
     template<C2 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
@@ -555,14 +555,14 @@ namespace constraints {
     template struct A<B>;
   } // namespace t8
   namespace t9 {
-    template<template<C1... T1s> class TT1> // expected-note {{'TT1' declared here}}
+    template<template<C1... T1s> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
     template<D1 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
     // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t9
   namespace t10 {
-    template<template<class...> requires C1<int> class TT1> // expected-note {{'TT1' declared here}}
+    template<template<class...> requires C1<int> class TT1> // expected-note {{template parameter is declared here}}
     struct A {};
 
     template<class> requires C2<int> struct B {}; // expected-note {{'B' declared here}}
@@ -613,7 +613,7 @@ namespace nttp_auto {
     // FIXME: Shouldn't accept parameters after a parameter pack.
     template<template<auto... Va1, auto Va2> class> struct A {};
     // expected-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
-    // expected-note at -2 {{previous template template parameter is here}}
+    // expected-note at -2 {{template parameter is declared here}}
     template<int... Vi> struct B;
     // expected-note at -1 {{template parameter is declared here}}
     template struct A<B>;
@@ -623,7 +623,7 @@ namespace nttp_auto {
     // FIXME: Shouldn't accept parameters after a parameter pack.
     template<template<auto... Va1, auto... Va2> class> struct A {};
     // expected-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
-    // expected-note at -2 {{previous template template parameter is here}}
+    // expected-note at -2 {{template parameter is declared here}}
     template<int... Vi> struct B;
     // expected-note at -1 {{template parameter is declared here}}
     template struct A<B>;
diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp
index 5ea34c0254ec1cb..4236d484015d0c6 100644
--- a/clang/test/SemaTemplate/default-arguments.cpp
+++ b/clang/test/SemaTemplate/default-arguments.cpp
@@ -1,12 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-template<typename T, int N = 2> struct X; // expected-note{{template is declared here}}
+template<typename T, int N = 2> struct X; // expected-note {{template parameter is declared here}}
 
 X<int, 1> *x1;
 X<int> *x2;
 
-X<> *x3; // expected-error{{too few template arguments for class template 'X'}}
+X<> *x3; // expected-error{{missing template argument for template parameter}}
 
 template<typename U = float, int M> struct X;
 
@@ -20,6 +20,7 @@ template<class T> struct a { };
 template<> struct a<int> { static const bool v = true; };
 
 template<class T, bool = a<T>::v> struct p { }; // expected-error {{no member named 'v'}}
+                                                // expected-note at -1 {{template parameter is declared here}}
 
 template struct p<bool>; // expected-note {{in instantiation of default argument for 'p<bool>' required here}}
 template struct p<int>;
@@ -50,12 +51,14 @@ template<typename T> struct X1 { };
 template<typename T>
 struct X2 {
   template<typename U = typename X1<T>::type> // expected-error{{no type named 'type' in 'X1<int>'}} \
-                                              // expected-error{{no type named 'type' in 'X1<char>'}}
-  struct Inner1 { }; // expected-note{{template is declared here}}
+                                              // expected-error{{no type named 'type' in 'X1<char>'}} \
+                                              // expected-note {{template parameter is declared here}}
+  struct Inner1 { };
 
   template<T Value = X1<T>::value> // expected-error{{no member named 'value' in 'X1<int>'}} \
-                                   // expected-error{{no member named 'value' in 'X1<char>'}}
-  struct NonType1 { }; // expected-note{{template is declared here}}
+                                   // expected-error{{no member named 'value' in 'X1<char>'}} \
+                                   // expected-note {{template parameter is declared here}}
+  struct NonType1 { };
 
   template<T Value>
   struct Inner2 { };
@@ -74,10 +77,10 @@ struct X2 {
 X2<int> x2i; // expected-note{{in instantiation of template class 'X2<int>' requested here}}
 X2<int>::Inner1<float> x2iif;
 
-X2<int>::Inner1<> x2bad; // expected-error{{too few template arguments for class template 'Inner1'}}
+X2<int>::Inner1<> x2bad; // expected-error{{missing template argument for template parameter}}
 
 X2<int>::NonType1<'a'> x2_nontype1;
-X2<int>::NonType1<> x2_nontype1_bad; // expected-error{{too few template arguments for class template 'NonType1'}}
+X2<int>::NonType1<> x2_nontype1_bad; // expected-error{{missing template argument for template parameter}}
 
 // Check multi-level substitution into template type arguments
 X2<int>::Inner3<float>::VeryInner<> vi;
@@ -112,12 +115,12 @@ template<typename T, template<typename> class X = T::template apply>
 int array4[is_same<X4<add_pointer>,
                    X4<add_pointer, add_pointer::apply> >::value? 1 : -1];
 
-template<int> struct X5 {};
+template<int> struct X5 {}; // expected-note {{template parameter is declared here}}
 template<long long> struct X5b {};
 template<typename T,
          template<T> class B = X5> // expected-error {{cannot be narrowed from type 'long long' to 'int'}}
                                    // expected-note at -1 {{has different template parameters}}
-                                   // expected-note at -2 {{previous template template parameter is here}}
+                                   // expected-note at -2 {{template parameter is declared here}}
   struct X6 {};
 
 X6<int> x6a;
diff --git a/clang/test/SemaTemplate/instantiate-member-pointers.cpp b/clang/test/SemaTemplate/instantiate-member-pointers.cpp
index 4757870d13b7081..4eeaa3db6e77c8f 100644
--- a/clang/test/SemaTemplate/instantiate-member-pointers.cpp
+++ b/clang/test/SemaTemplate/instantiate-member-pointers.cpp
@@ -17,7 +17,7 @@ template<typename T, typename Class>
 struct X2 {
   T f(Class &obj, T Class::*pm) { // expected-error{{to a reference}} \
                       // expected-error{{member pointer to void}}
-    return obj.*pm; 
+    return obj.*pm;
   }
 };
 
@@ -39,12 +39,12 @@ typedef int Y::*IntMember;
 template<IntMember Member>
 struct X4 {
   X3<int, Y, Member> member;
-  
+
   int &getMember(Y& y) { return y.*Member; }
 };
 
-int &get_X4(X4<&Y::x> x4, Y& y) { 
-  return x4.getMember(y); 
+int &get_X4(X4<&Y::x> x4, Y& y) {
+  return x4.getMember(y);
 }
 
 template<IntMember Member>
@@ -63,12 +63,12 @@ namespace ValueDepMemberPointer {
   template <typename T> void S<T>::instantiate() {
     int a[(int)sizeof(T)-42]; // expected-error{{array with a negative size}}
   }
-  S<int> s; 
+  S<int> s;
 }
 
 namespace PR18192 {
   struct A { struct { int n; }; };
-  template<int A::*> struct X {};
+  template<int A::*> struct X {}; // expected-note {{template parameter is declared here}}
   constexpr int A::*p = &A::n;
   X<p> x; // expected-error{{not a pointer to member constant}}
 }
diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
index dce30aa2af4ee3d..e78f5441cf8f35d 100644
--- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
+++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
@@ -20,12 +20,12 @@ apply<add_reference, int>::type ir = i;
 apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'int'}}
 
 // Template template parameters
-template<int> struct B;
+template<int> struct B; // expected-note {{template parameter is declared here}}
 
 template<typename T,
          template<T Value> class X> // expected-error{{cannot have type 'float'}}
                                     // expected-error at -1 {{cannot be narrowed from type 'long long' to 'int'}}
-                                    // expected-note at -2 {{previous template template parameter is here}}
+                                    // expected-note at -2 2{{template parameter is declared here}}
 struct X0 { };
 
 X0<int, B> x0b1;
diff --git a/clang/test/SemaTemplate/instantiation-default-1.cpp b/clang/test/SemaTemplate/instantiation-default-1.cpp
index 3e70a2148ca1a1f..8ef9f123e9c1cef 100644
--- a/clang/test/SemaTemplate/instantiation-default-1.cpp
+++ b/clang/test/SemaTemplate/instantiation-default-1.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 template<typename T, typename U = const T> struct Def1;
 
-template<> struct Def1<int> { 
+template<> struct Def1<int> {
   void foo();
 };
 
@@ -22,9 +22,10 @@ void test_Def1(Def1<int, const int> *d1, Def1<const int, const int> *d2,
 
 template<typename T,  // FIXME: bad error message below, needs better location info
          typename T2 = const T*>  // expected-error{{'T2' declared as a pointer to a reference}}
+                                  // expected-note at -1 {{template parameter is declared here}}
   struct Def2;
 
-template<> struct Def2<int> { 
+template<> struct Def2<int> {
   void foo();
 };
 
@@ -40,11 +41,11 @@ template<> struct Def1<const int> { }; // expected-error{{redefinition of 'Def1<
 
 template<typename T, typename T2 = T&> struct Def3;
 
-template<> struct Def3<int> { 
+template<> struct Def3<int> {
   void foo();
 };
 
-template<> struct Def3<int&> { 
+template<> struct Def3<int&> {
   void bar();
 };
 
@@ -83,7 +84,7 @@ template<typename R, typename Arg1, typename Arg2 = Arg1,
          typename FuncType = R (*)(Arg1, Arg2)>
   struct Def6;
 
-template<> struct Def6<int, float> { 
+template<> struct Def6<int, float> {
   void foo();
 };
 
@@ -91,7 +92,7 @@ template<> struct Def6<bool, int[5], float(double, double)> {
   void bar();
 };
 
-bool test_Def6(Def6<int, float, float> *d6a, 
+bool test_Def6(Def6<int, float, float> *d6a,
                Def6<int, float, float, int (*)(float, float)> *d6b,
                Def6<bool, int[5], float(double, double),
                     bool(*)(int*, float(*)(double, double))> *d6c) {
diff --git a/clang/test/SemaTemplate/instantiation-default-2.cpp b/clang/test/SemaTemplate/instantiation-default-2.cpp
index ffa77cf1ee5678a..e5db31000a41918 100644
--- a/clang/test/SemaTemplate/instantiation-default-2.cpp
+++ b/clang/test/SemaTemplate/instantiation-default-2.cpp
@@ -4,8 +4,7 @@
 
 template<typename T, T Value> struct Constant;
 // FIXME: bad location precxx20-error at -1 {{a non-type template parameter cannot have type 'float'}}
-// expected-note at -2 {{template parameter is declared here}}
-// cxx20-note at -3 {{template parameter is declared here}}
+// expected-note at -2 2{{template parameter is declared here}}
 
 Constant<int, 5> *c1;
 
diff --git a/clang/test/SemaTemplate/instantiation-dependence.cpp b/clang/test/SemaTemplate/instantiation-dependence.cpp
index 1a97dbf769ec63b..d98d98240db7c44 100644
--- a/clang/test/SemaTemplate/instantiation-dependence.cpp
+++ b/clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -17,7 +17,8 @@ namespace PR24076 {
   }
 
   template<class T,
-           class = void_t<decltype(declval<T>() + 1)>> // expected-error {{invalid operands to binary expression}}
+           class = // expected-note {{template parameter is declared here}}
+             void_t<decltype(declval<T>() + 1)>> // expected-error {{invalid operands to binary expression}}
   struct bar {};
 
   bar<s> bar; // expected-note {{in instantiation of}}
diff --git a/clang/test/SemaTemplate/instantiation-depth-defarg.cpp b/clang/test/SemaTemplate/instantiation-depth-defarg.cpp
index 24cd941042917e4..82bba72929553e3 100644
--- a/clang/test/SemaTemplate/instantiation-depth-defarg.cpp
+++ b/clang/test/SemaTemplate/instantiation-depth-defarg.cpp
@@ -1,12 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth=128 -ftemplate-backtrace-limit=4 %s
 
-template<int N> struct S {
+template<int N> struct S { // \
+// expected-error{{recursive template instantiation exceeded maximum depth of 128}} \
+// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
   typedef typename S<N-1>::type type;
   static int f(int n = S<N-1>::f()); // \
-// expected-error{{recursive template instantiation exceeded maximum depth of 128}} \
 // expected-note 3 {{instantiation of default function argument}} \
-// expected-note {{skipping 125 contexts in backtrace}} \
-// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
+// expected-note {{skipping 125 contexts in backtrace}}
 
 };
 template<> struct S<0> {
diff --git a/clang/test/SemaTemplate/instantiation-depth-exception-spec.cpp b/clang/test/SemaTemplate/instantiation-depth-exception-spec.cpp
index 4464fbb31b38300..a0d5a1458ce5d80 100644
--- a/clang/test/SemaTemplate/instantiation-depth-exception-spec.cpp
+++ b/clang/test/SemaTemplate/instantiation-depth-exception-spec.cpp
@@ -1,11 +1,11 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth=16 -fcxx-exceptions -fexceptions %s
 
-template<int N> struct X {
-  static int go(int a) noexcept(noexcept(X<N+1>::go(a))); // \
+template<int N> struct X { // \
 // expected-error {{recursive template instantiation exceeded maximum depth of 16}} \
-// expected-note 9{{in instantiation of exception specification}} \
-// expected-note {{skipping 7 context}} \
 // expected-note {{use -ftemplate-depth}}
+  static int go(int a) noexcept(noexcept(X<N+1>::go(a))); // \
+// expected-note 9{{in instantiation of exception specification}} \
+// expected-note {{skipping 7 context}}
 };
 
 void f() {
diff --git a/clang/test/SemaTemplate/instantiation-depth.cpp b/clang/test/SemaTemplate/instantiation-depth.cpp
index 15e2c2ba7c8bdbc..35cf42a2724bc86 100644
--- a/clang/test/SemaTemplate/instantiation-depth.cpp
+++ b/clang/test/SemaTemplate/instantiation-depth.cpp
@@ -19,11 +19,11 @@ void test() {
 // RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 -std=c++11 -DNOEXCEPT %s
 
 template<typename T> struct S {
+// expected-error at -1 {{recursive template instantiation exceeded maximum depth of 5}}
+// expected-note at -2  {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
   S() noexcept(noexcept(S<S>())); \
-// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
 // expected-note 3 {{in instantiation of exception spec}} \
-// expected-note {{skipping 2 contexts in backtrace}} \
-// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
+// expected-note {{skipping 2 contexts in backtrace}}
 };
 S<void> t; // expected-note {{in instantiation of exception spec}}
 
diff --git a/clang/test/SemaTemplate/ms-unqualified-base-class.cpp b/clang/test/SemaTemplate/ms-unqualified-base-class.cpp
index 5e926c5087f9354..d2b02e511e2edd6 100644
--- a/clang/test/SemaTemplate/ms-unqualified-base-class.cpp
+++ b/clang/test/SemaTemplate/ms-unqualified-base-class.cpp
@@ -84,7 +84,7 @@ int main() {
   return I;
 }
 
-template <typename Type, int TSize> class Vec {}; // expected-note {{template is declared here}}
+template <typename Type, int TSize> class Vec {}; // expected-note {{template parameter is declared here}}
 
 template <int TDim> class Index : public Vec<int, TDim> {
   // after-error at +1 {{member initializer 'Vec' does not name a non-static data member or base class}}
@@ -107,7 +107,7 @@ template <typename T> class Wrong : public Vec<T, 4> {
 template class Wrong<double>;
 
 template <typename T> class Wrong2 : public Vec<T, 4> {
-  Wrong2() : Vec<T>() {} // expected-error {{too few template arguments for class template 'Vec'}}
+  Wrong2() : Vec<T>() {} // expected-error {{missing template argument for template parameter}}
 };
 
 template class Wrong2<double>;
diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp
index 4d7f2d9c5c9469c..df813ab785fb948 100644
--- a/clang/test/SemaTemplate/nested-template.cpp
+++ b/clang/test/SemaTemplate/nested-template.cpp
@@ -114,11 +114,11 @@ template<typename T>
 struct X2 {
   template<template<class U, T Value> class>  // expected-error {{cannot have type 'float'}}
                                               // expected-error at -1 {{cannot be narrowed from type 'long long' to 'int'}}
-                                              // expected-note at -2 {{previous template template parameter is here}}
+                                              // expected-note at -2 {{template parameter is declared here}}
     struct Inner { };
 };
 
-template<typename T, int Value>
+template<typename T, int Value> // expected-note {{template parameter is declared here}}
   struct X2_arg;
 
 X2<int>::Inner<X2_arg> x2i1;
diff --git a/clang/test/SemaTemplate/partial-spec-instantiate.cpp b/clang/test/SemaTemplate/partial-spec-instantiate.cpp
index 0b84df69562e2c0..f171bf4c712b863 100644
--- a/clang/test/SemaTemplate/partial-spec-instantiate.cpp
+++ b/clang/test/SemaTemplate/partial-spec-instantiate.cpp
@@ -42,7 +42,7 @@ namespace WonkyAccess {
 }
 
 namespace rdar9169404 {
-  template<typename T, T N> struct X { };
+  template<typename T, T N> struct X { }; // #rdar9169404-X
   template<bool C> struct X<bool, C> {
     typedef int type;
   };
@@ -50,6 +50,7 @@ namespace rdar9169404 {
   X<bool, -1>::type value;
 #if __cplusplus >= 201103L
   // expected-error at -2 {{non-type template argument evaluates to -1, which cannot be narrowed to type 'bool'}}
+  // expected-note@#rdar9169404-X {{template parameter is declared here}}
 #endif
 }
 
diff --git a/clang/test/SemaTemplate/recovery-crash.cpp b/clang/test/SemaTemplate/recovery-crash.cpp
index ac8053da101ab34..26683b11a12563a 100644
--- a/clang/test/SemaTemplate/recovery-crash.cpp
+++ b/clang/test/SemaTemplate/recovery-crash.cpp
@@ -26,13 +26,14 @@ namespace PR16134 {
 }
 
 namespace PR16225 {
-  template <typename T> void f();
+  template <typename T> void f(); // #PR16225-f
   template <typename C> void g(C*) {
     struct LocalStruct : UnknownBase<Mumble, C> { };  // expected-error {{use of undeclared identifier 'Mumble'}}
     f<LocalStruct>();
 #if __cplusplus <= 199711L
     // expected-warning at -2 {{template argument uses local type 'LocalStruct'}}
     // expected-note at -3 {{while substituting explicitly-specified template arguments}}
+    // expected-note@#PR16225-f {{template parameter is declared here}}
 #endif
     struct LocalStruct2 : UnknownBase<C> { };  // expected-error {{no template named 'UnknownBase'}}
   }
diff --git a/clang/test/SemaTemplate/stack-exhaustion.cpp b/clang/test/SemaTemplate/stack-exhaustion.cpp
index c7bfea4132d5ed9..b6e2fc9d35999b7 100644
--- a/clang/test/SemaTemplate/stack-exhaustion.cpp
+++ b/clang/test/SemaTemplate/stack-exhaustion.cpp
@@ -33,11 +33,11 @@ int k = f(X<1000>());
 
 namespace template_argument_recursion {
   struct ostream;
-  template<typename T> T &&declval();
+  template<typename T> T &&declval(); // expected-error {{exceeded maximum depth}}
 
   namespace mlir {
     template<typename T, typename = decltype(declval<ostream&>() << declval<T&>())>
-    ostream &operator<<(ostream& os, const T& obj); // expected-error {{exceeded maximum depth}}
+    ostream &operator<<(ostream& os, const T& obj);
     struct Value;
   }
 
@@ -48,12 +48,12 @@ namespace template_argument_recursion {
 
 namespace template_parameter_type_recursion {
   struct ostream;
-  template<typename T> T &&declval();
+  template<typename T> T &&declval(); // expected-error {{exceeded maximum depth}}
   template<bool B, typename T> struct enable_if { using type = T; };
 
   namespace mlir {
     template<typename T, typename enable_if<declval<ostream&>() << declval<T&>(), void*>::type = nullptr>
-    ostream &operator<<(ostream& os, const T& obj); // expected-error {{exceeded maximum depth}}
+    ostream &operator<<(ostream& os, const T& obj);
     struct Value;
   }
 
diff --git a/clang/test/SemaTemplate/temp_arg.cpp b/clang/test/SemaTemplate/temp_arg.cpp
index 538056a4e44c738..9048744f3095ab4 100644
--- a/clang/test/SemaTemplate/temp_arg.cpp
+++ b/clang/test/SemaTemplate/temp_arg.cpp
@@ -1,10 +1,10 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx17 %std_cxx98-14 %s
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 %std_cxx17- %s
-template<typename T, 
-         int I, 
-         template<typename> class TT>
-  class A; // precxx17-note 3 {{template is declared here}} \
-              cxx17-note 2 {{template is declared here}} \
+template<typename T,
+         int I,
+         template<typename> class TT> // expected-note {{template parameter is declared here}}
+  class A; // precxx17-note 2 {{template is declared here}} \
+              cxx17-note {{template is declared here}} \
               cxx17-note {{candidate template ignored: couldn't infer template argument 'T'}} \
               cxx17-note {{implicit deduction guide declared as 'template <typename T, int I, template <typename> class TT> A(A<T, I, TT>) -> A<T, I, TT>'}} \
               cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
@@ -15,7 +15,7 @@ template<typename> class X;
 A<int, 0, X> * a1;
 
 A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
-A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
+A<float, 1> *a3; // expected-error{{missing template argument for template parameter}}
 A a4; // precxx17-error{{use of class template 'A' requires template arguments}} \
          cxx17-error{{no viable constructor or deduction guide for deduction of template arguments of 'A'}}
 
diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp
index 2a1c059df002ea3..36d7d9cb6f51987 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wconversion -verify %s
-template<int N> struct A; // expected-note 5{{template parameter is declared here}}
+template<int N> struct A; // expected-note 6{{template parameter is declared here}}
 
 A<0> *a0;
 
@@ -42,7 +42,7 @@ double g(double); // expected-note 2{{candidate function}}
 int h(int);
 float h2(float);
 
-template<int fp(int)> struct A3; // expected-note 1{{template parameter is declared here}}
+template<int fp(int)> struct A3; // expected-note 2{{template parameter is declared here}}
 A3<h> *a14_1;
 A3<&h> *a14_2;
 A3<f> *a14_3;
@@ -61,7 +61,7 @@ A4<*X_volatile_ptr> *a15_2; // expected-error{{non-type template argument does n
 A4<y> *15_3; //  expected-error{{non-type template parameter of reference type 'const X &' cannot bind to template argument of type 'struct Y'}} \
             // FIXME: expected-error{{expected unqualified-id}}
 
-template<int (&fr)(int)> struct A5; // expected-note{{template parameter is declared here}}
+template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
 A5<h> *a16_1;
 A5<f> *a16_3;
 A5<h2> *a16_6;  // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'float (float)'}}
@@ -86,7 +86,7 @@ A6<&Z::baz> *a17_3; // expected-error-re{{non-type template argument of type 'do
 
 
 template<int Z::*pm> struct A7;  // expected-note{{template parameter is declared here}}
-template<int Z::*pm> struct A7c;
+template<int Z::*pm> struct A7c; // expected-note{{template parameter is declared here}}
 A7<&Z::int_member> *a18_1;
 A7c<&Z::int_member> *a18_2;
 A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float Z::*' cannot be converted to a value of type 'int Z::*'}}
@@ -442,7 +442,10 @@ namespace dependent_nested_partial_specialization {
   A<Y>::B<int, &n> ay; // expected-error {{undefined}} expected-note {{instantiation of}}
 
   template<template<typename> class X> struct C {
-    template<typename T, int N, int M> struct D; // expected-note {{here}}
+    template<typename T, int N,
+      int M // expected-note {{template parameter is declared here}}
+    > struct D;
+    // expected-note at -1 {{template is declared here}}
     template<typename T, X<T> N> struct D<T*, N, N + 1> {}; // expected-error {{type of specialized non-type template argument depends on}}
   };
   C<X>::D<int*, 0, 1> cx;
@@ -492,7 +495,12 @@ namespace dependent_backreference {
   Incomplete f(int); // expected-note 2{{here}}
   int f(short);
 
-  template<typename T, T Value, int(*)[sizeof(f(Value))]> struct X {}; // expected-error 2{{incomplete}}
+  template<typename T, T Value,
+    int(*)[ // expected-note 2{{template parameter is declared here}}
+      sizeof(f(Value)) // expected-error 2{{incomplete}}
+    ]
+  > struct X {};
+
   int arr[sizeof(int)];
   // When checking this template-id, we must not treat 'Value' as having type
   // 'int'; its type is the dependent type 'T'.
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
index 5752cbac0291d6f..32bb678c4bf4e76 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
@@ -30,7 +30,7 @@ namespace Auto {
 
 namespace check_conversion_early {
   struct X {};
-  template<int> struct A {};
+  template<int> struct A {}; // expected-note {{template parameter is declared here}}
   template<X &x> struct A<x> {}; // expected-error {{not implicitly convertible}}
 
   struct Y { constexpr operator int() const { return 0; } };
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index c35743b87adbca9..724ac85b5f73dab 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
 
-template<typename T, T val> struct A {}; // expected-note 3{{template parameter is declared here}}
+template<typename T, T val> struct A {}; // expected-note 15{{template parameter is declared here}}
 
 template<typename T, typename U> constexpr bool is_same = false;
 template<typename T> constexpr bool is_same<T, T> = true;
@@ -254,8 +254,8 @@ namespace Auto {
   }
 
   namespace DecltypeAuto {
-    template<auto v> struct A { };
-    template<decltype(auto) v> struct DA { };
+    template<auto v> struct A { }; // expected-note {{template parameter is declared here}}
+    template<decltype(auto) v> struct DA { }; // expected-note {{template parameter is declared here}}
     template<auto&> struct R { };
 
     auto n = 0; // expected-note + {{declared here}}
@@ -448,7 +448,7 @@ namespace PR42108 {
   struct R {};
   struct S { constexpr S() {} constexpr S(R) {} };
   struct T { constexpr operator S() { return {}; } };
-  template <const S &> struct A {}; // expected-note {{template parameter is declared here}}
+  template <const S &> struct A {}; // expected-note 3{{template parameter is declared here}}
   void f() {
     A<R{}>(); // expected-error {{would bind reference to a temporary}}
     A<S{}>(); // expected-error {{reference to temporary object}}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
index 56ceb7af4ccd935..221f8595f43d55b 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -16,7 +16,7 @@ union U { int a, b; } u;
 int n; // expected-note 1+{{here}}
 
 // pointers to subobjects
-template<int *> struct IntPtr {};
+template<int *> struct IntPtr {}; // expected-note 2{{template parameter is declared here}}
 using IPn = IntPtr<&n + 1>;
 using IPn = IntPtr<&n + 1>;
 
@@ -30,7 +30,7 @@ using IP3 = IntPtr<s.n + 3>;
 
 using IP5 = IntPtr<&s.n[5]>; // expected-error {{not a constant expression}} expected-note {{cannot refer to element 5 of array of 3 elements}}
 
-template<int &> struct IntRef {};
+template<int &> struct IntRef {}; // expected-note 4{{template parameter is declared here}}
 using IRn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
 using IRn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
 
@@ -72,20 +72,20 @@ namespace ClassNTTP {
   static_assert(&id<A{1,3}> != &id<a>);
 
   int k = id<1>; // expected-error {{no viable conversion from 'int' to 'A'}}
-                 // expected-note@#ClassNTTP1 {{passing argument to parameter 'a' here}}
+                 // expected-note@#ClassNTTP1 {{template parameter is declared here}}
 
   struct B {
     constexpr B() {}
     constexpr B(int) = delete; // expected-note {{here}}
   };
-  template<B> struct Q {}; // expected-note {{passing argument to parameter here}}
+  template<B> struct Q {}; // expected-note {{template parameter is declared here}}
   Q<1> q; // expected-error {{conversion function from 'int' to 'B' invokes a deleted function}}
 
   struct C {
     constexpr C() {}
     C(const C&) = delete; // expected-note {{here}}
   };
-  template<C> struct R {}; // expected-note {{passing argument to parameter here}}
+  template<C> struct R {}; // expected-note {{template parameter is declared here}}
   constexpr C c;
   R<c> r; // expected-error {{call to deleted constructor}}
 }
@@ -228,7 +228,7 @@ namespace UnnamedBitfield {
   //
   // FIXME: We shouldn't track a value for unnamed bit-fields, nor number
   // them when computing field indexes.
-  template <A> struct X {};
+  template <A> struct X {}; // expected-note {{template parameter is declared here}}
   constexpr A a;
   using T = X<a>;
   using T = X<A{}>;
@@ -238,7 +238,7 @@ namespace UnnamedBitfield {
 }
 
 namespace Temporary {
-  template<const int &> struct A {}; // expected-note {{template parameter is declared here}}
+  template<const int &> struct A {}; // expected-note 6{{template parameter is declared here}}
   A<0> a0; // expected-error {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}}
 
   A<(const int&)1> a1; // expected-error {{reference to temporary object is not allowed in a template argument}}
@@ -254,18 +254,18 @@ namespace Temporary {
   X &&x = X{};
   A<x.a[3]> a5; // expected-error {{reference to subobject of temporary object}}
 
-  template<const int*> struct B {};
+  template<const int*> struct B {}; // expected-note 3{{template parameter is declared here}}
   B<&(int&)(int&&)0> b0; // expected-error {{pointer to temporary object}}
   B<&r3> b3; // expected-error {{pointer to temporary object}}
   B<&x.a[3]> b5; // expected-error {{pointer to subobject of temporary object}}
 
   struct C { const int *p[2]; };
-  template<C> struct D {};
+  template<C> struct D {}; // expected-note {{template parameter is declared here}}
   D<C{nullptr, &r3}> d; // expected-error {{pointer to temporary object}}
 }
 
 namespace StringLiteral {
-  template<decltype(auto)> struct Y {};
+  template<decltype(auto)> struct Y {}; // expected-note 6{{template parameter is declared here}}
   Y<&"hello"> y1; // expected-error {{pointer to string literal}}
   Y<"hello"> y2; // expected-error {{reference to string literal}}
   Y<+"hello"> y3; // expected-error {{pointer to subobject of string literal}}
@@ -278,7 +278,7 @@ namespace StringLiteral {
 }
 
 namespace TypeInfo {
-  template<decltype(auto)> struct Y {};
+  template<decltype(auto)> struct Y {}; // expected-note 4{{template parameter is declared here}}
   Y<&typeid(int)> y1; // expected-error {{pointer to type_info object}}
   Y<typeid(int)> y2; // expected-error {{reference to type_info object}}
 
@@ -289,7 +289,7 @@ namespace TypeInfo {
 }
 
 namespace Predefined {
-  template<decltype(auto)> struct Y {};
+  template<decltype(auto)> struct Y {}; // expected-note 7{{template parameter is declared here}}
 
   struct A { const char *p; };
   struct B { const char &r; };
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
index e74c031eba4c1c9..a87ffcbc666595b 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
@@ -5,16 +5,16 @@ struct Test {
     int b = 42;
 };
 
-template <Test t>
+template <Test t> // expected-note {{template parameter is declared here}}
 struct A {
     static constexpr auto a = t.a;
     static constexpr auto b = t.b;
 };
 
-template <auto N>
+template <auto N> // expected-note {{template parameter is declared here}}
 struct Auto {};
 
-template <typename T, T elem>
+template <typename T, T elem> // expected-note {{template parameter is declared here}}
 struct Explicit{};
 
 struct L {};
@@ -57,8 +57,8 @@ void test() {
     DefaultParam3<> d3;
 }
 
-template<auto n> struct B { /* ... */ };
-template<int i> struct C { /* ... */ };
+template<auto n> struct B { /* ... */ }; // expected-note 2{{template parameter is declared here}}
+template<int i> struct C { /* ... */ }; // expected-note {{template parameter is declared here}}
 C<{ 42 }> c1;  // expected-warning {{braces around scalar initializer}}
 
 struct J1 {
diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp b/clang/test/SemaTemplate/temp_arg_template.cpp
index aa53dba652050e0..8dc90cc56dc1aff 100644
--- a/clang/test/SemaTemplate/temp_arg_template.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template.cpp
@@ -2,13 +2,13 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 -std=c++17 %s
 
 template<template<typename T> class X> struct A; // #A
-// expected-note at -1 2{{previous template template parameter is here}}
+// expected-note at -1 3{{template parameter is declared here}}
 
-template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}}
+template<template<typename T, int I> class X> struct B; // expected-note{{template parameter is declared here}}
 
 template<template<int I> class X> struct C;
 // expected-error at -1 {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}}
-// expected-note at -2 {{previous template template parameter is here}}
+// expected-note at -2 {{template parameter is declared here}}
 
 template<class> struct X; // expected-note {{template is declared here}}
 template<int N> struct Y; // expected-note {{template parameter is declared here}}
@@ -18,7 +18,10 @@ template<const int &N> struct Yref; // expected-note {{template parameter is dec
 namespace N {
   template<class> struct Z;
 }
-template<class, class> struct TooMany; // expected-note{{template is declared here}}
+template<
+  class,
+  class> // expected-note {{template parameter is declared here}}
+struct TooMany;
 
 
 A<X> *a1;
@@ -27,7 +30,7 @@ A< ::N::Z> *a3;
 
 A<Y> *a4; // expected-error@#A {{template argument for non-type template parameter must be an expression}}
           // expected-note at -1 {{different template parameters}}
-A<TooMany> *a5; // expected-error {{too few template arguments for class template 'TooMany'}}
+A<TooMany> *a5; // expected-error@#A {{missing template parameter to bind to template template parameter}}
                 // expected-note at -1 {{different template parameters}}
 B<X> *a6; // expected-error {{too many template arguments for class template 'X'}}
           // expected-note at -1 {{different template parameters}}
@@ -109,7 +112,7 @@ void foo() {
 
 namespace CheckDependentNonTypeParamTypes {
   template<template<typename T, typename U, T v> class X> struct A {
-    // expected-note at -1 {{previous template template parameter is here}}
+    // expected-note at -1 {{template parameter is declared here}}
     void f() {
       X<int, void*, 3> x;
     }
diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index 2e5a36ae6ed082c..ddb61d8bd80a15b 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -1,8 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
 
-// expected-note at temp_arg_template_p0522.cpp:* 1+{{template is declared here}}
 // expected-note at temp_arg_template_p0522.cpp:* 1+{{template parameter is declared here}}
-// expected-note at temp_arg_template_p0522.cpp:* 1+{{previous template template parameter is here}}
 
 template<template<int> typename> struct Ti; // #Ti
 template<template<int...> typename> struct TPi; // #TPi
@@ -33,13 +31,13 @@ namespace IntParam {
         Ti<iDi>,
         Ti<Pi>,
         Ti<iDt>>;
-  using err1 = Ti<ii>; // expected-error {{too few template arguments for class template 'ii'}}
+  using err1 = Ti<ii>; // expected-error@#Ti {{missing template parameter to bind to template template parameter}}
                        // expected-note at -1 {{different template parameters}}
-  using err2 = Ti<iiPi>; // expected-error {{too few template arguments for class template 'iiPi'}}
+  using err2 = Ti<iiPi>; // expected-error@#Ti {{missing template parameter to bind to template template parameter}}
                          // expected-note at -1 {{different template parameters}}
   using err3 = Ti<t0>; // expected-error@#Ti {{template argument for template type parameter must be a type}}
                        // expected-note at -1 {{different template parameters}}
-  using err4 = Ti<it>; // expected-error {{too few template arguments for class template 'it'}}
+  using err4 = Ti<it>; // expected-error@#Ti {{missing template parameter to bind to template template parameter}}
                        // expected-note at -1 {{different template parameters}}
 }
 
@@ -64,7 +62,7 @@ namespace IntAndPackParam {
 
 namespace DependentType {
   using ok = Pt<tT0<int, i>, tT0<int, iDi>>;
-  using err1 = tT0<int, ii>; // expected-error {{too few template arguments for class template 'ii'}}
+  using err1 = tT0<int, ii>; // expected-error@#tT0 {{missing template parameter to bind to template template parameter}}
                              // expected-note at -1 {{different template parameters}}
   using err2 = tT0<short, i>;
   using err2a = tT0<long long, i>; // expected-error@#tT0 {{cannot be narrowed from type 'long long' to 'int'}}
@@ -159,11 +157,10 @@ namespace GH101394 {
   } // namespace t1
   namespace t2 {
     template<template<Y> class> struct A {}; // #A
-    template<X> struct B; // #B
+    template<X> struct B;
     template struct A<B>;
     // expected-error@#A {{no viable conversion from 'const Y' to 'X'}}
     // expected-note at -2  {{different template parameters}}
     // expected-note@#X 2{{not viable}}
-    // expected-note@#B  {{passing argument to parameter here}}
   } // namespace t2
 } // namespace GH101394
diff --git a/clang/test/SemaTemplate/temp_arg_type.cpp b/clang/test/SemaTemplate/temp_arg_type.cpp
index 392d2573d3d0e9c..a0d2bc383d917f6 100644
--- a/clang/test/SemaTemplate/temp_arg_type.cpp
+++ b/clang/test/SemaTemplate/temp_arg_type.cpp
@@ -1,9 +1,12 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
 
-template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}
+template<typename T> class A;
+// expected-note at -1 4{{template parameter is declared here}}
+// cxx98-note at -2    2{{template parameter is declared here}}
+// expected-note at -3  {{template is declared here}}
 
 // [temp.arg.type]p1
 A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}



More information about the llvm-branch-commits mailing list