[llvm-branch-commits] [clang] [clang-tools-extra] [clang] fix getTemplateInstantiationArgs (PR #199528)

Matheus Izvekov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon May 25 06:38:47 PDT 2026


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

>From c237f89c04d38db0de61a35493222462437f3d1e Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Wed, 29 Apr 2026 14:19:07 -0300
Subject: [PATCH] [clang] fix getTemplateInstantiationArgs

This implements a new strategy for collecting the template arguments, by
relying on the qualifiers and template parameter lists to navigate the template
context of out-of-line definitions.

This greatly simplifies the signature of that function, by removing a bunch
of workarounds, and simpliffying a couple that weren't removed yet.

Since this now relies on qualifiers and template parameter lists,
this patch expends most of its effort making sure these are placed,
transformed and propagated to template instantiations.

Also makes the explicit specialization AST nodes stop abusing the template
parameter lists by storing it's own template parameter list, creating a
dedicated field for them, similar to partial specializations.
---
 .../misc/DefinitionsInHeadersCheck.cpp        |   2 +-
 .../clangd/SemanticHighlighting.cpp           |  39 +-
 .../clangd/refactor/tweaks/DefineInline.cpp   |   2 +-
 clang/docs/ReleaseNotes.rst                   |   3 +
 clang/include/clang/AST/Decl.h                |  22 +-
 clang/include/clang/AST/DeclTemplate.h        | 191 +++---
 clang/include/clang/AST/JSONNodeDumper.h      |   1 +
 clang/include/clang/AST/RecursiveASTVisitor.h |  14 +-
 clang/include/clang/ASTMatchers/ASTMatchers.h |   5 +
 .../clang/ASTMatchers/ASTMatchersInternal.h   |   8 +-
 clang/include/clang/Basic/Specifiers.h        |   3 +
 clang/include/clang/Sema/Sema.h               | 143 ++--
 clang/lib/AST/ASTContext.cpp                  |   2 +
 clang/lib/AST/ASTDumper.cpp                   |   1 +
 clang/lib/AST/ASTImporter.cpp                 | 122 +++-
 clang/lib/AST/Comment.cpp                     |  10 +-
 clang/lib/AST/Decl.cpp                        |  45 +-
 clang/lib/AST/DeclPrinter.cpp                 |   1 +
 clang/lib/AST/DeclTemplate.cpp                | 156 ++---
 clang/lib/AST/JSONNodeDumper.cpp              |   3 +
 clang/lib/AST/TextNodeDumper.cpp              |   3 +
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |   1 +
 clang/lib/Analysis/ExprMutationAnalyzer.cpp   |  13 +-
 clang/lib/CodeGen/CGVTables.cpp               |  32 +-
 clang/lib/Index/IndexingContext.cpp           |   1 +
 clang/lib/InstallAPI/Visitor.cpp              |   5 +
 clang/lib/Parse/ParseDeclCXX.cpp              |  14 +-
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |  15 +-
 clang/lib/Sema/SemaConcept.cpp                | 188 ++----
 clang/lib/Sema/SemaDecl.cpp                   |  53 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |  11 +-
 clang/lib/Sema/SemaExprMember.cpp             |   5 +-
 clang/lib/Sema/SemaOverload.cpp               |   6 +-
 clang/lib/Sema/SemaTemplate.cpp               | 296 ++++-----
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  43 +-
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  57 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 611 ++++++------------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 432 ++++++++-----
 clang/lib/Serialization/ASTReaderDecl.cpp     |  77 +--
 clang/lib/Serialization/ASTWriterDecl.cpp     | 100 +--
 .../StaticAnalyzer/Core/BugSuppression.cpp    |  78 +--
 clang/lib/Tooling/Syntax/BuildTree.cpp        |  13 +-
 clang/test/AST/ast-dump-templates-pattern.cpp |  19 +-
 .../temp/temp.arg/temp.arg.template/p3-2a.cpp |  11 +-
 .../temp/temp.constr/temp.constr.decl/p4.cpp  |  17 +-
 .../SemaTemplate/concepts-out-of-line-def.cpp |   9 +-
 clang/test/SemaTemplate/instantiate-scope.cpp |  10 +-
 .../Templight/templight-default-func-arg.cpp  |  33 +-
 .../Templight/templight-empty-entries-fix.cpp |  88 +--
 clang/tools/libclang/CIndex.cpp               |   1 +
 clang/unittests/AST/ASTImporterTest.cpp       |   6 +-
 .../ASTMatchers/ASTMatchersTraversalTest.cpp  |   4 +-
 52 files changed, 1386 insertions(+), 1639 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
index ae063a19d779d..a1a705dd043a0 100644
--- a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
@@ -106,7 +106,7 @@ void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
       return;
     diag(FD->getLocation(), "mark the definition as 'inline'",
          DiagnosticIDs::Note)
-        << FixItHint::CreateInsertion(FD->getInnerLocStart(), "inline ");
+        << FixItHint::CreateInsertion(FD->getFunctionLocStart(), "inline ");
   } else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
     // C++14 variable templates are allowed.
     if (VD->getDescribedVarTemplate())
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 751ee254d3623..3c33b88d897fc 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -590,28 +590,28 @@ class CollectExtraHighlightings
 
   bool
   VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D) {
-    if (auto *Args = D->getTemplateArgsAsWritten())
-      H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
-    return true;
-  }
-
-  bool VisitClassTemplatePartialSpecializationDecl(
-      ClassTemplatePartialSpecializationDecl *D) {
-    if (auto *TPL = D->getTemplateParameters())
-      H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+    if (const auto *Info = D->getExplicitInstantiationInfo()) {
+      H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
+                              Info->TemplateArgsAsWritten->getRAngleLoc());
+    } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
+      H.addAngleBracketTokens(Info->TemplateParams->getLAngleLoc(),
+                              Info->TemplateParams->getRAngleLoc());
+      H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
+                              Info->TemplateArgsAsWritten->getRAngleLoc());
+    }
     return true;
   }
 
   bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
-    if (auto *Args = D->getTemplateArgsAsWritten())
-      H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
-    return true;
-  }
-
-  bool VisitVarTemplatePartialSpecializationDecl(
-      VarTemplatePartialSpecializationDecl *D) {
-    if (auto *TPL = D->getTemplateParameters())
-      H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+    if (const auto *Info = D->getExplicitInstantiationInfo()) {
+      H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
+                              Info->TemplateArgsAsWritten->getRAngleLoc());
+    } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
+      H.addAngleBracketTokens(Info->TemplateParams->getLAngleLoc(),
+                              Info->TemplateParams->getRAngleLoc());
+      H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
+                              Info->TemplateArgsAsWritten->getRAngleLoc());
+    }
     return true;
   }
 
@@ -625,6 +625,9 @@ class CollectExtraHighlightings
   }
 
   bool VisitFunctionDecl(FunctionDecl *D) {
+    if (const TemplateParameterList *TPL =
+            D->getTemplateSpecializationParameters())
+      H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
     if (D->isOverloadedOperator()) {
       const auto AddOpDeclToken = [&](SourceLocation Loc) {
         auto &Token = H.addToken(Loc, HighlightingKind::Operator)
diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
index c9704492bf1cd..5fcb1a24448b8 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
@@ -364,7 +364,7 @@ addInlineIfInHeader(const FunctionDecl *FD) {
   if (!isHeaderFile(FileName, FD->getASTContext().getLangOpts()))
     return std::nullopt;
 
-  return tooling::Replacement(SM, FD->getInnerLocStart(), 0, "inline ");
+  return tooling::Replacement(SM, FD->getFunctionLocStart(), 0, "inline ");
 }
 
 /// Moves definition of a function/method to its declaration location.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3c1eacfc05dc8..b6941e80b7750 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -642,7 +642,10 @@ Bug Fixes to C++ Support
 - Fixed an alias template CTAD crash.
 - Correctly diagnose uses of ``co_await`` / ``co_yield`` in the default argument of nested function declarations. (#GH98923)
 - Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
+- Fixed clang incorrectly rejecting several cases of out-ofline definitions.
 - Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439)
+- Fixed a bug matching constrained out-of-line definitions of class members.
+- Fixed a crash when instantiating an invalid out-of-line static data member definition in a local class. (#GH176152)
 - Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307)
 - Fix a problem where a substitution failure when evaluating a type requirement
   could directly make the program ill-formed.
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 01b9ba45be9ad..84fed785eaa03 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2147,8 +2147,9 @@ class FunctionDecl : public DeclaratorDecl,
       ASTContext &C, FunctionTemplateDecl *Template,
       TemplateArgumentList *TemplateArgs, void *InsertPos,
       TemplateSpecializationKind TSK,
+      const TemplateParameterList *TemplateParams,
       const TemplateArgumentListInfo *TemplateArgsAsWritten,
-      SourceLocation PointOfInstantiation);
+      SourceLocation PointOfInstantiation, bool AddSpecialization);
 
   /// Specify that this record is an instantiation of the
   /// member function FD.
@@ -2245,6 +2246,8 @@ class FunctionDecl : public DeclaratorDecl,
     return SourceLocation();
   }
 
+  SourceLocation getFunctionLocStart() const;
+
   SourceRange getSourceRange() const override LLVM_READONLY;
 
   // Function definitions.
@@ -3070,6 +3073,9 @@ class FunctionDecl : public DeclaratorDecl,
   const ASTTemplateArgumentListInfo*
   getTemplateSpecializationArgsAsWritten() const;
 
+  /// Returns the template parameter list for an explicit specialization.
+  const TemplateParameterList *getTemplateSpecializationParameters() const;
+
   /// Specify that this function declaration is actually a function
   /// template specialization.
   ///
@@ -3085,6 +3091,9 @@ class FunctionDecl : public DeclaratorDecl,
   ///
   /// \param TSK the kind of template specialization this is.
   ///
+  /// \param TemplateParams the template parameters if this is an explicit
+  /// specialization.
+  ///
   /// \param TemplateArgsAsWritten location info of template arguments.
   ///
   /// \param PointOfInstantiation point at which the function template
@@ -3093,17 +3102,20 @@ class FunctionDecl : public DeclaratorDecl,
       FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
       void *InsertPos,
       TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
+      const TemplateParameterList *TemplateParams = nullptr,
       TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
-      SourceLocation PointOfInstantiation = SourceLocation()) {
-    setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
-                                      InsertPos, TSK, TemplateArgsAsWritten,
-                                      PointOfInstantiation);
+      SourceLocation PointOfInstantiation = SourceLocation(),
+      bool AddSpecialization = true) {
+    setFunctionTemplateSpecialization(
+        getASTContext(), Template, TemplateArgs, InsertPos, TSK, TemplateParams,
+        TemplateArgsAsWritten, PointOfInstantiation, AddSpecialization);
   }
 
   /// Specifies that this function declaration is actually a
   /// dependent function template specialization.
   void setDependentTemplateSpecialization(
       ASTContext &Context, const UnresolvedSetImpl &Templates,
+      const TemplateParameterList *TemplateParams,
       const TemplateArgumentListInfo *TemplateArgs);
 
   DependentFunctionTemplateSpecializationInfo *
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 6ca9d67af0710..fbc6540538314 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -73,7 +73,7 @@ class TemplateParameterList final
     : private llvm::TrailingObjects<TemplateParameterList, NamedDecl *,
                                     Expr *> {
   /// The template argument list of the template parameter list.
-  TemplateArgument *InjectedArgs = nullptr;
+  mutable TemplateArgument *InjectedArgs = nullptr;
 
   /// The location of the 'template' keyword.
   SourceLocation TemplateLoc;
@@ -200,7 +200,8 @@ class TemplateParameterList final
   bool hasAssociatedConstraints() const;
 
   /// Get the template argument list of the template parameter list.
-  ArrayRef<TemplateArgument> getInjectedTemplateArgs(const ASTContext &Context);
+  ArrayRef<TemplateArgument>
+  getInjectedTemplateArgs(const ASTContext &Context) const;
 
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
   SourceLocation getLAngleLoc() const { return LAngleLoc; }
@@ -475,14 +476,18 @@ class FunctionTemplateSpecializationInfo final
   /// The function template from which this function template
   /// specialization was generated.
   ///
-  /// The two bits contain the top 4 values of TemplateSpecializationKind.
-  llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
+  /// The three bits contain the TemplateSpecializationKind.
+  llvm::PointerIntPair<FunctionTemplateDecl *, 3> Template;
 
 public:
   /// The template arguments used to produce the function template
   /// specialization from the function template.
   TemplateArgumentList *TemplateArguments;
 
+  // The template parameters if this is an explicit specialization.
+  /// FIXME: Normally null; tail-allocate this.
+  const TemplateParameterList *TemplateParameters;
+
   /// The template arguments as written in the sources, if provided.
   /// FIXME: Normally null; tail-allocate this.
   const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
@@ -495,12 +500,14 @@ class FunctionTemplateSpecializationInfo final
   FunctionTemplateSpecializationInfo(
       FunctionDecl *FD, FunctionTemplateDecl *Template,
       TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
+      const TemplateParameterList *TemplateParameters,
       const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
       SourceLocation POI, MemberSpecializationInfo *MSInfo)
       : Function(FD, MSInfo ? true : false), Template(Template, TSK - 1),
-        TemplateArguments(TemplateArgs),
+        TemplateArguments(TemplateArgs), TemplateParameters(TemplateParameters),
         TemplateArgumentsAsWritten(TemplateArgsAsWritten),
         PointOfInstantiation(POI) {
+    assert(TemplateParameters == nullptr || TSK == TSK_ExplicitSpecialization);
     if (MSInfo)
       getTrailingObjects()[0] = MSInfo;
   }
@@ -513,6 +520,7 @@ class FunctionTemplateSpecializationInfo final
   static FunctionTemplateSpecializationInfo *
   Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
          TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
+         const TemplateParameterList *TemplateParameters,
          const TemplateArgumentListInfo *TemplateArgsAsWritten,
          SourceLocation POI, MemberSpecializationInfo *MSInfo);
 
@@ -613,8 +621,8 @@ class FunctionTemplateSpecializationInfo final
 /// member class or member enumeration.
 class MemberSpecializationInfo {
   // The member declaration from which this member was instantiated, and the
-  // manner in which the instantiation occurred (in the lower two bits).
-  llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
+  // manner in which the instantiation occurred (in the lower three bits).
+  llvm::PointerIntPair<NamedDecl *, 3> MemberAndTSK;
 
   // The point at which this member was first instantiated.
   SourceLocation PointOfInstantiation;
@@ -693,14 +701,19 @@ class DependentFunctionTemplateSpecializationInfo final
 
   DependentFunctionTemplateSpecializationInfo(
       const UnresolvedSetImpl &Candidates,
+      const TemplateParameterList *TemplateParams,
       const ASTTemplateArgumentListInfo *TemplateArgsWritten);
 
 public:
+  // The template parameters if this is an explicit specialization.
+  const TemplateParameterList *TemplateParameters;
+
   /// The template arguments as written in the sources, if provided.
   const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
 
   static DependentFunctionTemplateSpecializationInfo *
   Create(ASTContext &Context, const UnresolvedSetImpl &Candidates,
+         const TemplateParameterList *TemplateParams,
          const TemplateArgumentListInfo *TemplateArgs);
 
   /// Returns the candidates for the primary function template.
@@ -1005,11 +1018,6 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
     return getTemplatedDecl()->isThisDeclarationADefinition();
   }
 
-  bool isCompatibleWithDefinition() const {
-    return getTemplatedDecl()->isInstantiatedFromMemberTemplate() ||
-           isThisDeclarationADefinition();
-  }
-
   // This bit closely tracks 'RedeclarableTemplateDecl::InstantiatedFromMember',
   // except this is per declaration, while the redeclarable field is
   // per chain. This indicates a template redeclaration which
@@ -1807,8 +1815,18 @@ struct ExplicitInstantiationInfo {
   ExplicitInstantiationInfo() = default;
 };
 
+struct ExplicitSpecializationInfo {
+  /// The list of template parameters
+  TemplateParameterList *TemplateParams = nullptr;
+
+  /// The template arguments as written.
+  const ASTTemplateArgumentListInfo *TemplateArgsAsWritten = nullptr;
+
+  ExplicitSpecializationInfo() = default;
+};
+
 using SpecializationOrInstantiationInfo =
-    llvm::PointerUnion<const ASTTemplateArgumentListInfo *,
+    llvm::PointerUnion<ExplicitSpecializationInfo *,
                        ExplicitInstantiationInfo *>;
 
 /// Represents a class template specialization, which refers to
@@ -2038,49 +2056,38 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
   /// Retrieve the template argument list as written in the sources,
   /// if any.
   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+    if (const auto *Info = getExplicitSpecializationInfo())
       return Info->TemplateArgsAsWritten;
-    return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
-  }
-
-  /// Set the template argument list as written in the sources.
-  void
-  setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
-      Info->TemplateArgsAsWritten = ArgsWritten;
-    else
-      ExplicitInfo = ArgsWritten;
+    if (const auto *Info = getExplicitInstantiationInfo())
+      return Info->TemplateArgsAsWritten;
+    return nullptr;
   }
 
-  /// Set the template argument list as written in the sources.
-  void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
-    setTemplateArgsAsWritten(
-        ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
+  /// Gets the explicit instantiation info, if present.
+  const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
+    return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
   }
 
