https://github.com/mizvekov updated 
https://github.com/llvm/llvm-project/pull/96023

>From be948d566e5e7cd1932d3c81c5500ae83f085f7a Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizve...@gmail.com>
Date: Mon, 17 Jun 2024 21:39:08 -0300
Subject: [PATCH] [clang] Finish implementation of P0522

This finishes the clang implementation of P0522, getting rid
of the fallback to the old, pre-P0522 rules.

Before this patch, when partial ordering template template parameters,
we would perform, in order:
* If the old rules would match, we would accept it. Otherwise, don't
  generate diagnostics yet.
* If the new rules would match, just accept it. Otherwise, don't
  generate any diagnostics yet again.
* Apply the old rules again, this time with diagnostics.

This situation was far from ideal, as we would sometimes:
* Accept some things we shouldn't.
* Reject some things we shouldn't.
* Only diagnose rejection in terms of the old rules.

With this patch, we apply the P0522 rules throughout.

This needed to extend template argument deduction in order
to accept the historial rule for TTP matching pack parameter to non-pack
arguments.
This change also makes us accept some combinations of historical and P0522
allowances we wouldn't before.

It also fixes a bunch of bugs that were documented in the test suite,
which I am not sure there are issues already created for them.

This causes a lot of changes to the way these failures are diagnosed,
with related test suite churn.

The problem here is that the old rules were very simple and
non-recursive, making it easy to provide customized diagnostics,
and to keep them consistent with each other.

The new rules are a lot more complex and rely on template argument
deduction, substitutions, and they are recursive.

The approach taken here is to mostly rely on existing diagnostics,
and create a new instantiation context that keeps track of this context.

So for example when a substitution failure occurs, we use the error
produced there unmodified, and just attach notes to it explaining
that it occurred in the context of partial ordering this template
argument against that template parameter.

This diverges from the old diagnostics, which would lead with an
error pointing to the template argument, explain the problem
in subsequent notes, and produce a final note pointing to the parameter.
---
 clang/docs/ReleaseNotes.rst                   |   8 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   7 +
 clang/include/clang/Sema/Sema.h               |  14 +-
 clang/lib/Frontend/FrontendActions.cpp        |   2 +
 clang/lib/Sema/SemaTemplate.cpp               |  94 ++---
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 353 +++++++++++++-----
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  15 +
 .../temp/temp.arg/temp.arg.template/p3-0x.cpp |  31 +-
 clang/test/CXX/temp/temp.param/p12.cpp        |  21 +-
 clang/test/Modules/cxx-templates.cpp          |  15 +-
 clang/test/SemaCXX/make_integer_seq.cpp       |   5 +-
 clang/test/SemaTemplate/cwg2398.cpp           | 139 ++++++-
 clang/test/SemaTemplate/temp_arg_nontype.cpp  |  46 ++-
 clang/test/SemaTemplate/temp_arg_template.cpp |  38 +-
 .../SemaTemplate/temp_arg_template_p0522.cpp  |  70 ++--
 .../Templight/templight-empty-entries-fix.cpp |  12 +
 .../templight-prior-template-arg.cpp          |  33 +-
 .../type_traits/is_specialization.verify.cpp  |   2 +-
 18 files changed, 632 insertions(+), 273 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 903461532940c..043604b3e5195 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -67,6 +67,8 @@ C++ Language Changes
 
 C++17 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- The implementation of the relaxed template template argument matching rules 
is
+  more complete and reliable, and should provide more accurate diagnostics.
 
 C++14 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
@@ -133,6 +135,10 @@ Improvements to Clang's diagnostics
 
 - Clang now diagnoses undefined behavior in constant expressions more 
consistently. This includes invalid shifts, and signed overflow in arithmetic.
 
+- Clang now properly explains the reason a template template argument failed to
+  match a template template parameter, in terms of the C++17 relaxed matching 
rules
+  instead of the old ones.
+
 Improvements to Clang's time-trace
 ----------------------------------
 
@@ -158,6 +164,8 @@ Bug Fixes to C++ Support
 - Fixed a failed assertion when checking invalid delete operator declaration. 
(#GH96191)
 - When performing partial ordering of function templates, clang now checks that
   the deduction was consistent. Fixes (#GH18291).
+- Fixes to several issues in partial ordering of template template parameters, 
which
+  were documented in the test suite.
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 810abe4f23e31..bb7bba73d1964 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5244,6 +5244,13 @@ def note_template_arg_refers_here_func : Note<
 def err_template_arg_template_params_mismatch : Error<
   "template template argument has different template parameters than its "
   "corresponding template template parameter">;
+def note_template_arg_template_params_mismatch : Note<
+  "template template argument has different template parameters than its "
+  "corresponding template template parameter">;
+def err_non_deduced_mismatch : Error<
+  "could not match %diff{$ against $|types}0,1">;
+def err_inconsistent_deduction : Error<
+  "conflicting deduction %diff{$ against $|types}0,1 for parameter">;
 def err_template_arg_not_integral_or_enumeral : Error<
   "non-type template argument of type %0 must have an integral or enumeration"
   " type">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9856c0f2a7b15..970de7a1f6321 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12457,8 +12457,9 @@ class Sema final : public SemaBase {
                                     sema::TemplateDeductionInfo &Info);
 
   bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
-      TemplateParameterList *PParam, TemplateDecl *AArg,
-      const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);
+      TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
+      const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
+      bool IsDeduced);
 
   /// Mark which template parameters are used in a given expression.
   ///
@@ -12767,6 +12768,9 @@ class Sema final : public SemaBase {
 
       /// We are instantiating a type alias template declaration.
       TypeAliasTemplateInstantiation,
+
+      /// We are performing partial ordering for template template parameters.
+      PartialOrderingTTP,
     } Kind;
 
     /// Was the enclosing context a non-instantiation SFINAE context?
@@ -12988,6 +12992,12 @@ class Sema final : public SemaBase {
                           TemplateDecl *Entity, BuildingDeductionGuidesTag,
                           SourceRange InstantiationRange = SourceRange());
 
+    struct PartialOrderingTTP {};
+    /// \brief Note that we are partial ordering template template parameters.
+    InstantiatingTemplate(Sema &SemaRef, SourceLocation ArgLoc,
+                          PartialOrderingTTP, TemplateDecl *PArg,
+                          SourceRange InstantiationRange = SourceRange());
+
     /// Note that we have finished instantiating this template.
     void Clear();
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e70210d55fe28..fc2ee4ea6081e 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -456,6 +456,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
       return "BuildingDeductionGuides";
     case CodeSynthesisContext::TypeAliasTemplateInstantiation:
       return "TypeAliasTemplateInstantiation";