-  /// Gets the location of the extern keyword, if present.
-  SourceLocation getExternKeywordLoc() const {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
-      return Info->ExternKeywordLoc;
-    return SourceLocation();
+  /// Sets the explicit instantiation info.
+  void setExplicitInstantiationInfo(
+      SourceLocation ExternKeywordLoc, SourceLocation TemplateKeywordLoc,
+      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
+    auto *Info = new (getASTContext()) ExplicitInstantiationInfo();
+    Info->ExternKeywordLoc = ExternKeywordLoc;
+    Info->TemplateKeywordLoc = TemplateKeywordLoc;
+    Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
+    ExplicitInfo = Info;
   }
 
-  /// Sets the location of the extern keyword.
-  void setExternKeywordLoc(SourceLocation Loc);
-
-  /// Gets the location of the template keyword, if present.
-  SourceLocation getTemplateKeywordLoc() const {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
-      return Info->TemplateKeywordLoc;
-    return SourceLocation();
+  /// Gets the explicit specialization info, if present.
+  const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
+    return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
   }
 
-  /// Sets the location of the template keyword.
-  void setTemplateKeywordLoc(SourceLocation Loc);
+  /// Sets the explicit specialization info.
+  void setExplicitSpecializationInfo(
+      TemplateParameterList *TemplateParams,
+      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
@@ -2105,10 +2112,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
 };
 
 class ClassTemplatePartialSpecializationDecl
-  : public ClassTemplateSpecializationDecl {
-  /// The list of template parameters
-  TemplateParameterList *TemplateParams = nullptr;
-
+    : public ClassTemplateSpecializationDecl {
   /// The class template partial specialization from which this
   /// class template partial specialization was instantiated.
   ///
@@ -2122,6 +2126,7 @@ class ClassTemplatePartialSpecializationDecl
   ClassTemplatePartialSpecializationDecl(
       ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
       SourceLocation IdLoc, TemplateParameterList *Params,
+      const ASTTemplateArgumentListInfo *ArgsAsWritten,
       ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
       CanQualType CanonInjectedTST,
       ClassTemplatePartialSpecializationDecl *PrevDecl);
@@ -2139,7 +2144,9 @@ class ClassTemplatePartialSpecializationDecl
   static ClassTemplatePartialSpecializationDecl *
   Create(ASTContext &Context, TagKind TK, DeclContext *DC,
          SourceLocation StartLoc, SourceLocation IdLoc,
-         TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
+         TemplateParameterList *Params,
+         const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
+         ClassTemplateDecl *SpecializedTemplate,
          ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
          ClassTemplatePartialSpecializationDecl *PrevDecl);
 
@@ -2154,7 +2161,10 @@ class ClassTemplatePartialSpecializationDecl
 
   /// Get the list of template parameters
   TemplateParameterList *getTemplateParameters() const {
-    return TemplateParams;
+    auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
+    assert(ExplicitSpecInfo &&
+           "A partial specialization is always an explicit specialization");
+    return ExplicitSpecInfo->TemplateParams;
   }
 
   /// \brief All associated constraints of this partial specialization,
@@ -2165,11 +2175,11 @@ class ClassTemplatePartialSpecializationDecl
   /// conjunction ("and").
   void getAssociatedConstraints(
       llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
-    TemplateParams->getAssociatedConstraints(AC);
+    getTemplateParameters()->getAssociatedConstraints(AC);
   }
 
   bool hasAssociatedConstraints() const {
-    return TemplateParams->hasAssociatedConstraints();
+    return getTemplateParameters()->hasAssociatedConstraints();
   }
 
   /// Retrieve the member class template partial specialization from
@@ -2806,49 +2816,38 @@ class VarTemplateSpecializationDecl : public VarDecl,
   /// Retrieve the template argument list as written in the sources,
   /// if any.
   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+    if (const auto *Info = getExplicitSpecializationInfo())
       return Info->TemplateArgsAsWritten;
-    return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
-  }
-
-  /// Set the template argument list as written in the sources.
-  void
-  setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
-      Info->TemplateArgsAsWritten = ArgsWritten;
-    else
-      ExplicitInfo = ArgsWritten;
+    if (const auto *Info = getExplicitInstantiationInfo())
+      return Info->TemplateArgsAsWritten;
+    return nullptr;
   }
 
-  /// Set the template argument list as written in the sources.
-  void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
-    setTemplateArgsAsWritten(
-        ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
+  /// Gets the explicit instantiation info, if present.
+  const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
+    return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
   }
 
-  /// Gets the location of the extern keyword, if present.
-  SourceLocation getExternKeywordLoc() const {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
-      return Info->ExternKeywordLoc;
-    return SourceLocation();
+  /// Sets the explicit instantiation info.
+  void setExplicitInstantiationInfo(
+      SourceLocation ExternKeywordLoc, SourceLocation TemplateKeywordLoc,
+      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
+    auto *Info = new (getASTContext()) ExplicitInstantiationInfo();
+    Info->ExternKeywordLoc = ExternKeywordLoc;
+    Info->TemplateKeywordLoc = TemplateKeywordLoc;
+    Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
+    ExplicitInfo = Info;
   }
 
-  /// Sets the location of the extern keyword.
-  void setExternKeywordLoc(SourceLocation Loc);
-
-  /// Gets the location of the template keyword, if present.
-  SourceLocation getTemplateKeywordLoc() const {
-    if (auto *Info =
-            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
-      return Info->TemplateKeywordLoc;
-    return SourceLocation();
+  /// Gets the explicit specialization info, if present.
+  const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
+    return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
   }
 
-  /// Sets the location of the template keyword.
-  void setTemplateKeywordLoc(SourceLocation Loc);
+  /// Sets the explicit specialization info.
+  void setExplicitSpecializationInfo(
+      TemplateParameterList *TemplateParams,
+      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
@@ -2874,9 +2873,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
 
 class VarTemplatePartialSpecializationDecl
     : public VarTemplateSpecializationDecl {
-  /// The list of template parameters
-  TemplateParameterList *TemplateParams = nullptr;
-
   /// The variable template partial specialization from which this
   /// variable template partial specialization was instantiated.
   ///
@@ -2888,6 +2884,7 @@ class VarTemplatePartialSpecializationDecl
   VarTemplatePartialSpecializationDecl(
       ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
       SourceLocation IdLoc, TemplateParameterList *Params,
+      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
       VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
       StorageClass S, ArrayRef<TemplateArgument> Args);
 
@@ -2905,6 +2902,7 @@ class VarTemplatePartialSpecializationDecl
   static VarTemplatePartialSpecializationDecl *
   Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
          SourceLocation IdLoc, TemplateParameterList *Params,
+         const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
          VarTemplateDecl *SpecializedTemplate, QualType T,
          TypeSourceInfo *TInfo, StorageClass S,
          ArrayRef<TemplateArgument> Args);
@@ -2920,7 +2918,10 @@ class VarTemplatePartialSpecializationDecl
 
   /// Get the list of template parameters
   TemplateParameterList *getTemplateParameters() const {
-    return TemplateParams;
+    auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
+    assert(ExplicitSpecInfo &&
+           "A partial specialization is always an explicit specialization");
+    return ExplicitSpecInfo->TemplateParams;
   }
 
   /// Get the template argument list of the template parameter list.
@@ -2937,11 +2938,11 @@ class VarTemplatePartialSpecializationDecl
   /// conjunction ("and").
   void getAssociatedConstraints(
       llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
-    TemplateParams->getAssociatedConstraints(AC);
+    getTemplateParameters()->getAssociatedConstraints(AC);
   }
 
   bool hasAssociatedConstraints() const {
-    return TemplateParams->hasAssociatedConstraints();
+    return getTemplateParameters()->hasAssociatedConstraints();
   }
 
   /// \brief Retrieve the member variable template partial specialization from
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index 4e8d1649bbf8b..7c8496d6164fc 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -417,6 +417,7 @@ class JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> {
           Visit(Redecl);
         DumpedAny = true;
         break;
+      case TSK_FriendDeclaration:
       case TSK_ExplicitSpecialization:
         break;
       }
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index febdf715698d9..3b9bafffe1bc1 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2002,6 +2002,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
       case TSK_ExplicitInstantiationDeclaration:
       case TSK_ExplicitInstantiationDefinition:
       case TSK_ExplicitSpecialization:
+      case TSK_FriendDeclaration:
         break;
       }
     }
@@ -2022,6 +2023,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
         TRY_TO(TraverseDecl(RD));
         break;
 
+      case TSK_FriendDeclaration:
       case TSK_ExplicitInstantiationDeclaration:
       case TSK_ExplicitInstantiationDefinition:
       case TSK_ExplicitSpecialization:
@@ -2056,6 +2058,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
         TRY_TO(TraverseDecl(RD));
         break;
 
+      case TSK_FriendDeclaration:
       case TSK_ExplicitSpecialization:
         break;
       }
@@ -2222,12 +2225,11 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
        handles traversal of template args and qualifier.                       \
        For explicit specializations ("template<> set<int> {...};"),            \
        we traverse template args here since there is no EID. */                \
-    if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) {             \
-      assert(D->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); \
-      if (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {  \
-        TRY_TO(TraverseTemplateArgumentLocsHelper(                             \
-            ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs));    \
-      }                                                                        \
+    if (const auto *Info = D->getExplicitSpecializationInfo()) {               \
+      const auto *ArgsWritten = Info->TemplateArgsAsWritten;                   \
+      TRY_TO(TraverseTemplateParameterListHelper(Info->TemplateParams));       \
+      TRY_TO(TraverseTemplateArgumentLocsHelper(                               \
+          ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs));      \
     }                                                                          \
                                                                                \
     if (getDerived().shouldVisitTemplateInstantiations() ||                    \
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index bc0f35898a2c9..c35206fb41b92 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5753,6 +5753,11 @@ AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) {
   return (Else != nullptr && InnerMatcher.matches(*Else, Finder, Builder));
 }
 
+/// Matches a declaration if it declares the same entity as the node.
+AST_MATCHER_P(Decl, declaresSameEntityAsNode, const Decl *, Other) {
+  return clang::declaresSameEntity(&Node, Other);
+}
+
 /// Matches if a node equals a previously bound node.
 ///
 /// Matches a node if it equals the node previously bound to \p ID.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index cb12d10d628b6..d3daf2eb4781d 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1993,16 +1993,12 @@ getTemplateArgsWritten(const OverloadExpr &OE) {
 
 inline unsigned
 getNumTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
-  if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
-    return Args->getNumTemplateArgs();
-  return 0;
+  return getTemplateArgsWritten(D).size();
 }
 
 inline unsigned
 getNumTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
-  if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
-    return Args->getNumTemplateArgs();
-  return 0;
+  return getTemplateArgsWritten(D).size();
 }
 
 inline unsigned getNumTemplateArgsWritten(const FunctionDecl &FD) {
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 8da6fd4cf454a..1fe50760eff9a 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -193,6 +193,8 @@ namespace clang {
     /// This template specialization was implicitly instantiated from a
     /// template. (C++ [temp.inst]).
     TSK_ImplicitInstantiation,
+    /// This template is a friend declaration.
+    TSK_FriendDeclaration,
     /// This template specialization was declared or defined by an
     /// explicit specialization (C++ [temp.expl.spec]) or partial
     /// specialization (C++ [temp.class.spec]).
@@ -227,6 +229,7 @@ namespace clang {
 
     case TSK_Undeclared:
     case TSK_ImplicitInstantiation:
+    case TSK_FriendDeclaration:
       return false;
     }
     llvm_unreachable("bad template specialization kind");
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e71794b2d92c9..7d4a15d1e552f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11750,7 +11750,7 @@ class Sema final : public SemaBase {
   TemplateParameterList *MatchTemplateParametersToScopeSpecifier(
       SourceLocation DeclStartLoc, SourceLocation DeclLoc,
       const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
-      ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
+      ArrayRef<TemplateParameterList *> &ParamLists, bool IsFriend,
       bool &IsMemberSpecialization, bool &Invalid,
       bool SuppressDiagnostic = false);
 
@@ -11816,8 +11816,7 @@ class Sema final : public SemaBase {
   DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
                                 SourceLocation TemplateLoc,
                                 SourceLocation TemplateNameLoc,
-                                const TemplateArgumentListInfo &TemplateArgs,
-                                bool SetWrittenArgs);
+                                const TemplateArgumentListInfo &TemplateArgs);
 
   /// Form a reference to the specialization of the given variable template
   /// corresponding to the specified argument list, or a null-but-valid result
@@ -11900,7 +11899,7 @@ class Sema final : public SemaBase {
       Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
       SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
       TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
-      MultiTemplateParamsArg TemplateParameterLists,
+      MultiTemplateParamsArg &TemplateParameterLists,
       SkipBodyInfo *SkipBody = nullptr);
 
   /// Check the non-type template arguments of a class template
@@ -11973,7 +11972,8 @@ class Sema final : public SemaBase {
   /// There really isn't any useful analysis we can do here, so we
   /// just store the information.
   bool CheckDependentFunctionTemplateSpecialization(
-      FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
+      FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+      const TemplateArgumentListInfo *ExplicitTemplateArgs,
       LookupResult &Previous);
 
   /// Perform semantic analysis for the given function template
@@ -11999,8 +11999,9 @@ class Sema final : public SemaBase {
   /// declaration with no explicit template argument list that might be
   /// befriending a function template specialization.
   bool CheckFunctionTemplateSpecialization(
-      FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
-      LookupResult &Previous, bool QualifiedFriend = false);
+      FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+      TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
+      bool QualifiedFriend = false);
 
   /// Perform semantic analysis for the given non-template member
   /// specialization.
@@ -12267,46 +12268,6 @@ class Sema final : public SemaBase {
     TPL_TemplateParamsEquivalent,
   };
 
-  // A struct to represent the 'new' declaration, which is either itself just
-  // the named decl, or the important information we need about it in order to
-  // do constraint comparisons.
-  class TemplateCompareNewDeclInfo {
-    const NamedDecl *ND = nullptr;
-    const DeclContext *DC = nullptr;
-    const DeclContext *LexicalDC = nullptr;
-    SourceLocation Loc;
-
-  public:
-    TemplateCompareNewDeclInfo(const NamedDecl *ND) : ND(ND) {}
-    TemplateCompareNewDeclInfo(const DeclContext *DeclCtx,
-                               const DeclContext *LexicalDeclCtx,
-                               SourceLocation Loc)
-
-        : DC(DeclCtx), LexicalDC(LexicalDeclCtx), Loc(Loc) {
-      assert(DC && LexicalDC &&
-             "Constructor only for cases where we have the information to put "
-             "in here");
-    }
-
-    // If this was constructed with no information, we cannot do substitution
-    // for constraint comparison, so make sure we can check that.
-    bool isInvalid() const { return !ND && !DC; }
-
-    const NamedDecl *getDecl() const { return ND; }
-
-    bool ContainsDecl(const NamedDecl *ND) const { return this->ND == ND; }
-
-    const DeclContext *getLexicalDeclContext() const {
-      return ND ? ND->getLexicalDeclContext() : LexicalDC;
-    }
-
-    const DeclContext *getDeclContext() const {
-      return ND ? ND->getDeclContext() : DC;
-    }
-
-    SourceLocation getLocation() const { return ND ? ND->getLocation() : Loc; }
-  };
-
   /// Determine whether the given template parameter lists are
   /// equivalent.
   ///
@@ -12331,19 +12292,11 @@ class Sema final : public SemaBase {
   /// \returns True if the template parameter lists are equal, false
   /// otherwise.
   bool TemplateParameterListsAreEqual(
-      const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
-      const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+      const Decl *NewInstFrom, TemplateParameterList *New,
+      const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
       TemplateParameterListEqualKind Kind,
       SourceLocation TemplateArgLoc = SourceLocation());
 
-  bool TemplateParameterListsAreEqual(
-      TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
-      TemplateParameterListEqualKind Kind,
-      SourceLocation TemplateArgLoc = SourceLocation()) {
-    return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
-                                          Kind, TemplateArgLoc);
-  }
-
   /// Check whether a template can be declared within this scope.
   ///
   /// If the template declaration is valid in this scope, returns
@@ -13575,44 +13528,27 @@ class Sema final : public SemaBase {
   /// Retrieve the template argument list(s) that should be used to
   /// instantiate the definition of the given declaration.
   ///
-  /// \param ND the declaration for which we are computing template
+  /// \param D the declaration for which we are computing template
   /// instantiation arguments.
   ///
-  /// \param DC In the event we don't HAVE a declaration yet, we instead provide
-  ///  the decl context where it will be created.  In this case, the `Innermost`
-  ///  should likely be provided.  If ND is non-null, this is ignored.
-  ///
-  /// \param Innermost if non-NULL, specifies a template argument list for the
-  /// template declaration passed as ND.
+  /// \param Innermost if present, specifies a template argument list for the
+  /// template-like (TemplateDecl or PartialSpec) declaration passed as D.
   ///
-  /// \param RelativeToPrimary true if we should get the template
-  /// arguments relative to the primary template, even when we're
-  /// dealing with a specialization. This is only relevant for function
-  /// template specializations.
+  /// \param NumLevels if present, specifies the maximum number of template
+  /// levels of the result. This is useful for instantiating a pattern that has
+  /// already had some levels instantiated. In that case, the Template Depth of
+  /// the pattern can be passed here.
   ///
-  /// \param Pattern If non-NULL, indicates the pattern from which we will be
-  /// instantiating the definition of the given declaration, \p ND. This is
-  /// used to determine the proper set of template instantiation arguments for
-  /// friend function template specializations.
+  /// \param SkipInnerNonInstantiated Skips adding template-like levels to the
+  /// result until hitting the first non-template-like level. This is a
+  /// workaround for dealing with the instantiation of the definition of generic
+  /// lambdas, which currently are eagerly substituted.
   ///
-  /// \param ForConstraintInstantiation when collecting arguments,
-  /// ForConstraintInstantiation indicates we should continue looking when
-  /// encountering a lambda generic call operator, and continue looking for
-  /// arguments on an enclosing class template.
-  ///
-  /// \param SkipForSpecialization when specified, any template specializations
-  /// in a traversal would be ignored.
-  ///
-  /// \param ForDefaultArgumentSubstitution indicates we should continue looking
-  /// when encountering a specialized member function template, rather than
-  /// returning immediately.
   MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
-      const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
+      const Decl *D,
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
-      bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
-      bool ForConstraintInstantiation = false,
-      bool SkipForSpecialization = false,
-      bool ForDefaultArgumentSubstitution = false);
+      UnsignedOrNone NumLevels = std::nullopt,
+      bool SkipInnerNonInstantiated = false);
 
   /// RAII object to handle the state changes required to synthesize
   /// a function body.
@@ -15032,14 +14968,13 @@ class Sema final : public SemaBase {
   // for figuring out the relative 'depth' of the constraint. The depth of the
   // 'primary template' and the 'instantiated from' templates aren't necessarily
   // the same, such as a case when one is a 'friend' defined in a class.
-  bool AreConstraintExpressionsEqual(const NamedDecl *Old,
-                                     const Expr *OldConstr,
-                                     const TemplateCompareNewDeclInfo &New,
-                                     const Expr *NewConstr);
+  bool AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
+                                     const Decl *New, const Expr *NewConstr);
 
   // Calculates whether the friend function depends on an enclosing template for
   // the purposes of [temp.friend] p9.
-  bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD);
+  bool
+  FriendConstraintsDependOnEnclosingTemplate(const FunctionTemplateDecl *FTD);
 
   /// \brief Ensure that the given template arguments satisfy the constraints
   /// associated with the given template, emitting a diagnostic if they do not.
@@ -15060,10 +14995,19 @@ class Sema final : public SemaBase {
       SourceRange TemplateIDRange);
 
   bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation,
-                                        FunctionDecl *Decl,
+                                        FunctionTemplateDecl *Template,
                                         ArrayRef<TemplateArgument> TemplateArgs,
                                         ConstraintSatisfaction &Satisfaction);
 
+  // FIXME: Constraints should be always checked before the declaration is
+  // specialized. This function exists to support a workaround for templated
+  // lambdas, where handling the instantiation scope for the captures is not
+  // implemented yet.
+  bool
+  CheckFunctionSpecializationConstraints(SourceLocation PointOfInstantiation,
+                                         FunctionDecl *Decl,
+                                         ConstraintSatisfaction &Satisfaction);
+
   /// \brief Emit diagnostics explaining why a constraint expression was deemed
   /// unsatisfied.
   /// \param First whether this is the first time an unsatisfied constraint is
@@ -15144,19 +15088,16 @@ class Sema final : public SemaBase {
   /// Used by SetupConstraintCheckingTemplateArgumentsAndScope to set up the
   /// LocalInstantiationScope of the current non-lambda function. For lambdas,
   /// use LambdaScopeForCallOperatorInstantiationRAII.
-  bool
-  SetupConstraintScope(FunctionDecl *FD,
-                       std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
-                       const MultiLevelTemplateArgumentList &MLTAL,
-                       LocalInstantiationScope &Scope);
+  bool SetupConstraintScope(FunctionDecl *FD,
+                            const MultiLevelTemplateArgumentList &MLTAL,
+                            LocalInstantiationScope &Scope);
 
   /// Used during constraint checking, sets up the constraint template argument
   /// lists, and calls SetupConstraintScope to set up the
   /// LocalInstantiationScope to have the proper set of ParVarDecls configured.
   std::optional<MultiLevelTemplateArgumentList>
   SetupConstraintCheckingTemplateArgumentsAndScope(
-      FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
-      LocalInstantiationScope &Scope);
+      FunctionDecl *FD, LocalInstantiationScope &Scope);
 
   ///@}
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a401a7471e6fc..8a8cbc3fa6a96 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -13048,6 +13048,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
   case TSK_ExplicitInstantiationDeclaration:
     return GVA_AvailableExternally;
 
+  case TSK_FriendDeclaration:
   case TSK_ImplicitInstantiation:
     External = GVA_DiscardableODR;
     break;
@@ -13236,6 +13237,7 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
   case TSK_ExplicitInstantiationDeclaration:
     return GVA_AvailableExternally;
 
+  case TSK_FriendDeclaration:
   case TSK_ImplicitInstantiation:
     return GVA_DiscardableODR;
   }
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index b3071d83ed51f..00c1140b538ec 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -134,6 +134,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
         Visit(Redecl);
       DumpedAny = true;
       break;
+    case TSK_FriendDeclaration:
     case TSK_ExplicitSpecialization:
       break;
     }
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f8527af2bfe6f..33cc8095bd7b2 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -815,6 +815,8 @@ ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization(
 template <>
 Expected<TemplateParameterList *>
 ASTNodeImporter::import(TemplateParameterList *From) {
+  if (!From)
+    return nullptr;
   SmallVector<NamedDecl *, 4> To(From->size());
   if (Error Err = ImportContainerChecked(*From, To))
     return std::move(Err);
@@ -3634,6 +3636,12 @@ Error ASTNodeImporter::ImportTemplateInformation(
           Importer.getToContext(), std::get<1>(*FunctionAndArgsOrErr));
 
     auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
+
+    Expected<TemplateParameterList *> TemplateParamsOrErr =
+        import(FTSInfo->TemplateParameters);
+    if (!TemplateParamsOrErr)
+      return TemplateParamsOrErr.takeError();
+
     TemplateArgumentListInfo ToTAInfo;
     const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten;
     if (FromTAArgsAsWritten)
@@ -3651,7 +3659,8 @@ Error ASTNodeImporter::ImportTemplateInformation(
     TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
     ToFD->setFunctionTemplateSpecialization(
         std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr,
-        TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr);
+        TSK, *TemplateParamsOrErr, FromTAArgsAsWritten ? &ToTAInfo : nullptr,
+        *POIOrErr);
     return Error::success();
   }
 
@@ -3665,6 +3674,11 @@ Error ASTNodeImporter::ImportTemplateInformation(
         return ToFTDOrErr.takeError();
     }
 
+    Expected<TemplateParameterList *> TemplateParamsOrErr =
+        import(FromInfo->TemplateParameters);
+    if (!TemplateParamsOrErr)
+      return TemplateParamsOrErr.takeError();
+
     // Import TemplateArgumentListInfo.
     TemplateArgumentListInfo ToTAInfo;
     const auto *FromTAArgsAsWritten = FromInfo->TemplateArgumentsAsWritten;
@@ -3674,7 +3688,7 @@ Error ASTNodeImporter::ImportTemplateInformation(
         return Err;
 
     ToFD->setDependentTemplateSpecialization(
-        Importer.getToContext(), Candidates,
+        Importer.getToContext(), Candidates, *TemplateParamsOrErr,
         FromTAArgsAsWritten ? &ToTAInfo : nullptr);
     return Error::success();
   }
@@ -6495,19 +6509,22 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
   if (!IdLocOrErr)
     return IdLocOrErr.takeError();
 
-  // Import TemplateArgumentListInfo.
-  TemplateArgumentListInfo ToTAInfo;
-  if (const auto *ASTTemplateArgs = D->getTemplateArgsAsWritten()) {
-    if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo))
-      return std::move(Err);
-  }
-
   // Create the specialization.
   ClassTemplateSpecializationDecl *D2 = nullptr;
   if (PartialSpec) {
+    TemplateArgumentListInfo ToTAInfo;
+    if (Error Err = ImportTemplateArgumentListInfo(
+            *cast<ClassTemplatePartialSpecializationDecl>(D)
+                 ->getTemplateArgsAsWritten(),
+            ToTAInfo))
+      return std::move(Err);
+
     if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
             D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
-            *IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs),
+            *IdLocOrErr, ToTPList,
+            ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
+                                                ToTAInfo),
+            ClassTemplate, ArrayRef(TemplateArgs),
             /*CanonInjectedTST=*/CanQualType(),
             cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
       return D2;
@@ -6538,6 +6555,34 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
     if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos))
       // Add this specialization to the class template.
       ClassTemplate->AddSpecialization(D2, InsertPos);
+
+    if (const auto *Info = D->getExplicitInstantiationInfo()) {
+      auto ExternKeywordLocOrErr = import(Info->ExternKeywordLoc);
+      if (!ExternKeywordLocOrErr)
+        return ExternKeywordLocOrErr.takeError();
+      auto TemplateKeywordLocOrErr = import(Info->TemplateKeywordLoc);
+      if (!TemplateKeywordLocOrErr)
+        return TemplateKeywordLocOrErr.takeError();
+      TemplateArgumentListInfo ToTAInfo;
+      if (Error Err = ImportTemplateArgumentListInfo(
+              *Info->TemplateArgsAsWritten, ToTAInfo))
+        return std::move(Err);
+      D2->setExplicitInstantiationInfo(*ExternKeywordLocOrErr,
+                                       *TemplateKeywordLocOrErr,
+                                       ASTTemplateArgumentListInfo::Create(
+                                           Importer.getToContext(), ToTAInfo));
+    } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
+      auto ParamsOrErr = import(Info->TemplateParams);
+      if (!ParamsOrErr)
+        return ParamsOrErr.takeError();
+      TemplateArgumentListInfo ToTAInfo;
+      if (Error Err = ImportTemplateArgumentListInfo(
+              *Info->TemplateArgsAsWritten, ToTAInfo))
+        return std::move(Err);
+      D2->setExplicitSpecializationInfo(*ParamsOrErr,
+                                        ASTTemplateArgumentListInfo::Create(
+                                            Importer.getToContext(), ToTAInfo));
+    }
   }
 
   D2->setSpecializationKind(D->getSpecializationKind());
@@ -6564,19 +6609,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
   else
     return LocOrErr.takeError();
 
-  if (D->getTemplateArgsAsWritten())
-    D2->setTemplateArgsAsWritten(ToTAInfo);
-
-  if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
-    D2->setTemplateKeywordLoc(*LocOrErr);
-  else
-    return LocOrErr.takeError();
-
-  if (auto LocOrErr = import(D->getExternKeywordLoc()))
-    D2->setExternKeywordLoc(*LocOrErr);
-  else
-    return LocOrErr.takeError();
-
   if (D->getPointOfInstantiation().isValid()) {
     if (auto POIOrErr = import(D->getPointOfInstantiation()))
       D2->setPointOfInstantiation(*POIOrErr);
@@ -6794,12 +6826,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
 
   VarTemplateSpecializationDecl *D2 = nullptr;
 
-  TemplateArgumentListInfo ToTAInfo;
-  if (const auto *Args = D->getTemplateArgsAsWritten()) {
-    if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
-      return std::move(Err);
-  }
-
   using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
   // Create a new specialization.
   if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
@@ -6807,9 +6833,16 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
     if (!ToTPListOrErr)
       return ToTPListOrErr.takeError();
 
+    TemplateArgumentListInfo ToTAInfo;
+    if (const auto *Args = D->getTemplateArgsAsWritten())
+      if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
+        return std::move(Err);
+
     PartVarSpecDecl *ToPartial;
     if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
                                 *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
+                                ASTTemplateArgumentListInfo::Create(
+                                    Importer.getToContext(), ToTAInfo),
                                 VarTemplate, QualType(), nullptr,
                                 D->getStorageClass(), TemplateArgs))
       return ToPartial;
@@ -6834,6 +6867,34 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
                                 QualType(), nullptr, D->getStorageClass(),
                                 TemplateArgs))
       return D2;
+
+    if (const auto *Info = D->getExplicitInstantiationInfo()) {
+      auto ExternKeywordLocOrErr = import(Info->ExternKeywordLoc);
+      if (!ExternKeywordLocOrErr)
+        return ExternKeywordLocOrErr.takeError();
+      auto TemplateKeywordLocOrErr = import(Info->TemplateKeywordLoc);
+      if (!TemplateKeywordLocOrErr)
+        return TemplateKeywordLocOrErr.takeError();
+      TemplateArgumentListInfo ToTAInfo;
+      if (Error Err = ImportTemplateArgumentListInfo(
+              *Info->TemplateArgsAsWritten, ToTAInfo))
+        return std::move(Err);
+      D2->setExplicitInstantiationInfo(*ExternKeywordLocOrErr,
+                                       *TemplateKeywordLocOrErr,
+                                       ASTTemplateArgumentListInfo::Create(
+                                           Importer.getToContext(), ToTAInfo));
+    } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
+      auto ParamsOrErr = import(Info->TemplateParams);
+      if (!ParamsOrErr)
+        return ParamsOrErr.takeError();
+      TemplateArgumentListInfo ToTAInfo;
+      if (Error Err = ImportTemplateArgumentListInfo(
+              *Info->TemplateArgsAsWritten, ToTAInfo))
+        return std::move(Err);
+      D2->setExplicitSpecializationInfo(*ParamsOrErr,
+                                        ASTTemplateArgumentListInfo::Create(
+                                            Importer.getToContext(), ToTAInfo));
+    }
   }
 
   // Update InsertPos, because preceding import calls may have invalidated
@@ -6860,9 +6921,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
 
   D2->setSpecializationKind(D->getSpecializationKind());
 
-  if (D->getTemplateArgsAsWritten())
-    D2->setTemplateArgsAsWritten(ToTAInfo);
-
   if (auto LocOrErr = import(D->getQualifierLoc()))
     D2->setQualifierInfo(*LocOrErr);
   else
diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp
index 3ea7288231c97..a8f77295c859e 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -233,11 +233,13 @@ void DeclInfo::fill() {
     Kind = FunctionKind;
     ParamVars = FD->parameters();
     ReturnType = FD->getReturnType();
-    ArrayRef<TemplateParameterList *> TPLs = FD->getTemplateParameterLists();
-    if (!TPLs.empty()) {
-      TemplateKind = TemplateSpecialization;
+    TemplateParameters = FD->getTemplateSpecializationParameters();
+    if (ArrayRef<TemplateParameterList *> TPLs =
+            FD->getTemplateParameterLists();
+        !TemplateParameters && !TPLs.empty())
       TemplateParameters = TPLs.back();
-    }
+    if (TemplateParameters)
+      TemplateKind = TemplateSpecialization;
 
     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index d660fa211db3d..8c20d082d5003 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -51,6 +51,7 @@
 #include "clang/Basic/TargetCXXABI.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/Visibility.h"
+#include "clang/Lex/Lexer.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
@@ -4204,6 +4205,7 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
   case TSK_ExplicitSpecialization:
     return false;
 
+  case TSK_FriendDeclaration:
   case TSK_ImplicitInstantiation:
     return true;
 
@@ -4324,12 +4326,21 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
   return nullptr;
 }
 
+const TemplateParameterList *
+FunctionDecl::getTemplateSpecializationParameters() const {
+  if (const auto *Info = getTemplateSpecializationInfo())
+    return Info->TemplateParameters;
+  if (const auto *Info = getDependentSpecializationInfo())
+    return Info->TemplateParameters;
+  return nullptr;
+}
+
 void FunctionDecl::setFunctionTemplateSpecialization(
     ASTContext &C, FunctionTemplateDecl *Template,
     TemplateArgumentList *TemplateArgs, void *InsertPos,
-    TemplateSpecializationKind TSK,
+    TemplateSpecializationKind TSK, const TemplateParameterList *TemplateParams,
     const TemplateArgumentListInfo *TemplateArgsAsWritten,
-    SourceLocation PointOfInstantiation) {
+    SourceLocation PointOfInstantiation, bool AddSpecialization) {
   assert((TemplateOrSpecialization.isNull() ||
           isa<MemberSpecializationInfo *>(TemplateOrSpecialization)) &&
          "Member function is already a specialization");
@@ -4341,21 +4352,23 @@ void FunctionDecl::setFunctionTemplateSpecialization(
          "Member specialization must be an explicit specialization");
   FunctionTemplateSpecializationInfo *Info =
       FunctionTemplateSpecializationInfo::Create(
-          C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
-          PointOfInstantiation,
+          C, this, Template, TSK, TemplateArgs, TemplateParams,
+          TemplateArgsAsWritten, PointOfInstantiation,
           dyn_cast_if_present<MemberSpecializationInfo *>(
               TemplateOrSpecialization));
   TemplateOrSpecialization = Info;
-  Template->addSpecialization(Info, InsertPos);
+  if (AddSpecialization)
+    Template->addSpecialization(Info, InsertPos);
 }
 
 void FunctionDecl::setDependentTemplateSpecialization(
     ASTContext &Context, const UnresolvedSetImpl &Templates,
+    const TemplateParameterList *TemplateParams,
     const TemplateArgumentListInfo *TemplateArgs) {
   assert(TemplateOrSpecialization.isNull());
   DependentFunctionTemplateSpecializationInfo *Info =
-      DependentFunctionTemplateSpecializationInfo::Create(Context, Templates,
-                                                          TemplateArgs);
+      DependentFunctionTemplateSpecializationInfo::Create(
+          Context, Templates, TemplateParams, TemplateArgs);
   TemplateOrSpecialization = Info;
 }
 
@@ -4368,19 +4381,22 @@ FunctionDecl::getDependentSpecializationInfo() const {
 DependentFunctionTemplateSpecializationInfo *
 DependentFunctionTemplateSpecializationInfo::Create(
     ASTContext &Context, const UnresolvedSetImpl &Candidates,
+    const TemplateParameterList *TemplateParams,
     const TemplateArgumentListInfo *TArgs) {
   const auto *TArgsWritten =
       TArgs ? ASTTemplateArgumentListInfo::Create(Context, *TArgs) : nullptr;
   return new (Context.Allocate(
       totalSizeToAlloc<FunctionTemplateDecl *>(Candidates.size())))
-      DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten);
+      DependentFunctionTemplateSpecializationInfo(Candidates, TemplateParams,
+                                                  TArgsWritten);
 }
 
 DependentFunctionTemplateSpecializationInfo::
     DependentFunctionTemplateSpecializationInfo(
         const UnresolvedSetImpl &Candidates,
+        const TemplateParameterList *TemplateParams,
         const ASTTemplateArgumentListInfo *TemplateArgsWritten)
-    : NumCandidates(Candidates.size()),
+    : NumCandidates(Candidates.size()), TemplateParameters(TemplateParams),
       TemplateArgumentsAsWritten(TemplateArgsWritten) {
   std::transform(Candidates.begin(), Candidates.end(), getTrailingObjects(),
                  [](NamedDecl *ND) {
@@ -4520,6 +4536,17 @@ bool FunctionDecl::isOutOfLine() const {
   return false;
 }
 
+SourceLocation FunctionDecl::getFunctionLocStart() const {
+  if (const TemplateParameterList *TemplateParams =
+          getTemplateSpecializationParameters()) {
+    const ASTContext &Ctx = getASTContext();
+    return Lexer::findNextToken(TemplateParams->getSourceRange().getEnd(),
+                                Ctx.getSourceManager(), Ctx.getLangOpts())
+        ->getLocation();
+  }
+  return getInnerLocStart();
+}
+
 SourceRange FunctionDecl::getSourceRange() const {
   return SourceRange(getOuterLocStart(), EndRangeLoc);
 }
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 95591d3a09431..6a8046763c788 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1105,6 +1105,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
     Out << *Attrs << ' ';
 
   if (D->getIdentifier()) {
+    // FIXME: Missing template parameter lists.
     D->getQualifier().print(Out, Policy);
     Out << *D;
 
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 275fe364e306d..861974848d6b3 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -245,8 +245,8 @@ bool TemplateParameterList::hasAssociatedConstraints() const {
   return HasRequiresClause || HasConstrainedParameters;
 }
 
-ArrayRef<TemplateArgument>
-TemplateParameterList::getInjectedTemplateArgs(const ASTContext &Context) {
+ArrayRef<TemplateArgument> TemplateParameterList::getInjectedTemplateArgs(
+    const ASTContext &Context) const {
   if (!InjectedArgs) {
     InjectedArgs = new (Context) TemplateArgument[size()];
     llvm::transform(*this, InjectedArgs, [&](NamedDecl *ND) {
@@ -946,6 +946,7 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
 FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
     ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
     TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
+    const TemplateParameterList *TemplateParams,
     const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI,
     MemberSpecializationInfo *MSInfo) {
   const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
@@ -956,7 +957,8 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
   void *Mem =
       C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
   return new (Mem) FunctionTemplateSpecializationInfo(
-      FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
+      FD, Template, TSK, TemplateArgs, TemplateParams, ArgsAsWritten, POI,
+      MSInfo);
 }
 
 //===----------------------------------------------------------------------===//
@@ -1050,54 +1052,38 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
       return CTPSD->getSourceRange();
     return cast<ClassTemplateDecl *>(Pattern)->getSourceRange();
   }
+  case TSK_FriendDeclaration:
   case TSK_ExplicitSpecialization: {
-    SourceRange Range = CXXRecordDecl::getSourceRange();
-    if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
-        !isThisDeclarationADefinition() && Args)
-      Range.setEnd(Args->getRAngleLoc());
-    return Range;
+    const auto *Info = getExplicitSpecializationInfo();
+    auto TPLs = getTemplateParameterLists();
+    return SourceRange(TPLs.empty() ? Info->TemplateParams->getTemplateLoc()
+                                    : TPLs.front()->getTemplateLoc(),
+                       isThisDeclarationADefinition()
+                           ? CXXRecordDecl::getSourceRange().getEnd()
+                           : Info->TemplateArgsAsWritten->getRAngleLoc());
   }
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ExplicitInstantiationDefinition: {
-    SourceRange Range = CXXRecordDecl::getSourceRange();
-    if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
-      Range.setBegin(ExternKW);
-    else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
-             TemplateKW.isValid())
-      Range.setBegin(TemplateKW);
-    if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
-      Range.setEnd(Args->getRAngleLoc());
-    return Range;
+    const auto *Info = getExplicitInstantiationInfo();
+    return SourceRange(Info->ExternKeywordLoc.isValid()
+                           ? Info->ExternKeywordLoc
+                           : Info->TemplateKeywordLoc,
+                       Info->TemplateArgsAsWritten->getRAngleLoc());
   }
   }
   llvm_unreachable("unhandled template specialization kind");
 }
 
-void ClassTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
-  auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
-  if (!Info) {
-    // Don't allocate if the location is invalid.
-    if (Loc.isInvalid())
-      return;
-    Info = new (getASTContext()) ExplicitInstantiationInfo;
-    Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
-    ExplicitInfo = Info;
-  }
-  Info->ExternKeywordLoc = Loc;
-}
-
-void ClassTemplateSpecializationDecl::setTemplateKeywordLoc(
-    SourceLocation Loc) {
-  auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
-  if (!Info) {
-    // Don't allocate if the location is invalid.
-    if (Loc.isInvalid())
-      return;
-    Info = new (getASTContext()) ExplicitInstantiationInfo;
-    Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
-    ExplicitInfo = Info;
-  }
-  Info->TemplateKeywordLoc = Loc;
+void ClassTemplateSpecializationDecl::setExplicitSpecializationInfo(
+    TemplateParameterList *TemplateParams,
+    const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
+  auto *Info = new (getASTContext()) ExplicitSpecializationInfo();
+  Info->TemplateParams = TemplateParams;
+  Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
+  ExplicitInfo = Info;
+
+  if (AdoptTemplateParameterList(TemplateParams, this))
+    setInvalidDecl();
 }
 
 //===----------------------------------------------------------------------===//
@@ -1168,6 +1154,7 @@ void ClassTemplatePartialSpecializationDecl::anchor() {}
 ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
     ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
     SourceLocation IdLoc, TemplateParameterList *Params,
+    const ASTTemplateArgumentListInfo *ArgsAsWritten,
     ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
     CanQualType CanonInjectedTST,
     ClassTemplatePartialSpecializationDecl *PrevDecl)
@@ -1176,25 +1163,24 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
           // Tracking StrictPackMatch for Partial
           // Specializations is not needed.
           SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
-      TemplateParams(Params), InstantiatedFromMember(nullptr, false),
+      InstantiatedFromMember(nullptr, false),
       CanonInjectedTST(CanonInjectedTST) {
-  if (AdoptTemplateParameterList(Params, this))
-    setInvalidDecl();
+  setSpecializationKind(TSK_ExplicitSpecialization);
+  setExplicitSpecializationInfo(Params, ArgsAsWritten);
 }
 
 ClassTemplatePartialSpecializationDecl *
 ClassTemplatePartialSpecializationDecl::Create(
     ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
     SourceLocation IdLoc, TemplateParameterList *Params,
+    const ASTTemplateArgumentListInfo *ArgsAsWritten,
     ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
     CanQualType CanonInjectedTST,
     ClassTemplatePartialSpecializationDecl *PrevDecl) {
   assert(!Params->empty() && "template with no template parameters");
-  auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
-      Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
-      CanonInjectedTST, PrevDecl);
-  Result->setSpecializationKind(TSK_ExplicitSpecialization);
-  return Result;
+  return new (Context, DC) ClassTemplatePartialSpecializationDecl(
+      Context, TK, DC, StartLoc, IdLoc, Params, ArgsAsWritten,
+      SpecializedTemplate, Args, CanonInjectedTST, PrevDecl);
 }
 
 ClassTemplatePartialSpecializationDecl *
@@ -1221,11 +1207,7 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
           getInstantiatedFromMember();
       MT && !isMemberSpecialization())
     return MT->getSourceRange();
-  SourceRange Range = ClassTemplateSpecializationDecl::getSourceRange();
-  if (const TemplateParameterList *TPL = getTemplateParameters();
-      TPL && getTemplateParameterLists().empty())
-    Range.setBegin(TPL->getTemplateLoc());
-  return Range;
+  return ClassTemplateSpecializationDecl::getSourceRange();
 }
 
 //===----------------------------------------------------------------------===//
@@ -1484,8 +1466,11 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
     }
     return VTD->getCanonicalDecl()->getSourceRange();
   }
+  case TSK_FriendDeclaration:
   case TSK_ExplicitSpecialization: {
     SourceRange Range = VarDecl::getSourceRange();
+    if (const auto *Info = getExplicitSpecializationInfo())
+      Range.setBegin(Info->TemplateParams->getTemplateLoc());
     if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
         !hasInit() && Args)
       Range.setEnd(Args->getRAngleLoc());
@@ -1493,10 +1478,11 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
   }
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ExplicitInstantiationDefinition: {
+    const auto *Info = getExplicitInstantiationInfo();
     SourceRange Range = VarDecl::getSourceRange();
-    if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
+    if (SourceLocation ExternKW = Info->ExternKeywordLoc; ExternKW.isValid())
       Range.setBegin(ExternKW);
-    else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
+    else if (SourceLocation TemplateKW = Info->TemplateKeywordLoc;
              TemplateKW.isValid())
       Range.setBegin(TemplateKW);
     if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
@@ -1507,30 +1493,16 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
   llvm_unreachable("unhandled template specialization kind");
 }
 
-void VarTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
-  auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
-  if (!Info) {
-    // Don't allocate if the location is invalid.
-    if (Loc.isInvalid())
-      return;
-    Info = new (getASTContext()) ExplicitInstantiationInfo;
-    Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
-    ExplicitInfo = Info;
-  }
-  Info->ExternKeywordLoc = Loc;
-}
-
-void VarTemplateSpecializationDecl::setTemplateKeywordLoc(SourceLocation Loc) {
-  auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
-  if (!Info) {
-    // Don't allocate if the location is invalid.
-    if (Loc.isInvalid())
-      return;
-    Info = new (getASTContext()) ExplicitInstantiationInfo;
-    Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
-    ExplicitInfo = Info;
-  }
-  Info->TemplateKeywordLoc = Loc;
+void VarTemplateSpecializationDecl::setExplicitSpecializationInfo(
+    TemplateParameterList *TemplateParams,
+    const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
+  auto *Info = new (getASTContext()) ExplicitSpecializationInfo();
+  Info->TemplateParams = TemplateParams;
+  Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
+  ExplicitInfo = Info;
+
+  if (AdoptTemplateParameterList(TemplateParams, getDeclContext()))
+    setInvalidDecl();
 }
 
 //===----------------------------------------------------------------------===//
@@ -1542,28 +1514,28 @@ void VarTemplatePartialSpecializationDecl::anchor() {}
 VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
     ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
     SourceLocation IdLoc, TemplateParameterList *Params,
+    const ASTTemplateArgumentListInfo *ArgsAsWritten,
     VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
     StorageClass S, ArrayRef<TemplateArgument> Args)
     : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context,
                                     DC, StartLoc, IdLoc, SpecializedTemplate, T,
                                     TInfo, S, Args),
-      TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
-  if (AdoptTemplateParameterList(Params, DC))
-    setInvalidDecl();
+      InstantiatedFromMember(nullptr, false) {
+  setSpecializationKind(TSK_ExplicitSpecialization);
+  setExplicitSpecializationInfo(Params, ArgsAsWritten);
 }
 
 VarTemplatePartialSpecializationDecl *
 VarTemplatePartialSpecializationDecl::Create(
     ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
     SourceLocation IdLoc, TemplateParameterList *Params,
+    const ASTTemplateArgumentListInfo *ArgsAsWritten,
     VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
     StorageClass S, ArrayRef<TemplateArgument> Args) {
   assert(!Params->empty() && "template with no template parameters");
-  auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
-      Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
-      Args);
-  Result->setSpecializationKind(TSK_ExplicitSpecialization);
-  return Result;
+  return new (Context, DC) VarTemplatePartialSpecializationDecl(
+      Context, DC, StartLoc, IdLoc, Params, ArgsAsWritten, SpecializedTemplate,
+      T, TInfo, S, Args);
 }
 
 VarTemplatePartialSpecializationDecl *
@@ -1577,11 +1549,7 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
           getInstantiatedFromMember();
       MT && !isMemberSpecialization())
     return MT->getSourceRange();
-  SourceRange Range = VarTemplateSpecializationDecl::getSourceRange();
-  if (const TemplateParameterList *TPL = getTemplateParameters();
-      TPL && getTemplateParameterLists().empty())
-    Range.setBegin(TPL->getTemplateLoc());
-  return Range;
+  return VarTemplateSpecializationDecl::getSourceRange();
 }
 
 static TemplateParameterList *createBuiltinTemplateParameterList(
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 8373dd8e373e0..ffb3d74f6b9f4 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1131,6 +1131,9 @@ void JSONNodeDumper::VisitExplicitInstantiationDecl(
   case TSK_ImplicitInstantiation:
     JOS.attribute("templateSpecializationKind", "implicit_instantiation");
     break;
+  case TSK_FriendDeclaration:
+    JOS.attribute("templateSpecializationKind", "friend_declaration");
+    break;
   case TSK_ExplicitSpecialization:
     JOS.attribute("templateSpecializationKind", "explicit_specialization");
     break;
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 2b1c0cac25b6d..abb6869a2b46e 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1044,6 +1044,9 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind(
   case TSK_ImplicitInstantiation:
     OS << " implicit_instantiation";
     break;
+  case TSK_FriendDeclaration:
+    OS << " friend_declaration";
+    break;
   case TSK_ExplicitSpecialization:
     OS << " explicit_specialization";
     break;
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index a04070971f0eb..8cb8d6ebf297f 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -99,6 +99,7 @@ RegistryMaps::RegistryMaps() {
   //
   // Other:
   // equalsNode
+  // declaresSameEntityAsNode
 
   registerMatcher("mapAnyOf",
                   std::make_unique<internal::MapAnyOfBuilderDescriptor>());
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index dd394a8c8d93c..8c3e36514a1a8 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -697,7 +697,7 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
       canResolveToExpr(Exp),
       parmVarDecl(hasType(nonConstReferenceType())).bind("parm"));
   const auto IsInstantiated = hasDeclaration(isInstantiated());
-  const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
+  const auto FuncDecl = hasDeclaration(functionDecl());
   const auto Matches = match(
       traverse(
           TK_AsIs,
@@ -711,13 +711,16 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
       Stm, Context);
   for (const auto &Nodes : Matches) {
     const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
-    const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
-    if (!Func->getBody() || !Func->getPrimaryTemplate())
+    const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
+    const auto *Func =
+        cast<FunctionDecl>(Parm->getDeclContext())->getDefinition();
+    if (!Func || !Func->doesThisDeclarationHaveABody())
       return Exp;
+    Parm = Func->getParamDecl(Parm->getFunctionScopeIndex());
 
-    const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
     const ArrayRef<ParmVarDecl *> AllParams =
-        Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
+        Func->getTemplateInstantiationPattern(/*ForDefinition=*/true)
+            ->parameters();
     QualType ParmType =
         AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
                                    AllParams.size() - 1)]
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 1254c708cd8e1..90bd34028d7c5 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -1145,21 +1145,22 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
 
       return llvm::GlobalVariable::ExternalLinkage;
 
-      case TSK_ImplicitInstantiation:
-        return !Context.getLangOpts().AppleKext ?
-                 llvm::GlobalVariable::LinkOnceODRLinkage :
-                 llvm::Function::InternalLinkage;
-
-      case TSK_ExplicitInstantiationDefinition:
-        return !Context.getLangOpts().AppleKext ?
-                 llvm::GlobalVariable::WeakODRLinkage :
-                 llvm::Function::InternalLinkage;
-
-      case TSK_ExplicitInstantiationDeclaration:
-        return IsExternalDefinition
-                   ? llvm::GlobalVariable::AvailableExternallyLinkage
-                   : llvm::GlobalVariable::ExternalLinkage;
-      }
+    case TSK_FriendDeclaration:
+    case TSK_ImplicitInstantiation:
+      return !Context.getLangOpts().AppleKext
+                 ? llvm::GlobalVariable::LinkOnceODRLinkage
+                 : llvm::Function::InternalLinkage;
+
+    case TSK_ExplicitInstantiationDefinition:
+      return !Context.getLangOpts().AppleKext
+                 ? llvm::GlobalVariable::WeakODRLinkage
+                 : llvm::Function::InternalLinkage;
+
+    case TSK_ExplicitInstantiationDeclaration:
+      return IsExternalDefinition
+                 ? llvm::GlobalVariable::AvailableExternallyLinkage
+                 : llvm::GlobalVariable::ExternalLinkage;
+    }
   }
 
   // -fapple-kext mode does not support weak linkage, so we must use
@@ -1184,6 +1185,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
     case TSK_Undeclared:
     case TSK_ExplicitSpecialization:
     case TSK_ImplicitInstantiation:
+    case TSK_FriendDeclaration:
       return DiscardableODRLinkage;
 
     case TSK_ExplicitInstantiationDeclaration:
diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp
index bdd6c5acf1d34..ac532d6a2f5ef 100644
--- a/clang/lib/Index/IndexingContext.cpp
+++ b/clang/lib/Index/IndexingContext.cpp
@@ -185,6 +185,7 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
       return isa<ClassTemplateSpecializationDecl>(D);
     case TSK_ExplicitSpecialization:
       return false;
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
     case TSK_ExplicitInstantiationDeclaration:
     case TSK_ExplicitInstantiationDefinition:
diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp
index 53fbc36ae7600..08d2e556ad57c 100644
--- a/clang/lib/InstallAPI/Visitor.cpp
+++ b/clang/lib/InstallAPI/Visitor.cpp
@@ -318,6 +318,7 @@ static bool hasVTable(const CXXRecordDecl *D) {
     case TSK_Undeclared:
     case TSK_ExplicitSpecialization:
     case TSK_ImplicitInstantiation:
+    case TSK_FriendDeclaration:
     case TSK_ExplicitInstantiationDefinition:
       return true;
     case TSK_ExplicitInstantiationDeclaration:
@@ -334,6 +335,7 @@ static bool hasVTable(const CXXRecordDecl *D) {
   case TSK_Undeclared:
   case TSK_ExplicitSpecialization:
   case TSK_ImplicitInstantiation:
+  case TSK_FriendDeclaration:
     return false;
 
   case TSK_ExplicitInstantiationDeclaration:
@@ -361,6 +363,7 @@ static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
       if (isInlined(KeyFunctionD))
         return CXXLinkage::LinkOnceODRLinkage;
       return CXXLinkage::ExternalLinkage;
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
       llvm_unreachable("No external vtable for implicit instantiations");
     case TSK_ExplicitInstantiationDefinition:
@@ -375,6 +378,7 @@ static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
   case TSK_Undeclared:
   case TSK_ExplicitSpecialization:
   case TSK_ImplicitInstantiation:
+  case TSK_FriendDeclaration:
     return CXXLinkage::LinkOnceODRLinkage;
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ExplicitInstantiationDefinition:
@@ -601,6 +605,7 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
     case TSK_Undeclared:
     case TSK_ExplicitSpecialization:
       break;
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
       continue;
     case TSK_ExplicitInstantiationDeclaration:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 893989bd2398f..86f18d10f08b0 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2059,15 +2059,17 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
           TemplateParams = &FakedParamLists;
         }
       }
-
+      MultiTemplateParamsArg ParamLists(
+          TemplateParams ? &(*TemplateParams)[0] : nullptr,
+          TemplateParams ? TemplateParams->size() : 0);
       // Build the class template specialization.
       TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
           getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
-          SS, *TemplateId, attrs,
-          MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
-                                                : nullptr,
-                                 TemplateParams ? TemplateParams->size() : 0),
-          &SkipBody);
+          SS, *TemplateId, attrs, ParamLists, &SkipBody);
+      // Some template parameter lists may have been dropped because they were
+      // extraneous.
+      if (TemplateParams)
+        TemplateParams->resize(ParamLists.size());
     }
   } else if (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation &&
              TUK == TagUseKind::Declaration) {
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index ae61b590a1f71..13c8ae5dc5995 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -313,12 +313,6 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
           ElaboratedTypeKeyword::Class, TemplateName(TextureTemplate),
           {TemplateArgument(VectorType)}, {}));
 
-  auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
-      AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
-      SourceLocation(), TemplateParams, TextureTemplate,
-      {TemplateArgument(VectorType)},
-      CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
-
   // Set the template arguments as written.
   TemplateArgument Arg(VectorType);
   TemplateArgumentLoc ArgLoc =
@@ -326,8 +320,13 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
   TemplateArgumentListInfo ArgsInfo =
       TemplateArgumentListInfo(SourceLocation(), SourceLocation());
   ArgsInfo.addArgument(ArgLoc);
-  PartialSpec->setTemplateArgsAsWritten(
-      ASTTemplateArgumentListInfo::Create(AST, ArgsInfo));
+
+  auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
+      AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
+      SourceLocation(), TemplateParams,
+      ASTTemplateArgumentListInfo::Create(AST, ArgsInfo), TextureTemplate,
+      {TemplateArgument(VectorType)},
+      CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
 
   PartialSpec->setImplicit(true);
   PartialSpec->setLexicalDeclContext(HLSLNamespace);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ea03c3f408986..5c829d3d7c7fb 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -200,15 +200,10 @@ static bool DiagRecursiveConstraintEval(
 // Figure out the to-translation-unit depth for this function declaration for
 // the purpose of seeing if they differ by constraints. This isn't the same as
 // getTemplateDepth, because it includes already instantiated parents.
-static unsigned
-CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
-                                     bool SkipForSpecialization = false) {
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      ND, ND->getLexicalDeclContext(), /*Final=*/false,
-      /*Innermost=*/std::nullopt,
-      /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+static unsigned CalculateTemplateDepthForConstraints(Sema &S,
+                                                     const NamedDecl *ND) {
+  // FIXME: This is a very expensive way to calculate this.
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
   return MLTAL.getNumLevels();
 }
 
@@ -1321,10 +1316,8 @@ bool Sema::CheckConstraintSatisfaction(
   return false;
 }
 
-static ExprResult
-SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
-                                         const ConceptSpecializationExpr *CSE,
-                                         UnsignedOrNone SubstIndex) {
+static ExprResult SubstituteConceptsInConstraintExpression(
+    Sema &S, const ConceptSpecializationExpr *CSE, UnsignedOrNone SubstIndex) {
   Sema::SFINAETrap Trap(S);
   // [C++2c] [temp.constr.normal]
   // Otherwise, to form CE, any non-dependent concept template argument Ai
@@ -1332,7 +1325,8 @@ SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
   // If any such substitution results in an invalid concept-id,
   // the program is ill-formed; no diagnostic is required.
 
-  ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl();
+  Expr *ConstraintExpr =
+      CSE->getNamedConcept()->getCanonicalDecl()->getConstraintExpr();
   Sema::ArgPackSubstIndexRAII _(S, SubstIndex);
 
   const ASTTemplateArgumentListInfo *ArgsAsWritten =
@@ -1342,23 +1336,17 @@ SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
             return !ArgLoc.getArgument().isDependent() &&
                    ArgLoc.getArgument().isConceptOrConceptTemplateParameter();
           })) {
-    return Concept->getConstraintExpr();
+    return ConstraintExpr;
   }
 
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      Concept, Concept->getLexicalDeclContext(),
-      /*Final=*/false, CSE->getTemplateArguments(),
-      /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/true);
-  return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(),
-                                         MLTAL);
+  return S.SubstConceptTemplateArguments(
+      CSE, ConstraintExpr,
+      S.getTemplateInstantiationArgs(CSE->getSpecializationDecl()));
 }
 
-bool Sema::SetupConstraintScope(
-    FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
-    const MultiLevelTemplateArgumentList &MLTAL,
-    LocalInstantiationScope &Scope) {
+bool Sema::SetupConstraintScope(FunctionDecl *FD,
+                                const MultiLevelTemplateArgumentList &MLTAL,
+                                LocalInstantiationScope &Scope) {
   assert(!isLambdaCallOperator(FD) &&
          "Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
          "instantiations");
@@ -1367,8 +1355,7 @@ bool Sema::SetupConstraintScope(
     InstantiatingTemplate Inst(
         *this, FD->getPointOfInstantiation(),
         Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
-        TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
-        SourceRange());
+        FD->getTemplateSpecializationArgs()->asArray(), SourceRange());
     if (Inst.isInvalid())
       return true;
 
@@ -1404,11 +1391,10 @@ bool Sema::SetupConstraintScope(
             ? FD->getInstantiatedFromMemberFunction()
             : FD->getInstantiatedFromDecl();
 
-    InstantiatingTemplate Inst(
-        *this, FD->getPointOfInstantiation(),
-        Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
-        TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
-        SourceRange());
+    InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
+                               Sema::InstantiatingTemplate::ConstraintsCheck{},
+                               InstantiatedFrom, ArrayRef<TemplateArgument>(),
+                               SourceRange());
     if (Inst.isInvalid())
       return true;
 
@@ -1425,23 +1411,12 @@ bool Sema::SetupConstraintScope(
 // constraint-instantiation and checking.
 std::optional<MultiLevelTemplateArgumentList>
 Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
-    FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
-    LocalInstantiationScope &Scope) {
-  MultiLevelTemplateArgumentList MLTAL;
-
-  // Collect the list of template arguments relative to the 'primary' template.
-  // We need the entire list, since the constraint is completely uninstantiated
-  // at this point.
-  MLTAL =
-      getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
-                                   /*Final=*/false, /*Innermost=*/std::nullopt,
-                                   /*RelativeToPrimary=*/true,
-                                   /*Pattern=*/nullptr,
-                                   /*ForConstraintInstantiation=*/true);
+    FunctionDecl *FD, LocalInstantiationScope &Scope) {
+  MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(FD);
   // Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
   if (isLambdaCallOperator(FD))
     return MLTAL;
-  if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
+  if (SetupConstraintScope(FD, MLTAL, Scope))
     return std::nullopt;
 
   return MLTAL;
@@ -1488,7 +1463,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
   LocalInstantiationScope Scope(*this, !ForOverloadResolution);
   std::optional<MultiLevelTemplateArgumentList> MLTAL =
       SetupConstraintCheckingTemplateArgumentsAndScope(
-          const_cast<FunctionDecl *>(FD), {}, Scope);
+          const_cast<FunctionDecl *>(FD), Scope);
 
   if (!MLTAL)
     return true;
@@ -1511,15 +1486,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
       Satisfaction);
 }
 