+    case CodeSynthesisContext::PartialOrderingTTP:
+      return "PartialOrderingTTP";
     }
     return "";
   }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 40aa890adc0ee..c1e583acc8934 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5316,8 +5316,7 @@ bool Sema::CheckTemplateArgumentList(
         DefaultArgs && ParamIdx >= DefaultArgs.StartPos) {
       // All written arguments should have been consumed by this point.
       assert(ArgIdx == NumArgs && "bad default argument deduction");
-      // FIXME: Don't ignore parameter packs.
-      if (ParamIdx == DefaultArgs.StartPos && !(*Param)->isParameterPack()) {
+      if (ParamIdx == DefaultArgs.StartPos) {
         assert(Param + DefaultArgs.Args.size() <= ParamEnd);
         // Default arguments from a DeducedTemplateName are already converted.
         for (const TemplateArgument &DefArg : DefaultArgs.Args) {
@@ -5561,8 +5560,9 @@ bool Sema::CheckTemplateArgumentList(
   // pack expansions; they might be empty. This can happen even if
   // PartialTemplateArgs is false (the list of arguments is complete but
   // still dependent).
-  if (ArgIdx < NumArgs && CurrentInstantiationScope &&
-      CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+  if (PartialOrderingTTP ||
+      (CurrentInstantiationScope &&
+       CurrentInstantiationScope->getPartiallySubstitutedPack())) {
     while (ArgIdx < NumArgs &&
            NewArgs[ArgIdx].getArgument().isPackExpansion()) {
       const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
@@ -7160,64 +7160,46 @@ bool 
Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
       << Template;
   }
 
+  if (!getLangOpts().RelaxedTemplateTemplateArgs)
+    return !TemplateParameterListsAreEqual(
+        Template->getTemplateParameters(), Params, /*Complain=*/true,
+        TPL_TemplateTemplateArgumentMatch, Arg.getLocation());
+
   // C++1z [temp.arg.template]p3: (DR 150)
   //   A template-argument matches a template template-parameter P when P
   //   is at least as specialized as the template-argument A.
-  if (getLangOpts().RelaxedTemplateTemplateArgs) {
-    // Quick check for the common case:
-    //   If P contains a parameter pack, then A [...] matches P if each of A's
-    //   template parameters matches the corresponding template parameter in
-    //   the template-parameter-list of P.
-    if (TemplateParameterListsAreEqual(
-            Template->getTemplateParameters(), Params, false,
-            TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) &&
-        // If the argument has no associated constraints, then the parameter is
-        // definitely at least as specialized as the argument.
-        // Otherwise - we need a more thorough check.
-        !Template->hasAssociatedConstraints())
-      return false;
-
-    if (isTemplateTemplateParameterAtLeastAsSpecializedAs(
-            Params, Template, DefaultArgs, Arg.getLocation(), IsDeduced)) {
-      // P2113
-      // C++20[temp.func.order]p2
-      //   [...] If both deductions succeed, the partial ordering selects the
-      // more constrained template (if one exists) as determined below.
-      SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
-      Params->getAssociatedConstraints(ParamsAC);
-      // C++2a[temp.arg.template]p3
-      //   [...] In this comparison, if P is unconstrained, the constraints on 
A
-      //   are not considered.
-      if (ParamsAC.empty())
-        return false;
+  if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
+          Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced))
+    return true;
+  // P2113
+  // C++20[temp.func.order]p2
+  //   [...] If both deductions succeed, the partial ordering selects the
+  // more constrained template (if one exists) as determined below.
+  SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
+  Params->getAssociatedConstraints(ParamsAC);
+  // C++20[temp.arg.template]p3
+  //   [...] In this comparison, if P is unconstrained, the constraints on A
+  //   are not considered.
+  if (ParamsAC.empty())
+    return false;
 
-      Template->getAssociatedConstraints(TemplateAC);
+  Template->getAssociatedConstraints(TemplateAC);
 
-      bool IsParamAtLeastAsConstrained;
-      if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
-                                 IsParamAtLeastAsConstrained))
-        return true;
-      if (!IsParamAtLeastAsConstrained) {
-        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);
-        return true;
-      }
-      return false;
-    }
-    // FIXME: Produce better diagnostics for deduction failures.
+  bool IsParamAtLeastAsConstrained;
+  if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
+                             IsParamAtLeastAsConstrained))
+    return true;
+  if (!IsParamAtLeastAsConstrained) {
+    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);
+    return true;
   }
-
-  return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
-                                         Params,
-                                         true,
-                                         TPL_TemplateTemplateArgumentMatch,
-                                         Arg.getLocation());
+  return false;
 }
 
 static Sema::SemaDiagnosticBuilder noteLocation(Sema &S, const NamedDecl &Decl,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9bf318d939480..521a13757ed02 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -144,7 +144,9 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
     PartialOrderingKind POK, bool DeducedFromArrayBound,
     bool *HasDeducedAnyParam);
 
-enum class PackFold { ParameterToArgument, ArgumentToParameter };
+/// What directions packs are allowed to match non-packs.
+enum class PackFold { ParameterToArgument, ArgumentToParameter, Both };
+
 static TemplateDeductionResult
 DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
                         ArrayRef<TemplateArgument> Ps,
@@ -1704,7 +1706,21 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
     DeducedTemplateArgument Result =
         checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced);
     if (Result.isNull()) {
-      Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+      // We can also get inconsistencies when matching NTTP type.
+      switch (NamedDecl *Param = TemplateParams->getParam(Index);
+              Param->getKind()) {
+      case Decl::TemplateTypeParm:
+        Info.Param = cast<TemplateTypeParmDecl>(Param);
+        break;
+      case Decl::NonTypeTemplateParm:
+        Info.Param = cast<NonTypeTemplateParmDecl>(Param);
+        break;
+      case Decl::TemplateTemplateParm:
+        Info.Param = cast<TemplateTemplateParmDecl>(Param);
+        break;
+      default:
+        llvm_unreachable("unexpected kind");
+      }
       Info.FirstArg = Deduced[Index];
       Info.SecondArg = NewDeduced;
       return TemplateDeductionResult::Inconsistent;
@@ -2577,8 +2593,31 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
     if (const NonTypeTemplateParmDecl *NTTP =
             getDeducedParameterFromExpr(Info, P.getAsExpr())) {
       switch (A.getKind()) {
+      case TemplateArgument::Expression: {
+        const Expr *E = A.getAsExpr();
+        // When checking NTTP, if either the parameter or the argument is
+        // dependent, as there would be otherwise nothing to deduce, we force
+        // the argument to the parameter type using this dependent implicit
+        // cast, in order to maintain invariants. Now we can deduce the
+        // resulting type from the original type, and deduce the original type
+        // against the parameter we are checking.
+        if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E);
+            ICE && ICE->getCastKind() == clang::CK_Dependent) {
+          E = ICE->getSubExpr();
+          if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+                  S, TemplateParams, ICE->getType(), E->getType(), Info,
+                  Deduced, TDF_SkipNonDependent,
+                  PartialOrdering ? PartialOrderingKind::NonCall
+                                  : PartialOrderingKind::None,
+                  /*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
+              Result != TemplateDeductionResult::Success)
+            return Result;
+        }
+        return DeduceNonTypeTemplateArgument(
+            S, TemplateParams, NTTP, DeducedTemplateArgument(A), E->getType(),
+            Info, PartialOrdering, Deduced, HasDeducedAnyParam);
+      }
       case TemplateArgument::Integral:
-      case TemplateArgument::Expression:
       case TemplateArgument::StructuralValue:
         return DeduceNonTypeTemplateArgument(
             S, TemplateParams, NTTP, DeducedTemplateArgument(A),
@@ -2667,50 +2706,75 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
                         SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                         bool NumberOfArgumentsMustMatch, bool PartialOrdering,
                         PackFold PackFold, bool *HasDeducedAnyParam) {
-  if (PackFold == PackFold::ArgumentToParameter)
-    std::swap(Ps, As);
+  bool FoldPackParameter = PackFold == PackFold::ParameterToArgument ||
+                           PackFold == PackFold::Both,
+       FoldPackArgument = PackFold == PackFold::ArgumentToParameter ||
+                          PackFold == PackFold::Both;
+
   // C++0x [temp.deduct.type]p9:
   //   If the template argument list of P contains a pack expansion that is not
   //   the last template argument, the entire template argument list is a
   //   non-deduced context.
-  if (hasPackExpansionBeforeEnd(Ps))
+  if (FoldPackParameter && hasPackExpansionBeforeEnd(Ps))
+    return TemplateDeductionResult::Success;
+
+  if (FoldPackArgument && hasPackExpansionBeforeEnd(As))
     return TemplateDeductionResult::Success;
 
   // C++0x [temp.deduct.type]p9:
   //   If P has a form that contains <T> or <i>, then each argument Pi of the
   //   respective template argument list P is compared with the corresponding
   //   argument Ai of the corresponding template argument list of A.
-  unsigned ArgIdx = 0, ParamIdx = 0;
-  for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) {
-    const TemplateArgument &P = Ps[ParamIdx];
-    if (!P.isPackExpansion()) {
+  for (unsigned ArgIdx = 0, ParamIdx = 0; /**/; /**/) {
+    if (!hasTemplateArgumentForDeduction(Ps, ParamIdx))
+      return !FoldPackParameter && hasTemplateArgumentForDeduction(As, ArgIdx)
+                 ? TemplateDeductionResult::MiscellaneousDeductionFailure
+                 : TemplateDeductionResult::Success;
+
+    if (!Ps[ParamIdx].isPackExpansion()) {
       // The simple case: deduce template arguments by matching Pi and Ai.
 
       // Check whether we have enough arguments.
       if (!hasTemplateArgumentForDeduction(As, ArgIdx))
-        return NumberOfArgumentsMustMatch
+        return !FoldPackArgument && NumberOfArgumentsMustMatch
                    ? TemplateDeductionResult::MiscellaneousDeductionFailure
                    : TemplateDeductionResult::Success;
 
-      // C++1z [temp.deduct.type]p9:
-      //   During partial ordering, if Ai was originally a pack expansion [and]
-      //   Pi is not a pack expansion, template argument deduction fails.
-      if (As[ArgIdx].isPackExpansion())
-        return TemplateDeductionResult::MiscellaneousDeductionFailure;
+      if (As[ArgIdx].isPackExpansion()) {
+        // C++1z [temp.deduct.type]p9:
+        //   During partial ordering, if Ai was originally a pack expansion
+        //   [and] Pi is not a pack expansion, template argument deduction
+        //   fails.
+        if (!FoldPackArgument)
+          return TemplateDeductionResult::MiscellaneousDeductionFailure;
+
+        TemplateArgument Pattern = As[ArgIdx].getPackExpansionPattern();
+        for (;;) {
+          // Deduce template parameters from the pattern.
+          if (auto Result = DeduceTemplateArguments(
+                  S, TemplateParams, Ps[ParamIdx], Pattern, Info,
+                  PartialOrdering, Deduced, HasDeducedAnyParam);
+              Result != TemplateDeductionResult::Success)
+            return Result;
 
-      // Perform deduction for this Pi/Ai pair.
-      TemplateArgument Pi = P, Ai = As[ArgIdx];
-      if (PackFold == PackFold::ArgumentToParameter)
-        std::swap(Pi, Ai);
-      if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, 
Info,
-                                                PartialOrdering, Deduced,
-                                                HasDeducedAnyParam);
-          Result != TemplateDeductionResult::Success)
-        return Result;
+          ++ParamIdx;
+          if (!hasTemplateArgumentForDeduction(Ps, ParamIdx))
+            return TemplateDeductionResult::Success;
+          if (Ps[ParamIdx].isPackExpansion())
+            break;
+        }
+      } else {
+        // Perform deduction for this Pi/Ai pair.
+        if (auto Result = DeduceTemplateArguments(
+                S, TemplateParams, Ps[ParamIdx], As[ArgIdx], Info,
+                PartialOrdering, Deduced, HasDeducedAnyParam);
+            Result != TemplateDeductionResult::Success)
+          return Result;
 
-      // Move to the next argument.
-      ++ArgIdx;
-      continue;
+        ++ArgIdx;
+        ++ParamIdx;
+        continue;
+      }
     }
 
     // The parameter is a pack expansion.
@@ -2720,7 +2784,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
     //   each remaining argument in the template argument list of A. Each
     //   comparison deduces template arguments for subsequent positions in the
     //   template parameter packs expanded by Pi.
-    TemplateArgument Pattern = P.getPackExpansionPattern();
+    TemplateArgument Pattern = Ps[ParamIdx].getPackExpansionPattern();
 
     // Prepare to deduce the packs within the pattern.
     PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
@@ -2731,13 +2795,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
     for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
            PackScope.hasNextElement();
          ++ArgIdx) {
-      TemplateArgument Pi = Pattern, Ai = As[ArgIdx];
-      if (PackFold == PackFold::ArgumentToParameter)
-        std::swap(Pi, Ai);
+      if (!FoldPackParameter && !As[ArgIdx].isPackExpansion())
+        return TemplateDeductionResult::MiscellaneousDeductionFailure;
       // Deduce template arguments from the pattern.
-      if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, 
Info,
-                                                PartialOrdering, Deduced,
-                                                HasDeducedAnyParam);
+      if (auto Result = DeduceTemplateArguments(
+              S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering,
+              Deduced, HasDeducedAnyParam);
           Result != TemplateDeductionResult::Success)
         return Result;
 