-static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
-    Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
-    const Expr *ConstrExpr) {
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      DeclInfo.getDecl(), DeclInfo.getDeclContext(), /*Final=*/false,
-      /*Innermost=*/std::nullopt,
-      /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
-      /*SkipForSpecialization*/ false);
+static const Expr *
+SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
+                                                  const Expr *ConstrExpr) {
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
 
   if (MLTAL.getNumSubstitutedLevels() == 0)
     return ConstrExpr;
@@ -1529,8 +1499,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
   // this may happen while we're comparing two templates' constraint
   // equivalence.
   std::optional<LocalInstantiationScope> ScopeForParameters;
-  if (const NamedDecl *ND = DeclInfo.getDecl();
-      ND && ND->isFunctionOrFunctionTemplate()) {
+  if (ND->isFunctionOrFunctionTemplate()) {
     ScopeForParameters.emplace(S, /*CombineWithOuterScope=*/true);
     const FunctionDecl *FD = ND->getAsFunction();
     if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate();
@@ -1574,13 +1543,9 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
   // possible that e.g. constraints involving C<Class<T>> and C<Class> are
   // perceived identical.
   std::optional<Sema::ContextRAII> ContextScope;
-  const DeclContext *DC = [&] {
-    if (!DeclInfo.getDecl())
-      return DeclInfo.getDeclContext();
-    return DeclInfo.getDecl()->getFriendObjectKind()
-               ? DeclInfo.getLexicalDeclContext()
-               : DeclInfo.getDeclContext();
-  }();
+  const DeclContext *DC = ND->getFriendObjectKind()
+                              ? ND->getLexicalDeclContext()
+                              : ND->getDeclContext();
   if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
     ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
     ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
@@ -1596,15 +1561,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
   return SubstConstr.get();
 }
 
-bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
-                                         const Expr *OldConstr,
-                                         const TemplateCompareNewDeclInfo &New,
+bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
+                                         const Decl *New,
                                          const Expr *NewConstr) {
   if (OldConstr == NewConstr)
     return true;
   // C++ [temp.constr.decl]p4
-  if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
-      Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
+  if (Old != New &&
+      Old->getLexicalDeclContext() != New->getLexicalDeclContext()) {
     Sema::SFINAETrap _(*this);
     if (const Expr *SubstConstr =
             SubstituteConstraintExpressionWithoutSatisfaction(*this, Old,
@@ -1626,19 +1590,15 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
   return ID1 == ID2;
 }
 
-bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
-  assert(FD->getFriendObjectKind() && "Must be a friend!");
-
-  // The logic for non-templates is handled in ASTContext::isSameEntity, so we
-  // don't have to bother checking 'DependsOnEnclosingTemplate' for a
-  // non-function-template.
-  assert(FD->getDescribedFunctionTemplate() &&
-         "Non-function templates don't need to be checked");
+bool Sema::FriendConstraintsDependOnEnclosingTemplate(
+    const FunctionTemplateDecl *FTD) {
+  assert(FTD->getFriendObjectKind() && "Must be a friend!");
 
   SmallVector<AssociatedConstraint, 3> ACs;
-  FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+  FTD->getAssociatedConstraints(ACs);
 
-  unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+  const FunctionDecl *FD = FTD->getTemplatedDecl();
+  unsigned OldTemplateDepth = FTD->getTemplateDepth();
   for (const AssociatedConstraint &AC : ACs)
     if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
                                                        AC.ConstraintExpr))
@@ -1674,9 +1634,9 @@ bool Sema::EnsureTemplateArgumentListConstraints(
   return false;
 }
 
-static bool CheckFunctionConstraintsWithoutInstantiation(
-    Sema &SemaRef, SourceLocation PointOfInstantiation,
-    FunctionTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
+bool Sema::CheckFunctionTemplateConstraints(
+    SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
+    ArrayRef<TemplateArgument> TemplateArgs,
     ConstraintSatisfaction &Satisfaction) {
   SmallVector<AssociatedConstraint, 3> TemplateAC;
   Template->getAssociatedConstraints(TemplateAC);
@@ -1685,47 +1645,22 @@ static bool CheckFunctionConstraintsWithoutInstantiation(
     return false;
   }
 
-  LocalInstantiationScope Scope(SemaRef);
+  LocalInstantiationScope Scope(*this);
 
-  FunctionDecl *FD = Template->getTemplatedDecl();
-  // Collect the list of template arguments relative to the 'primary'
-  // template. We need the entire list, since the constraint is completely
-  // uninstantiated at this point.
+  MultiLevelTemplateArgumentList MLTAL =
+      getTemplateInstantiationArgs(Template, TemplateArgs);
 
-  MultiLevelTemplateArgumentList MLTAL;
-  {
-    // getTemplateInstantiationArgs uses this instantiation context to find out
-    // template arguments for uninstantiated functions.
-    // We don't want this RAII object to persist, because there would be
-    // otherwise duplicate diagnostic notes.
-    Sema::InstantiatingTemplate Inst(
-        SemaRef, PointOfInstantiation,
-        Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
-        PointOfInstantiation);
-    if (Inst.isInvalid())
-      return true;
-    MLTAL = SemaRef.getTemplateInstantiationArgs(
-        /*D=*/FD, FD,
-        /*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
-  }
-
-  Sema::ContextRAII SavedContext(SemaRef, FD);
-  return SemaRef.CheckConstraintSatisfaction(
-      Template, TemplateAC, MLTAL, PointOfInstantiation, Satisfaction);
+  Sema::ContextRAII SavedContext(*this, Template->getTemplatedDecl());
+  return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
+                                     PointOfInstantiation, Satisfaction);
 }
 
-bool Sema::CheckFunctionTemplateConstraints(
+bool Sema::CheckFunctionSpecializationConstraints(
     SourceLocation PointOfInstantiation, FunctionDecl *Decl,
-    ArrayRef<TemplateArgument> TemplateArgs,
     ConstraintSatisfaction &Satisfaction) {
   // In most cases we're not going to have constraints, so check for that first.
   FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
-
-  if (!Template)
-    return ::CheckFunctionConstraintsWithoutInstantiation(
-        *this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
-        TemplateArgs, Satisfaction);
+  assert(Template && "Function is not a specialization");
 
   // Note - code synthesis context for the constraints check is created
   // inside CheckConstraintsSatisfaction.
@@ -1742,8 +1677,7 @@ bool Sema::CheckFunctionTemplateConstraints(
   LocalInstantiationScope Scope(*this);
 
   std::optional<MultiLevelTemplateArgumentList> MLTAL =
-      SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
-                                                       Scope);
+      SetupConstraintCheckingTemplateArgumentsAndScope(Decl, Scope);
 
   if (!MLTAL)
     return true;
@@ -2327,12 +2261,8 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
       InnerArgs = std::move(CTAI.SugaredConverted);
     }
 
-    MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
-        Concept, Concept->getLexicalDeclContext(),
-        /*Final=*/true, InnerArgs,
-        /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
-        /*ForConstraintInstantiation=*/true);
+    MultiLevelTemplateArgumentList MLTAL =
+        SemaRef.getTemplateInstantiationArgs(Concept, InnerArgs);
 
     return SubstituteParameterMappings(SemaRef, &MLTAL,
                                        CSE->getTemplateArgsAsWritten(),
@@ -2413,7 +2343,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
     // [...]
     NormalizedConstraint *SubNF;
     if (ExprResult Res =
-            SubstituteConceptsInConstraintExpression(S, D, CSE, SubstIndex);
+            SubstituteConceptsInConstraintExpression(S, CSE, SubstIndex);
         Res.isUsable())
       // Use canonical declarations to merge ConceptDecls across different
       // modules.
@@ -2563,8 +2493,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
     return false;
   }
 
-  unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
-  unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
+  unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
+  unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
 
   for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
     if (Depth2 > Depth1) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 62cb9360d1322..eff5c163ac2f0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4750,10 +4750,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
   adjustDeclContextForDeclaratorDecl(New, Old);
 
   // Ensure the template parameters are compatible.
-  if (NewTemplate &&
-      !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
-                                      OldTemplate->getTemplateParameters(),
-                                      /*Complain=*/true, TPL_TemplateMatch))
+  if (NewTemplate && !TemplateParameterListsAreEqual(
+                         NewTemplate, NewTemplate->getTemplateParameters(),
+                         OldTemplate, OldTemplate->getTemplateParameters(),
+                         /*Complain=*/true, TPL_TemplateMatch))
     return New->setInvalidDecl();
 
   // C++ [class.mem]p1:
@@ -8023,6 +8023,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
     }
 
     if (IsVariableTemplateSpecialization) {
+      // FIXME: This should be the template keyword location for the last
+      // template parameter list.
       SourceLocation TemplateKWLoc =
           TemplateParamLists.size() > 0
               ? TemplateParamLists[0]->getTemplateLoc()
@@ -8065,10 +8067,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
 
     // If we have any template parameter lists that don't directly belong to
     // the variable (matching the scope specifier), store them.
-    // An explicit variable template specialization does not own any template
-    // parameter lists.
     unsigned VDTemplateParamLists =
-        (TemplateParams && !IsExplicitSpecialization) ? 1 : 0;
+        IsVariableTemplate || IsVariableTemplateSpecialization ? 1 : 0;
     if (TemplateParamLists.size() > VDTemplateParamLists)
       NewVD->setTemplateParameterListsInfo(
           Context, TemplateParamLists.drop_back(VDTemplateParamLists));
@@ -10119,6 +10119,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   bool isMemberSpecialization = false;
   bool isFunctionTemplateSpecialization = false;
 
+  TemplateParameterList *TemplateParams = nullptr;
   bool HasExplicitTemplateArgs = false;
   TemplateArgumentListInfo TemplateArgs;
 
@@ -10203,11 +10204,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
         D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
             ? D.getName().TemplateId
             : nullptr;
-    TemplateParameterList *TemplateParams =
-        MatchTemplateParametersToScopeSpecifier(
-            D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
-            D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend,
-            isMemberSpecialization, Invalid);
+    TemplateParamListsRef = TemplateParamLists;
+    TemplateParams = MatchTemplateParametersToScopeSpecifier(
+        D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
+        D.getCXXScopeSpec(), TemplateId, TemplateParamListsRef, isFriend,
+        isMemberSpecialization, Invalid);
+    // Some template parameter lists may have been dropped because they were
+    // extraneous.
+    TemplateParamLists.resize(TemplateParamListsRef.size());
     if (TemplateParams) {
       // Check that we can declare a template here.
       if (CheckTemplateDeclScope(S, TemplateParams))
@@ -10242,19 +10246,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                                                         NewFD);
         FunctionTemplate->setLexicalDeclContext(CurContext);
         NewFD->setDescribedFunctionTemplate(FunctionTemplate);
-
-        // For source fidelity, store the other template param lists.
-        if (TemplateParamLists.size() > 1) {
-          NewFD->setTemplateParameterListsInfo(Context,
-              ArrayRef<TemplateParameterList *>(TemplateParamLists)
-                  .drop_back(1));
-        }
       } else {
         // This is a function template specialization.
         isFunctionTemplateSpecialization = true;
-        // For source fidelity, store all the template param lists.
-        if (TemplateParamLists.size() > 0)
-          NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
+        NewFD->setInnerLocStart(TemplateParams->getTemplateLoc());
 
         // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
         if (isFriend) {
@@ -10284,6 +10279,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
           TemplateArgs.setRAngleLoc(InsertLoc);
         }
       }
+      // For source fidelity, store the other template param lists.
+      if (TemplateParamLists.size() > 1) {
+        NewFD->setTemplateParameterListsInfo(
+            Context,
+            ArrayRef<TemplateParameterList *>(TemplateParamLists).drop_back(1));
+      }
     } else {
       // Check that we can declare a template here.
       if (!TemplateParamLists.empty() && isMemberSpecialization &&
@@ -10885,11 +10886,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
         // template is instantiated. In such cases, we store the declarations
         // found by name lookup and defer resolution until instantiation.
         if (CheckDependentFunctionTemplateSpecialization(
-                NewFD, ExplicitTemplateArgs, Previous))
+                NewFD, TemplateParams, ExplicitTemplateArgs, Previous))
           NewFD->setInvalidDecl();
       } else if (!NewFD->isInvalidDecl()) {
-        if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs,
-                                                Previous))
+        if (CheckFunctionTemplateSpecialization(NewFD, TemplateParams,
+                                                ExplicitTemplateArgs, Previous))
           NewFD->setInvalidDecl();
       }
     } else if (isMemberSpecialization && !FunctionTemplate) {
@@ -11193,7 +11194,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     // Precalculate whether this is a friend function template with a constraint
     // that depends on an enclosing template, per [temp.friend]p9.
     if (isFriend && FunctionTemplate &&
-        FriendConstraintsDependOnEnclosingTemplate(NewFD)) {
+        FriendConstraintsDependOnEnclosingTemplate(FunctionTemplate)) {
       NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
 
       // C++ [temp.friend]p9:
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index de837ff0608d0..cf366378a7d8c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13935,10 +13935,13 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
       }
 
       if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
-        if (TemplateParameterListsAreEqual(TemplateParams,
-                                           OldDecl->getTemplateParameters(),
-                                           /*Complain=*/true,
-                                           TPL_TemplateMatch))
+        // It's ok that we don't pass the declarations corresponding to the
+        // template parameter lists here, because type alias templates cannot be
+        // declared out-of-line.
+        if (TemplateParameterListsAreEqual(
+                /*NewInstFrom=*/nullptr, TemplateParams,
+                /*OldInstFrom=*/nullptr, OldDecl->getTemplateParameters(),
+                /*Complain=*/true, TPL_TemplateMatch))
           OldTemplateParams =
               OldDecl->getMostRecentDecl()->getTemplateParameters();
         else
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 851d58c49f7b9..833e73922cfc9 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1129,9 +1129,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       return ExprError();
     }
 
-    DeclResult VDecl =
-        CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
-                           *TemplateArgs, /*SetWrittenArgs=*/false);
+    DeclResult VDecl = CheckVarTemplateId(
+        VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
     if (VDecl.isInvalid())
       return ExprError();
 
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index e11bbd7085798..83fde956e34b2 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1325,8 +1325,10 @@ OverloadKind Sema::CheckOverload(Scope *S, FunctionDecl *New,
       !New->getType()->isDependentType()) {
     LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
     TemplateSpecResult.addAllDecls(Old);
-    if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
-                                            /*QualifiedFriend*/true)) {
+    if (CheckFunctionTemplateSpecialization(New, /*TemplateParams=*/nullptr,
+                                            /*ExplicitTemplateArgs=*/nullptr,
+                                            TemplateSpecResult,
+                                            /*QualifiedFriend*/ true)) {
       New->setInvalidDecl();
       return OverloadKind::Overload;
     }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 5667cf53fee0b..85fae55228678 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2118,19 +2118,77 @@ DeclResult Sema::CheckClassTemplate(
     }
   }
 
+  if (!PrevClassTemplate && PrevDecl) {
+    // C++ [temp]p5:
+    //   A class template shall not have the same name as any other
+    //   template, class, function, object, enumeration, enumerator,
+    //   namespace, or type in the same scope (3.3), except as specified
+    //   in (14.5.4).
+    Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+    Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+    return true;
+  }
+
+  // If this is a templated friend in a dependent context we should not put it
+  // on the redecl chain. In some cases, the templated friend can be the most
+  // recent declaration tricking the template instantiator to make substitutions
+  // there.
+  // FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious
+  bool ShouldAddRedecl =
+      !(TUK == TagUseKind::Friend && CurContext->isDependentContext());
+
+  CXXRecordDecl *NewClass = CXXRecordDecl::Create(
+      Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
+      /*PrevDecl=*/PrevClassTemplate && ShouldAddRedecl
+          ? PrevClassTemplate->getTemplatedDecl()
+          : nullptr);
+  SetNestedNameSpecifier(*this, NewClass, SS);
+  if (NumOuterTemplateParamLists > 0)
+    NewClass->setTemplateParameterListsInfo(
+        Context,
+        llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
+
+  // Add alignment attributes if necessary; these attributes are checked when
+  // the ASTContext lays out the structure.
+  if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
+    if (LangOpts.HLSL)
+      NewClass->addAttr(PackedAttr::CreateImplicit(Context));
+    AddAlignmentAttributesForRecord(NewClass);
+    AddMsStructLayoutForRecord(NewClass);
+  }
+
+  ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(
+      Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams,
+      NewClass);
+
+  NewClass->setDescribedClassTemplate(NewTemplate);
+
+  if (ModulePrivateLoc.isValid())
+    NewTemplate->setModulePrivate();
+
+  // If we are providing an explicit specialization of a member that is a
+  // class template, make a note of that.
+  if (PrevClassTemplate &&
+      PrevClassTemplate->getInstantiatedFromMemberTemplate())
+    PrevClassTemplate->setMemberSpecialization();
+
+  // Set the lexical context of these templates
+  NewClass->setLexicalDeclContext(CurContext);
+  NewTemplate->setLexicalDeclContext(CurContext);
+
   if (PrevClassTemplate) {
     // Ensure that the template parameter lists are compatible. Skip this check
     // for a friend in a dependent context: the template parameter list itself
     // could be dependent.
     if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
         !TemplateParameterListsAreEqual(
-            TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
-                                                       : CurContext,
-                                       CurContext, KWLoc),
-            TemplateParams, PrevClassTemplate,
+            NewTemplate, TemplateParams, PrevClassTemplate,
             PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
-            TPL_TemplateMatch))
+            TPL_TemplateMatch)) {
+      NewTemplate->setInvalidDecl();
+      NewClass->setInvalidDecl();
       return true;
+    }
 
     // C++ [temp.class]p4:
     //   In a redeclaration, partial specialization, explicit
@@ -2175,15 +2233,6 @@ DeclResult Sema::CheckClassTemplate(
         }
       }
     }
-  } else if (PrevDecl) {
-    // C++ [temp]p5:
-    //   A class template shall not have the same name as any other
-    //   template, class, function, object, enumeration, enumerator,
-    //   namespace, or type in the same scope (3.3), except as specified
-    //   in (14.5.4).
-    Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
-    Diag(PrevDecl->getLocation(), diag::note_previous_definition);
-    return true;
   }
 
   // Check the template parameter list of this declaration, possibly
@@ -2215,61 +2264,13 @@ DeclResult Sema::CheckClassTemplate(
     }
   }
 
-  // If this is a templated friend in a dependent context we should not put it
-  // on the redecl chain. In some cases, the templated friend can be the most
-  // recent declaration tricking the template instantiator to make substitutions
-  // there.
-  // FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious
-  bool ShouldAddRedecl =
-      !(TUK == TagUseKind::Friend && CurContext->isDependentContext());
-
-  CXXRecordDecl *NewClass = CXXRecordDecl::Create(
-      Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
-      PrevClassTemplate && ShouldAddRedecl
-          ? PrevClassTemplate->getTemplatedDecl()
-          : nullptr);
-  SetNestedNameSpecifier(*this, NewClass, SS);
-  if (NumOuterTemplateParamLists > 0)
-    NewClass->setTemplateParameterListsInfo(
-        Context,
-        llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
-
-  // Add alignment attributes if necessary; these attributes are checked when
-  // the ASTContext lays out the structure.
-  if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
-    if (LangOpts.HLSL)
-      NewClass->addAttr(PackedAttr::CreateImplicit(Context));
-    AddAlignmentAttributesForRecord(NewClass);
-    AddMsStructLayoutForRecord(NewClass);
-  }
-
-  ClassTemplateDecl *NewTemplate
-    = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
-                                DeclarationName(Name), TemplateParams,
-                                NewClass);
-
-  if (ShouldAddRedecl)
-    NewTemplate->setPreviousDecl(PrevClassTemplate);
-
-  NewClass->setDescribedClassTemplate(NewTemplate);
-
-  if (ModulePrivateLoc.isValid())
-    NewTemplate->setModulePrivate();
-
-  // If we are providing an explicit specialization of a member that is a
-  // class template, make a note of that.
-  if (PrevClassTemplate &&
-      PrevClassTemplate->getInstantiatedFromMemberTemplate())
-    PrevClassTemplate->setMemberSpecialization();
-
   // Set the access specifier.
   if (!Invalid && TUK != TagUseKind::Friend &&
       NewTemplate->getDeclContext()->isRecord())
     SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
 
-  // Set the lexical context of these templates
-  NewClass->setLexicalDeclContext(CurContext);
-  NewTemplate->setLexicalDeclContext(CurContext);
+  if (ShouldAddRedecl && PrevClassTemplate)
+    NewTemplate->setPreviousDecl(PrevClassTemplate);
 
   if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
     NewClass->startDefinition();
@@ -2843,7 +2844,7 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
 TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
     SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
     TemplateIdAnnotation *TemplateId,
-    ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
+    ArrayRef<TemplateParameterList *> &ParamLists, bool IsFriend,
     bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {
   IsMemberSpecialization = false;
   Invalid = false;
@@ -3109,10 +3110,12 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
 
       if (ParamIdx < ParamLists.size()) {
         // Check the template parameter list, if we can.
+        // FIXME: Should pass the declaration corresponding to each list.
         if (ExpectedTemplateParams &&
-            !TemplateParameterListsAreEqual(ParamLists[ParamIdx],
-                                            ExpectedTemplateParams,
-                                            !SuppressDiagnostic, TPL_TemplateMatch))
+            !TemplateParameterListsAreEqual(
+                /*NewInstFrom=*/nullptr, ParamLists[ParamIdx],
+                /*OldInstFrom=*/nullptr, ExpectedTemplateParams,
+                /*Complain=*/!SuppressDiagnostic, TPL_TemplateMatch))
           Invalid = true;
 
         if (!Invalid &&
@@ -3179,6 +3182,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
            diag::note_explicit_template_spec_does_not_need_header)
         << NestedTypes.back();
 
+    // Recover as if those extra template parameter lists weren't there.
+    ParamLists = ParamLists.take_back(ParamIdx + 1);
+
     // We have a template parameter list with no corresponding scope, which
     // means that the resulting template declaration can't be instantiated
     // properly (we'll end up with dependent nodes when we shouldn't).
@@ -4486,9 +4492,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
     VarTemplatePartialSpecializationDecl *Partial =
         VarTemplatePartialSpecializationDecl::Create(
             Context, VarTemplate->getDeclContext(), TemplateKWLoc,
-            TemplateNameLoc, TemplateParams, VarTemplate, TSI->getType(), TSI,
-            SC, CTAI.CanonicalConverted);
-    Partial->setTemplateArgsAsWritten(TemplateArgs);
+            TemplateNameLoc, TemplateParams,
+            ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
+            VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
 
     if (!PrevPartial)
       VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4506,7 +4512,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
     Specialization = VarTemplateSpecializationDecl::Create(
         Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
         VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
-    Specialization->setTemplateArgsAsWritten(TemplateArgs);
+    Specialization->setExplicitSpecializationInfo(
+        TemplateParams,
+        ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
 
     if (!PrevDecl)
       VarTemplate->AddSpecialization(Specialization, InsertPos);
@@ -4592,8 +4600,7 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
 DeclResult
 Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
                          SourceLocation TemplateNameLoc,
-                         const TemplateArgumentListInfo &TemplateArgs,
-                         bool SetWrittenArgs) {
+                         const TemplateArgumentListInfo &TemplateArgs) {
   assert(Template && "A variable template id without template?");
 
   // Check that the template argument list is well-formed for this template.
@@ -4792,8 +4799,6 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
       TemplateNameLoc /*, LateAttrs, StartingScope*/);
   if (!Decl)
     return true;
-  if (SetWrittenArgs)
-    Decl->setTemplateArgsAsWritten(TemplateArgs);
 
   if (VarTemplatePartialSpecializationDecl *D =
           dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
@@ -4811,7 +4816,7 @@ ExprResult Sema::CheckVarTemplateId(
     const TemplateArgumentListInfo *TemplateArgs) {
 
   DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
-                                       *TemplateArgs, /*SetWrittenArgs=*/false);
+                                       *TemplateArgs);
   if (Decl.isInvalid())
     return ExprError();
 
@@ -6203,7 +6208,8 @@ bool Sema::CheckTemplateArgumentList(
   if (UpdateArgsWithConversions)
     TemplateArgs = std::move(NewArgs);
 
-  if (!PartialTemplateArgs) {
+  // Template template parameters can never have their constraints checked.
+  if (!PartialTemplateArgs && !isa<TemplateTemplateParmDecl>(Template)) {
     // Setup the context/ThisScope for the case where we are needing to
     // re-instantiate constraints outside of normal instantiation.
     DeclContext *NewContext = Template->getDeclContext();
@@ -6222,11 +6228,8 @@ bool Sema::CheckTemplateArgumentList(
     ContextRAII Context(*this, NewContext);
     CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
 
-    MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
-        Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
-        /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
-        /*ForConceptInstantiation=*/true);
+    MultiLevelTemplateArgumentList MLTAL =
+        getTemplateInstantiationArgs(Template, CTAI.SugaredConverted);
     if (!isa<ConceptDecl>(Template) &&
         EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
@@ -8220,9 +8223,8 @@ Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
 
 /// Match two template parameters within template parameter lists.
 static bool MatchTemplateParameterKind(
-    Sema &S, NamedDecl *New,
-    const Sema::TemplateCompareNewDeclInfo &NewInstFrom, NamedDecl *Old,
-    const NamedDecl *OldInstFrom, bool Complain,
+    Sema &S, NamedDecl *New, const Decl *NewInstFrom, NamedDecl *Old,
+    const Decl *OldInstFrom, bool Complain,
     Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
   // Check the actual kind (type, non-type, template).
   if (Old->getKind() != New->getKind()) {
@@ -8310,7 +8312,7 @@ static bool MatchTemplateParameterKind(
     if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
       return false;
     if (!S.TemplateParameterListsAreEqual(
-            NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
+            NewTTP, NewTTP->getTemplateParameters(), OldTTP,
             OldTTP->getTemplateParameters(), Complain,
             (Kind == Sema::TPL_TemplateMatch
                  ? Sema::TPL_TemplateTemplateParmMatch
@@ -8388,8 +8390,8 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
 }
 
 bool Sema::TemplateParameterListsAreEqual(
-    const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
-    const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+    const Decl *NewInstFrom, TemplateParameterList *New,
+    const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
     TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
   if (Old->size() != New->size()) {
     if (Complain)
@@ -8771,7 +8773,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
     Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
     SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
     TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
-    MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) {
+    MultiTemplateParamsArg &TemplateParameterLists, SkipBodyInfo *SkipBody) {
   assert(TUK != TagUseKind::Reference && "References are not specializations");
 
   SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc;
@@ -8969,15 +8971,13 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
     Specialization = ClassTemplateSpecializationDecl::Create(
         Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
         ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
-    Specialization->setTemplateArgsAsWritten(TemplateArgs);
-    SetNestedNameSpecifier(*this, Specialization, SS);
-    if (TemplateParameterLists.size() > 0) {
-      Specialization->setTemplateParameterListsInfo(Context,
-                                                    TemplateParameterLists);
-    }
 
     if (!PrevDecl)
       ClassTemplate->AddSpecialization(Specialization, InsertPos);
+
+    Specialization->setExplicitSpecializationInfo(
+        TemplateParams,
+        ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
   } else {
     CanQualType CanonType = CanQualType::CreateUnsafe(
         Context.getCanonicalTemplateSpecializationType(
@@ -9013,13 +9013,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
     ClassTemplatePartialSpecializationDecl *Partial =
         ClassTemplatePartialSpecializationDecl::Create(
             Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
+            ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
             ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial);
-    Partial->setTemplateArgsAsWritten(TemplateArgs);
-    SetNestedNameSpecifier(*this, Partial, SS);
-    if (TemplateParameterLists.size() > 1 && SS.isSet()) {
-      Partial->setTemplateParameterListsInfo(
-          Context, TemplateParameterLists.drop_back(1));
-    }
 
     if (!PrevPartial)
       ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -9029,10 +9024,18 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
     // template specialization, make a note of that.
     if (PrevPartial && PrevPartial->getInstantiatedFromMember())
       PrevPartial->setMemberSpecialization();
+  }
 
-    CheckTemplatePartialSpecialization(Partial);
+  SetNestedNameSpecifier(*this, Specialization, SS);
+  if (TemplateParameterLists.size() > 1 && SS.isSet()) {
+    Specialization->setTemplateParameterListsInfo(
+        Context, TemplateParameterLists.drop_back(1));
   }
 
+  if (isPartialSpecialization)
+    CheckTemplatePartialSpecialization(
+        cast<ClassTemplatePartialSpecializationDecl>(Specialization));
+
   // C++ [temp.expl.spec]p6:
   //   If a template, a member template or the member of a class template is
   //   explicitly specialized then that specialization shall be declared
@@ -9392,6 +9395,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
   switch (NewTSK) {
   case TSK_Undeclared:
   case TSK_ImplicitInstantiation:
+  case TSK_FriendDeclaration:
     assert(
         (PrevTSK == TSK_Undeclared || PrevTSK == TSK_ImplicitInstantiation) &&
         "previous declaration must be implicit!");
@@ -9406,6 +9410,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
       // instantiation.
       return false;
 
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
       if (PrevPointOfInstantiation.isInvalid()) {
         // The declaration itself has not actually been instantiated, so it is
@@ -9452,6 +9457,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
       return false;
 
     case TSK_Undeclared:
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
       // We're explicitly instantiating something that may have already been
       // implicitly instantiated; that's fine.
@@ -9487,6 +9493,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
   case TSK_ExplicitInstantiationDefinition:
     switch (PrevTSK) {
     case TSK_Undeclared:
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
       // We're explicitly instantiating something that may have already been
       // implicitly instantiated; that's fine.
@@ -9546,7 +9553,8 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
 }
 
 bool Sema::CheckDependentFunctionTemplateSpecialization(
-    FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
+    FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+    const TemplateArgumentListInfo *ExplicitTemplateArgs,
     LookupResult &Previous) {
   // Remove anything from Previous that isn't a function template in
   // the correct context.
@@ -9583,13 +9591,14 @@ bool Sema::CheckDependentFunctionTemplateSpecialization(
   }
 
   FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
-                                         ExplicitTemplateArgs);
+                                         TemplateParams, ExplicitTemplateArgs);
   return false;
 }
 
 bool Sema::CheckFunctionTemplateSpecialization(
-    FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
-    LookupResult &Previous, bool QualifiedFriend) {
+    FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+    TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
+    bool QualifiedFriend) {
   // The set of function template specializations that could match this
   // explicit function template specialization.
   UnresolvedSet<8> Candidates;
@@ -9840,7 +9849,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
       Context, Specialization->getTemplateSpecializationArgs()->asArray());
   FD->setFunctionTemplateSpecialization(
       Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
-      SpecInfo->getTemplateSpecializationKind(),
+      SpecInfo->getTemplateSpecializationKind(), TemplateParams,
       ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr);
 
   // A function template specialization inherits the target attributes
@@ -9991,14 +10000,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
   // FIXME: Is this really valid? Other compilers reject.
   if (Member->getFriendObjectKind() != Decl::FOK_None) {
     // Preserve instantiation information.
-    if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
-      cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
-                                      cast<CXXMethodDecl>(InstantiatedFrom),
-        cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
-    } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
-      cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
-                                      cast<CXXRecordDecl>(InstantiatedFrom),
-        cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind());
+    if (InstantiatedFrom) {
+      if (auto *MD = dyn_cast<CXXMethodDecl>(Member))
+        MD->setInstantiationOfMemberFunction(
+            cast<CXXMethodDecl>(InstantiatedFrom), TSK_FriendDeclaration);
+      else if (auto *RD = dyn_cast<CXXRecordDecl>(Member))
+        RD->setInstantiationOfMemberClass(cast<CXXRecordDecl>(InstantiatedFrom),
+                                          TSK_FriendDeclaration);
     }
 
     Previous.clear();
@@ -10085,7 +10093,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
 template<typename DeclT>
 static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
                                              SourceLocation Loc) {
-  if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
+  if (auto Kind = OrigD->getTemplateSpecializationKind();
+      Kind != TSK_ImplicitInstantiation && Kind != TSK_FriendDeclaration)
     return;
 
   // FIXME: Inform AST mutation listeners of this AST mutation.
@@ -10415,7 +10424,6 @@ DeclResult Sema::ActOnExplicitInstantiation(
     Specialization = ClassTemplateSpecializationDecl::Create(
         Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
         ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
-    SetNestedNameSpecifier(*this, Specialization, SS);
 
     // A MSInheritanceAttr attached to the previous declaration must be
     // propagated to the new node prior to instantiation.
@@ -10434,22 +10442,19 @@ DeclResult Sema::ActOnExplicitInstantiation(
     }
   }
 
-  Specialization->setTemplateArgsAsWritten(TemplateArgs);
-
-  // Set source locations for keywords.
-  Specialization->setExternKeywordLoc(ExternLoc);
-  Specialization->setTemplateKeywordLoc(TemplateLoc);
+  Specialization->setExplicitInstantiationInfo(
+      ExternLoc, TemplateLoc,
+      ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
   Specialization->setBraceRange(SourceRange());
 
   bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
   ProcessDeclAttributeList(S, Specialization, Attr);
   ProcessAPINotes(Specialization);
 
-  // Add the explicit instantiation into its lexical context. However,
-  // since explicit instantiations are never found by name lookup, we
-  // just put it into the declaration context directly.
-  Specialization->setLexicalDeclContext(CurContext);
-  CurContext->addDecl(Specialization);
+  // Add the explicit instantiation into its lexical context.
+  auto *LexicalDC = ClassTemplate->getLexicalDeclContext();
+  Specialization->setLexicalDeclContext(LexicalDC);
+  LexicalDC->addDecl(Specialization);
 
   // Syntax is now OK, so return if it has no other effect on semantics.
   if (HasNoEffect) {
@@ -10778,6 +10783,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
   LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
                    /*ObjectType=*/QualType());
 
+  // If the declarator is a template-id, translate the parser's template
+  // argument list into our AST format.
+  bool HasExplicitTemplateArgs = false;
+  TemplateArgumentListInfo TemplateArgs;
+  if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
+    TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
+    HasExplicitTemplateArgs = true;
+  }
+
   if (!R->isFunctionType()) {
     // C++ [temp.explicit]p1:
     //   A [...] static data member of a class template can be explicitly
@@ -10827,7 +10841,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
         return true;
       }
 
-      if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
+      if (!HasExplicitTemplateArgs) {
         // C++1y [temp.explicit]p3:
         //   If the explicit instantiation is for a variable, the unqualified-id
         //   in the declaration shall be a template-id.
@@ -10839,13 +10853,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
         return true;
       }
 
-      // Translate the parser's template argument list into our AST format.
-      TemplateArgumentListInfo TemplateArgs =
-          makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
-
-      DeclResult Res =
-          CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
-                             TemplateArgs, /*SetWrittenArgs=*/true);
+      DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
+                                          D.getIdentifierLoc(), TemplateArgs);
       if (Res.isInvalid())
         return true;
 
@@ -10893,8 +10902,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
       // Instantiate static data member or variable template.
       Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
       if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Prev)) {
-        VTSD->setExternKeywordLoc(ExternLoc);
-        VTSD->setTemplateKeywordLoc(TemplateLoc);
+        assert(HasExplicitTemplateArgs);
+        VTSD->setExplicitInstantiationInfo(
+            ExternLoc, TemplateLoc,
+            ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
       }
 
       // Merge attributes.
@@ -10923,15 +10934,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     return (Decl *)nullptr;
   }
 
-  // If the declarator is a template-id, translate the parser's template
-  // argument list into our AST format.
-  bool HasExplicitTemplateArgs = false;
-  TemplateArgumentListInfo TemplateArgs;
-  if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
-    TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
-    HasExplicitTemplateArgs = true;
-  }
-
   // C++ [temp.explicit]p1:
   //   A [...] function [...] can be explicitly instantiated from its template.
   //   A member function [...] of a class template can be explicitly
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1544fd56b82ae..b9226894b2c28 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3184,36 +3184,16 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
                                 ArrayRef<TemplateArgument> CanonicalDeducedArgs,
                                 TemplateDeductionInfo &Info) {
   llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
-  bool DeducedArgsNeedReplacement = false;
-  if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) {
+  if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
     TD->getAssociatedConstraints(AssociatedConstraints);
-    DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
-  } else if (auto *TD =
-                 dyn_cast<VarTemplatePartialSpecializationDecl>(Template)) {
+  else if (auto *TD = dyn_cast<VarTemplatePartialSpecializationDecl>(Template))
     TD->getAssociatedConstraints(AssociatedConstraints);
-    DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
-  } else {
+  else
     cast<TemplateDecl>(Template)->getAssociatedConstraints(
         AssociatedConstraints);
-  }
-
-  std::optional<ArrayRef<TemplateArgument>> Innermost;
-  // If we don't need to replace the deduced template arguments,
-  // we can add them immediately as the inner-most argument list.
-  if (!DeducedArgsNeedReplacement)
-    Innermost = SugaredDeducedArgs;
 
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      Template, Template->getDeclContext(), /*Final=*/false, Innermost,
-      /*RelativeToPrimary=*/true, /*Pattern=*/
-      nullptr, /*ForConstraintInstantiation=*/true);
-
-  // getTemplateInstantiationArgs picks up the non-deduced version of the
-  // template args when this is a variable template partial specialization and
-  // not class-scope explicit specialization, so replace with Deduced Args
-  // instead of adding to inner-most.
-  if (!Innermost)
-    MLTAL.replaceInnermostTemplateArguments(Template, SugaredDeducedArgs);
+  MultiLevelTemplateArgumentList MLTAL =
+      S.getTemplateInstantiationArgs(Template, SugaredDeducedArgs);
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
@@ -3974,9 +3954,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
   if (!IsLambda && !IsIncomplete) {
     if (CheckFunctionTemplateConstraints(
-            Info.getLocation(),
-            FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
-            CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
+            Info.getLocation(), FunctionTemplate, CTAI.CanonicalConverted,
+            Info.AssociatedConstraintsSatisfaction))
       return TemplateDeductionResult::MiscellaneousDeductionFailure;
     if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
       Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
@@ -4022,8 +4001,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   //   ([temp.constr.constr]). If the constraints are not satisfied, type
   //   deduction fails.
   if (IsLambda && !IsIncomplete) {
-    if (CheckFunctionTemplateConstraints(
-            Info.getLocation(), Specialization, CTAI.CanonicalConverted,
+    if (CheckFunctionSpecializationConstraints(
+            Info.getLocation(), Specialization,
             Info.AssociatedConstraintsSatisfaction))
       return TemplateDeductionResult::MiscellaneousDeductionFailure;
 
@@ -6030,7 +6009,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
   //   function parameters that positionally correspond between the two
   //   templates are not of the same type, neither template is more specialized
   //   than the other.
-  if (!TemplateParameterListsAreEqual(TPL1, TPL2, false,
+  if (!TemplateParameterListsAreEqual(FT1, TPL1, FT2, TPL2, false,
                                       Sema::TPL_TemplateParamsEquivalent))
     return nullptr;
 
@@ -6385,7 +6364,7 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
   // function parameters that positionally correspond between the two
   // templates are not of the same type, neither template is more specialized
   // than the other.
-  if (!S.TemplateParameterListsAreEqual(TPL1, TPL2, false,
+  if (!S.TemplateParameterListsAreEqual(P1, TPL1, P2, TPL2, false,
                                         Sema::TPL_TemplateParamsEquivalent))
     return nullptr;
 
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index fa740d5581e5f..15b6aea749584 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -65,10 +65,9 @@ static bool HaveSameAssociatedConstraints(
     return true;
 
   // General case: pairwise compare each associated constraint expression.
-  Sema::TemplateCompareNewDeclInfo NewInfo(New);
   for (size_t I = 0, E = OldACs.size(); I != E; ++I)
-    if (!SemaRef.AreConstraintExpressionsEqual(
-            Old, OldACs[I].ConstraintExpr, NewInfo, NewACs[I].ConstraintExpr))
+    if (!SemaRef.AreConstraintExpressionsEqual(Old, OldACs[I].ConstraintExpr,
+                                               New, NewACs[I].ConstraintExpr))
       return false;
 
   return true;
@@ -503,6 +502,7 @@ struct ConvertConstructorToDeductionGuideTransform {
       : SemaRef(S), Template(Template) {
     // If the template is nested, then we need to use the original
     // pattern to iterate over the constructors.
+    // FIXME: Should this just use getTemplateInstantiationPattern?
     ClassTemplateDecl *Pattern = Template;
     while (Pattern->getInstantiatedFromMemberTemplate()) {
       if (Pattern->isMemberSpecialization())
@@ -510,9 +510,9 @@ struct ConvertConstructorToDeductionGuideTransform {
       Pattern = Pattern->getInstantiatedFromMemberTemplate();
       NestedPattern = Pattern;
     }
-
     if (NestedPattern)
-      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
+      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(
+          Decl::castFromDeclContext(Template->getDeclContext()));
   }
 
   Sema &SemaRef;
@@ -1053,52 +1053,9 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
     }
   }
 
-  // A list of template arguments for transforming the require-clause of F.
-  // It must contain the entire set of template argument lists.
-  MultiLevelTemplateArgumentList ArgsForBuildingRC;
+  MultiLevelTemplateArgumentList ArgsForBuildingRC =
+      SemaRef.getTemplateInstantiationArgs(F, TemplateArgsForBuildingRC);
   ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
-  ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
-  // For 2), if the underlying deduction guide F is nested in a class template,
-  // we need the entire template argument list, as the constraint AST in the
-  // require-clause of F remains completely uninstantiated.
-  //
-  // For example:
-  //   template <typename T> // depth 0
-  //   struct Outer {
-  //      template <typename U>
-  //      struct Foo { Foo(U); };
-  //
-  //      template <typename U> // depth 1
-  //      requires C<U>
-  //      Foo(U) -> Foo<int>;
-  //   };
-  //   template <typename U>
-  //   using AFoo = Outer<int>::Foo<U>;
-  //
-  // In this scenario, the deduction guide for `Foo` inside `Outer<int>`:
-  //   - The occurrence of U in the require-expression is [depth:1, index:0]
-  //   - The occurrence of U in the function parameter is [depth:0, index:0]
-  //   - The template parameter of U is [depth:0, index:0]
-  //
-  // We add the outer template arguments which is [int] to the multi-level arg
-  // list to ensure that the occurrence U in `C<U>` will be replaced with int
-  // during the substitution.
-  //
-  // NOTE: The underlying deduction guide F is instantiated -- either from an
-  // explicitly-written deduction guide member, or from a constructor.
-  // getInstantiatedFromMemberTemplate() can only handle the former case, so we
-  // check the DeclContext kind.
-  if (F->getLexicalDeclContext()->getDeclKind() ==
-      clang::Decl::ClassTemplateSpecialization) {
-    auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
-        F, F->getLexicalDeclContext(),
-        /*Final=*/false, /*Innermost=*/std::nullopt,
-        /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
-        /*ForConstraintInstantiation=*/true);
-    for (auto It : OuterLevelArgs)
-      ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
-  }
 
   ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
   if (E.isInvalid())
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index f168c99d1ac1a..7a74f53f7a107 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -49,38 +49,6 @@ using namespace sema;
 //===----------------------------------------------------------------------===/
 
 namespace {
-namespace TemplateInstArgsHelpers {
-struct Response {
-  const Decl *NextDecl = nullptr;
-  bool IsDone = false;
-  bool ClearRelativeToPrimary = true;
-  static Response Done() {
-    Response R;
-    R.IsDone = true;
-    return R;
-  }
-  static Response ChangeDecl(const Decl *ND) {
-    Response R;
-    R.NextDecl = ND;
-    return R;
-  }
-  static Response ChangeDecl(const DeclContext *Ctx) {
-    Response R;
-    R.NextDecl = Decl::castFromDeclContext(Ctx);
-    return R;
-  }
-
-  static Response UseNextDecl(const Decl *CurDecl) {
-    return ChangeDecl(CurDecl->getDeclContext());
-  }
-
-  static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
-    Response R = Response::UseNextDecl(CurDecl);
-    R.ClearRelativeToPrimary = false;
-    return R;
-  }
-};
-
 // Retrieve the primary template for a lambda call operator. It's
 // unfortunate that we only have the mappings of call operators rather
 // than lambda classes.
@@ -168,397 +136,197 @@ bool isLambdaEnclosedByTypeAliasDecl(
               .TraverseType(Underlying);
 }
 
-// Add template arguments from a variable template instantiation.
-Response
-HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
-                      MultiLevelTemplateArgumentList &Result,
-                      bool SkipForSpecialization) {
-  // For a class-scope explicit specialization, there are no template arguments
-  // at this level, but there may be enclosing template arguments.
-  if (VarTemplSpec->isClassScopeExplicitSpecialization())
-    return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
-
-  // We're done when we hit an explicit specialization.
-  if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
-      !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec))
-    return Response::Done();
-
-  // If this variable template specialization was instantiated from a
-  // specialized member that is a variable template, we're done.
-  assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?");
-  llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
-      Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
-  if (VarTemplatePartialSpecializationDecl *Partial =
-          dyn_cast<VarTemplatePartialSpecializationDecl *>(Specialized)) {
-    if (!SkipForSpecialization)
-      Result.addOuterTemplateArguments(
-          Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
-    if (Partial->isMemberSpecialization())
-      return Response::Done();
-  } else {
-    VarTemplateDecl *Tmpl = cast<VarTemplateDecl *>(Specialized);
-    if (!SkipForSpecialization)
-      Result.addOuterTemplateArguments(
-          Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
-    if (Tmpl->isMemberSpecialization())
-      return Response::Done();
-  }
-  return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
-}
-
-// If we have a template template parameter with translation unit context,
-// then we're performing substitution into a default template argument of
-// this template template parameter before we've constructed the template
-// that will own this template template parameter. In this case, we
-// use empty template parameter lists for all of the outer templates
-// to avoid performing any substitutions.
-Response
-HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
-                                      MultiLevelTemplateArgumentList &Result) {
-  for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
-    Result.addOuterTemplateArguments(std::nullopt);
-  return Response::Done();
-}
-
-Response HandlePartialClassTemplateSpec(
-    const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
-    MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
-  if (!SkipForSpecialization)
-    Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
-  return Response::Done();
-}
-
-// Add template arguments from a class template instantiation.
-Response
-HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
-                        MultiLevelTemplateArgumentList &Result,
-                        bool SkipForSpecialization) {
-  if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
-    // We're done when we hit an explicit specialization.
-    if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
-        !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
-      return Response::Done();
-
-    if (!SkipForSpecialization)
-      Result.addOuterTemplateArguments(
-          const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
-          ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
-
-    // If this class template specialization was instantiated from a
-    // specialized member that is a class template, we're done.
-    assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
-    if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
-      return Response::Done();
-
-    // If this was instantiated from a partial template specialization, we need
-    // to get the next level of declaration context from the partial
-    // specialization, as the ClassTemplateSpecializationDecl's
-    // DeclContext/LexicalDeclContext will be for the primary template.
-    if (auto *InstFromPartialTempl =
-            ClassTemplSpec->getSpecializedTemplateOrPartial()
-                .dyn_cast<ClassTemplatePartialSpecializationDecl *>())
-      return Response::ChangeDecl(
-          InstFromPartialTempl->getLexicalDeclContext());
-  }
-  return Response::UseNextDecl(ClassTemplSpec);
-}
+} // namespace
 
-Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
-                        MultiLevelTemplateArgumentList &Result,
-                        const FunctionDecl *Pattern, bool RelativeToPrimary,
-                        bool ForConstraintInstantiation,
-                        bool ForDefaultArgumentSubstitution) {
-  // Add template arguments from a function template specialization.
-  if (!RelativeToPrimary &&
-      Function->getTemplateSpecializationKindForInstantiation() ==
-          TSK_ExplicitSpecialization)
-    return Response::Done();
-
-  if (!RelativeToPrimary &&
-      Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
-    // This is an implicit instantiation of an explicit specialization. We
-    // don't get any template arguments from this function but might get
-    // some from an enclosing template.
-    return Response::UseNextDecl(Function);
-  } else if (const TemplateArgumentList *TemplateArgs =
-                 Function->getTemplateSpecializationArgs()) {
-    // Add the template arguments for this specialization.
-    Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
-                                     TemplateArgs->asArray(),
-                                     /*Final=*/false);
-
-    if (RelativeToPrimary &&
-        (Function->getTemplateSpecializationKind() ==
-             TSK_ExplicitSpecialization ||
-         (Function->getFriendObjectKind() &&
-          !Function->getPrimaryTemplate()->getFriendObjectKind())))
-      return Response::UseNextDecl(Function);
-
-    // If this function was instantiated from a specialized member that is
-    // a function template, we're done.
-    assert(Function->getPrimaryTemplate() && "No function template?");
-    if (!ForDefaultArgumentSubstitution &&
-        Function->getPrimaryTemplate()->isMemberSpecialization())
-      return Response::Done();
-
-    // If this function is a generic lambda specialization, we are done.
-    if (!ForConstraintInstantiation &&
-        isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
-      return Response::Done();
-
-  } else if (auto *Template = Function->getDescribedFunctionTemplate()) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "Outer template not instantiated?");
-    if (ForConstraintInstantiation) {
-      for (auto &Inst : llvm::reverse(SemaRef.CodeSynthesisContexts)) {
-        if (Inst.Kind == Sema::CodeSynthesisContext::ConstraintsCheck &&
-            Inst.Entity == Template) {
-          // After CWG2369, the outer templates are not instantiated when
-          // checking its associated constraints. So add them back through the
-          // synthesis context; this is useful for e.g. nested constraints
-          // involving lambdas.
-          Result.addOuterTemplateArguments(Template, Inst.template_arguments(),
-                                           /*Final=*/false);
-          break;
+MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
+    const Decl *D, std::optional<ArrayRef<TemplateArgument>> Innermost,
+    UnsignedOrNone NumLevels, bool SkipInnerNonInstantiated) {
+  MultiLevelTemplateArgumentList TemplateArgs;
+
+  // The scope being followed for an out-of-line-definition.
+  NestedNameSpecifier Qualifier = std::nullopt;
+  ArrayRef<TemplateParameterList *> TPLs;
+
+  while (!NumLevels || *NumLevels != 0U) {
+    bool Final = false;
+    if (const TemplateParameterList *TPL =
+            isa<TemplateDecl>(D)
+                ? cast<TemplateDecl>(D)->getTemplateParameters()
+                : D->getDescribedTemplateParams()) {
+      // Template-like entities should always produce a final substitution
+      // level, as they shouldn't be transformed again.
+      Final = true;
+      // If Innermost is provided, use that as the template arguments.
+      if (!Innermost)
+        Innermost = TPL->getInjectedTemplateArgs(Context);
+      else
+        SkipInnerNonInstantiated = false;
+    } else {
+      assert(!Innermost &&
+             "Shouldn't provide innermost for a non-template-like declaration");
+
+      if (isa<ClassTemplateSpecializationDecl, VarTemplateSpecializationDecl>(
+              D)) {
+        auto specCase = [&](const auto *ND) {
+          if (ND->getSpecializationKind() == TSK_ExplicitSpecialization) {
+            assert(TPLs.empty());
+            return;
+          }
+          SkipInnerNonInstantiated = false;
+          Innermost = ND->getTemplateInstantiationArgs().asArray();
+        };
+        if (isa<ClassTemplateSpecializationDecl>(D))
+          specCase(cast<ClassTemplateSpecializationDecl>(D));
+        else
+          specCase(cast<VarTemplateSpecializationDecl>(D));
+      } else if (isa<ImplicitConceptSpecializationDecl>(D)) {
+        SkipInnerNonInstantiated = false;
+        Innermost =
+            cast<ImplicitConceptSpecializationDecl>(D)->getTemplateArguments();
+        Final = true;
+      } else if (const auto *ND = dyn_cast<FunctionDecl>(D)) {
+        const FunctionTemplateSpecializationInfo *Info =
+            ND->getTemplateSpecializationInfo();
+        if (!Info || Info->getTemplateSpecializationKind() ==
+                         TSK_ExplicitSpecialization) {
+          assert(TPLs.empty());
+        } else {
+          SkipInnerNonInstantiated = false;
+          Innermost = Info->TemplateArguments->asArray();
         }
+      } else if (const auto *ND = dyn_cast<CXXRecordDecl>(D);
+                 ND && ND->isLambda()) {
+        assert(TPLs.empty() &&
+               "lambdas can't be part of an out-of-line definition");
+        // FIXME: If this lambda is enclosed by a type alias template, look
+        // into the current CodeSynthesisContexts to find the template
+        // arguments used to specialize it.
+        if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
+            TypeAlias &&
+            isLambdaEnclosedByTypeAliasDecl(ND->getLambdaCallOperator(),
+                                            TypeAlias.PrimaryTypeAliasDecl)) {
+          Innermost = TypeAlias.AssociatedTemplateArguments;
+          Final = true;
+          D = TypeAlias.Template;
+          continue;
+        }
+        if (const Decl *LCD = ND->getLambdaContextDecl()) {
+          D = LCD;
+          continue;
+        }
+      } else if (isa<TranslationUnitDecl, NamespaceBaseDecl, ExportDecl,
+                     LinkageSpecDecl>(D)) {
+        // The end of the line, there can't be any template arguments further.
+        assert(TPLs.empty());
+        assert(!NumLevels && "Declaration had less levels than expected");
+        return TemplateArgs;
       }
     }
-  }
-  // If this is a friend or local declaration and it declares an entity at
-  // namespace scope, take arguments from its lexical parent
-  // instead of its semantic parent, unless of course the pattern we're
-  // instantiating actually comes from the file's context!
-  if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
-      Function->getNonTransparentDeclContext()->isFileContext() &&
-      (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
-    return Response::ChangeDecl(Function->getLexicalDeclContext());
-  }
-
-  if (ForConstraintInstantiation && Function->getFriendObjectKind())
-    return Response::ChangeDecl(Function->getLexicalDeclContext());
-  return Response::UseNextDecl(Function);
-}
-
-Response HandleFunctionTemplateDecl(Sema &SemaRef,
-                                    const FunctionTemplateDecl *FTD,
-                                    MultiLevelTemplateArgumentList &Result) {
-  if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
-    Result.addOuterTemplateArguments(
-        const_cast<FunctionTemplateDecl *>(FTD),
-        const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(
-            SemaRef.Context),
-        /*Final=*/false);
-
-    NestedNameSpecifier NNS = FTD->getTemplatedDecl()->getQualifier();
-
-    for (const Type *Ty = NNS.getKind() == NestedNameSpecifier::Kind::Type
-                              ? NNS.getAsType()
-                              : nullptr,
-                    *NextTy = nullptr;
-         Ty && Ty->isInstantiationDependentType();
-         Ty = std::exchange(NextTy, nullptr)) {
-      if (NestedNameSpecifier P = Ty->getPrefix();
-          P.getKind() == NestedNameSpecifier::Kind::Type)
-        NextTy = P.getAsType();
-      const auto *TSTy = dyn_cast<TemplateSpecializationType>(Ty);
-      if (!TSTy)
-        continue;
 
-      ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
-      // Prefer template arguments from the injected-class-type if possible.
-      // For example,
-      // ```cpp
-      // template <class... Pack> struct S {
-      //   template <class T> void foo();
-      // };
-      // template <class... Pack> template <class T>
-      //           ^^^^^^^^^^^^^ InjectedTemplateArgs
-      //           They're of kind TemplateArgument::Pack, not of
-      //           TemplateArgument::Type.
-      // void S<Pack...>::foo() {}
-      //        ^^^^^^^
-      //        TSTy->template_arguments() (which are of PackExpansionType)
-      // ```
-      // This meets the contract in
-      // TreeTransform::TryExpandParameterPacks that the template arguments
-      // for unexpanded parameters should be of a Pack kind.
-      if (TSTy->isCurrentInstantiation()) {
-        auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
-        if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
-          Arguments = CTD->getInjectedTemplateArgs(SemaRef.Context);
-        else if (auto *Specialization =
-                     dyn_cast<ClassTemplateSpecializationDecl>(RD))
-          Arguments = Specialization->getTemplateInstantiationArgs().asArray();
+    const Decl *CurDecl = D;
+
+    // There is either a current qualifier for an out-of-line definition being
+    // followed, in which case it should be advanced, or the next qualifier
+    // and template parameter listss should be retrieved from the current
+    // declaration, if any.
+    bool InOutOfLineDefinition = Qualifier != std::nullopt;
+    switch (Qualifier.getKind()) {
+    case NestedNameSpecifier::Kind::Null: {
+      // Get the current qualifier and template parameter lists.
+      assert(TPLs.empty());
+      if (auto *TD = dyn_cast<TemplateDecl>(D)) {
+        D = TD->getTemplatedDecl();
+        // One of the template entities which doesn't have a templated decl.
+        if (!D)
+          break;
       }
-      Result.addOuterTemplateArguments(
-          TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
-          /*Final=*/false);
-    }
-  }
-
-  return Response::ChangeDecl(FTD->getLexicalDeclContext());
-}
-
-Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
-                          MultiLevelTemplateArgumentList &Result,
-                          ASTContext &Context,
-                          bool ForConstraintInstantiation) {
-  if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "Outer template not instantiated?");
-    if (ClassTemplate->isMemberSpecialization())
-      return Response::Done();
-    if (ForConstraintInstantiation)
-      Result.addOuterTemplateArguments(
-          const_cast<CXXRecordDecl *>(Rec),
-          ClassTemplate->getInjectedTemplateArgs(SemaRef.Context),
-          /*Final=*/false);
-  }
-
-  if (const MemberSpecializationInfo *MSInfo =
-          Rec->getMemberSpecializationInfo())
-    if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-      return Response::Done();
-
-  bool IsFriend = Rec->getFriendObjectKind() ||
-                  (Rec->getDescribedClassTemplate() &&
-                   Rec->getDescribedClassTemplate()->getFriendObjectKind());
-  if (ForConstraintInstantiation && IsFriend &&
-      Rec->getNonTransparentDeclContext()->isFileContext()) {
-    return Response::ChangeDecl(Rec->getLexicalDeclContext());
-  }
-
-  // This is to make sure we pick up the VarTemplateSpecializationDecl or the
-  // TypeAliasTemplateDecl that this lambda is defined inside of.
-  if (Rec->isLambda()) {
-    if (const Decl *LCD = Rec->getLambdaContextDecl())
-      return Response::ChangeDecl(LCD);
-    // Retrieve the template arguments for a using alias declaration.
-    // This is necessary for constraint checking, since we always keep
-    // constraints relative to the primary template.
-    if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
-        ForConstraintInstantiation && TypeAlias) {
-      if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
-                                          TypeAlias.PrimaryTypeAliasDecl)) {
-        Result.addOuterTemplateArguments(TypeAlias.Template,
-                                         TypeAlias.AssociatedTemplateArguments,
-                                         /*Final=*/false);
-        // Visit the parent of the current type alias declaration rather than
-        // the lambda thereof.
-        // E.g., in the following example:
-        // struct S {
-        //  template <class> using T = decltype([]<Concept> {} ());
-        // };
-        // void foo() {
-        //   S::T var;
-        // }
-        // The instantiated lambda expression (which we're visiting at 'var')
-        // has a function DeclContext 'foo' rather than the Record DeclContext
-        // S. This seems to be an oversight to me that we may want to set a
-        // Sema Context from the CXXScopeSpec before substituting into T.
-        return Response::ChangeDecl(TypeAlias.Template->getDeclContext());
+      if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
+        TPLs = DD->getTemplateParameterLists();
+        Qualifier = DD->getQualifier();
+      } else if (const auto *TD = dyn_cast<TagDecl>(D)) {
+        TPLs = TD->getTemplateParameterLists();
+        Qualifier = TD->getQualifier();
       }
+      assert((Qualifier || TPLs.empty()) &&
+             "template parameter lists without qualifier");
+      break;
+    }
+    case NestedNameSpecifier::Kind::Namespace:
+    case NestedNameSpecifier::Kind::Global:
+      llvm_unreachable("handled above");
+    case NestedNameSpecifier::Kind::Type:
+      Qualifier = Qualifier.getAsType()->getPrefix();
+      break;
+    case NestedNameSpecifier::Kind::MicrosoftSuper:
+      Qualifier = std::nullopt;
+      break;
     }
-  }
 
-  return Response::UseNextDecl(Rec);
-}
+    // Get the next declaration from the current qualifier.
+    switch (Qualifier.getKind()) {
+    case NestedNameSpecifier::Kind::Null:
+      // If there is no qualifier, the template context always follows
+      // lexically.
+      D = Decl::castFromDeclContext(CurDecl->getLexicalDeclContext());
+      break;
+    case NestedNameSpecifier::Kind::Namespace:
+    case NestedNameSpecifier::Kind::Global:
+      // Skip namespace, as they are never templated.
+      D = Context.getTranslationUnitDecl();
+      break;
+    case NestedNameSpecifier::Kind::Type:
+      if (const Type *T = Qualifier.getAsType();
+          const auto *TT = T->getAs<TagType>())
+        D = TT->getDecl();
+      else if (const auto *TST = T->getAsNonAliasTemplateSpecializationType())
+        D = TST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true);
+      else
+        llvm_unreachable("unexpected type kind");
+      break;
+    case NestedNameSpecifier::Kind::MicrosoftSuper:
+      D = Qualifier.getAsMicrosoftSuper();
+      break;
+    }
 
-Response HandleImplicitConceptSpecializationDecl(
-    const ImplicitConceptSpecializationDecl *CSD,
-    MultiLevelTemplateArgumentList &Result) {
-  Result.addOuterTemplateArguments(
-      const_cast<ImplicitConceptSpecializationDecl *>(CSD),
-      CSD->getTemplateArguments(),
-      /*Final=*/false);
-  return Response::UseNextDecl(CSD);
-}
+    if (!Innermost)
+      continue;
 
-Response HandleGenericDeclContext(const Decl *CurDecl) {
-  return Response::UseNextDecl(CurDecl);
-}
-} // namespace TemplateInstArgsHelpers
-} // namespace
+    auto DeclArgs = *std::exchange(Innermost, std::nullopt);
+    assert(!DeclArgs.empty());
+
+    if (InOutOfLineDefinition) {
+      // There either may or may not be a template parameter list corresponding
+      // to the current qualifier chunk.
+      // A template level only exists where there is a non-empty template
+      // parameter list. Explicit specializations, ie `template <>` are never a
+      // template level.
+      TemplateParameterList *TPL =
+          !TPLs.empty() ? TPLs.consume_back() : nullptr;
+      if (!TPL || TPL->empty())
+        continue;
+    }
 
-MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
-    const NamedDecl *ND, const DeclContext *DC, bool Final,
-    std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
-    const FunctionDecl *Pattern, bool ForConstraintInstantiation,
-    bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
-  assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
-  // Accumulate the set of template argument lists in this structure.
-  MultiLevelTemplateArgumentList Result;
-
-  using namespace TemplateInstArgsHelpers;
-  const Decl *CurDecl = ND;
-
-  if (Innermost) {
-    Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
-                                     Final);
-    // Populate placeholder template arguments for TemplateTemplateParmDecls.
-    // This is essential for the case e.g.
-    //
-    // template <class> concept Concept = false;
-    // template <template <Concept C> class T> void foo(T<int>)
-    //
-    // where parameter C has a depth of 1 but the substituting argument `int`
-    // has a depth of 0.
-    if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
-      HandleDefaultTempArgIntoTempTempParam(TTP, Result);
-    CurDecl = DC ? Decl::castFromDeclContext(DC)
-                 : Response::UseNextDecl(CurDecl).NextDecl;
-  } else if (!CurDecl)
-    CurDecl = Decl::castFromDeclContext(DC);
-
-  while (!CurDecl->isFileContextDecl()) {
-    Response R;
-    if (const auto *VarTemplSpec =
-            dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
-      R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization);
-    } else if (const auto *PartialClassTemplSpec =
-                   dyn_cast<ClassTemplatePartialSpecializationDecl>(CurDecl)) {
-      R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result,
-                                         SkipForSpecialization);
-    } else if (const auto *ClassTemplSpec =
-                   dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
-      R = HandleClassTemplateSpec(ClassTemplSpec, Result,
-                                  SkipForSpecialization);
-    } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
-      R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
-                         ForConstraintInstantiation,
-                         ForDefaultArgumentSubstitution);
-    } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
-      R = HandleRecordDecl(*this, Rec, Result, Context,
-                           ForConstraintInstantiation);
-    } else if (const auto *CSD =
-                   dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
-      R = HandleImplicitConceptSpecializationDecl(CSD, Result);
-    } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) {
-      R = HandleFunctionTemplateDecl(*this, FTD, Result);
-    } else if (const auto *CTD = dyn_cast<ClassTemplateDecl>(CurDecl)) {
-      R = Response::ChangeDecl(CTD->getLexicalDeclContext());
-    } else if (!isa<DeclContext>(CurDecl)) {
-      R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
-      if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
-        R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
+    if (!SkipInnerNonInstantiated)
+      TemplateArgs.addOuterTemplateArguments(const_cast<Decl *>(CurDecl),
+                                             DeclArgs, Final);
+
+    // A new level was just added. So if there is a level limit, decrement it.
+    if (NumLevels)
+      NumLevels = *NumLevels - 1U;
+
+    // FIXME: Workaround for template template parameters on other template
+    // template parameters and on type alias templates.
+    if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
+      unsigned ExtraLevels = TTP->getDepth() - D->getTemplateDepth() + 1;
+      if (NumLevels) {
+        ExtraLevels = std::min(ExtraLevels, *NumLevels);
+        NumLevels = *NumLevels - ExtraLevels;
       }
-    } else {
-      R = HandleGenericDeclContext(CurDecl);
+      for (unsigned I = 0; I < ExtraLevels; ++I)
+        TemplateArgs.addOuterTemplateArguments(std::nullopt);
     }