@@ -2746,12 +2809,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList 
*TemplateParams,
 
     // Build argument packs for each of the parameter packs expanded by this
     // pack expansion.
-    if (auto Result = PackScope.finish();
-        Result != TemplateDeductionResult::Success)
-      return Result;
+    return PackScope.finish();
   }
-
-  return TemplateDeductionResult::Success;
 }
 
 TemplateDeductionResult Sema::DeduceTemplateArguments(
@@ -3327,7 +3386,6 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
   // Unevaluated SFINAE context.
   EnterExpressionEvaluationContext Unevaluated(
       S, Sema::ExpressionEvaluationContext::Unevaluated);
-  Sema::SFINAETrap Trap(S);
 
   Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template));
 
@@ -3345,20 +3403,36 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
 
   // Check that we produced the correct argument list.
   TemplateParameterList *TemplateParams = Template->getTemplateParameters();
+  auto isSame = [&](unsigned I, const TemplateArgument &P,
+                    const TemplateArgument &A) {
+    if (isSameTemplateArg(S.Context, P, A, PartialOrdering,
+                          /*PackExpansionMatchesPack=*/true))
+      return true;
+    Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
+    Info.FirstArg = P;
+    Info.SecondArg = A;
+    return false;
+  };
   for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
-    TemplateArgument InstArg = CanonicalBuilder[I];
-    if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, 
PartialOrdering,
-                           /*PackExpansionMatchesPack=*/true)) {
-      Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
-      Info.FirstArg = TemplateArgs[I];
-      Info.SecondArg = InstArg;
-      return TemplateDeductionResult::NonDeducedMismatch;
+    const TemplateArgument &P = TemplateArgs[I];
+    if (P.isPackExpansion()) {
+      assert(I == TemplateArgs.size() - 1);
+      for (/**/; I != E; ++I) {
+        const TemplateArgument &A = CanonicalBuilder[I];
+        if (A.getKind() == TemplateArgument::Pack) {
+          for (const TemplateArgument &Ai : A.getPackAsArray())
+            if (!isSame(I, P, Ai))
+              return TemplateDeductionResult::NonDeducedMismatch;
+        } else if (!isSame(I, P, A)) {
+          return TemplateDeductionResult::NonDeducedMismatch;
+        }
+      }
+      break;
     }
+    if (!isSame(I, P, CanonicalBuilder[I]))
+      return TemplateDeductionResult::NonDeducedMismatch;
   }
 
-  if (Trap.hasErrorOccurred())
-    return TemplateDeductionResult::SubstitutionFailure;
-
   if (auto Result = CheckDeducedArgumentConstraints(S, Template, 
SugaredBuilder,
                                                     CanonicalBuilder, Info);
       Result != TemplateDeductionResult::Success)
@@ -3376,7 +3450,6 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
   // Unevaluated SFINAE context.
   EnterExpressionEvaluationContext Unevaluated(
       S, Sema::ExpressionEvaluationContext::Unevaluated);
-  Sema::SFINAETrap Trap(S);
 
   Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(TD));
 
@@ -3385,20 +3458,13 @@ static TemplateDeductionResult 
FinishTemplateArgumentDeduction(
   //   explicitly specified, template argument deduction fails.
   SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
   if (auto Result = ConvertDeducedTemplateArguments(
-          S, TD, /*IsPartialOrdering=*/false, Deduced, Info, SugaredBuilder,
+          S, TD, /*IsDeduced=*/false, Deduced, Info, SugaredBuilder,
           CanonicalBuilder);
       Result != TemplateDeductionResult::Success)
     return Result;
 
-  if (Trap.hasErrorOccurred())
-    return TemplateDeductionResult::SubstitutionFailure;
-
-  if (auto Result = CheckDeducedArgumentConstraints(S, TD, SugaredBuilder,
-                                                    CanonicalBuilder, Info);
-      Result != TemplateDeductionResult::Success)
-    return Result;
-
-  return TemplateDeductionResult::Success;
+  return ::CheckDeducedArgumentConstraints(S, TD, SugaredBuilder,
+                                           CanonicalBuilder, Info);
 }
 
 /// Perform template argument deduction to determine whether the given template
@@ -3445,16 +3511,20 @@ DeduceTemplateArguments(Sema &S, T *Partial,
   if (Inst.isInvalid())
     return TemplateDeductionResult::InstantiationDepth;
 
-  if (Trap.hasErrorOccurred())
-    return TemplateDeductionResult::SubstitutionFailure;
-
   TemplateDeductionResult Result;
   S.runWithSufficientStackSpace(Info.getLocation(), [&] {
     Result = ::FinishTemplateArgumentDeduction(S, Partial,
                                                /*IsPartialOrdering=*/false,
                                                TemplateArgs, Deduced, Info);
   });
-  return Result;
+
+  if (Result != TemplateDeductionResult::Success)
+    return Result;
+
+  if (Trap.hasErrorOccurred())
+    return TemplateDeductionResult::SubstitutionFailure;
+
+  return TemplateDeductionResult::Success;
 }
 
 TemplateDeductionResult
@@ -3512,14 +3582,18 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, 
QualType FromType,
   if (Inst.isInvalid())
     return TemplateDeductionResult::InstantiationDepth;
 
-  if (Trap.hasErrorOccurred())
-    return TemplateDeductionResult::SubstitutionFailure;
-
   TemplateDeductionResult Result;
   runWithSufficientStackSpace(Info.getLocation(), [&] {
     Result = ::FinishTemplateArgumentDeduction(*this, TD, Deduced, Info);
   });