-
-    if (R.IsDone)
-      return Result;
-    if (R.ClearRelativeToPrimary)
-      RelativeToPrimary = false;
-    assert(R.NextDecl);
-    CurDecl = R.NextDecl;
   }
-  return Result;
+  return TemplateArgs;
 }
 
 bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@@ -1741,10 +1509,8 @@ namespace {
 
     CXXRecordDecl::LambdaDependencyKind
     ComputeLambdaDependency(LambdaScopeInfo *LSI) {
-      if (auto TypeAlias =
-              TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
-                  getSema());
-          TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+      if (auto TypeAlias = ::getEnclosingTypeAliasTemplateDecl(getSema());
+          TypeAlias && ::isLambdaEnclosedByTypeAliasDecl(
                            LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
         unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
         if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@@ -4082,6 +3848,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
     ClassTemplateSpecializationDecl *ClassTemplateSpec,
     TemplateSpecializationKind TSK, bool Complain,
     bool PrimaryStrictPackMatch) {
+  assert(ClassTemplateSpec->getTemplateDepth() == 0 &&
+         "non-instantiated declaration");
+
   // Perform the actual instantiation on the canonical declaration.
   ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
       ClassTemplateSpec->getCanonicalDecl());
@@ -4105,9 +3874,12 @@ bool Sema::InstantiateClassTemplateSpecialization(
   if (!Pattern.isUsable())
     return Pattern.isInvalid();
 
-  bool Err = InstantiateClassImpl(
-      PointOfInstantiation, ClassTemplateSpec, Pattern.get(),
-      getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);
+  MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+      ClassTemplateSpec, /*Innermost=*/std::nullopt,
+      /*NumLevels=*/Pattern.get()->getTemplateDepth());
+
+  bool Err = InstantiateClassImpl(PointOfInstantiation, ClassTemplateSpec,
+                                  Pattern.get(), TemplateArgs, TSK, Complain);
 
   // If we haven't already warn on avaibility, consider the avaibility
   // attributes of the partial specialization.
@@ -4469,14 +4241,7 @@ ExprResult Sema::SubstConceptTemplateArguments(
       [](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); });
 
   MultiLevelTemplateArgumentList MLTALForConstraint =
-      getTemplateInstantiationArgs(
-          CSE->getNamedConcept(),
-          CSE->getNamedConcept()->getLexicalDeclContext(),
-          /*Final=*/false,
-          /*Innermost=*/NewArgList,
-          /*RelativeToPrimary=*/true,
-          /*Pattern=*/nullptr,
-          /*ForConstraintInstantiation=*/true);
+      getTemplateInstantiationArgs(CSE->getNamedConcept(), NewArgList);
 
   // Rebuild a constraint, only substituting non-dependent concept names
   // and nothing else.
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c9bc613a7c4ea..09bb18b9d62d1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -49,40 +49,63 @@ static bool isDeclWithinFunction(const Decl *D) {
   return false;
 }
 
-template<typename DeclT>
+template <typename DeclT>
 static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl,
-                           const MultiLevelTemplateArgumentList &TemplateArgs) {
-  if (!OldDecl->getQualifierLoc())
-    return false;
+                           const MultiLevelTemplateArgumentList &TemplateArgs,
+                           DeclContext *Owner) {
+  if (auto TPLs = OldDecl->getTemplateParameterLists(); !TPLs.empty()) {
+    SmallVector<TemplateParameterList *, 4> TempParamLists(TPLs.size());
+    MultiLevelTemplateArgumentList MLTAL;
+
+    for (auto I = 0U; I < MLTAL.getNumRetainedOuterLevels(); ++I) {
+      TemplateParameterList *InstParams = SemaRef.SubstTemplateParams(
+          TPLs[I], Owner, MLTAL, /*EvaluateConstraints=*/true);
+      assert(InstParams);
+      TempParamLists[I] = InstParams;
+      MLTAL.addOuterRetainedLevel();
+    }
+
+    auto *It = TemplateArgs.begin();
+    for (unsigned I = 0; I != TPLs.size(); ++I) {
+      TemplateParameterList *InstParams = SemaRef.SubstTemplateParams(
+          TPLs[I], Owner, MLTAL, /*EvaluateConstraints=*/true);
+      assert(InstParams);
+      TempParamLists[I] = InstParams;
+      if (It < TemplateArgs.end()) {
+        auto [DeclAndFinal, Args] = *(It++);
+        MLTAL.addOuterTemplateArguments(DeclAndFinal.getPointer(), Args,
+                                        DeclAndFinal.getInt());
+      }
+    }
+    NewDecl->setTemplateParameterListsInfo(SemaRef.Context, TempParamLists);
+  }
+  if (NestedNameSpecifierLoc QualifierLoc = OldDecl->getQualifierLoc()) {
+    Sema::ContextRAII SavedContext(
+        SemaRef,
+        const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
+                                      ? NewDecl->getLexicalDeclContext()
+                                      : OldDecl->getLexicalDeclContext()));
 
-  assert((NewDecl->getFriendObjectKind() ||
-          !OldDecl->getLexicalDeclContext()->isDependentContext()) &&
-         "non-friend with qualified name defined in dependent context");
-  Sema::ContextRAII SavedContext(
-      SemaRef,
-      const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
-                                    ? NewDecl->getLexicalDeclContext()
-                                    : OldDecl->getLexicalDeclContext()));
-
-  NestedNameSpecifierLoc NewQualifierLoc
-      = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+    NestedNameSpecifierLoc NewQualifierLoc =
+        SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
                                             TemplateArgs);
 
-  if (!NewQualifierLoc)
-    return true;
+    if (!NewQualifierLoc)
+      return true;
 
-  NewDecl->setQualifierInfo(NewQualifierLoc);
+    NewDecl->setQualifierInfo(NewQualifierLoc);
+  }
   return false;
 }
 
 bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
                                               DeclaratorDecl *NewDecl) {
-  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
+  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
 }
 
 bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
                                               TagDecl *NewDecl) {
-  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
+  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
 }
 
 // Include attribute instantiation code.
@@ -1759,10 +1782,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
   return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
 }
 
-Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
-                                             bool InstantiatingVarTemplate,
-                                             ArrayRef<BindingDecl*> *Bindings) {
-
+Decl *
+TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
+                                       bool InstantiatingVarTemplate,
+                                       ArrayRef<BindingDecl *> *Bindings) {
   // Do substitution on the type of the declaration
   TypeSourceInfo *TSI = SemaRef.SubstType(
       D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(),
@@ -2396,8 +2419,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
 
       // Make sure the parameter lists match.
       if (!SemaRef.TemplateParameterListsAreEqual(
-              RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
-              PrevParams, true, Sema::TPL_TemplateMatch))
+              RecordInst, InstParams, MostRecentPrevCT, PrevParams, true,
+              Sema::TPL_TemplateMatch))
         return nullptr;
 
       // Do some additional validation, then merge default arguments
@@ -2755,16 +2778,21 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     }
   }
 
+  FunctionDecl *PrevDecl = nullptr;
   if (FunctionTemplate && !TemplateParams) {
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
 
     void *InsertPos = nullptr;
-    FunctionDecl *SpecFunc
-      = FunctionTemplate->findSpecialization(Innermost, InsertPos);
-
-    // If we already have a function template specialization, return it.
-    if (SpecFunc)
-      return SpecFunc;
+    PrevDecl = FunctionTemplate->findSpecialization(Innermost, InsertPos);
+    if (PrevDecl) {
+      if (PrevDecl->getTemplateSpecializationInfo()->isExplicitSpecialization())
+        return PrevDecl;
+      for (FunctionDecl *F : PrevDecl->redecls())
+        // If we already have a function template specialization for this
+        // function template, return it.
+        if (F->getPrimaryTemplate() == FunctionTemplate)
+          return F;
+    }
   }
 
   bool MergeWithParentScope = (TemplateParams != nullptr) ||
@@ -2857,6 +2885,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         D->FriendConstraintRefersToEnclosingTemplate());
     Function->setRangeEnd(D->getSourceRange().getEnd());
   }
+  Function->setPreviousDeclaration(PrevDecl);
+  if (PrevDecl)
+    SemaRef.mergeDeclAttributes(Function, PrevDecl);
 
   if (D->isInlined())
     Function->setImplicitlyInline();
@@ -2913,6 +2944,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
 
     FunctionTemplate->setLexicalDeclContext(LexicalDC);
 
+    if (PrevDecl)
+      FunctionTemplate->setPreviousDecl(
+          PrevDecl->getDescribedFunctionTemplate());
+
     if (isFriend && D->isThisDeclarationADefinition()) {
       FunctionTemplate->setInstantiatedFromMemberTemplate(
                                            D->getDescribedFunctionTemplate());
@@ -2922,10 +2957,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
                  Sema::CodeSynthesisContext::BuildingDeductionGuides) {
     // Record this function template specialization.
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
-    Function->setFunctionTemplateSpecialization(FunctionTemplate,
-                            TemplateArgumentList::CreateCopy(SemaRef.Context,
-                                                             Innermost),
-                                                /*InsertPos=*/nullptr);
+    Function->setFunctionTemplateSpecialization(
+        FunctionTemplate,
+        TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
+        /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
+        /*TemplateParams=*/nullptr,
+        /*TemplateArgsAsWritten=*/nullptr,
+        /*PointOfInstantiation=*/SourceLocation(),
+        /*AddSpecialization=*/PrevDecl == nullptr);
   } else if (FunctionRewriteKind == RewriteKind::None) {
     if (isFriend && D->isThisDeclarationADefinition()) {
       // Do not connect the friend to the template unless it's actually a
@@ -2983,7 +3022,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     }
 
     if (SemaRef.CheckFunctionTemplateSpecialization(
-            Function,
+            Function, DFTSI->TemplateParameters ? TemplateParams : nullptr,
             DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
             Previous))
       Function->setInvalidDecl();
@@ -3001,9 +3040,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
                                        ExplicitArgs))
       return nullptr;
 
-    if (SemaRef.CheckFunctionTemplateSpecialization(Function,
-                                                    &ExplicitArgs,
-                                                    Previous))
+    if (SemaRef.CheckFunctionTemplateSpecialization(Function, TemplateParams,
+                                                    &ExplicitArgs, Previous))
       Function->setInvalidDecl();
 
     IsExplicitSpecialization = true;
@@ -3120,6 +3158,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     CXXMethodDecl *D, TemplateParameterList *TemplateParams,
     RewriteKind FunctionRewriteKind) {
   FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+
+  FunctionDecl *PrevDecl = nullptr;
   if (FunctionTemplate && !TemplateParams) {
     // We are creating a function template specialization from a function
     // template. Check whether there is already a function template
@@ -3127,12 +3167,16 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
 
     void *InsertPos = nullptr;
-    FunctionDecl *SpecFunc
-      = FunctionTemplate->findSpecialization(Innermost, InsertPos);
-
-    // If we already have a function template specialization, return it.
-    if (SpecFunc)
-      return SpecFunc;
+    PrevDecl = FunctionTemplate->findSpecialization(Innermost, InsertPos);
+    if (PrevDecl) {
+      if (PrevDecl->getTemplateSpecializationInfo()->isExplicitSpecialization())
+        return PrevDecl;
+      for (FunctionDecl *F : PrevDecl->redecls())
+        // If we already have a function template specialization for this
+        // function template, return it.
+        if (F->getPrimaryTemplate() == FunctionTemplate)
+          return F;
+    }
   }
 
   bool isFriend;
@@ -3149,19 +3193,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
   Sema::LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
       SemaRef, D, TemplateArgs, Scope);
 
-  // Instantiate enclosing template arguments for friends.
-  SmallVector<TemplateParameterList *, 4> TempParamLists;
-  ArrayRef<TemplateParameterList *> TPLs = D->getTemplateParameterLists();
-  if (isFriend && !TPLs.empty()) {
-    TempParamLists.resize(TPLs.size());
-    for (unsigned I = 0; I != TPLs.size(); ++I) {
-      TemplateParameterList *InstParams = SubstTemplateParams(TPLs[I]);
-      if (!InstParams)
-        return nullptr;
-      TempParamLists[I] = InstParams;
-    }
-  }
-
   auto InstantiatedExplicitSpecifier = ExplicitSpecifier::getFromDecl(D);
   // deduction guides need this
   const bool CouldInstantiate =
@@ -3287,6 +3318,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
         D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(),
         D->getEndLoc(), TrailingRequiresClause);
   }
+  Method->setPreviousDeclaration(PrevDecl);
+  if (PrevDecl)
+    SemaRef.mergeDeclAttributes(Method, PrevDecl);
 
   if (D->isInlined())
     Method->setImplicitlyInline();
@@ -3318,25 +3352,33 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     } else if (D->isOutOfLine())
       FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
     Method->setDescribedFunctionTemplate(FunctionTemplate);
+
+    if (PrevDecl)
+      FunctionTemplate->setPreviousDecl(
+          PrevDecl->getDescribedFunctionTemplate());
   } else if (FunctionTemplate) {
     // Record this function template specialization.
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
-    Method->setFunctionTemplateSpecialization(FunctionTemplate,
-                         TemplateArgumentList::CreateCopy(SemaRef.Context,
-                                                          Innermost),
-                                              /*InsertPos=*/nullptr);
+    Method->setFunctionTemplateSpecialization(
+        FunctionTemplate,
+        TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
+        /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
+        /*TemplateParams=*/nullptr,
+        /*TemplateArgsAsWritten=*/nullptr,
+        /*PointOfInstantiation=*/SourceLocation(),
+        /*AddSpecialization=*/PrevDecl == nullptr);
   } else if (!isFriend && FunctionRewriteKind == RewriteKind::None) {
     // Record that this is an instantiation of a member function.
     Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
   }
 
+  if (SubstQualifier(D, Method))
+    return nullptr;
+
   // If we are instantiating a member function defined
   // out-of-line, the instantiation will have the same lexical
   // context (which will be a namespace scope) as the template.
   if (isFriend) {
-    if (!TempParamLists.empty())
-      Method->setTemplateParameterListsInfo(SemaRef.Context, TempParamLists);
-
     Method->setLexicalDeclContext(Owner);
     Method->setObjectOfFriendDecl();
   } else if (D->isOutOfLine())
@@ -3379,7 +3421,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     }
 
     if (SemaRef.CheckFunctionTemplateSpecialization(
-            Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
+            Method, DFTSI->TemplateParameters,
+            DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
             Previous))
       Method->setInvalidDecl();
 
@@ -3395,9 +3438,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
                                        ExplicitArgs))
       return nullptr;
 
-    if (SemaRef.CheckFunctionTemplateSpecialization(Method,
-                                                    &ExplicitArgs,
-                                                    Previous))
+    if (SemaRef.CheckFunctionTemplateSpecialization(Method, TemplateParams,
+                                                    &ExplicitArgs, Previous))
       Method->setInvalidDecl();
 
     IsExplicitSpecialization = true;
@@ -4527,16 +4569,22 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
 
   // Substitute into the template arguments of the class template explicit
   // specialization.
+  // The template parameters list for an explicit specialization is always empty
+  // and has no constraints, so there is nothing to substitute.
   TemplateArgumentListInfo InstTemplateArgs;
-  if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
-          D->getTemplateArgsAsWritten()) {
-    InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
-    InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
-
-    if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
-                                       TemplateArgs, InstTemplateArgs))
+  const ExplicitSpecializationInfo *ExplicitSpecInfo =
+      D->getExplicitSpecializationInfo();
+  if (ExplicitSpecInfo) {
+    auto *Args = ExplicitSpecInfo->TemplateArgsAsWritten;
+    InstTemplateArgs.setLAngleLoc(Args->getLAngleLoc());
+    InstTemplateArgs.setRAngleLoc(Args->getRAngleLoc());
+
+    if (SemaRef.SubstTemplateArguments(Args->arguments(), TemplateArgs,
+                                       InstTemplateArgs))
       return nullptr;
   }
+  // Otherwise, an ExplicitInstantiation always occurs in a non-dependent
+  // context, so there is nothing to substitute.
 
   // Check that the template argument list is well-formed for this
   // class template.
@@ -4591,7 +4639,14 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
           SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
           D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
           CTAI.StrictPackMatch, PrevDecl);
-  InstD->setTemplateArgsAsWritten(InstTemplateArgs);
+  if (ExplicitSpecInfo)
+    InstD->setExplicitSpecializationInfo(
+        ExplicitSpecInfo->TemplateParams,
+        ASTTemplateArgumentListInfo::Create(SemaRef.Context, InstTemplateArgs));
+  else if (const auto *Info = D->getExplicitInstantiationInfo())
+    InstD->setExplicitInstantiationInfo(Info->ExternKeywordLoc,
+                                        Info->TemplateKeywordLoc,
+                                        Info->TemplateArgsAsWritten);
 
   // Add this partial specialization to the set of class template partial
   // specializations.
@@ -4605,8 +4660,6 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
   InstD->setAccess(D->getAccess());
   InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
   InstD->setSpecializationKind(D->getSpecializationKind());
-  InstD->setExternKeywordLoc(D->getExternKeywordLoc());
-  InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
 
   Owner->addDecl(InstD);
 
@@ -4626,7 +4679,6 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
 Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
     VarTemplateSpecializationDecl *D) {
 
-  TemplateArgumentListInfo VarTemplateArgsInfo;
   VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
   assert(VarTemplate &&
          "A template specialization without specialized template?");
@@ -4637,9 +4689,15 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
   if (!InstVarTemplate)
     return nullptr;
 
+  assert(!D->getExplicitInstantiationInfo());
+  const auto *ExplicitSpecializationInfo = D->getExplicitSpecializationInfo();
   // Substitute the current template arguments.
-  if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
-          D->getTemplateArgsAsWritten()) {
+  TemplateArgumentListInfo VarTemplateArgsInfo;
+  if (ExplicitSpecializationInfo) {
+    // The template parameters for an explicit specialization are empty and
+    // never need to be transformed.
+    const auto *TemplateArgsInfo =
+        ExplicitSpecializationInfo->TemplateArgsAsWritten;
     VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
     VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
 
@@ -4670,12 +4728,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
                       PrevDecl->getPointOfInstantiation(), Ignored))
     return nullptr;
 
-  if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
-          InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
-    VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
-    return VTSD;
-  }
-  return nullptr;
+  VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
+      InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl);
+  if (!VTSD)
+    return nullptr;
+  if (ExplicitSpecializationInfo)
+    VTSD->setExplicitSpecializationInfo(
+        ExplicitSpecializationInfo->TemplateParams,
+        ASTTemplateArgumentListInfo::Create(
+            SemaRef.Context,
+            ExplicitSpecializationInfo->TemplateArgsAsWritten));
+  return VTSD;
 }
 
 VarTemplateSpecializationDecl *
@@ -4684,6 +4747,8 @@ TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
     ArrayRef<TemplateArgument> Converted,
     VarTemplateSpecializationDecl *PrevDecl) {
 
+  LocalInstantiationScope Scope(SemaRef);
+
   // Do substitution on the type of the declaration
   TypeSourceInfo *TSI =
       SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
@@ -4939,16 +5004,17 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
                                                InstParams, InsertPos);
 
   // Create the class template partial specialization declaration.
+  // FIXME: Avoid recreating the ASTTemplateArgumentListInfo if nothing changed.
   ClassTemplatePartialSpecializationDecl *InstPartialSpec =
       ClassTemplatePartialSpecializationDecl::Create(
           SemaRef.Context, PartialSpec->getTagKind(), Owner,
           PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
+          ASTTemplateArgumentListInfo::Create(SemaRef.Context,
+                                              InstTemplateArgs),
           ClassTemplate, CTAI.CanonicalConverted,
           /*CanonInjectedTST=*/CanQualType(),
           /*PrevDecl=*/nullptr);
 
-  InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
-
   // Substitute the nested name specifier, if any.
   if (SubstQualifier(PartialSpec, InstPartialSpec))
     return nullptr;
@@ -5065,10 +5131,11 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
   VarTemplatePartialSpecializationDecl *InstPartialSpec =
       VarTemplatePartialSpecializationDecl::Create(
           SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
-          PartialSpec->getLocation(), InstParams, VarTemplate, TSI->getType(),
-          TSI, PartialSpec->getStorageClass(), CTAI.CanonicalConverted);
-
-  InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
+          PartialSpec->getLocation(), InstParams,
+          ASTTemplateArgumentListInfo::Create(SemaRef.Context,
+                                              InstTemplateArgs),
+          VarTemplate, TSI->getType(), TSI, PartialSpec->getStorageClass(),
+          CTAI.CanonicalConverted);
 
   // Substitute the nested name specifier, if any.
   if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -5303,8 +5370,11 @@ bool Sema::addInstantiatedParametersToScope(
 
 bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
+  assert(FD->getTemplateDepth() == 0 && "function not instantiated");
   assert(Param->hasUninstantiatedDefaultArg());
 
+  const auto *PatternDecl =
+      FD->getTemplateInstantiationPattern(/*ForDefinition=*/false);
   // FIXME: We don't track member specialization info for non-defining
   // friend declarations, so we will not be able to later find the function
   // pattern. As a workaround, don't instantiate the default argument in this
@@ -5312,34 +5382,31 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   // purposes. [dcl.fct.default]p4:
   //   if a friend declaration D specifies a default argument expression,
   //   that declaration shall be a definition.
-  if (FD->getFriendObjectKind() != Decl::FOK_None &&
-      !FD->getTemplateInstantiationPattern())
+  if (!PatternDecl)
     return true;
 
-  // Instantiate the expression.
-  //
-  // FIXME: Pass in a correct Pattern argument, otherwise
-  // getTemplateInstantiationArgs uses the lexical context of FD, e.g.
-  //
-  // template<typename T>
-  // struct A {
-  //   static int FooImpl();
-  //
-  //   template<typename Tp>
-  //   // bug: default argument A<T>::FooImpl() is evaluated with 2-level
-  //   // template argument list [[T], [Tp]], should be [[Tp]].
-  //   friend A<Tp> Foo(int a);
-  // };
-  //
-  // template<typename T>
-  // A<T> Foo(int a = A<T>::FooImpl());
-  MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-      FD, FD->getLexicalDeclContext(),
-      /*Final=*/false, /*Innermost=*/std::nullopt,
-      /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
-      /*ForDefaultArgumentSubstitution=*/true);
+  unsigned NumLevels = PatternDecl->getTemplateDepth();
+  MultiLevelTemplateArgumentList TemplateArgs;
+  // The default argument for a templated function must always be defined on
+  // it's first declaration.
+  if (const auto *Info = FD->getTemplateSpecializationInfo();
+      Info &&
+      Info->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+    TemplateArgs = getTemplateInstantiationArgs(
+        Info->getTemplate()->getFirstDecl(), Info->TemplateArguments->asArray(),
+        NumLevels);
+  } else {
+    if (Info)
+      FD = InstantiateFunctionDeclaration(
+          cast<FunctionTemplateDecl>(Info->getTemplate()->getFirstDecl()),
+          Info->TemplateArguments, CallLoc);
+    else
+      FD = FD->getFirstDecl();
+    TemplateArgs =
+        getTemplateInstantiationArgs(FD, /*Innermost=*/std::nullopt, NumLevels);
+  }
 
+  // Instantiate the expression.
   if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
     return true;
 
@@ -5380,15 +5447,22 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
   Sema::ContextRAII savedContext(*this, Decl);
   LocalInstantiationScope Scope(*this);
 
-  MultiLevelTemplateArgumentList TemplateArgs =
-      getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
-                                   /*Final=*/false, /*Innermost=*/std::nullopt,
-                                   /*RelativeToPrimary*/ true);
+  // FIXME: getTemplateInstantiationPattern doesn't work for non-defining friend
+  // declarations, because we don't store enough information to map back to the
+  // friend declaration in the template.
+  FunctionDecl *PD =
+      Decl->getTemplateInstantiationPattern(/*ForDefinition=*/false);
+  auto NumLevels = PD ? UnsignedOrNone(PD->getTemplateDepth()) : std::nullopt;
+  MultiLevelTemplateArgumentList TemplateArgs;
+  if (const auto *Info = Decl->getTemplateSpecializationInfo();
+      Info &&
+      Info->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+    TemplateArgs = getTemplateInstantiationArgs(
+        Info->getTemplate(), Info->TemplateArguments->asArray(), NumLevels);
+  else
+    TemplateArgs = getTemplateInstantiationArgs(
+        Decl, /*Innermost=*/std::nullopt, NumLevels);
 
-  // FIXME: We can't use getTemplateInstantiationPattern(false) in general
-  // here, because for a non-defining friend declaration in a class template,
-  // we don't store enough information to map back to the friend declaration in
-  // the template.
   FunctionDecl *Template = Proto->getExceptionSpecTemplate();
   if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
     UpdateExceptionSpec(Decl, EST_None);
@@ -5554,7 +5628,10 @@ FunctionDecl *Sema::InstantiateFunctionDeclaration(
   MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
                                        /*Final=*/false);
 
-  return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
+  return cast_or_null<FunctionDecl>(SubstDecl(
+      FD,
+      isa<CXXMethodDecl>(FD) ? FD->getParent() : FD->getLexicalDeclContext(),
+      MArgs));
 }
 
 void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
@@ -5909,36 +5986,52 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     RebuildTypeSourceInfoForDefaultSpecialMembers();
     SetDeclDefaulted(Function, PatternDecl->getLocation());
   } else {
-    DeclContext *DC = Function->getLexicalDeclContext();
-    std::optional<ArrayRef<TemplateArgument>> Innermost;
-    if (auto *Primary = Function->getPrimaryTemplate();
-        Primary &&
-        !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
-        Function->getTemplateSpecializationKind() !=
-            TSK_ExplicitSpecialization) {
-      auto It = llvm::find_if(Primary->redecls(),
-                              [](const RedeclarableTemplateDecl *RTD) {
-                                return cast<FunctionTemplateDecl>(RTD)
-                                    ->isCompatibleWithDefinition();
-                              });
-      assert(It != Primary->redecls().end() &&
-             "Should't get here without a definition");
-      if (FunctionDecl *Def = cast<FunctionTemplateDecl>(*It)
-                                  ->getTemplatedDecl()
-                                  ->getDefinition())
-        DC = Def->getLexicalDeclContext();
-      else
-        DC = (*It)->getLexicalDeclContext();
-      Innermost.emplace(Function->getTemplateSpecializationArgs()->asArray());
+    if (const FunctionTemplateSpecializationInfo *Info =
+            Function->getTemplateSpecializationInfo();
+        Info && !Info->isExplicitSpecialization()) {
+      const FunctionDecl *TemplatedDecl =
+          Info->getTemplate()->getTemplatedDecl();
+      // Find the primary template redeclaration which corresponds to the
+      // definition.
+      auto Redecls = TemplatedDecl->redecls();
+      auto It = llvm::find_if(Redecls, [](const FunctionDecl *FD) {
+        return FD->isInstantiatedFromMemberTemplate() ||
+               FD->isThisDeclarationADefinition();
+      });
+      assert(It != Redecls.end() && "Should't get here without a definition");
+      if (*It != TemplatedDecl) {
+        // If the primary template found is not the same as this function's
+        // primary template, then instantiate that primary template and use it
+        // instead.
+        FunctionDecl *NewFunction = InstantiateFunctionDeclaration(
+            (*It)->getDescribedFunctionTemplate(), Info->TemplateArguments,
+            PointOfInstantiation);
+        assert(NewFunction && "Failed to instantiate function template");
+        assert(NewFunction != Function && "Expected a new specialization");
+        assert(declaresSameEntity(NewFunction, Function));
+        Function = NewFunction;
+      }
+    } else {
+      for (FunctionDecl *F : Function->redecls()) {
+        MemberSpecializationInfo *Info = F->getMemberSpecializationInfo();
+        if (!Info)
+          break;
+        // Avoid friend member declarations, as they are never definitions
+        // themselves and may not be declared in a template context compatible
+        // with it.
+        if (Info->getTemplateSpecializationKind() != TSK_FriendDeclaration) {
+          Function = F;
+          break;
+        }
+      }
+      assert(Function->getTemplateSpecializationKind() !=
+                 TSK_FriendDeclaration &&
+             "Expected to find an instantiation");
     }
     MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-        Function, DC, /*Final=*/false, Innermost, false, PatternDecl);
-
-    // Substitute into the qualifier; we can get a substitution failure here
-    // through evil use of alias templates.
-    // FIXME: Is CurContext correct for this? Should we go to the (instantiation
-    // of the) lexical context of the pattern?
-    SubstQualifier(*this, PatternDecl, Function, TemplateArgs);
+        Function, /*Innermost=*/std::nullopt,
+        /*NumLevels=*/PatternDecl->getTemplateDepth(),
+        /*SkipInnerNonInstantiated=*/true);
 
     ActOnStartOfFunctionDef(nullptr, Function);
 
@@ -6304,6 +6397,8 @@ void Sema::InstantiateVariableInitializer(
 void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
                                          VarDecl *Var, bool Recursive,
                                       bool DefinitionRequired, bool AtEndOfTU) {
+  assert(Var->getTemplateDepth() == 0 && "variable not already instantiated");
+
   if (Var->isInvalidDecl())
     return;
 
@@ -6321,8 +6416,9 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
   // Find the pattern and the arguments to substitute into it.
   VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
   assert(PatternDecl && "no pattern for templated variable");
-  MultiLevelTemplateArgumentList TemplateArgs =
-      getTemplateInstantiationArgs(Var);
+  MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+      Var, /*Innermost=*/std::nullopt,
+      /*NumLevels=*/PatternDecl->getTemplateDepth());
 
   VarTemplateSpecializationDecl *VarSpec =
       dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -6483,15 +6579,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
     TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
                                           TemplateArgs);
 
-    TemplateArgumentListInfo TemplateArgInfo;
-    if (const ASTTemplateArgumentListInfo *ArgInfo =
-            VarSpec->getTemplateArgsAsWritten()) {
-      TemplateArgInfo.setLAngleLoc(ArgInfo->getLAngleLoc());
-      TemplateArgInfo.setRAngleLoc(ArgInfo->getRAngleLoc());
-      for (const TemplateArgumentLoc &Arg : ArgInfo->arguments())
-        TemplateArgInfo.addArgument(Arg);
-    }
-
     VarTemplateSpecializationDecl *VTSD =
         Instantiator.VisitVarTemplateSpecializationDecl(
             VarSpec->getSpecializedTemplate(), Def,
@@ -6499,7 +6586,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
     Var = VTSD;
 
     if (Var) {
-      VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
+      if (const auto *Info = VarSpec->getExplicitInstantiationInfo())
+        VTSD->setExplicitInstantiationInfo(Info->ExternKeywordLoc,
+                                           Info->TemplateKeywordLoc,
+                                           Info->TemplateArgsAsWritten);
+      else if (const auto *Info = VarSpec->getExplicitSpecializationInfo())
+        VTSD->setExplicitSpecializationInfo(Info->TemplateParams,
+                                            Info->TemplateArgsAsWritten);
 
       llvm::PointerUnion<VarTemplateDecl *,
                          VarTemplatePartialSpecializationDecl *> PatternPtr =
@@ -7289,6 +7382,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) {
       if (Var != Var->getMostRecentDecl())
         continue;
       break;
+    case TSK_FriendDeclaration:
     case TSK_ImplicitInstantiation:
       break;
     }
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 6815a27537034..99834f0e6bebe 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -905,9 +905,10 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
   if (Record.readInt()) { // hasExtInfo
     auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
     Record.readQualifierInfo(*Info);
-    Info->TrailingRequiresClause = AssociatedConstraint(
-        Record.readExpr(),
-        UnsignedOrNone::fromInternalRepresentation(Record.readUInt32()));
+    Expr *ConstraintExpr = Record.readExpr();
+    UnsignedOrNone ArgPackSubstIndex = Record.readUnsignedOrNone();
+    Info->TrailingRequiresClause =
+        AssociatedConstraint(ConstraintExpr, ArgPackSubstIndex);
     DD->DeclInfo = Info;
   }
   QualType TSIType = Record.readType();
@@ -949,6 +950,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
     SmallVector<TemplateArgument, 8> TemplArgs;
     Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
 
+    const TemplateParameterList *TemplateParams =
+        Record.readBool() ? Record.readTemplateParameterList() : nullptr;
+
     // Template args as written.
     TemplateArgumentListInfo TemplArgsWritten;
     bool HasTemplateArgumentsAsWritten = Record.readBool();
@@ -973,7 +977,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
 
     FunctionTemplateSpecializationInfo *FTInfo =
         FunctionTemplateSpecializationInfo::Create(
-            C, FD, Template, TSK, TemplArgList,
+            C, FD, Template, TSK, TemplArgList, TemplateParams,
             HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI,
             MSInfo);
     FD->TemplateOrSpecialization = FTInfo;
@@ -1010,6 +1014,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
     while (NumCandidates--)
       Candidates.addDecl(readDeclAs<NamedDecl>());
 
+    const TemplateParameterList *TemplateParams =
+        Record.readBool() ? Record.readTemplateParameterList() : nullptr;
+
     // Templates args.
     TemplateArgumentListInfo TemplArgsWritten;
     bool HasTemplateArgumentsAsWritten = Record.readBool();
@@ -1017,7 +1024,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
       Record.readTemplateArgumentListInfo(TemplArgsWritten);
 
     FD->setDependentTemplateSpecialization(
-        Reader.getContext(), Candidates,
+        Reader.getContext(), Candidates, TemplateParams,
         HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr);
     // These are not merged; we don't need to merge redeclarations of dependent
     // template friends.
@@ -2550,6 +2557,20 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
   D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
   D->StrictPackMatch = Record.readBool();
 
+  // extern/template keyword locations for explicit instantiations
+  if (auto K = D->SpecializationKind;
+      K == TSK_ExplicitInstantiationDeclaration ||
+      K == TSK_ExplicitInstantiationDefinition) {
+    SourceLocation ExternKeywordLoc = readSourceLocation();
+    SourceLocation TemplateKeywordLoc = readSourceLocation();
+    D->setExplicitInstantiationInfo(ExternKeywordLoc, TemplateKeywordLoc,
+                                    Record.readASTTemplateArgumentListInfo());
+  } else if (K == TSK_ExplicitSpecialization) {
+    auto *TemplateParams = Record.readTemplateParameterList();
+    D->setExplicitSpecializationInfo(TemplateParams,
+                                     Record.readASTTemplateArgumentListInfo());
+  }
+
   bool writtenAsCanonicalDecl = Record.readInt();
   if (writtenAsCanonicalDecl) {
     auto *CanonPattern = readDeclAs<ClassTemplateDecl>();
@@ -2580,27 +2601,11 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
     }
   }
 
-  // extern/template keyword locations for explicit instantiations
-  if (Record.readBool()) {
-    auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
-    ExplicitInfo->ExternKeywordLoc = readSourceLocation();
-    ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
-    D->ExplicitInfo = ExplicitInfo;
-  }
-
-  if (Record.readBool())
-    D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());
-
   return Redecl;
 }
 
 void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
-                                    ClassTemplatePartialSpecializationDecl *D) {
-  // We need to read the template params first because redeclarable is going to
-  // need them for profiling
-  TemplateParameterList *Params = Record.readTemplateParameterList();
-  D->TemplateParams = Params;
-
+    ClassTemplatePartialSpecializationDecl *D) {
   RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
 
   // These are read/set from/to the first declaration.
@@ -2646,17 +2651,6 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
     }
   }
 
-  // extern/template keyword locations for explicit instantiations
-  if (Record.readBool()) {
-    auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
-    ExplicitInfo->ExternKeywordLoc = readSourceLocation();
-    ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
-    D->ExplicitInfo = ExplicitInfo;
-  }
-
-  if (Record.readBool())
-    D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());
-
   SmallVector<TemplateArgument, 8> TemplArgs;
   Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
   D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
@@ -2664,6 +2658,20 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
   D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
   D->IsCompleteDefinition = Record.readInt();
 
+  // extern/template keyword locations for explicit instantiations
+  if (auto K = D->SpecializationKind;
+      K == TSK_ExplicitInstantiationDeclaration ||
+      K == TSK_ExplicitInstantiationDefinition) {
+    SourceLocation ExternKeywordLoc = readSourceLocation();
+    SourceLocation TemplateKeywordLoc = readSourceLocation();
+    D->setExplicitInstantiationInfo(ExternKeywordLoc, TemplateKeywordLoc,
+                                    Record.readASTTemplateArgumentListInfo());
+  } else if (K == TSK_ExplicitSpecialization) {
+    auto *TemplateParams = Record.readTemplateParameterList();
+    D->setExplicitSpecializationInfo(TemplateParams,
+                                     Record.readASTTemplateArgumentListInfo());
+  }
+
   RedeclarableResult Redecl = VisitVarDeclImpl(D);
 
   bool writtenAsCanonicalDecl = Record.readInt();
@@ -2694,9 +2702,6 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
 ///        using Template(Partial)SpecializationDecl as input type.
 void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
-  TemplateParameterList *Params = Record.readTemplateParameterList();
-  D->TemplateParams = Params;
-
   RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
 
   // These are read/set from/to the first declaration.
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 7f5005aa666c7..1390bc7c8dc9a 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -805,6 +805,10 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
     // Template arguments.
     Record.AddTemplateArgumentList(FTSInfo->TemplateArguments);
 
+    Record.push_back(FTSInfo->TemplateParameters != nullptr);
+    if (FTSInfo->TemplateParameters)
+      Record.AddTemplateParameterList(FTSInfo->TemplateParameters);
+
     // Template args as written.
     Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
     if (FTSInfo->TemplateArgumentsAsWritten)
@@ -839,6 +843,10 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
     for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates())
       Record.AddDeclRef(FTD);
 
+    Record.push_back(DFTSInfo->TemplateParameters != nullptr);
+    if (DFTSInfo->TemplateParameters)
+      Record.AddTemplateParameterList(DFTSInfo->TemplateParameters);
+
     // Templates args.
     Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr);
     if (DFTSInfo->TemplateArgumentsAsWritten)
@@ -1746,6 +1754,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
       if (FTSInfo->TemplateArguments->size() == 1) {
         const TemplateArgument &TA = FTSInfo->TemplateArguments->get(0);
         if (TA.getKind() == TemplateArgument::Type &&
+            !FTSInfo->TemplateParameters &&
             !FTSInfo->TemplateArgumentsAsWritten &&
             !FTSInfo->getMemberSpecializationInfo())
           AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
@@ -1754,7 +1763,8 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
                FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
       DependentFunctionTemplateSpecializationInfo *DFTSInfo =
           D->getDependentSpecializationInfo();
-      if (!DFTSInfo->TemplateArgumentsAsWritten)
+      if (!DFTSInfo->TemplateArgumentsAsWritten &&
+          !DFTSInfo->TemplateParameters)
         AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
     }
   }