-  return Result;
+
+  if (Result != TemplateDeductionResult::Success)
+    return Result;
+
+  if (Trap.hasErrorOccurred())
+    return TemplateDeductionResult::SubstitutionFailure;
+
+  return TemplateDeductionResult::Success;
 }
 
 /// Determine whether the given type T is a simple-template-id type.
@@ -6220,14 +6294,23 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType 
T1, QualType T2,
     return false;
 
   const auto *TST1 = cast<TemplateSpecializationType>(T1);
-  bool AtLeastAsSpecialized;
+
+  Sema::SFINAETrap Trap(S);
+
+  TemplateDeductionResult Result;
   S.runWithSufficientStackSpace(Info.getLocation(), [&] {
-    AtLeastAsSpecialized =
-        FinishTemplateArgumentDeduction(
-            S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(),
-            Deduced, Info) == TemplateDeductionResult::Success;
+    Result = ::FinishTemplateArgumentDeduction(
+        S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced,
+        Info);
   });
-  return AtLeastAsSpecialized;
+
+  if (Result != TemplateDeductionResult::Success)
+    return false;
+
+  if (Trap.hasErrorOccurred())
+    return false;
+
+  return true;
 }
 
 namespace {
@@ -6467,8 +6550,9 @@ bool Sema::isMoreSpecializedThanPrimary(
 }
 
 bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
-    TemplateParameterList *P, TemplateDecl *AArg,
-    const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced) {
+    TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
+    const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
+    bool IsDeduced) {
   // C++1z [temp.arg.template]p4: (DR 150)
   //   A template template-parameter P is at least as specialized as a
   //   template template-argument A if, given the following rewrite to two
@@ -6480,6 +6564,12 @@ bool 
Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
   //
   TemplateParameterList *A = AArg->getTemplateParameters();
 
+  Sema::InstantiatingTemplate Inst(
+      *this, ArgLoc, Sema::InstantiatingTemplate::PartialOrderingTTP(), PArg,
+      SourceRange(P->getTemplateLoc(), P->getRAngleLoc()));
+  if (Inst.isInvalid())
+    return false;
+
   //   Given an invented class template X with the template parameter list of
   //   A (including default arguments):
   //    - Each function template has a single function parameter whose type is
@@ -6494,8 +6584,6 @@ bool 
Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
   // templates.
   SmallVector<TemplateArgument, 4> PArgs;
   {
-    SFINAETrap Trap(*this);
-
     Context.getInjectedTemplateArgs(P, PArgs);
     TemplateArgumentListInfo PArgList(P->getLAngleLoc(),
                                       P->getRAngleLoc());
@@ -6515,18 +6603,17 @@ bool 
Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
     // C++1z [temp.arg.template]p3:
     //   If the rewrite produces an invalid type, then P is not at least as
     //   specialized as A.
-    SmallVector<TemplateArgument, 4> SugaredPArgs;
-    if (CheckTemplateArgumentList(AArg, Loc, PArgList, DefaultArgs, false,
-                                  SugaredPArgs, PArgs,
+    SmallVector<TemplateArgument, 4> CanonicalPArgs;
+    if (CheckTemplateArgumentList(AArg, ArgLoc, PArgList, DefaultArgs, false,
+                                  PArgs, CanonicalPArgs,
                                   /*UpdateArgsWithConversions=*/true,
                                   /*ConstraintsNotSatisfied=*/nullptr,
-                                  /*PartialOrderTTP=*/true) ||
-        Trap.hasErrorOccurred())
+                                  /*PartialOrderingTTP=*/true))
       return false;
   }
 
   // Determine whether P1 is at least as specialized as P2.
-  TemplateDeductionInfo Info(Loc, A->getDepth());
+  TemplateDeductionInfo Info(ArgLoc, A->getDepth());
   SmallVector<DeducedTemplateArgument, 4> Deduced;
   Deduced.resize(A->size());
 
@@ -6541,29 +6628,89 @@ bool 
Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
   //   be inverted between Ps and As. On non-deduced context, matching needs to
   //   happen both ways, according to [temp.arg.template]p3, but this is
   //   currently implemented as a special case elsewhere.
-  if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced,
-                                /*NumberOfArgumentsMustMatch=*/false,
-                                /*PartialOrdering=*/true,
-                                IsDeduced ? PackFold::ArgumentToParameter
-                                          : PackFold::ParameterToArgument,
-                                /*HasDeducedAnyParam=*/nullptr) !=
-      TemplateDeductionResult::Success)
+  switch (TemplateDeductionResult Result = ::DeduceTemplateArguments(
+              *this, A, AArgs, PArgs, Info, Deduced,
+              /*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true,
+              IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
+              /*HasDeducedAnyParam=*/nullptr)) {
+  case clang::TemplateDeductionResult::Success:
+    break;
+
+  case TemplateDeductionResult::MiscellaneousDeductionFailure:
+    Diag(AArg->getLocation(), diag::err_template_param_list_different_arity)
+        << (A->size() > P->size()) << /*isTemplateTemplateParameter=*/true
+        << SourceRange(A->getTemplateLoc(), P->getRAngleLoc());
+    return false;
+  case TemplateDeductionResult::NonDeducedMismatch:
+    Diag(AArg->getLocation(), diag::err_non_deduced_mismatch)
+        << Info.FirstArg << Info.SecondArg;
+    return false;
+  case TemplateDeductionResult::Inconsistent:
+    Diag(getAsNamedDecl(Info.Param)->getLocation(),
+         diag::err_inconsistent_deduction)
+        << Info.FirstArg << Info.SecondArg;
     return false;
+  case TemplateDeductionResult::AlreadyDiagnosed:
+    return false;
+
+  // None of these should happen for a plain deduction.
+  case TemplateDeductionResult::Invalid:
+  case TemplateDeductionResult::InstantiationDepth:
+  case TemplateDeductionResult::Incomplete:
+  case TemplateDeductionResult::IncompletePack:
+  case TemplateDeductionResult::Underqualified:
+  case TemplateDeductionResult::SubstitutionFailure:
+  case TemplateDeductionResult::DeducedMismatch:
+  case TemplateDeductionResult::DeducedMismatchNested:
+  case TemplateDeductionResult::TooManyArguments:
+  case TemplateDeductionResult::TooFewArguments:
+  case TemplateDeductionResult::InvalidExplicitArguments:
+  case TemplateDeductionResult::NonDependentConversionFailure:
+  case TemplateDeductionResult::ConstraintsNotSatisfied:
+  case TemplateDeductionResult::CUDATargetMismatch:
+    llvm_unreachable("Unexpected Result");
+  }
 
   SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
-  Sema::InstantiatingTemplate Inst(*this, Info.getLocation(), AArg, 
DeducedArgs,
-                                   Info);
-  if (Inst.isInvalid())
-    return false;
 
-  bool AtLeastAsSpecialized;
+  TemplateDeductionResult TDK;
   runWithSufficientStackSpace(Info.getLocation(), [&] {
-    AtLeastAsSpecialized =
-        ::FinishTemplateArgumentDeduction(
-            *this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info) ==
-        TemplateDeductionResult::Success;
+    TDK = ::FinishTemplateArgumentDeduction(
+        *this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info);
   });
-  return AtLeastAsSpecialized;
+  switch (TDK) {
+  case TemplateDeductionResult::Success:
+    return true;
+
+  // It doesn't seem possible to get a non-deduced mismatch when partial
+  // ordering TTPs.
+  case TemplateDeductionResult::NonDeducedMismatch:
+    llvm_unreachable("Unexpected NonDeducedMismatch");
+
+  // Substitution failures should have already been diagnosed.
+  case TemplateDeductionResult::AlreadyDiagnosed:
+  case TemplateDeductionResult::SubstitutionFailure:
+  case TemplateDeductionResult::InstantiationDepth:
+    return false;
+
+  // None of these should happen when just converting deduced arguments.
+  case TemplateDeductionResult::Invalid:
+  case TemplateDeductionResult::Incomplete:
+  case TemplateDeductionResult::IncompletePack:
+  case TemplateDeductionResult::Inconsistent:
+  case TemplateDeductionResult::Underqualified:
+  case TemplateDeductionResult::DeducedMismatch:
+  case TemplateDeductionResult::DeducedMismatchNested:
+  case TemplateDeductionResult::TooManyArguments:
+  case TemplateDeductionResult::TooFewArguments:
+  case TemplateDeductionResult::InvalidExplicitArguments:
+  case TemplateDeductionResult::NonDependentConversionFailure:
+  case TemplateDeductionResult::ConstraintsNotSatisfied:
+  case TemplateDeductionResult::MiscellaneousDeductionFailure:
+  case TemplateDeductionResult::CUDATargetMismatch:
+    llvm_unreachable("Unexpected Result");
+  }
+  llvm_unreachable("Unexpected TDK");
 }
 
 namespace {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 71ce6ec0e10b4..5a874c5c6f260 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -570,6 +570,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() 
const {
   case LambdaExpressionSubstitution:
   case BuildingDeductionGuides:
   case TypeAliasTemplateInstantiation:
+  case PartialOrderingTTP:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -802,6 +803,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
           SemaRef, CodeSynthesisContext::BuildingDeductionGuides,
           PointOfInstantiation, InstantiationRange, Entity) {}
 
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+    Sema &SemaRef, SourceLocation ArgLoc, PartialOrderingTTP,
+    TemplateDecl *PArg, SourceRange InstantiationRange)
+    : InstantiatingTemplate(SemaRef, CodeSynthesisContext::PartialOrderingTTP,
+                            ArgLoc, InstantiationRange, PArg) {}
 
 void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
   Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