@@ -1935,29 +1945,36 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
   Record.AddSourceLocation(D->getPointOfInstantiation());
   Record.push_back(D->getSpecializationKind());
   Record.push_back(D->hasStrictPackMatch());
-  Record.push_back(D->isCanonicalDecl());
 
+  switch (D->getSpecializationKind()) {
+  case TSK_Undeclared:
+  case TSK_ImplicitInstantiation:
+  case TSK_FriendDeclaration:
+    assert(!D->getExplicitSpecializationInfo());
+    assert(!D->getExplicitInstantiationInfo());
+    break;
+  case TSK_ExplicitSpecialization: {
+    const auto *Info = D->getExplicitSpecializationInfo();
+    Record.AddTemplateParameterList(Info->TemplateParams);
+    Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
+    break;
+  }
+  case TSK_ExplicitInstantiationDeclaration:
+  case TSK_ExplicitInstantiationDefinition: {
+    const auto *Info = D->getExplicitInstantiationInfo();
+    Record.AddSourceLocation(Info->ExternKeywordLoc);
+    Record.AddSourceLocation(Info->TemplateKeywordLoc);
+    Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
+    break;
+  }
+  }
+
+  Record.push_back(D->isCanonicalDecl());
   if (D->isCanonicalDecl()) {
     // When reading, we'll add it to the folding set of the following template.
     Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl());
   }
 
-  bool ExplicitInstantiation =
-      D->getTemplateSpecializationKind() ==
-          TSK_ExplicitInstantiationDeclaration ||
-      D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
-  Record.push_back(ExplicitInstantiation);
-  if (ExplicitInstantiation) {
-    Record.AddSourceLocation(D->getExternKeywordLoc());
-    Record.AddSourceLocation(D->getTemplateKeywordLoc());
-  }
-
-  const ASTTemplateArgumentListInfo *ArgsWritten =
-      D->getTemplateArgsAsWritten();
-  Record.push_back(!!ArgsWritten);
-  if (ArgsWritten)
-    Record.AddASTTemplateArgumentListInfo(ArgsWritten);
-
   // Mention the implicitly generated C++ deduction guide to make sure the
   // deduction guide will be rewritten as expected.
   //
@@ -1979,9 +1996,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
 }
 
 void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
-                                    ClassTemplatePartialSpecializationDecl *D) {
-  Record.AddTemplateParameterList(D->getTemplateParameters());
-
+    ClassTemplatePartialSpecializationDecl *D) {
   VisitClassTemplateSpecializationDecl(D);
 
   // These are read/set from/to the first declaration.
@@ -2014,27 +2029,34 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
     Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs());
   }
 
-  bool ExplicitInstantiation =
-      D->getTemplateSpecializationKind() ==
-          TSK_ExplicitInstantiationDeclaration ||
-      D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
-  Record.push_back(ExplicitInstantiation);
-  if (ExplicitInstantiation) {
-    Record.AddSourceLocation(D->getExternKeywordLoc());
-    Record.AddSourceLocation(D->getTemplateKeywordLoc());
-  }
-
-  const ASTTemplateArgumentListInfo *ArgsWritten =
-      D->getTemplateArgsAsWritten();
-  Record.push_back(!!ArgsWritten);
-  if (ArgsWritten)
-    Record.AddASTTemplateArgumentListInfo(ArgsWritten);
-
   Record.AddTemplateArgumentList(&D->getTemplateArgs());
   Record.AddSourceLocation(D->getPointOfInstantiation());
   Record.push_back(D->getSpecializationKind());
   Record.push_back(D->IsCompleteDefinition);
 
+  switch (D->getSpecializationKind()) {
+  case TSK_Undeclared:
+  case TSK_ImplicitInstantiation:
+  case TSK_FriendDeclaration:
+    assert(!D->getExplicitSpecializationInfo());
+    assert(!D->getExplicitInstantiationInfo());
+    break;
+  case TSK_ExplicitSpecialization: {
+    const auto *Info = D->getExplicitSpecializationInfo();
+    Record.AddTemplateParameterList(Info->TemplateParams);
+    Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
+    break;
+  }
+  case TSK_ExplicitInstantiationDeclaration:
+  case TSK_ExplicitInstantiationDefinition: {
+    const auto *Info = D->getExplicitInstantiationInfo();
+    Record.AddSourceLocation(Info->ExternKeywordLoc);
+    Record.AddSourceLocation(Info->TemplateKeywordLoc);
+    Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
+    break;
+  }
+  }
+
   VisitVarDecl(D);
 
   Record.push_back(D->isCanonicalDecl());
@@ -2053,8 +2075,6 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
 
 void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
-  Record.AddTemplateParameterList(D->getTemplateParameters());
-
   VisitVarTemplateSpecializationDecl(D);
 
   // These are read/set from/to the first declaration.
@@ -2431,6 +2451,7 @@ getFunctionDeclAbbrev(serialization::DeclCode Code) {
     Abv->Add(
         BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template Argument Type
     Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Is Defaulted
+    Abv->Add(BitCodeAbbrevOp(0));                         // TemplateParams
     Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
     Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
     Abv->Add(BitCodeAbbrevOp(0));
@@ -2440,6 +2461,7 @@ getFunctionDeclAbbrev(serialization::DeclCode Code) {
                                    TK_DependentFunctionTemplateSpecialization) {
     // Candidates of specialization
     Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+    Abv->Add(BitCodeAbbrevOp(0)); // TemplateParams
     Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
   } else {
     llvm_unreachable("Unknown templated kind?");
diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
index 6c1a55f79b908..4283741d7f29f 100644
--- a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -166,55 +166,6 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
          isSuppressed(UniqueingLocation, DeclWithIssue, {});
 }
 
-static const ClassTemplateDecl *
-walkInstantiatedFromChain(const ClassTemplateDecl *Tmpl) {
-  // For nested member templates (e.g., S2 inside S1<T>), getInstantiatedFrom
-  // may return the member template as instantiated within an outer
-  // specialization (e.g., S2 as it appears in S1<int>).  That instantiated
-  // member template has no definition redeclaration itself; we need to walk
-  // up the member template chain to reach the primary template definition.
-  // \code
-  //   template <class> struct S1 {
-  //     template <class> struct S2 {
-  //       int i;
-  //       template <class T> int m(const S2<T>& s2) {
-  //         return s2.i;
-  //       }
-  //     };
-  //   }
-  // /code
-  const ClassTemplateDecl *MemberTmpl;
-  while ((MemberTmpl = Tmpl->getInstantiatedFromMemberTemplate())) {
-    if (Tmpl->isMemberSpecialization())
-      break;
-    Tmpl = MemberTmpl;
-  }
-  return Tmpl;
-}
-
-static const ClassTemplatePartialSpecializationDecl *walkInstantiatedFromChain(
-    const ClassTemplatePartialSpecializationDecl *PartialSpec) {
-  const ClassTemplatePartialSpecializationDecl *MemberPS;
-  while ((MemberPS = PartialSpec->getInstantiatedFromMember())) {
-    if (PartialSpec->isMemberSpecialization())
-      break;
-    PartialSpec = MemberPS;
-  }
-  return PartialSpec;
-}
-
-template <class T> static const T *chooseDefinitionRedecl(const T *Tmpl) {
-  static_assert(llvm::is_one_of<T, ClassTemplateDecl,
-                                ClassTemplatePartialSpecializationDecl>::value);
-  for (const auto *Redecl : Tmpl->redecls()) {
-    if (const T *D = cast<T>(Redecl); D->isThisDeclarationADefinition()) {
-      return D;
-    }
-  }
-  assert(false && "This template must have a redecl that is a definition");
-  return Tmpl;
-}
-
 // For template specializations, returns the primary template definition or
 // partial specialization that was used to instantiate the specialization.
 // This ensures suppression attributes on templates apply to their
@@ -229,26 +180,10 @@ template <class T> static const T *chooseDefinitionRedecl(const T *Tmpl) {
 // attribute.
 //
 // The function handles specializations (and partial specializations) of
-// class and function templates.
-// For any other decl, it returns the input unchagned.
+// class templates.
+// For any other decl, it returns the input unchanged.
 static const Decl *
 preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
-  // For function template specializations (including instantiated friend
-  // function templates), map back to the primary template's FunctionDecl so
-  // that the lexical parent chain walk reaches the class where the template
-  // was defined inline.
-  //
-  // This handles the case where a friend function template is defined inline
-  // inside a [[clang::suppress]]-annotated class but was pre-declared at
-  // namespace scope.  In that case the instantiation's lexical DC is the
-  // namespace (from the pre-declaration), not the class.  Walking back to the
-  // primary template FunctionDecl — whose lexical DC IS the class — lets the
-  // existing parent-chain walk find the suppression attribute.
-  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
-    if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
-      return Pattern->getDefinition();
-  }
-
   const auto *SpecializationDecl = dyn_cast<ClassTemplateSpecializationDecl>(D);
   if (!SpecializationDecl)
     return D;
@@ -257,13 +192,14 @@ preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
   if (!InstantiatedFrom)
     return D;
 
-  if (const auto *Tmpl = InstantiatedFrom.dyn_cast<ClassTemplateDecl *>()) {
+  if (const auto *Tmpl = dyn_cast<ClassTemplateDecl *>(InstantiatedFrom)) {
     // Interestingly, the source template might be a forward declaration, so we
     // need to find the definition redeclaration.
-    return chooseDefinitionRedecl(walkInstantiatedFromChain(Tmpl));
+    return Tmpl->getTemplatedDecl()
+        ->getDefinitionOrSelf()
+        ->getDescribedClassTemplate();
   }
-  return chooseDefinitionRedecl(walkInstantiatedFromChain(
-      cast<ClassTemplatePartialSpecializationDecl *>(InstantiatedFrom)));
+  return cast<ClassTemplatePartialSpecializationDecl *>(InstantiatedFrom);
 }
 
 bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 3d3acea89d170..c8088f622e185 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -726,14 +726,14 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
   TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) {
     if (!RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(C))
       return false;
-    if (C->isExplicitSpecialization())
+    const auto *Info = C->getExplicitInstantiationInfo();
+    if (!Info)
       return true; // we are only interested in explicit instantiations.
     auto *Declaration =
         cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C));
     foldExplicitTemplateInstantiation(
-        Builder.getTemplateRange(C),
-        Builder.findToken(C->getExternKeywordLoc()),
-        Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C);
+        Builder.getTemplateRange(C), Builder.findToken(Info->ExternKeywordLoc),
+        Builder.findToken(Info->TemplateKeywordLoc), Declaration, C);
     return true;
   }
 
@@ -778,8 +778,9 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
           foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
       DeclarationRange = R;
     };
-    if (auto *S = dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
-      ConsumeTemplateParameters(*S->getTemplateParameters());
+    if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(C))
+      if (const auto *Info = S->getExplicitSpecializationInfo())
+        ConsumeTemplateParameters(*Info->TemplateParams);
     for (TemplateParameterList *TPL : C->getTemplateParameterLists())
       ConsumeTemplateParameters(*TPL);
     return Result;
diff --git a/clang/test/AST/ast-dump-templates-pattern.cpp b/clang/test/AST/ast-dump-templates-pattern.cpp
index aec86664f9988..c16e0870639af 100644
--- a/clang/test/AST/ast-dump-templates-pattern.cpp
+++ b/clang/test/AST/ast-dump-templates-pattern.cpp
@@ -32,11 +32,12 @@ namespace TestFunctionRedecl {
 // CHECK-LABEL: Dumping TestFunctionRedecl:
 // CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T1:[^ ]+]] <line:[[@LINE-4]]:{{.+}} f external-linkage
 // CHECK: | |-FunctionDecl 0x[[TestFunctionRedecl_D1:[^ ]+]] {{.+}} f 'void ()'
-// CHECK: | `-FunctionDecl 0x[[TestFunctionRedecl_S1:[^ ]+]] {{.+}} f 'void ()' explicit_instantiation_definition instantiated_from 0x[[TestFunctionRedecl_D2:[^ ]+]] external-linkage
-// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T2:[^ ]+]] prev 0x[[TestFunctionRedecl_T1]] <line:[[@LINE-6]]:{{.+}} f external-linkage
+// CHECK: | |-FunctionDecl {{.+}} prev 0x[[TestFunctionRedecl_S1:[^ ]+]] <col:22, col:32> col:27 f 'void ()' implicit_instantiation instantiated_from 0x[[TestFunctionRedecl_D1]] external-linkage
+// CHECK: | `-FunctionDecl 0x[[TestFunctionRedecl_S1]] {{.+}} f 'void ()' explicit_instantiation_definition instantiated_from 0x[[TestFunctionRedecl_D2:[^ ]+]] external-linkage
+// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T2:[^ ]+]] prev 0x[[TestFunctionRedecl_T1]] <line:[[@LINE-7]]:{{.+}} f external-linkage
 // CHECK: | |-FunctionDecl 0x[[TestFunctionRedecl_D2]] prev 0x[[TestFunctionRedecl_D1]] {{.+}} f 'void ()'
 // CHECK: | `-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
-// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-8]]:{{.+}} 'f'
+// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-9]]:{{.+}} 'f'
 // CHECK:   |-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
 // CHECK:   |-FunctionProtoTypeLoc {{.+}} 'void ()' cdecl
 // CHECK:   | `-BuiltinTypeLoc {{.+}} 'void'
@@ -76,15 +77,15 @@ namespace TestNestedClassRedecl {
 // CHECK: | | `-ClassTemplateDecl 0x[[TestNestedClassRedecl_B_T1:[^ ]+]] <line:[[@LINE-8]]:{{.+}} B external-linkage
 // CHECK: | |   `-CXXRecordDecl 0x[[TestNestedClassRedecl_B_D1:[^ ]+]] {{.+}} struct B
 // CHECK: | `-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_A_S1:[^ ]+]] <line:[[@LINE-8]]:{{.+}} line:[[@LINE-11]]:{{.+}} struct A definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_A_D2:[^ ]+]] implicit_instantiation
-// CHECK: |   `-ClassTemplateDecl 0x{{.+}} <line:[[@LINE-11]]:{{.+}} B external-linkage
-// CHECK: |     |-CXXRecordDecl 0x{{.+}} struct B
-// CHECK: |     `-ClassTemplateSpecialization  0x[[TestNestedClassRedecl_B_S1:[^ ]+]] 'B'
-// CHECK: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-12]]:{{.+}} A external-linkage
+// CHECK: |   |-ClassTemplateDecl 0x{{.+}} <line:[[@LINE-11]]:{{.+}} B external-linkage
+// CHECK: |   | |-CXXRecordDecl 0x{{.+}} struct B
+// CHECK: |   | `-ClassTemplateSpecialization  0x[[TestNestedClassRedecl_B_S1:[^ ]+]] 'B'
+// CHECK: |   `-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_B_S1]] <line:[[@LINE-10]]:{{.+}} struct B definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_B_D1]] explicit_instantiation_definition
+// CHECK: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-13]]:{{.+}} A external-linkage
 // CHECK: | |-CXXRecordDecl 0x[[TestNestedClassRedecl_A_D2]] prev 0x[[TestNestedClassRedecl_A_D1]] {{.+}} struct A
 // CHECK: | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_A_S1]] 'A'
-// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-14]]:{{.+}} B external-linkage
+// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-15]]:{{.+}} B external-linkage
 // CHECK: | `-CXXRecordDecl 0x[[TestNestedClassRedecl_B_D2:[^ ]+]] parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_D1]] {{.+}} struct B definition
-// CHECK: |-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_B_S1]] parent 0x[[TestNestedClassRedecl_A_S1]] <line:[[@LINE-15]]:{{.+}} struct B definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_B_D1]] explicit_instantiation_definition
 // CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-16]]:{{.+}} 'B'
 // CHECK:   |-NestedNameSpecifier TypeSpec {{.+}}
 // CHECK:   |-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1]] 'B'
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 342ffba53dbfa..ae8d5917a9664 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
@@ -73,18 +73,15 @@ template <class> struct S {};
 template<template<True T> typename Wrapper>
 using Test = Wrapper<int>;
 
-template<template<False T> typename Wrapper> // #TTP-Wrapper
-using Test = Wrapper<int>; // expected-error {{constraints not satisfied for template template parameter 'Wrapper' [with T = int]}}
-
-// expected-note@#TTP-Wrapper {{'int' does not satisfy 'False'}}
-// expected-note@#False {{evaluated to false}}
+template<template<False T> typename Wrapper>
+using Test = Wrapper<int>;
 
 template <typename U, template<False> typename T>
 void foo(T<U>); // #foo
 
 void bar() {
-  foo<int>(S<int>{}); // expected-error {{no matching function for call to 'foo'}}
-  // expected-note@#foo {{substitution failure [with U = int]: constraints not satisfied for template template parameter 'T' [with $0 = int]}}
+  // FIXME: CWG2980: There is no way to check the constraints on the template template parameter.
+  foo<int>(S<int>{});
 }
 
 }
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
index fefe86a448b18..70064f867e18e 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -1,10 +1,11 @@
 // RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
 
 template<typename T>
 concept D = true;
 
 template<typename T>
-struct A { // expected-note {{defined here}}
+struct A {
   template<typename U, bool V>
   void f() requires V;
 
@@ -16,7 +17,6 @@ struct A { // expected-note {{defined here}}
 
   template<typename U, bool V> requires V
   struct B;
-  // expected-note at -2 {{previous template declaration is here}}
 
   template<typename U, bool V> requires V
   struct B<U*, V>;
@@ -26,14 +26,12 @@ struct A { // expected-note {{defined here}}
 
   template<D U>
   struct C;
-  // expected-note at -2 {{previous template declaration is here}}
 
   template<D U>
   struct C<U*>;
 
   template<typename U, bool V> requires V
   static int x;
-  // expected-note at -2 {{previous template declaration is here}}
 
   template<typename U, bool V> requires V
   static int x<U*, V>;
@@ -43,7 +41,6 @@ struct A { // expected-note {{defined here}}
 
   template<D U>
   static int y;
-  // expected-note at -2 {{previous template declaration is here}}
 
   template<D U>
   static int y<U*>;
@@ -97,11 +94,9 @@ template<typename T>
 template<D U>
 int A<T>::y<U*> = 0;
 
-// FIXME: This should be accepted.
 template<>
 template<typename U, bool V>
 void A<short>::f() requires V;
-// expected-error at -1 {{out-of-line declaration of 'f' does not match any declaration in 'A<short>'}}
 
 template<>
 template<>
@@ -115,11 +110,9 @@ template<>
 template<D U>
 void A<short>::g();
 
-// FIXME: This should be accepted.
 template<>
 template<typename U, bool V> requires V
 struct A<int>::B;
-// expected-error at -2 {{requires clause differs in template redeclaration}}
 
 template<>
 template<>
@@ -137,11 +130,9 @@ template<>
 template<typename U, bool V> requires V
 struct A<int>::B<U&, V>;
 
-// FIXME: This should be accepted.
 template<>
 template<D U>
 struct A<int>::C;
-// expected-error at -2 {{type constraint differs in template redeclaration}}
 
 template<>
 template<D U>
@@ -151,11 +142,9 @@ template<>
 template<D U>
 struct A<int>::C<U&>;
 
-// FIXME: This should be accepted.
 template<>
 template<typename U, bool V> requires V
 int A<long>::x;
-// expected-error at -2 {{requires clause differs in template redeclaration}}
 
 template<>
 template<>
@@ -173,11 +162,9 @@ template<>
 template<typename U, bool V> requires V
 int A<long>::x<U&, V>;
 
-// FIXME: This should be accepted.
 template<>
 template<D U>
 int A<long>::y;
-// expected-error at -2 {{type constraint differs in template redeclaration}}
 
 template<>
 template<D U>
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 6c41853cf3b4f..01db2a54ae381 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -840,7 +840,7 @@ namespace PackIndexExpr1 {
 template <int... T>
 concept C = true;
 
-template <typename...> struct TplClass { // #PackIndexExpr1-TplClassDef
+template <typename...> struct TplClass {
   template <int... Ts>
   requires C<Ts...[0]>
   static auto buggy() -> void;
@@ -850,9 +850,6 @@ template <>
 template <int... Ts>
 requires C<Ts...[0]>
 auto TplClass<int>::buggy() -> void {}
-// FIXME: These shouldn't diagnose, but are a result of a revert: #193558
-// expected-error at -2{{does not match any declaration in}}
-// expected-note@#PackIndexExpr1-TplClassDef{{TplClass defined here}}
 } // namespace PackIndexExpr1
 
 namespace PackIndexExpr2 {
@@ -903,18 +900,16 @@ namespace FuncTemplateInClass {
   template <int T> concept C = true;
 
   namespace t1 {
-    template <int> struct TplClass { // expected-note {{defined here}}
+    template <int> struct TplClass {
       template <int Ts>
       requires C<Ts>
       static auto buggy() -> void;
     };
 
-    // FIXME: This should be accepted.
     template <>
     template <int Ts>
     requires C<Ts>
     auto TplClass<0>::buggy() -> void {}
-    // expected-error at -1 {{out-of-line definition of 'buggy' does not match any declaration}}
   } //namespace t1
   namespace t2 {
     template <int> struct TplClass { // expected-note {{defined here}}
diff --git a/clang/test/SemaTemplate/instantiate-scope.cpp b/clang/test/SemaTemplate/instantiate-scope.cpp
index 733105674b7a4..7dca971470e6a 100644
--- a/clang/test/SemaTemplate/instantiate-scope.cpp
+++ b/clang/test/SemaTemplate/instantiate-scope.cpp
@@ -8,10 +8,9 @@ template<typename ...T> struct X {
 
 template<typename T, typename U> using A = T;
 
-// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
-// so this defines the member of the primary template.
+// FIXME: These definitions are not OK, X<A<T, decltype(...)>...> is not equivalent to X<T...>.
 template<typename ...T>
-void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
+void X<A<T, decltype(f(T()))>...>::f(int) {}
 
 template<typename ...T>
 int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
@@ -23,8 +22,7 @@ void g() {
   X<Y>().f(0);
   X<Y>::n = 1;
 
-  // Error, substitution fails; this should not be treated as a SFINAE-able
-  // condition, so we don't select X<void>::f(...).
-  X<void>().f(0); // expected-note {{instantiation of}}
+  // FIXME: There should be no substitutiton failure since the out-of-line definitions were not valid.
+  X<void>().f(0);
   X<void>::n = 1; // expected-note {{instantiation of}}
 }
diff --git a/clang/test/Templight/templight-default-func-arg.cpp b/clang/test/Templight/templight-default-func-arg.cpp
index 19e6039379724..f2533bffb9b99 100644
--- a/clang/test/Templight/templight-default-func-arg.cpp
+++ b/clang/test/Templight/templight-default-func-arg.cpp
@@ -10,64 +10,77 @@ int main()
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+foo$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+foo$}}
 // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+foo$}}
 // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'foo<int>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'foo<int>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+//
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+foo$}}
+// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+Begin$}}
+// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+foo$}}
+// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+End$}}
+// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+b$}}
 // CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:12'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+b$}}
 // CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:12'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 //
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'foo<int>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'foo<int>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
   foo<int>();
 }
diff --git a/clang/test/Templight/templight-empty-entries-fix.cpp b/clang/test/Templight/templight-empty-entries-fix.cpp
index 7f34b10134929..43fcf2f50bbbc 100644
--- a/clang/test/Templight/templight-empty-entries-fix.cpp
+++ b/clang/test/Templight/templight-empty-entries-fix.cpp
@@ -207,6 +207,18 @@ template <bool = true> void d(int = 0) { d(); }
 // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
 // CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
 // CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+d$}}
+// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+Begin$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
+// CHECK-LABEL: {{^---$}}
+// CHECK: {{^name:[ ]+d$}}
+// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
+// CHECK: {{^event:[ ]+End$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
+// CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'unnamed function parameter 0 of d<true>'$}}
 // CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
@@ -225,41 +237,41 @@ void e() {
 }
 
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
 
 
 template <template<typename> class>
@@ -275,71 +287,71 @@ void foo() {
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
 // CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
 // CHECK: {{^poi:[ ]+''$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
 // CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277: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:265:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283: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:265:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'d<C>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'d<C>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
 // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
 // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 85760968cdbde..0577c442e38d6 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -732,6 +732,7 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl(
   switch (D->getSpecializationKind()) {
   case TSK_Undeclared:
   case TSK_ImplicitInstantiation:
+  case TSK_FriendDeclaration:
     // Nothing to visit
     return false;
 
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 92085e30ace74..aa92ee1173414 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -5289,11 +5289,13 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
   Decl *FromTU = getTuDecl(Code, Lang_CXX03);
   auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU,
       functionDecl(hasName("f"), isExplicitTemplateSpecialization()));
-  ASSERT_EQ(FromD->getTemplateParameterLists().size(), 1u);
+  ASSERT_EQ(FromD->getTemplateSpecializationInfo()->TemplateParameters->size(),
+            0u);
 
   auto *ToD = Import(FromD, Lang_CXX03);
   // The template parameter list should exist.
-  EXPECT_EQ(ToD->getTemplateParameterLists().size(), 1u);
+  ASSERT_EQ(ToD->getTemplateSpecializationInfo()->TemplateParameters->size(),
+            0u);
 }
 
 const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index a3281f948fdb7..35d169fb1234d 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -6071,14 +6071,14 @@ class ForCallablePreservesBindingWithMultipleParentsTestCallback
         FunDecl);
 
     ExpectCorrectResult("ForCallable first",
-                        callExpr(forCallable(equalsNode(FunDecl)),
+                        callExpr(forCallable(declaresSameEntityAsNode(FunDecl)),
                                  callee(cxxMethodDecl().bind("callee")))
                             .bind("call"),
                         FunDecl);
 
     ExpectCorrectResult("ForCallable second",
                         callExpr(callee(cxxMethodDecl().bind("callee")),
-                                 forCallable(equalsNode(FunDecl)))
+                                 forCallable(declaresSameEntityAsNode(FunDecl)))
                             .bind("call"),
                         FunDecl);
 



More information about the llvm-branch-commits mailing list