@@ -1242,6 +1248,14 @@ void Sema::PrintInstantiationStack() {
           << cast<TypeAliasTemplateDecl>(Active->Entity)
           << Active->InstantiationRange;
       break;
+    case CodeSynthesisContext::PartialOrderingTTP:
+      Diags.Report(Active->PointOfInstantiation,
+                   diag::note_template_arg_template_params_mismatch);
+      if (SourceLocation ParamLoc = Active->Entity->getLocation();
+          ParamLoc.isValid())
+        Diags.Report(ParamLoc, diag::note_template_prev_declaration)
+            << /*isTemplateTemplateParam=*/true << Active->InstantiationRange;
+      break;
     }
   }
 }
@@ -1284,6 +1298,7 @@ std::optional<TemplateDeductionInfo *> 
Sema::isSFINAEContext() const {
     case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
     case CodeSynthesisContext::DefaultTemplateArgumentChecking:
     case CodeSynthesisContext::RewritingOperatorAsSpaceship:
+    case CodeSynthesisContext::PartialOrderingTTP:
       // 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.
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 19793fe826372..1bbbd1d3429dd 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
@@ -2,13 +2,13 @@
 
 template <class T> struct eval; // expected-note 3{{template is declared here}}
 
-template <template <class, class...> class TT, class T1, class... Rest> 
+template <template <class, class...> class TT, class T1, class... Rest>
 struct eval<TT<T1, Rest...>> { };
 
-template <class T1> struct A; 
-template <class T1, class T2> struct B; 
-template <int N> struct C; 
-template <class T1, int N> struct D; 
+template <class T1> struct A;
+template <class T1, class T2> struct B;
+template <int N> struct C;
+template <class T1, int N> struct D;
 template <class T1, class T2, int N = 17> struct E;
 
 eval<A<int>> eA;
@@ -17,27 +17,32 @@ eval<C<17>> eC; // expected-error{{implicit instantiation 
of undefined template
 eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined 
template 'eval<D<int, 17>>'}}
 eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined 
template 'eval<E<int, float>>}}
 
-template<template <int ...N> class TT> struct X0 { }; // 
expected-note{{previous non-type template parameter with type 'int' is here}}
+template<
+  template <int ...N> // expected-error{{deduced non-type template argument 
does not have the same type as the corresponding template parameter ('int' vs 
'long')}}
+  class TT // expected-note {{previous template template parameter is here}}
+> struct X0 { };
+
 template<int I, int J, int ...Rest> struct X0a;
 template<int ...Rest> struct X0b;
-template<int I, long J> struct X0c; // expected-note{{template non-type 
parameter has a different type 'long' in template argument}}
+template<int I, long J> struct X0c; // expected-note{{template parameter is 
declared here}}
 
 X0<X0a> inst_x0a;
 X0<X0b> inst_x0b;
-X0<X0c> inst_x0c; // expected-error{{template template argument has different 
template parameters than its corresponding template template parameter}}
+X0<X0c> inst_x0c; // expected-note{{template template argument has different 
template parameters than its corresponding template template parameter}}
 
-template<typename T, 
-         template <T ...N> class TT>  // expected-note{{previous non-type 
template parameter with type 'short' is here}}
-struct X1 { };
+template<typename T,
+         template <T ...N> // expected-error{{deduced non-type template 
argument does not have the same type as the corresponding template parameter 
('short' vs 'long')}}
+         class TT // expected-note {{previous template template parameter is 
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; // expected-note{{template non-type 
parameter has a different type 'long' in template argument}}
+template<short I, long J> struct X1d; // expected-note{{template parameter is 
declared here}}
 
 X1<int, X1a> inst_x1a;
 X1<long, X1b> inst_x1b;
 X1<short, X1c> inst_x1c;
-X1<short, X1d> inst_x1d; // expected-error{{template template argument has 
different template parameters than its corresponding template template 
paramete}}
+X1<short, X1d> inst_x1d; // expected-note{{template template argument has 
different template parameters than its corresponding template template 
parameter}}
 
 template <int> class X2; // expected-note{{template is declared here}} \
                          // expected-note{{template is declared here}}
diff --git a/clang/test/CXX/temp/temp.param/p12.cpp 
b/clang/test/CXX/temp/temp.param/p12.cpp
index 7be38790905fa..8317e7f24152c 100644
--- a/clang/test/CXX/temp/temp.param/p12.cpp
+++ b/clang/test/CXX/temp/temp.param/p12.cpp
@@ -1,39 +1,40 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s 
-template<typename> struct Y1; // expected-note{{too few template parameters in 
template template argument}}
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<typename> struct Y1; // expected-note{{template is declared here}}
 template<typename, int> struct Y2;
 
 // C++ [temp.param]p12:
-template<class T1, 
+template<class T1,
          class T2 = int> // expected-note{{previous default template argument 
defined here}}
   class B3;
 template<class T1, typename T2> class B3;
-template<class T1, 
+template<class T1,
          typename T2 = float> // expected-error{{template parameter redefines 
default argument}}
   class B3;
 
-template<template<class, int> class, 
+template<template<class, int> class,
          template<class> class = Y1> // expected-note{{previous default 
template argument defined here}}
   class B3t;
 
 template<template<class, int> class, template<class> class> class B3t;
 
-template<template<class, int> class, 
+template<template<class, int> class,
          template<class> class = Y1> // expected-error{{template parameter 
redefines default argument}}
   class B3t;
 
-template<int N, 
+template<int N,
          int M = 5> // expected-note{{previous default template argument 
defined here}}
   class B3n;
 
 template<int N, int M> class B3n;
 
-template<int N, 
+template<int N,
          int M = 7>  // expected-error{{template parameter redefines default 
argument}}
   class B3n;
 
 // Check validity of default arguments
-template<template<class, int> class // expected-note{{previous template 
template parameter is here}}
-           = Y1> // expected-error{{template template argument has different 
template parameters than its corresponding template template parameter}}
+template<template<class, int> class =// expected-note {{previous template 
template parameter is here}}
+           Y1> // expected-error{{too many template arguments for class 
template 'Y1'}}
+               // expected-note@-1 {{template template argument has different 
template parameters than its corresponding template template parameter}}
   class C1 {};
 
 C1<> c1; // expected-note{{while checking a default template argument}}
diff --git a/clang/test/Modules/cxx-templates.cpp 
b/clang/test/Modules/cxx-templates.cpp
index b7d5741e69af6..953fc0d9e867c 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -40,23 +40,14 @@ void g() {
 
   template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
   template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
-
-  template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching 
function}}
-  // expected-note@Inputs/cxx-templates-a.h:11 {{invalid explicitly-specified 
argument}}
-  // expected-note@Inputs/cxx-templates-b.h:11 {{invalid explicitly-specified 
argument}}
+  template_param_kinds_2<Tmpl_T_C>(); // ok, from cxx-templates-b.h
 
   template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}}
   // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}}
   // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}}
 
-  // FIXME: This should be valid, but we incorrectly match the template 
template
-  // argument against both template template parameters.
-  template_param_kinds_3<Tmpl_T_T_A>(); // expected-error {{ambiguous}}
-  // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
-  // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
-  template_param_kinds_3<Tmpl_T_T_B>(); // expected-error {{ambiguous}}
-  // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
-  // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
+  template_param_kinds_3<Tmpl_T_T_A>();
+  template_param_kinds_3<Tmpl_T_T_B>();
 
   // Trigger the instantiation of a template in 'a' that uses a type defined in
   // 'common'. That type is not visible here.
diff --git a/clang/test/SemaCXX/make_integer_seq.cpp 
b/clang/test/SemaCXX/make_integer_seq.cpp
index 8f72ce15eef47..71b7b8260d4ab 100644
--- a/clang/test/SemaCXX/make_integer_seq.cpp
+++ b/clang/test/SemaCXX/make_integer_seq.cpp
@@ -48,6 +48,5 @@ using illformed2 = ErrorSeq<int, -5>; // expected-note{{in 
instantiation}}
 template <typename T, T N> void f() {}
 __make_integer_seq<f, int, 0> x; // expected-error{{template template 
parameter must be a class template or type alias template}}
 
-__make_integer_seq<__make_integer_seq, int, 10> PR28494; // 
expected-error{{different template parameters}}
-// expected-note@make_integer_seq.cpp:* {{template parameter has a different 
kind}}
-// expected-note@make_integer_seq.cpp:* {{previous template template parameter 
is here}}
+__make_integer_seq<__make_integer_seq, int, 10> PR28494; // 
expected-note{{different template parameters}}
+// expected-error@make_integer_seq.cpp:* {{template argument for template 
template parameter must be a class template or type alias template}}
diff --git a/clang/test/SemaTemplate/cwg2398.cpp 
b/clang/test/SemaTemplate/cwg2398.cpp
index 1d9747276fbe0..f5ff4ca92cb96 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -106,12 +106,10 @@ namespace type_pack3 {
   template<class T3> struct B;
 
   template<template<class T4              > class TT1, class T5              > 
struct B<TT1<T5        >>;
-  // new-note@-1 {{template is declared here}}
-  template<template<class T6, class ...T7s> class TT2, class T8, class ...T9s> 
struct B<TT2<T8, T9s...>>;
-  // old-note@-1 {{template is declared here}}
+
+  template<template<class T6, class ...T7s> class TT2, class T8, class ...T9s> 
struct B<TT2<T8, T9s...>> {};
 
   template struct B<A<int>>;
-  // expected-error@-1 {{explicit instantiation of undefined template}}
 } // namespace type_pack3
 
 namespace gcc_issue {
@@ -364,6 +362,51 @@ namespace classes {
   } // namespace defaulted
 } // namespace classes
 
+namespace packs {
+  namespace t1 {
+    // FIXME: This should be rejected
+    template<template<int, int...> class> struct A {};
+    // old-note@-1 {{previous non-type template parameter with type 'int' is 
here}}
+
+    template<char> struct B;
+    // old-note@-1 {{template non-type parameter has a different type 'char' 
in template argument}}
+
+    template struct A<B>;
+    // old-error@-1 {{has different template parameters}}
+  } // namespace t1
+  namespace t2 {
+    template<template<char, int...> class> struct A {};
+    // old-note@-1 {{previous non-type template parameter with type 'char' is 
here}}
+
+    template<int> struct B;
+    // old-note@-1 {{template non-type parameter has a different type 'int' in 
template argument}}
+
+    template struct A<B>;
+    // old-error@-1 {{has different template parameters}}
+  } // namespace t2
+  namespace t3 {
+    // FIXME: This should be rejected
+    template<template<int...> class> struct A {};
+    // old-note@-1 {{previous non-type template parameter with type 'int' is 
here}}
+
+    template<char> struct B;
+    // old-note@-1 {{template non-type parameter has a different type 'char' 
in template argument}}
+
+    template struct A<B>;
+    // old-error@-1 {{has different template parameters}}
+  } // namespace t3
+  namespace t4 {
+    template<template<char...> class> struct A {};
+    // old-note@-1 {{previous non-type template parameter with type 'char' is 
here}}
+
+    template<int> struct B;
+    // old-note@-1 {{template non-type parameter has a different type 'int' in 
template argument}}
+
+    template struct A<B>;
+    // old-error@-1 {{has different template parameters}}
+  } // namespace t4
+} // namespace packs
+
 namespace regression1 {
   template <typename T, typename Y> struct map {};
   template <typename T> class foo {};
@@ -379,3 +422,91 @@ namespace regression1 {
     bar(input);
   }
 } // namespace regression1
+
+namespace constraints {
+  template <class T> concept C1 = true;
+  // new-note@-1 {{similar constraint expression here}}
+  // new-note@-2 2{{similar constraint expressions not considered equivalent}}
+
+  template <class T> concept C2 = C1<T> && true;
+  // new-note@-1 2{{similar constraint expression here}}
+
+  template <class T> concept D1 = true;
+  // new-note@-1 {{similar constraint expressions not considered equivalent}}
+
+  namespace t1 {
+    template<template<C1, class... T1s> class TT1> // new-note {{TT1' declared 
here}}
+    struct A {};
+    template<D1, class T2> struct B {}; // new-note {{'B' declared here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t1
+  namespace t2 {
+    template<template<C2, class... T1s> class TT1> struct A {};
+    template<C1, class T2> struct B {};
+    template struct A<B>;
+  } // namespace t2
+  namespace t3 {
+    template<template<C1, class... T1s> class TT1> // new-note {{'TT1' 
declared here}}
+    struct A {};
+    template<C2, class T2> struct B {}; // new-note {{'B' declared here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t2
+  namespace t4 {
+    // FIXME: This should be accepted.
+    template<template<C1... T1s> class TT1> // new-note {{'TT1' declared here}}
+    struct A {};
+    template<C1 T2> struct B {}; // new-note {{'B' declared here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t4
+  namespace t5 {
+    // FIXME: This should be accepted
+    template<template<C2... T1s> class TT1> // new-note {{'TT1' declared here}}
+    struct A {};
+    template<C1 T2> struct B {}; // new-note {{'B' declared here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t5
+  namespace t6 {
+    template<template<C1... T1s> class TT1> // new-note {{'TT1' declared here}}
+    struct A {};
+    template<C2 T2> struct B {}; // new-note {{'B' declared here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t6
+  namespace t7 {
+    // FIXME: This should be rejected.
+    template<template<class... T1s> class TT1>
+    struct A {};
+    template<C1 T2> struct B {};
+    template struct A<B>;
+  } // namespace t7
+  namespace t8 {
+    template<template<C1... T1s> class TT1>
+    struct A {};
+    template<class T2> struct B {};
+    template struct A<B>;
+  } // namespace t8
+  namespace t9 {
+    template<template<C1... T1s> class TT1> // new-note {{'TT1' declared here}}
+    struct A {};
+    template<D1 T2> struct B {}; // new-note {{'B' declared here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t9
+  namespace t10 {
+    template<template<class...> requires C1<int> class TT1> // new-note 
{{'TT1' declared here}}
+    struct A {};
+
+    template<class> requires C2<int> struct B {}; // new-note {{'B' declared 
here}}
+    template struct A<B>;
+    // new-error@-1 {{'B' is more constrained than template template parameter 
'TT1'}}
+  } // namespace t10
+  namespace t11 {
+    template<template<class...> requires C2<int> class TT1> struct A {};
+    template<class> requires C1<int> struct B {};
+    template struct A<B>;
+  } // namespace t11
+} // namespace
diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp 
b/clang/test/SemaTemplate/temp_arg_nontype.cpp
index cbcfb2a5b8674..cb384bc246cf2 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp
@@ -128,28 +128,28 @@ namespace ns {
   struct Foo {
     static const bool value = true;
   };
-  
+
   template <bool b>
   struct Bar {};
-  
+
   const bool value = false;
-  
+
   Bar<bool(ns::Foo<int>::value)> x;
 }
 
 // PR5349
 namespace ns {
   enum E { k };
-  
+
   template <E e>
   struct Baz  {};
-  
+
   Baz<k> f1;  // This works.
   Baz<E(0)> f2;  // This too.
   Baz<static_cast<E>(0)> f3;  // And this.
-  
+
   Baz<ns::E(0)> b1;  // This doesn't work.
-  Baz<static_cast<ns::E>(0)> b2;  // This neither.  
+  Baz<static_cast<ns::E>(0)> b2;  // This neither.
 }
 
 // PR5597
@@ -193,7 +193,7 @@ namespace EntityReferenced {
 
   template<typename T>
   struct Y {
-    static void f(T x) { 
+    static void f(T x) {
       x = 1; // expected-error{{incompatible integer to pointer conversion 
assigning to 'int *' from 'int'}}
     }
   };
@@ -208,7 +208,7 @@ namespace PR6964 {
   // expected-note {{template parameter is declared here}}
   struct as_nview { };
 
-  template <typename Sequence, int I0> 
+  template <typename Sequence, int I0>
   struct as_nview<Sequence, I0>  // expected-note{{while checking a default 
template argument used here}}
   { };
 }
@@ -235,7 +235,7 @@ namespace test8 {
     char y;
     double z;
   };
-  
+
   template <C* cp> struct B {
     C* p;
     B() : p(cp) {}
@@ -387,12 +387,11 @@ namespace PR17696 {
 
 namespace partial_order_different_types {
   template<int, int, typename T, typename, T> struct A;
-  template<int N, typename T, typename U, T V> struct A<0, N, T, U, V>; // 
expected-note {{matches}}
-  // FIXME: It appears that this partial specialization should be ill-formed as
-  // it is not more specialized than the primary template. V is not deducible
-  // because it does not have the same type as the corresponding parameter.
-  template<int N, typename T, typename U, U V> struct A<0, N, T, U, V> {}; // 
expected-note {{matches}}
-  A<0, 0, int, int, 0> a; // expected-error {{ambiguous}}
+  // expected-note@-1 {{template is declared here}}
+  template<int N, typename T, typename U, T V> struct A<0, N, T, U, V> {};
+  template<int N, typename T, typename U, U V> struct A<0, N, T, U, V>;
+  // expected-error@-1 {{class template partial specialization is not more 
specialized than the primary template}}
+  A<0, 0, int, int, 0> a;
 }
 
 namespace partial_order_references {
@@ -458,13 +457,24 @@ namespace dependent_nested_partial_specialization {
 namespace nondependent_default_arg_ordering {
   int n, m;
   template<typename A, A B = &n> struct X {};
+
   template<typename A> void f(X<A>);
+  // expected-note@-1 {{candidate function}}
   template<typename A> void f(X<A, &m>);
+  // expected-note@-1 {{candidate function}}
   template<typename A, A B> void f(X<A, B>);
+  // expected-note@-1 2{{candidate function}}
   template<template<typename U, U> class T, typename A, int *B> void f(T<A, 
B>);
+  // expected-note@-1 2{{candidate function}}
+
+  // FIXME: When partial ordering, we get an inconsistent deduction between
+  // `A` (type-parameter-0-0) and `int *`, when deducing the first parameter.
+  // The deduction mechanism needs to be extended to be able to correctly
+  // handle these cases where the argument's template parameters appear in
+  // the result.
   void g() {
-    X<int *, &n> x; f(x);
-    X<int *, &m> y; f(y);
+    X<int *, &n> x; f(x); // expected-error {{call to 'f' is ambiguous}}
+    X<int *, &m> y; f(y); // expected-error {{call to 'f' is ambiguous}}
   }
 }
 
diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp 
b/clang/test/SemaTemplate/temp_arg_template.cpp
index a7236669276aa..9908af5e78669 100644
--- a/clang/test/SemaTemplate/temp_arg_template.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template.cpp
@@ -1,33 +1,40 @@
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,precxx17 %std_cxx98-14 %s
 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 -std=c++17 %s
 
-template<template<typename T> class X> struct A; // expected-note 2{{previous 
template template parameter is here}}
+template<template<typename T> class X> struct A; // #A
+// expected-note@-1 2{{previous template template parameter is here}}
 
 template<template<typename T, int I> class X> struct B; // 
expected-note{{previous template template parameter is here}}
 
-template<template<int I> class X> struct C;  // expected-note {{previous 
non-type template parameter with type 'int' is here}}
+template<template<int I> class X> struct C;
+// precxx17-error@-1 {{deduced non-type template argument does not have the 
same type as the corresponding template parameter ('int' vs 'const int &')}}
+// cxx17-error@-2 {{conversion from 'int' to 'const int &' in converted 
constant expression would bind reference to a temporary}}
+// expected-note@-3 {{previous template template parameter is here}}
 
-template<class> struct X; // expected-note{{too few template parameters in 
template template argument}}
-template<int N> struct Y; // expected-note{{template parameter has a different 
kind in template argument}}
+template<class> struct X; // expected-note {{template is declared here}}
+template<int N> struct Y; // expected-note {{template parameter is declared 
here}}
 template<long N> struct Ylong;
-template<const int &N> struct Yref; // expected-note{{template non-type 
parameter has a different type 'const int &' in template argument}}
+template<const int &N> struct Yref; // precxx17-note {{template parameter is 
declared here}}
 
 namespace N {
   template<class> struct Z;
 }
-template<class, class> struct TooMany; // expected-note{{too many template 
parameters in template template argument}}
+template<class, class> struct TooMany; // expected-note{{template is declared 
here}}
 
 
 A<X> *a1;
 A<N::Z> *a2;
 A< ::N::Z> *a3;
 
-A<Y> *a4; // expected-error{{template template argument has different template 
parameters than its corresponding template template parameter}}
-A<TooMany> *a5; // expected-error{{template template argument has different 
template parameters than its corresponding template template parameter}}
-B<X> *a6; // expected-error{{template template argument has different template 
parameters than its corresponding template template parameter}}
+A<Y> *a4; // expected-error@#A {{template argument for non-type template 
parameter must be an expression}}
+          // expected-note@-1 {{different template parameters}}
+A<TooMany> *a5; // expected-error {{too few template arguments for class 
template 'TooMany'}}
+                // expected-note@-1 {{different template parameters}}
+B<X> *a6; // expected-error {{too many template arguments for class template 
'X'}}
+          // expected-note@-1 {{different template parameters}}
 C<Y> *a7;
 C<Ylong> *a8;
-C<Yref> *a9; // expected-error{{template template argument has different 
template parameters than its corresponding template template parameter}}
+C<Yref> *a9; // expected-note {{different template parameters}}
 
 template<typename T> void f(int);
 
@@ -103,9 +110,9 @@ void foo() {
 
 namespace CheckDependentNonTypeParamTypes {
   template<template<typename T, typename U, T v> class X> struct A {
+    // expected-note@-1 {{previous template template parameter is here}}
     void f() {
-      X<int, void*, 3> x; // precxx17-error {{does not refer to any 
declaration}} \
-                             cxx17-error {{value of type 'int' is not 
implicitly convertible to 'void *'}}
+      X<int, void*, 3> x;
     }
     void g() {
       X<int, long, 3> x;
@@ -124,15 +131,16 @@ namespace CheckDependentNonTypeParamTypes {
     }
   };
 
-  template<typename T, typename U, U v> struct B { // precxx17-note 
{{parameter}}
+  template<typename T, typename U, U v> struct B {
+    // expected-error@-1 {{conflicting deduction 'U' against 'T' for 
parameter}}
     static const U value = v;
   };
 
   // FIXME: This should probably be rejected, but the rules are at best 
unclear.
-  A<B> ab;
+  A<B> ab; // expected-note {{different template parameters}}
 
   void use() {
-    ab.f(); // expected-note {{instantiation of}}
+    ab.f();
     ab.g();
     ab.h();
   }
diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp 
b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index 251b6fc7d2be1..9529481893dde 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -1,14 +1,16 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s
 
-// expected-note@temp_arg_template_p0522.cpp:* 1+{{}}
+// expected-note@temp_arg_template_p0522.cpp:* 1+{{template is declared here}}
+// expected-note@temp_arg_template_p0522.cpp:* 1+{{template parameter is 
declared here}}
+// expected-note@temp_arg_template_p0522.cpp:* 1+{{previous template template 
parameter is here}}
 
-template<template<int> typename> struct Ti;
-template<template<int...> typename> struct TPi;
+template<template<int> typename> struct Ti; // #Ti
+template<template<int...> typename> struct TPi; // #TPi
 template<template<int, int...> typename> struct TiPi;
 template<template<int..., int...> typename> struct TPiPi; // FIXME: Why is 
this not ill-formed?
 
-template<typename T, template<T> typename> struct tT0;
-template<template<typename T, T> typename> struct Tt0;
+template<typename T, template<T> typename> struct tT0; // #tT0
+template<template<typename T, T> typename> struct Tt0; // #Tt0
 
 template<template<typename> typename> struct Tt;
 template<template<typename, typename...> typename> struct TtPt;
@@ -19,8 +21,8 @@ template<int, int> struct ii;
 template<int...> struct Pi;
 template<int, int, int...> struct iiPi;
 
-template<int, typename = int> struct iDt;
-template<int, typename> struct it;
+template<int, typename = int> struct iDt; // #iDt
+template<int, typename> struct it; // #it
 
 template<typename T, T v> struct t0;
 
@@ -31,10 +33,14 @@ namespace IntParam {
         Ti<iDi>,
         Ti<Pi>,
         Ti<iDt>>;
-  using err1 = Ti<ii>; // expected-error {{different template parameters}}
-  using err2 = Ti<iiPi>; // expected-error {{different template parameters}}
-  using err3 = Ti<t0>; // expected-error {{different template parameters}}
-  using err4 = Ti<it>; // expected-error {{different template parameters}}
+  using err1 = Ti<ii>; // expected-error {{too few template arguments for 
class template 'ii'}}
+                       // expected-note@-1 {{different template parameters}}
+  using err2 = Ti<iiPi>; // expected-error {{too few template arguments for 
class template 'iiPi'}}
+                         // expected-note@-1 {{different template parameters}}
+  using err3 = Ti<t0>; // expected-error@#Ti {{template argument for template 
type parameter must be a type}}
+                       // expected-note@-1 {{different template parameters}}
+  using err4 = Ti<it>; // expected-error {{too few template arguments for 
class template 'it'}}
+                       // expected-note@-1 {{different template parameters}}
 }
 
 // These are accepted by the backwards-compatibility "parameter pack in
@@ -42,9 +48,12 @@ namespace IntParam {
 namespace IntPackParam {
   using ok = TPi<Pi>;
   using ok_compat = Pt<TPi<i>, TPi<iDi>, TPi<ii>, TPi<iiPi>>;
-  using err1 = TPi<t0>; // expected-error {{different template parameters}}
-  using err2 = TPi<iDt>; // expected-error {{different template parameters}}
-  using err3 = TPi<it>; // expected-error {{different template parameters}}
+  using err1 = TPi<t0>; // expected-error@#TPi {{template argument for 
template type parameter must be a type}}
+                        // expected-note@-1 {{different template parameters}}
+  using err2 = TPi<iDt>; // expected-error@#iDt {{could not match 
'type-parameter-0-1' against}}
+                         // expected-note@-1 {{different template parameters}}
+  using err3 = TPi<it>; // expected-error@#it {{could not match 
'type-parameter-0-1' against}}
+                        // expected-note@-1 {{different template parameters}}
 }
 
 namespace IntAndPackParam {
@@ -55,42 +64,50 @@ namespace IntAndPackParam {
 
 namespace DependentType {
   using ok = Pt<tT0<int, i>, tT0<int, iDi>>;
-  using err1 = tT0<int, ii>; // expected-error {{different template 
parameters}}
+  using err1 = tT0<int, ii>; // expected-error {{too few template arguments 
for class template 'ii'}}
+                             // expected-note@-1 {{different template 
parameters}}
   using err2 = tT0<short, i>; // FIXME: should this be OK?
   using err2a = tT0<long long, i>; // FIXME: should this be OK (if long long 
is larger than int)?
-  using err2b = tT0<void*, i>; // expected-error {{different template 
parameters}}
-  using err3 = tT0<short, t0>; // expected-error {{different template 
parameters}}
+  using err2b = tT0<void*, i>; // expected-error@#tT0 {{value of type 'void *' 
is not implicitly convertible to 'int'}}
+                               // expected-note@-1 {{different template 
parameters}}
+  using err3 = tT0<short, t0>; // expected-error@#tT0 {{template argument for 
template type parameter must be a type}}
+                               // expected-note@-1 {{different template 
parameters}}
 
   using ok2 = Tt0<t0>;
-  using err4 = Tt0<it>; // expected-error {{different template parameters}}
+  using err4 = Tt0<it>; // expected-error@#Tt0 {{template argument for 
non-type template parameter must be an expression}}
+                        // expected-note@-1 {{different template parameters}}
 }
 
 namespace Auto {
-  template<template<int> typename T> struct TInt {};
-  template<template<int*> typename T> struct TIntPtr {};
+  template<template<int> typename T> struct TInt {}; // #TInt
+  template<template<int*> typename T> struct TIntPtr {}; // #TIntPtr
   template<template<auto> typename T> struct TAuto {};
   template<template<auto*> typename T> struct TAutoPtr {};
   template<template<decltype(auto)> typename T> struct TDecltypeAuto {};
   template<auto> struct Auto;
-  template<auto*> struct AutoPtr;
+  template<auto*> struct AutoPtr; // #AutoPtr
   template<decltype(auto)> struct DecltypeAuto;
   template<int> struct Int;
   template<int*> struct IntPtr;
 
   TInt<Auto> ia;
-  TInt<AutoPtr> iap; // FIXME: ill-formed (?)
+  TInt<AutoPtr> iap; // expected-error@#TInt {{non-type template parameter '' 
with type 'auto *' has incompatible initializer of type 'int'}}
+                     // expected-note@-1 {{different template parameters}}
   TInt<DecltypeAuto> ida;
   TInt<Int> ii;
-  TInt<IntPtr> iip; // expected-error {{different template parameters}}
+  TInt<IntPtr> iip; // expected-error@#TInt {{conversion from 'int' to 'int *' 
is not allowed in a converted constant expression}}
+                    // expected-note@-1 {{different template parameters}}
 
   TIntPtr<Auto> ipa;
   TIntPtr<AutoPtr> ipap;
   TIntPtr<DecltypeAuto> ipda;
-  TIntPtr<Int> ipi; // expected-error {{different template parameters}}
+  TIntPtr<Int> ipi; // expected-error@#TIntPtr {{value of type 'int *' is not 
implicitly convertible to 'int'}}
+                    // expected-note@-1 {{different template parameters}}
   TIntPtr<IntPtr> ipip;
 
   TAuto<Auto> aa;
-  TAuto<AutoPtr> aap; // FIXME: ill-formed (?)
+  TAuto<AutoPtr> aap; // expected-error@#AutoPtr {{could not match 'auto *' 
against 'auto'}}
+                      // expected-note@-1 {{different template parameters}}
   TAuto<Int> ai; // FIXME: ill-formed (?)
   TAuto<IntPtr> aip; // FIXME: ill-formed (?)
 
@@ -111,7 +128,8 @@ namespace Auto {
   // parameters (such as 'user-defined-type &') that are not valid 'auto'
   // parameters.
   TDecltypeAuto<Auto> daa;
-  TDecltypeAuto<AutoPtr> daap; // FIXME: should probably be ill-formed
+  TDecltypeAuto<AutoPtr> daap; // expected-error@#AutoPtr {{could not match 
'auto *' against 'decltype(auto)'}}
+                               // expected-note@-1 {{different template 
parameters}}
 
   int n;
   template<auto A, decltype(A) B = &n> struct SubstFailure;
diff --git a/clang/test/Templight/templight-empty-entries-fix.cpp 
b/clang/test/Templight/templight-empty-entries-fix.cpp
index e17be9012e59c..d13b748068efe 100644
--- a/clang/test/Templight/templight-empty-entries-fix.cpp
+++ b/clang/test/Templight/templight-empty-entries-fix.cpp
@@ -314,6 +314,18 @@ void foo() {
 // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}}
 // CHECK: {{^poi:[ ]+''$}}
 // CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
+// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
+// CHECK: {{^event:[ ]+Begin$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:5'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
+// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
+// CHECK: {{^event:[ ]+End$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:5'$}}
+// CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
diff --git a/clang/test/Templight/templight-prior-template-arg.cpp 
b/clang/test/Templight/templight-prior-template-arg.cpp
index e9b1dd47bb603..14bcb6a4d48f6 100644
--- a/clang/test/Templight/templight-prior-template-arg.cpp
+++ b/clang/test/Templight/templight-prior-template-arg.cpp
@@ -10,63 +10,76 @@ class B {};
 // CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:5:40'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:1'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:1'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B::Outer'$}}
 // CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:5:40'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:1'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:1'$}}
+//
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+'B::Outer'$}}
+// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
+// CHECK: {{^event:[ ]+Begin$}}
+// CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:5:40'}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:3'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+'B::Outer'$}}
+// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
+// CHECK: {{^event:[ ]+End$}}
+// CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:5:40'}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:3'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'B<A>'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-prior-template-arg.cpp:6:7'}}
-// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:72:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-prior-template-arg.cpp:85:6'$}}
 B<A> b;
diff --git a/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp 
b/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
index a798647d56ee1..3593c2e095db9 100644
--- a/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
+++ b/libcxx/test/libcxx/type_traits/is_specialization.verify.cpp
@@ -17,5 +17,5 @@
 #include <array>
 #include <utility>
 
-// expected-error@+1 {{template template argument has different template 
parameters than its corresponding template template parameter}}
+// expected-error-re@*:* {{{{could not match _Size against 
'type-parameter-0-0'|different template parameters}}}}
 static_assert(!std::__is_specialization_v<std::pair<int, std::size_t>, 
std::array>);

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to