[llvm-branch-commits] [clang-tools-extra] 3228793 - Revert "[clang] fix getTemplateInstantiationArgs (#199528)"

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jun 2 04:03:08 PDT 2026


Author: Hans Wennborg
Date: 2026-06-02T13:03:03+02:00
New Revision: 3228793fa61ef7dc2504028e321a6e53519ff32f

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

LOG: Revert "[clang] fix getTemplateInstantiationArgs (#199528)"

This reverts commit ccd2606d0c30c58554cc11038a2160672ef529d5.

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
    clang-tools-extra/clangd/SemanticHighlighting.cpp
    clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/Decl.h
    clang/include/clang/AST/DeclTemplate.h
    clang/include/clang/AST/JSONNodeDumper.h
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/include/clang/ASTMatchers/ASTMatchers.h
    clang/include/clang/ASTMatchers/ASTMatchersInternal.h
    clang/include/clang/Basic/Specifiers.h
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/ASTDumper.cpp
    clang/lib/AST/ASTImporter.cpp
    clang/lib/AST/Comment.cpp
    clang/lib/AST/Decl.cpp
    clang/lib/AST/DeclPrinter.cpp
    clang/lib/AST/DeclTemplate.cpp
    clang/lib/AST/JSONNodeDumper.cpp
    clang/lib/AST/TextNodeDumper.cpp
    clang/lib/ASTMatchers/Dynamic/Registry.cpp
    clang/lib/Analysis/ExprMutationAnalyzer.cpp
    clang/lib/CodeGen/CGVTables.cpp
    clang/lib/Index/IndexingContext.cpp
    clang/lib/InstallAPI/Visitor.cpp
    clang/lib/Parse/ParseDeclCXX.cpp
    clang/lib/Sema/HLSLExternalSemaSource.cpp
    clang/lib/Sema/SemaConcept.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaExprMember.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/lib/Sema/SemaTemplateDeductionGuide.cpp
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/lib/Serialization/ASTReaderDecl.cpp
    clang/lib/Serialization/ASTWriterDecl.cpp
    clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
    clang/lib/Tooling/Syntax/BuildTree.cpp
    clang/test/AST/ast-dump-templates-pattern.cpp
    clang/test/CXX/basic/basic.link/p11.cpp
    clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
    clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
    clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
    clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
    clang/test/SemaTemplate/concepts-out-of-line-def.cpp
    clang/test/SemaTemplate/friend-template.cpp
    clang/test/SemaTemplate/instantiate-scope.cpp
    clang/test/Templight/templight-default-func-arg.cpp
    clang/test/Templight/templight-empty-entries-fix.cpp
    clang/tools/libclang/CIndex.cpp
    clang/unittests/AST/ASTImporterTest.cpp
    clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
index a1a705dd043a0..ae063a19d779d 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->getFunctionLocStart(), "inline ");
+        << FixItHint::CreateInsertion(FD->getInnerLocStart(), "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 856904bc810d1..d1ed3ea9bc88a 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 (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());
-    }
+    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());
     return true;
   }
 
   bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
-    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());
-    }
+    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());
     return true;
   }
 
@@ -625,9 +625,6 @@ 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 5fcb1a24448b8..c9704492bf1cd 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->getFunctionLocStart(), 0, "inline ");
+  return tooling::Replacement(SM, FD->getInnerLocStart(), 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 35ffb37897007..132d9128a795b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -687,7 +687,6 @@ 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-of-line definitions. (#GH101330)
 - Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439)
 - Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307)
 - Fixed crash instantiating class member specializations.

diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e3f513732e588..620206612f98f 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2122,6 +2122,34 @@ class FunctionDecl : public DeclaratorDecl,
   /// the DeclaratorDecl base class.
   DeclarationNameLoc DNLoc;
 
+  /// Specify that this function declaration is actually a function
+  /// template specialization.
+  ///
+  /// \param C the ASTContext.
+  ///
+  /// \param Template the function template that this function template
+  /// specialization specializes.
+  ///
+  /// \param TemplateArgs the template arguments that produced this
+  /// function template specialization from the template.
+  ///
+  /// \param InsertPos If non-NULL, the position in the function template
+  /// specialization set where the function template specialization data will
+  /// be inserted.
+  ///
+  /// \param TSK the kind of template specialization this is.
+  ///
+  /// \param TemplateArgsAsWritten location info of template arguments.
+  ///
+  /// \param PointOfInstantiation point at which the function template
+  /// specialization was first instantiated.
+  void setFunctionTemplateSpecialization(
+      ASTContext &C, FunctionTemplateDecl *Template,
+      TemplateArgumentList *TemplateArgs, void *InsertPos,
+      TemplateSpecializationKind TSK,
+      const TemplateArgumentListInfo *TemplateArgsAsWritten,
+      SourceLocation PointOfInstantiation);
+
   /// Specify that this record is an instantiation of the
   /// member function FD.
   void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD,
@@ -2217,8 +2245,6 @@ class FunctionDecl : public DeclaratorDecl,
     return SourceLocation();
   }
 
-  SourceLocation getFunctionLocStart() const;
-
   SourceRange getSourceRange() const override LLVM_READONLY;
 
   // Function definitions.
@@ -3044,14 +3070,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.
   ///
-  /// \param C the ASTContext.
-  ///
   /// \param Template the function template that this function template
   /// specialization specializes.
   ///
@@ -3064,30 +3085,25 @@ 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
   /// specialization was first instantiated.
-  ///
-  /// \param AddSpecialization whether to add this specialization to the
-  /// template's specialization set.
-  ///
   void setFunctionTemplateSpecialization(
-      ASTContext &C, FunctionTemplateDecl *Template,
-      TemplateArgumentList *TemplateArgs, void *InsertPos,
-      TemplateSpecializationKind TSK,
-      const TemplateParameterList *TemplateParams,
-      const TemplateArgumentListInfo *TemplateArgsAsWritten,
-      SourceLocation PointOfInstantiation, bool AddSpecialization);
+      FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
+      void *InsertPos,
+      TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
+      TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
+      SourceLocation PointOfInstantiation = SourceLocation()) {
+    setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
+                                      InsertPos, TSK, TemplateArgsAsWritten,
+                                      PointOfInstantiation);
+  }
 
   /// 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 672648c3fc03c..4f5a4e1b7b8a6 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.
-  mutable TemplateArgument *InjectedArgs = nullptr;
+  TemplateArgument *InjectedArgs = nullptr;
 
   /// The location of the 'template' keyword.
   SourceLocation TemplateLoc;
@@ -200,8 +200,7 @@ class TemplateParameterList final
   bool hasAssociatedConstraints() const;
 
   /// Get the template argument list of the template parameter list.
-  ArrayRef<TemplateArgument>
-  getInjectedTemplateArgs(const ASTContext &Context) const;
+  ArrayRef<TemplateArgument> getInjectedTemplateArgs(const ASTContext &Context);
 
   SourceLocation getTemplateLoc() const { return TemplateLoc; }
   SourceLocation getLAngleLoc() const { return LAngleLoc; }
@@ -476,18 +475,14 @@ class FunctionTemplateSpecializationInfo final
   /// The function template from which this function template
   /// specialization was generated.
   ///
-  /// The three bits contain the TemplateSpecializationKind.
-  llvm::PointerIntPair<FunctionTemplateDecl *, 3> Template;
+  /// The two bits contain the top 4 values of TemplateSpecializationKind.
+  llvm::PointerIntPair<FunctionTemplateDecl *, 2> 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;
@@ -500,14 +495,12 @@ 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), TemplateParameters(TemplateParameters),
+        TemplateArguments(TemplateArgs),
         TemplateArgumentsAsWritten(TemplateArgsAsWritten),
         PointOfInstantiation(POI) {
-    assert(TemplateParameters == nullptr || TSK == TSK_ExplicitSpecialization);
     if (MSInfo)
       getTrailingObjects()[0] = MSInfo;
   }
@@ -520,7 +513,6 @@ 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);
 
@@ -621,8 +613,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 three bits).
-  llvm::PointerIntPair<NamedDecl *, 3> MemberAndTSK;
+  // manner in which the instantiation occurred (in the lower two bits).
+  llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
 
   // The point at which this member was first instantiated.
   SourceLocation PointOfInstantiation;
@@ -701,19 +693,14 @@ 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.
@@ -1018,6 +1005,11 @@ 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
@@ -1815,18 +1807,8 @@ 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<ExplicitSpecializationInfo *,
+    llvm::PointerUnion<const ASTTemplateArgumentListInfo *,
                        ExplicitInstantiationInfo *>;
 
 /// Represents a class template specialization, which refers to
@@ -2056,38 +2038,49 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
   /// Retrieve the template argument list as written in the sources,
   /// if any.
   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
-    if (const auto *Info = getExplicitSpecializationInfo())
+    if (auto *Info =
+            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
       return Info->TemplateArgsAsWritten;
-    if (const auto *Info = getExplicitInstantiationInfo())
-      return Info->TemplateArgsAsWritten;
-    return nullptr;
+    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;
   }
 
-  /// Gets the explicit instantiation info, if present.
-  const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
-    return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+  /// Set the template argument list as written in the sources.
+  void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
+    setTemplateArgsAsWritten(
+        ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
   }
 
-  /// 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;
+  /// 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();
   }
 
-  /// Gets the explicit specialization info, if present.
-  const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
-    return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
+  /// 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();
   }
 
-  /// Sets the explicit specialization info.
-  void setExplicitSpecializationInfo(
-      TemplateParameterList *TemplateParams,
-      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
+  /// Sets the location of the template keyword.
+  void setTemplateKeywordLoc(SourceLocation Loc);
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
@@ -2112,7 +2105,10 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
 };
 
 class ClassTemplatePartialSpecializationDecl
-    : public ClassTemplateSpecializationDecl {
+  : public ClassTemplateSpecializationDecl {
+  /// The list of template parameters
+  TemplateParameterList *TemplateParams = nullptr;
+
   /// The class template partial specialization from which this
   /// class template partial specialization was instantiated.
   ///
@@ -2126,7 +2122,6 @@ 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);
@@ -2144,9 +2139,7 @@ class ClassTemplatePartialSpecializationDecl
   static ClassTemplatePartialSpecializationDecl *
   Create(ASTContext &Context, TagKind TK, DeclContext *DC,
          SourceLocation StartLoc, SourceLocation IdLoc,
-         TemplateParameterList *Params,
-         const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
-         ClassTemplateDecl *SpecializedTemplate,
+         TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
          ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
          ClassTemplatePartialSpecializationDecl *PrevDecl);
 
@@ -2161,10 +2154,7 @@ class ClassTemplatePartialSpecializationDecl
 
   /// Get the list of template parameters
   TemplateParameterList *getTemplateParameters() const {
-    auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
-    assert(ExplicitSpecInfo &&
-           "A partial specialization is always an explicit specialization");
-    return ExplicitSpecInfo->TemplateParams;
+    return TemplateParams;
   }
 
   /// \brief All associated constraints of this partial specialization,
@@ -2175,11 +2165,11 @@ class ClassTemplatePartialSpecializationDecl
   /// conjunction ("and").
   void getAssociatedConstraints(
       llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
-    getTemplateParameters()->getAssociatedConstraints(AC);
+    TemplateParams->getAssociatedConstraints(AC);
   }
 
   bool hasAssociatedConstraints() const {
-    return getTemplateParameters()->hasAssociatedConstraints();
+    return TemplateParams->hasAssociatedConstraints();
   }
 
   /// Retrieve the member class template partial specialization from
@@ -2816,38 +2806,49 @@ class VarTemplateSpecializationDecl : public VarDecl,
   /// Retrieve the template argument list as written in the sources,
   /// if any.
   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
-    if (const auto *Info = getExplicitSpecializationInfo())
-      return Info->TemplateArgsAsWritten;
-    if (const auto *Info = getExplicitInstantiationInfo())
+    if (auto *Info =
+            dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
       return Info->TemplateArgsAsWritten;
-    return nullptr;
+    return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
   }
 
-  /// Gets the explicit instantiation info, if present.
-  const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
-    return dyn_cast_if_present<ExplicitInstantiationInfo *>(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;
   }
 
-  /// 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;
+  /// Set the template argument list as written in the sources.
+  void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
+    setTemplateArgsAsWritten(
+        ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
   }
 
-  /// Gets the explicit specialization info, if present.
-  const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
-    return dyn_cast_if_present<ExplicitSpecializationInfo *>(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 specialization info.
-  void setExplicitSpecializationInfo(
-      TemplateParameterList *TemplateParams,
-      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
+  /// 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();
+  }
+
+  /// Sets the location of the template keyword.
+  void setTemplateKeywordLoc(SourceLocation Loc);
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
@@ -2873,6 +2874,9 @@ 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.
   ///
@@ -2884,7 +2888,6 @@ 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);
 
@@ -2902,7 +2905,6 @@ 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);
@@ -2918,10 +2920,7 @@ class VarTemplatePartialSpecializationDecl
 
   /// Get the list of template parameters
   TemplateParameterList *getTemplateParameters() const {
-    auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
-    assert(ExplicitSpecInfo &&
-           "A partial specialization is always an explicit specialization");
-    return ExplicitSpecInfo->TemplateParams;
+    return TemplateParams;
   }
 
   /// Get the template argument list of the template parameter list.
@@ -2938,11 +2937,11 @@ class VarTemplatePartialSpecializationDecl
   /// conjunction ("and").
   void getAssociatedConstraints(
       llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
-    getTemplateParameters()->getAssociatedConstraints(AC);
+    TemplateParams->getAssociatedConstraints(AC);
   }
 
   bool hasAssociatedConstraints() const {
-    return getTemplateParameters()->hasAssociatedConstraints();
+    return TemplateParams->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 7c8496d6164fc..4e8d1649bbf8b 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -417,7 +417,6 @@ 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 3b9bafffe1bc1..febdf715698d9 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2002,7 +2002,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
       case TSK_ExplicitInstantiationDeclaration:
       case TSK_ExplicitInstantiationDefinition:
       case TSK_ExplicitSpecialization:
-      case TSK_FriendDeclaration:
         break;
       }
     }
@@ -2023,7 +2022,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
         TRY_TO(TraverseDecl(RD));
         break;
 
-      case TSK_FriendDeclaration:
       case TSK_ExplicitInstantiationDeclaration:
       case TSK_ExplicitInstantiationDefinition:
       case TSK_ExplicitSpecialization:
@@ -2058,7 +2056,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
         TRY_TO(TraverseDecl(RD));
         break;
 
-      case TSK_FriendDeclaration:
       case TSK_ExplicitSpecialization:
         break;
       }
@@ -2225,11 +2222,12 @@ 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 *Info = D->getExplicitSpecializationInfo()) {               \
-      const auto *ArgsWritten = Info->TemplateArgsAsWritten;                   \
-      TRY_TO(TraverseTemplateParameterListHelper(Info->TemplateParams));       \
-      TRY_TO(TraverseTemplateArgumentLocsHelper(                               \
-          ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs));      \
+    if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) {             \
+      assert(D->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); \
+      if (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {  \
+        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 c35206fb41b92..bc0f35898a2c9 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5753,11 +5753,6 @@ 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 d3daf2eb4781d..cb12d10d628b6 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1993,12 +1993,16 @@ getTemplateArgsWritten(const OverloadExpr &OE) {
 
 inline unsigned
 getNumTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
-  return getTemplateArgsWritten(D).size();
+  if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
+    return Args->getNumTemplateArgs();
+  return 0;
 }
 
 inline unsigned
 getNumTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
-  return getTemplateArgsWritten(D).size();
+  if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
+    return Args->getNumTemplateArgs();
+  return 0;
 }
 
 inline unsigned getNumTemplateArgsWritten(const FunctionDecl &FD) {

diff  --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 1fe50760eff9a..8da6fd4cf454a 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -193,8 +193,6 @@ 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]).
@@ -229,7 +227,6 @@ 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 ff474fdd99562..b8d760e7e0975 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11753,7 +11753,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);
 
@@ -11819,7 +11819,8 @@ class Sema final : public SemaBase {
   DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
                                 SourceLocation TemplateLoc,
                                 SourceLocation TemplateNameLoc,
-                                const TemplateArgumentListInfo &TemplateArgs);
+                                const TemplateArgumentListInfo &TemplateArgs,
+                                bool SetWrittenArgs);
 
   /// Form a reference to the specialization of the given variable template
   /// corresponding to the specified argument list, or a null-but-valid result
@@ -11903,7 +11904,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
@@ -11976,8 +11977,7 @@ 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 TemplateParameterList *TemplateParams,
-      const TemplateArgumentListInfo *ExplicitTemplateArgs,
+      FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
       LookupResult &Previous);
 
   /// Perform semantic analysis for the given function template
@@ -12003,9 +12003,8 @@ class Sema final : public SemaBase {
   /// declaration with no explicit template argument list that might be
   /// befriending a function template specialization.
   bool CheckFunctionTemplateSpecialization(
-      FunctionDecl *FD, const TemplateParameterList *TemplateParams,
-      TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
-      bool QualifiedFriend = false);
+      FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
+      LookupResult &Previous, bool QualifiedFriend = false);
 
   /// Perform semantic analysis for the given non-template member
   /// specialization.
@@ -12271,6 +12270,46 @@ 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.
   ///
@@ -12295,11 +12334,19 @@ class Sema final : public SemaBase {
   /// \returns True if the template parameter lists are equal, false
   /// otherwise.
   bool TemplateParameterListsAreEqual(
-      const Decl *NewInstFrom, TemplateParameterList *New,
-      const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+      const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
+      const NamedDecl *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
@@ -13530,27 +13577,44 @@ class Sema final : public SemaBase {
   /// Retrieve the template argument list(s) that should be used to
   /// instantiate the definition of the given declaration.
   ///
-  /// \param D the declaration for which we are computing template
+  /// \param ND the declaration for which we are computing template
   /// instantiation arguments.
   ///
-  /// \param Innermost if present, specifies a template argument list for the
-  /// template-like (TemplateDecl or PartialSpec) declaration passed as D.
+  /// \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 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 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 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 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 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 Decl *D,
+      const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
-      UnsignedOrNone NumLevels = std::nullopt,
-      bool SkipInnerNonInstantiated = false);
+      bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
+      bool ForConstraintInstantiation = false,
+      bool SkipForSpecialization = false,
+      bool ForDefaultArgumentSubstitution = false);
 
   /// RAII object to handle the state changes required to synthesize
   /// a function body.
@@ -14970,13 +15034,14 @@ 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 Decl *Old, const Expr *OldConstr,
-                                     const Decl *New, const Expr *NewConstr);
+  bool AreConstraintExpressionsEqual(const NamedDecl *Old,
+                                     const Expr *OldConstr,
+                                     const TemplateCompareNewDeclInfo &New,
+                                     const Expr *NewConstr);
 
   // Calculates whether the friend function depends on an enclosing template for
   // the purposes of [temp.friend] p9.
-  bool
-  FriendConstraintsDependOnEnclosingTemplate(const FunctionTemplateDecl *FTD);
+  bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD);
 
   /// \brief Ensure that the given template arguments satisfy the constraints
   /// associated with the given template, emitting a diagnostic if they do not.
@@ -14997,19 +15062,10 @@ class Sema final : public SemaBase {
       SourceRange TemplateIDRange);
 
   bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation,
-                                        FunctionTemplateDecl *Template,
+                                        FunctionDecl *Decl,
                                         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
@@ -15090,16 +15146,19 @@ 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,
-                            const MultiLevelTemplateArgumentList &MLTAL,
-                            LocalInstantiationScope &Scope);
+  bool
+  SetupConstraintScope(FunctionDecl *FD,
+                       std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+                       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, LocalInstantiationScope &Scope);
+      FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+      LocalInstantiationScope &Scope);
 
   ///@}
 

diff  --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8a8cbc3fa6a96..a401a7471e6fc 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -13048,7 +13048,6 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
   case TSK_ExplicitInstantiationDeclaration:
     return GVA_AvailableExternally;
 
-  case TSK_FriendDeclaration:
   case TSK_ImplicitInstantiation:
     External = GVA_DiscardableODR;
     break;
@@ -13237,7 +13236,6 @@ 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 00c1140b538ec..b3071d83ed51f 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -134,7 +134,6 @@ 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 2aa83362d1070..f8c641789bd10 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -815,8 +815,6 @@ 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);
@@ -955,8 +953,7 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
       ToInfo = TemplateArgumentLocInfo(*TSIOrErr);
     else
       return TSIOrErr.takeError();
-  } else if (Arg.getKind() == TemplateArgument::Template ||
-             Arg.getKind() == TemplateArgument::TemplateExpansion) {
+  } else {
     auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc());
     if (!ToTemplateKWLocOrErr)
       return ToTemplateKWLocOrErr.takeError();
@@ -974,9 +971,6 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
         Importer.getToContext(), *ToTemplateKWLocOrErr,
         *ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr,
         *ToTemplateEllipsisLocOrErr);
-  } else {
-    ToInfo = TemplateArgumentLocInfo(Importer.getToContext(),
-                                     FromInfo.getTrivialLoc());
   }
 
   return TemplateArgumentLoc(Arg, ToInfo);
@@ -3645,12 +3639,6 @@ 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)
@@ -3667,10 +3655,8 @@ Error ASTNodeImporter::ImportTemplateInformation(
 
     TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
     ToFD->setFunctionTemplateSpecialization(
-        Importer.getToContext(), std::get<0>(*FunctionAndArgsOrErr), ToTAList,
-        /*InsertPos=*/nullptr, TSK, *TemplateParamsOrErr,
-        FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr,
-        /*AddSpecialization=*/true);
+        std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr,
+        TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr);
     return Error::success();
   }
 
@@ -3684,11 +3670,6 @@ 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;
@@ -3698,7 +3679,7 @@ Error ASTNodeImporter::ImportTemplateInformation(
         return Err;
 
     ToFD->setDependentTemplateSpecialization(
-        Importer.getToContext(), Candidates, *TemplateParamsOrErr,
+        Importer.getToContext(), Candidates,
         FromTAArgsAsWritten ? &ToTAInfo : nullptr);
     return Error::success();
   }
@@ -6519,22 +6500,19 @@ 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,
-            ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
-                                                ToTAInfo),
-            ClassTemplate, ArrayRef(TemplateArgs),
+            *IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs),
             /*CanonInjectedTST=*/CanQualType(),
             cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
       return D2;
@@ -6565,34 +6543,6 @@ 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());
@@ -6619,6 +6569,19 @@ 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);
@@ -6836,6 +6799,12 @@ 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)) {
@@ -6843,16 +6812,9 @@ 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;
@@ -6877,34 +6839,6 @@ 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
@@ -6931,6 +6865,9 @@ 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 6e107c87edb01..a1c73f9ec179b 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -233,13 +233,11 @@ void DeclInfo::fill() {
     Kind = FunctionKind;
     ParamVars = FD->parameters();
     ReturnType = FD->getReturnType();
-    TemplateParameters = FD->getTemplateSpecializationParameters();
-    if (ArrayRef<TemplateParameterList *> TPLs =
-            FD->getTemplateParameterLists();
-        !TemplateParameters && !TPLs.empty())
-      TemplateParameters = TPLs.back();
-    if (TemplateParameters)
+    ArrayRef<TemplateParameterList *> TPLs = FD->getTemplateParameterLists();
+    if (!TPLs.empty()) {
       TemplateKind = TemplateSpecialization;
+      TemplateParameters = TPLs.back();
+    }
 
     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 a6de9959e0f62..b797ebfa1a7e1 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -51,7 +51,6 @@
 #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"
@@ -4205,7 +4204,6 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
   case TSK_ExplicitSpecialization:
     return false;
 
-  case TSK_FriendDeclaration:
   case TSK_ImplicitInstantiation:
     return true;
 
@@ -4326,21 +4324,12 @@ 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, const TemplateParameterList *TemplateParams,
+    TemplateSpecializationKind TSK,
     const TemplateArgumentListInfo *TemplateArgsAsWritten,
-    SourceLocation PointOfInstantiation, bool AddSpecialization) {
+    SourceLocation PointOfInstantiation) {
   assert((TemplateOrSpecialization.isNull() ||
           isa<MemberSpecializationInfo *>(TemplateOrSpecialization)) &&
          "Member function is already a specialization");
@@ -4352,23 +4341,21 @@ void FunctionDecl::setFunctionTemplateSpecialization(
          "Member specialization must be an explicit specialization");
   FunctionTemplateSpecializationInfo *Info =
       FunctionTemplateSpecializationInfo::Create(
-          C, this, Template, TSK, TemplateArgs, TemplateParams,
-          TemplateArgsAsWritten, PointOfInstantiation,
+          C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
+          PointOfInstantiation,
           dyn_cast_if_present<MemberSpecializationInfo *>(
               TemplateOrSpecialization));
   TemplateOrSpecialization = Info;
-  if (AddSpecialization)
-    Template->addSpecialization(Info, InsertPos);
+  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, TemplateParams, TemplateArgs);
+      DependentFunctionTemplateSpecializationInfo::Create(Context, Templates,
+                                                          TemplateArgs);
   TemplateOrSpecialization = Info;
 }
 
@@ -4381,22 +4368,19 @@ 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, TemplateParams,
-                                                  TArgsWritten);
+      DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten);
 }
 
 DependentFunctionTemplateSpecializationInfo::
     DependentFunctionTemplateSpecializationInfo(
         const UnresolvedSetImpl &Candidates,
-        const TemplateParameterList *TemplateParams,
         const ASTTemplateArgumentListInfo *TemplateArgsWritten)
-    : NumCandidates(Candidates.size()), TemplateParameters(TemplateParams),
+    : NumCandidates(Candidates.size()),
       TemplateArgumentsAsWritten(TemplateArgsWritten) {
   std::transform(Candidates.begin(), Candidates.end(), getTrailingObjects(),
                  [](NamedDecl *ND) {
@@ -4556,17 +4540,6 @@ 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 6a8046763c788..95591d3a09431 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1105,7 +1105,6 @@ 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 861974848d6b3..275fe364e306d 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) const {
+ArrayRef<TemplateArgument>
+TemplateParameterList::getInjectedTemplateArgs(const ASTContext &Context) {
   if (!InjectedArgs) {
     InjectedArgs = new (Context) TemplateArgument[size()];
     llvm::transform(*this, InjectedArgs, [&](NamedDecl *ND) {
@@ -946,7 +946,6 @@ 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;
@@ -957,8 +956,7 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
   void *Mem =
       C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
   return new (Mem) FunctionTemplateSpecializationInfo(
-      FD, Template, TSK, TemplateArgs, TemplateParams, ArgsAsWritten, POI,
-      MSInfo);
+      FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
 }
 
 //===----------------------------------------------------------------------===//
@@ -1052,38 +1050,54 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
       return CTPSD->getSourceRange();
     return cast<ClassTemplateDecl *>(Pattern)->getSourceRange();
   }
-  case TSK_FriendDeclaration:
   case TSK_ExplicitSpecialization: {
-    const auto *Info = getExplicitSpecializationInfo();
-    auto TPLs = getTemplateParameterLists();
-    return SourceRange(TPLs.empty() ? Info->TemplateParams->getTemplateLoc()
-                                    : TPLs.front()->getTemplateLoc(),
-                       isThisDeclarationADefinition()
-                           ? CXXRecordDecl::getSourceRange().getEnd()
-                           : Info->TemplateArgsAsWritten->getRAngleLoc());
+    SourceRange Range = CXXRecordDecl::getSourceRange();
+    if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
+        !isThisDeclarationADefinition() && Args)
+      Range.setEnd(Args->getRAngleLoc());
+    return Range;
   }
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ExplicitInstantiationDefinition: {
-    const auto *Info = getExplicitInstantiationInfo();
-    return SourceRange(Info->ExternKeywordLoc.isValid()
-                           ? Info->ExternKeywordLoc
-                           : Info->TemplateKeywordLoc,
-                       Info->TemplateArgsAsWritten->getRAngleLoc());
+    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;
   }
   }
   llvm_unreachable("unhandled template specialization kind");
 }
 
-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();
+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;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1154,7 +1168,6 @@ 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)
@@ -1163,24 +1176,25 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
           // Tracking StrictPackMatch for Partial
           // Specializations is not needed.
           SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
-      InstantiatedFromMember(nullptr, false),
+      TemplateParams(Params), InstantiatedFromMember(nullptr, false),
       CanonInjectedTST(CanonInjectedTST) {
-  setSpecializationKind(TSK_ExplicitSpecialization);
-  setExplicitSpecializationInfo(Params, ArgsAsWritten);
+  if (AdoptTemplateParameterList(Params, this))
+    setInvalidDecl();
 }
 
 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");
-  return new (Context, DC) ClassTemplatePartialSpecializationDecl(
-      Context, TK, DC, StartLoc, IdLoc, Params, ArgsAsWritten,
-      SpecializedTemplate, Args, CanonInjectedTST, PrevDecl);
+  auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
+      Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
+      CanonInjectedTST, PrevDecl);
+  Result->setSpecializationKind(TSK_ExplicitSpecialization);
+  return Result;
 }
 
 ClassTemplatePartialSpecializationDecl *
@@ -1207,7 +1221,11 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
           getInstantiatedFromMember();
       MT && !isMemberSpecialization())
     return MT->getSourceRange();
-  return ClassTemplateSpecializationDecl::getSourceRange();
+  SourceRange Range = ClassTemplateSpecializationDecl::getSourceRange();
+  if (const TemplateParameterList *TPL = getTemplateParameters();
+      TPL && getTemplateParameterLists().empty())
+    Range.setBegin(TPL->getTemplateLoc());
+  return Range;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1466,11 +1484,8 @@ 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());
@@ -1478,11 +1493,10 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
   }
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ExplicitInstantiationDefinition: {
-    const auto *Info = getExplicitInstantiationInfo();
     SourceRange Range = VarDecl::getSourceRange();
-    if (SourceLocation ExternKW = Info->ExternKeywordLoc; ExternKW.isValid())
+    if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
       Range.setBegin(ExternKW);
-    else if (SourceLocation TemplateKW = Info->TemplateKeywordLoc;
+    else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
              TemplateKW.isValid())
       Range.setBegin(TemplateKW);
     if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
@@ -1493,16 +1507,30 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
   llvm_unreachable("unhandled template specialization kind");
 }
 
-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();
+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;
 }
 
 //===----------------------------------------------------------------------===//
@@ -1514,28 +1542,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),
-      InstantiatedFromMember(nullptr, false) {
-  setSpecializationKind(TSK_ExplicitSpecialization);
-  setExplicitSpecializationInfo(Params, ArgsAsWritten);
+      TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
+  if (AdoptTemplateParameterList(Params, DC))
+    setInvalidDecl();
 }
 
 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");
-  return new (Context, DC) VarTemplatePartialSpecializationDecl(
-      Context, DC, StartLoc, IdLoc, Params, ArgsAsWritten, SpecializedTemplate,
-      T, TInfo, S, Args);
+  auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
+      Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
+      Args);
+  Result->setSpecializationKind(TSK_ExplicitSpecialization);
+  return Result;
 }
 
 VarTemplatePartialSpecializationDecl *
@@ -1549,7 +1577,11 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
           getInstantiatedFromMember();
       MT && !isMemberSpecialization())
     return MT->getSourceRange();
-  return VarTemplateSpecializationDecl::getSourceRange();
+  SourceRange Range = VarTemplateSpecializationDecl::getSourceRange();
+  if (const TemplateParameterList *TPL = getTemplateParameters();
+      TPL && getTemplateParameterLists().empty())
+    Range.setBegin(TPL->getTemplateLoc());
+  return Range;
 }
 
 static TemplateParameterList *createBuiltinTemplateParameterList(

diff  --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index ffb3d74f6b9f4..8373dd8e373e0 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1131,9 +1131,6 @@ 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 abb6869a2b46e..2b1c0cac25b6d 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1044,9 +1044,6 @@ 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 8cb8d6ebf297f..a04070971f0eb 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -99,7 +99,6 @@ 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 45f0f0eaf7e70..3709fd0af3486 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -702,7 +702,7 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
       canResolveToExpr(Exp),
       parmVarDecl(hasType(nonConstReferenceType())).bind("parm"));
   const auto IsInstantiated = hasDeclaration(isInstantiated());
-  const auto FuncDecl = hasDeclaration(functionDecl());
+  const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
   const auto Matches = match(
       traverse(
           TK_AsIs,
@@ -716,16 +716,13 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
       Stm, Context);
   for (const auto &Nodes : Matches) {
     const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
-    const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
-    const auto *Func =
-        cast<FunctionDecl>(Parm->getDeclContext())->getDefinition();
-    if (!Func || !Func->doesThisDeclarationHaveABody())
+    const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
+    if (!Func->getBody() || !Func->getPrimaryTemplate())
       return Exp;
-    Parm = Func->getParamDecl(Parm->getFunctionScopeIndex());
 
+    const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
     const ArrayRef<ParmVarDecl *> AllParams =
-        Func->getTemplateInstantiationPattern(/*ForDefinition=*/true)
-            ->parameters();
+        Func->getPrimaryTemplate()->getTemplatedDecl()->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 40abf4570f219..64fdc0150ab8a 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -1143,22 +1143,21 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
 
       return 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;
-    }
+      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
@@ -1183,7 +1182,6 @@ 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 ac532d6a2f5ef..bdd6c5acf1d34 100644
--- a/clang/lib/Index/IndexingContext.cpp
+++ b/clang/lib/Index/IndexingContext.cpp
@@ -185,7 +185,6 @@ 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 08d2e556ad57c..53fbc36ae7600 100644
--- a/clang/lib/InstallAPI/Visitor.cpp
+++ b/clang/lib/InstallAPI/Visitor.cpp
@@ -318,7 +318,6 @@ 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:
@@ -335,7 +334,6 @@ static bool hasVTable(const CXXRecordDecl *D) {
   case TSK_Undeclared:
   case TSK_ExplicitSpecialization:
   case TSK_ImplicitInstantiation:
-  case TSK_FriendDeclaration:
     return false;
 
   case TSK_ExplicitInstantiationDeclaration:
@@ -363,7 +361,6 @@ 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:
@@ -378,7 +375,6 @@ 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:
@@ -605,7 +601,6 @@ 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 86f18d10f08b0..893989bd2398f 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2059,17 +2059,15 @@ 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, ParamLists, &SkipBody);
-      // Some template parameter lists may have been dropped because they were
-      // extraneous.
-      if (TemplateParams)
-        TemplateParams->resize(ParamLists.size());
+          SS, *TemplateId, attrs,
+          MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
+                                                : nullptr,
+                                 TemplateParams ? TemplateParams->size() : 0),
+          &SkipBody);
     }
   } else if (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation &&
              TUK == TagUseKind::Declaration) {

diff  --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index e57bad6f5c548..f9fb7745721fe 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -312,6 +312,12 @@ 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 =
@@ -319,13 +325,8 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
   TemplateArgumentListInfo ArgsInfo =
       TemplateArgumentListInfo(SourceLocation(), SourceLocation());
   ArgsInfo.addArgument(ArgLoc);
-
-  auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
-      AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
-      SourceLocation(), TemplateParams,
-      ASTTemplateArgumentListInfo::Create(AST, ArgsInfo), TextureTemplate,
-      {TemplateArgument(VectorType)},
-      CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
+  PartialSpec->setTemplateArgsAsWritten(
+      ASTTemplateArgumentListInfo::Create(AST, ArgsInfo));
 
   PartialSpec->setImplicit(true);
   PartialSpec->setLexicalDeclContext(HLSLNamespace);

diff  --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 32a07b6266666..f41f37b8a3d19 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -200,10 +200,15 @@ static bool DiagRecursiveConstraintEval(
 // Figure out the to-translation-unit depth for this function declaration for
 // the purpose of seeing if they 
diff er by constraints. This isn't the same as
 // getTemplateDepth, because it includes already instantiated parents.
-static unsigned CalculateTemplateDepthForConstraints(Sema &S,
-                                                     const NamedDecl *ND) {
-  // FIXME: This is a very expensive way to calculate this.
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
+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);
   return MLTAL.getNumLevels();
 }
 
@@ -1330,8 +1335,10 @@ bool Sema::CheckConstraintSatisfaction(
   return false;
 }
 
-static ExprResult SubstituteConceptsInConstraintExpression(
-    Sema &S, const ConceptSpecializationExpr *CSE, UnsignedOrNone SubstIndex) {
+static ExprResult
+SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
+                                         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
@@ -1339,8 +1346,7 @@ static ExprResult SubstituteConceptsInConstraintExpression(
   // If any such substitution results in an invalid concept-id,
   // the program is ill-formed; no diagnostic is required.
 
-  Expr *ConstraintExpr =
-      CSE->getNamedConcept()->getCanonicalDecl()->getConstraintExpr();
+  ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl();
   Sema::ArgPackSubstIndexRAII _(S, SubstIndex);
 
   const ASTTemplateArgumentListInfo *ArgsAsWritten =
@@ -1350,17 +1356,23 @@ static ExprResult SubstituteConceptsInConstraintExpression(
             return !ArgLoc.getArgument().isDependent() &&
                    ArgLoc.getArgument().isConceptOrConceptTemplateParameter();
           })) {
-    return ConstraintExpr;
+    return Concept->getConstraintExpr();
   }
 
-  return S.SubstConceptTemplateArguments(
-      CSE, ConstraintExpr,
-      S.getTemplateInstantiationArgs(CSE->getSpecializationDecl()));
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+      Concept, Concept->getLexicalDeclContext(),
+      /*Final=*/false, CSE->getTemplateArguments(),
+      /*RelativeToPrimary=*/true,
+      /*Pattern=*/nullptr,
+      /*ForConstraintInstantiation=*/true);
+  return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(),
+                                         MLTAL);
 }
 
-bool Sema::SetupConstraintScope(FunctionDecl *FD,
-                                const MultiLevelTemplateArgumentList &MLTAL,
-                                LocalInstantiationScope &Scope) {
+bool Sema::SetupConstraintScope(
+    FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+    const MultiLevelTemplateArgumentList &MLTAL,
+    LocalInstantiationScope &Scope) {
   assert(!isLambdaCallOperator(FD) &&
          "Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
          "instantiations");
@@ -1369,7 +1381,8 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
     InstantiatingTemplate Inst(
         *this, FD->getPointOfInstantiation(),
         Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
-        FD->getTemplateSpecializationArgs()->asArray(), SourceRange());
+        TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+        SourceRange());
     if (Inst.isInvalid())
       return true;
 
@@ -1405,10 +1418,11 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
             ? FD->getInstantiatedFromMemberFunction()
             : FD->getInstantiatedFromDecl();
 
-    InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
-                               Sema::InstantiatingTemplate::ConstraintsCheck{},
-                               InstantiatedFrom, ArrayRef<TemplateArgument>(),
-                               SourceRange());
+    InstantiatingTemplate Inst(
+        *this, FD->getPointOfInstantiation(),
+        Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
+        TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+        SourceRange());
     if (Inst.isInvalid())
       return true;
 
@@ -1425,12 +1439,23 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
 // constraint-instantiation and checking.
 std::optional<MultiLevelTemplateArgumentList>
 Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
-    FunctionDecl *FD, LocalInstantiationScope &Scope) {
-  MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(FD);
+    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);
   // Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
   if (isLambdaCallOperator(FD))
     return MLTAL;
-  if (SetupConstraintScope(FD, MLTAL, Scope))
+  if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
     return std::nullopt;
 
   return MLTAL;
@@ -1477,7 +1502,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;
@@ -1500,10 +1525,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
       Satisfaction);
 }
 
-static const Expr *
-SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
-                                                  const Expr *ConstrExpr) {
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
+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);
 
   if (MLTAL.getNumSubstitutedLevels() == 0)
     return ConstrExpr;
@@ -1513,7 +1543,8 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
   // this may happen while we're comparing two templates' constraint
   // equivalence.
   std::optional<LocalInstantiationScope> ScopeForParameters;
-  if (ND->isFunctionOrFunctionTemplate()) {
+  if (const NamedDecl *ND = DeclInfo.getDecl();
+      ND && ND->isFunctionOrFunctionTemplate()) {
     ScopeForParameters.emplace(S, /*CombineWithOuterScope=*/true);
     const FunctionDecl *FD = ND->getAsFunction();
     if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate();
@@ -1557,9 +1588,13 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
   // possible that e.g. constraints involving C<Class<T>> and C<Class> are
   // perceived identical.
   std::optional<Sema::ContextRAII> ContextScope;
-  const DeclContext *DC = ND->getFriendObjectKind()
-                              ? ND->getLexicalDeclContext()
-                              : ND->getDeclContext();
+  const DeclContext *DC = [&] {
+    if (!DeclInfo.getDecl())
+      return DeclInfo.getDeclContext();
+    return DeclInfo.getDecl()->getFriendObjectKind()
+               ? DeclInfo.getLexicalDeclContext()
+               : DeclInfo.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)),
@@ -1575,14 +1610,15 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
   return SubstConstr.get();
 }
 
-bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
-                                         const Decl *New,
+bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
+                                         const Expr *OldConstr,
+                                         const TemplateCompareNewDeclInfo &New,
                                          const Expr *NewConstr) {
   if (OldConstr == NewConstr)
     return true;
   // C++ [temp.constr.decl]p4
-  if (Old != New &&
-      Old->getLexicalDeclContext() != New->getLexicalDeclContext()) {
+  if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
+      Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
     Sema::SFINAETrap _(*this);
     if (const Expr *SubstConstr =
             SubstituteConstraintExpressionWithoutSatisfaction(*this, Old,
@@ -1604,15 +1640,19 @@ bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
   return ID1 == ID2;
 }
 
-bool Sema::FriendConstraintsDependOnEnclosingTemplate(
-    const FunctionTemplateDecl *FTD) {
-  assert(FTD->getFriendObjectKind() && "Must be a friend!");
+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");
 
   SmallVector<AssociatedConstraint, 3> ACs;
-  FTD->getAssociatedConstraints(ACs);
+  FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
 
-  const FunctionDecl *FD = FTD->getTemplatedDecl();
-  unsigned OldTemplateDepth = FTD->getTemplateDepth();
+  unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
   for (const AssociatedConstraint &AC : ACs)
     if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
                                                        AC.ConstraintExpr))
@@ -1648,9 +1688,9 @@ bool Sema::EnsureTemplateArgumentListConstraints(
   return false;
 }
 
-bool Sema::CheckFunctionTemplateConstraints(
-    SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
-    ArrayRef<TemplateArgument> TemplateArgs,
+static bool CheckFunctionConstraintsWithoutInstantiation(
+    Sema &SemaRef, SourceLocation PointOfInstantiation,
+    FunctionTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
     ConstraintSatisfaction &Satisfaction) {
   SmallVector<AssociatedConstraint, 3> TemplateAC;
   Template->getAssociatedConstraints(TemplateAC);
@@ -1659,22 +1699,47 @@ bool Sema::CheckFunctionTemplateConstraints(
     return false;
   }
 
-  LocalInstantiationScope Scope(*this);
+  LocalInstantiationScope Scope(SemaRef);
 
-  MultiLevelTemplateArgumentList MLTAL =
-      getTemplateInstantiationArgs(Template, TemplateArgs);
+  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.
 
-  Sema::ContextRAII SavedContext(*this, Template->getTemplatedDecl());
-  return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
-                                     PointOfInstantiation, Satisfaction);
+  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);
 }
 
-bool Sema::CheckFunctionSpecializationConstraints(
+bool Sema::CheckFunctionTemplateConstraints(
     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();
-  assert(Template && "Function is not a specialization");
+
+  if (!Template)
+    return ::CheckFunctionConstraintsWithoutInstantiation(
+        *this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
+        TemplateArgs, Satisfaction);
 
   // Note - code synthesis context for the constraints check is created
   // inside CheckConstraintsSatisfaction.
@@ -1691,7 +1756,8 @@ bool Sema::CheckFunctionSpecializationConstraints(
   LocalInstantiationScope Scope(*this);
 
   std::optional<MultiLevelTemplateArgumentList> MLTAL =
-      SetupConstraintCheckingTemplateArgumentsAndScope(Decl, Scope);
+      SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
+                                                       Scope);
 
   if (!MLTAL)
     return true;
@@ -2275,8 +2341,12 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
       InnerArgs = std::move(CTAI.SugaredConverted);
     }
 
-    MultiLevelTemplateArgumentList MLTAL =
-        SemaRef.getTemplateInstantiationArgs(Concept, InnerArgs);
+    MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
+        Concept, Concept->getLexicalDeclContext(),
+        /*Final=*/true, InnerArgs,
+        /*RelativeToPrimary=*/true,
+        /*Pattern=*/nullptr,
+        /*ForConstraintInstantiation=*/true);
 
     return SubstituteParameterMappings(SemaRef, &MLTAL,
                                        CSE->getTemplateArgsAsWritten(),
@@ -2357,7 +2427,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
     // [...]
     NormalizedConstraint *SubNF;
     if (ExprResult Res =
-            SubstituteConceptsInConstraintExpression(S, CSE, SubstIndex);
+            SubstituteConceptsInConstraintExpression(S, D, CSE, SubstIndex);
         Res.isUsable())
       // Use canonical declarations to merge ConceptDecls across 
diff erent
       // modules.
@@ -2507,8 +2577,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
     return false;
   }
 
-  unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
-  unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
+  unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
+  unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
 
   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 694067bea9e48..cddcf3a010279 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, NewTemplate->getTemplateParameters(),
-                         OldTemplate, OldTemplate->getTemplateParameters(),
-                         /*Complain=*/true, TPL_TemplateMatch))
+  if (NewTemplate &&
+      !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+                                      OldTemplate->getTemplateParameters(),
+                                      /*Complain=*/true, TPL_TemplateMatch))
     return New->setInvalidDecl();
 
   // C++ [class.mem]p1:
@@ -8023,8 +8023,6 @@ 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()
@@ -8067,8 +8065,10 @@ 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 =
-        IsVariableTemplate || IsVariableTemplateSpecialization ? 1 : 0;
+        (TemplateParams && !IsExplicitSpecialization) ? 1 : 0;
     if (TemplateParamLists.size() > VDTemplateParamLists)
       NewVD->setTemplateParameterListsInfo(
           Context, TemplateParamLists.drop_back(VDTemplateParamLists));
@@ -10119,7 +10119,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   bool isMemberSpecialization = false;
   bool isFunctionTemplateSpecialization = false;
 
-  TemplateParameterList *TemplateParams = nullptr;
   bool HasExplicitTemplateArgs = false;
   TemplateArgumentListInfo TemplateArgs;
 
@@ -10204,14 +10203,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
         D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
             ? D.getName().TemplateId
             : nullptr;
-    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());
+    TemplateParameterList *TemplateParams =
+        MatchTemplateParametersToScopeSpecifier(
+            D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
+            D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend,
+            isMemberSpecialization, Invalid);
     if (TemplateParams) {
       // Check that we can declare a template here.
       if (CheckTemplateDeclScope(S, TemplateParams))
@@ -10246,10 +10242,19 @@ 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;
-        NewFD->setInnerLocStart(TemplateParams->getTemplateLoc());
+        // For source fidelity, store all the template param lists.
+        if (TemplateParamLists.size() > 0)
+          NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
 
         // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
         if (isFriend) {
@@ -10279,12 +10284,6 @@ 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 &&
@@ -10886,11 +10885,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, TemplateParams, ExplicitTemplateArgs, Previous))
+                NewFD, ExplicitTemplateArgs, Previous))
           NewFD->setInvalidDecl();
       } else if (!NewFD->isInvalidDecl()) {
-        if (CheckFunctionTemplateSpecialization(NewFD, TemplateParams,
-                                                ExplicitTemplateArgs, Previous))
+        if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs,
+                                                Previous))
           NewFD->setInvalidDecl();
       }
     } else if (isMemberSpecialization && !FunctionTemplate) {
@@ -11194,7 +11193,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(FunctionTemplate)) {
+        FriendConstraintsDependOnEnclosingTemplate(NewFD)) {
       NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
 
       // C++ [temp.friend]p9:

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 56ae96cae3e5b..9bbe99df064c3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13938,13 +13938,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
       }
 
       if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
-        // 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))
+        if (TemplateParameterListsAreEqual(TemplateParams,
+                                           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 833e73922cfc9..851d58c49f7b9 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1129,8 +1129,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       return ExprError();
     }
 
-    DeclResult VDecl = CheckVarTemplateId(
-        VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
+    DeclResult VDecl =
+        CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
+                           *TemplateArgs, /*SetWrittenArgs=*/false);
     if (VDecl.isInvalid())
       return ExprError();
 

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 83fde956e34b2..e11bbd7085798 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1325,10 +1325,8 @@ OverloadKind Sema::CheckOverload(Scope *S, FunctionDecl *New,
       !New->getType()->isDependentType()) {
     LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
     TemplateSpecResult.addAllDecls(Old);
-    if (CheckFunctionTemplateSpecialization(New, /*TemplateParams=*/nullptr,
-                                            /*ExplicitTemplateArgs=*/nullptr,
-                                            TemplateSpecResult,
-                                            /*QualifiedFriend*/ true)) {
+    if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
+                                            /*QualifiedFriend*/true)) {
       New->setInvalidDecl();
       return OverloadKind::Overload;
     }

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7228cc6ff4026..8c94a1ad39208 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2108,71 +2108,19 @@ 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_
diff erent_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();
-
-  // 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(
-            NewTemplate, TemplateParams, PrevClassTemplate,
+            TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
+                                                       : CurContext,
+                                       CurContext, KWLoc),
+            TemplateParams, PrevClassTemplate,
             PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
-            TPL_TemplateMatch)) {
-      NewTemplate->setInvalidDecl();
-      NewClass->setInvalidDecl();
+            TPL_TemplateMatch))
       return true;
-    }
 
     // C++ [temp.class]p4:
     //   In a redeclaration, partial specialization, explicit
@@ -2217,6 +2165,15 @@ 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_
diff erent_kind) << Name;
+    Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+    return true;
   }
 
   // Check the template parameter list of this declaration, possibly
@@ -2248,20 +2205,62 @@ DeclResult Sema::CheckClassTemplate(
     }
   }
 
-  // Set the access specifier.
-  if (!Invalid && TUK != TagUseKind::Friend &&
-      NewTemplate->getDeclContext()->isRecord())
-    SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+  // 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());
 
-  if (ShouldAddRedecl && PrevClassTemplate)
+  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 (IsMemberSpecialization) {
     assert(PrevClassTemplate &&
            "Member specialization without a primary template?");
     NewTemplate->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 (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
     NewClass->startDefinition();
 
@@ -2834,7 +2833,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;
@@ -3100,12 +3099,10 @@ 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(
-                /*NewInstFrom=*/nullptr, ParamLists[ParamIdx],
-                /*OldInstFrom=*/nullptr, ExpectedTemplateParams,
-                /*Complain=*/!SuppressDiagnostic, TPL_TemplateMatch))
+            !TemplateParameterListsAreEqual(ParamLists[ParamIdx],
+                                            ExpectedTemplateParams,
+                                            !SuppressDiagnostic, TPL_TemplateMatch))
           Invalid = true;
 
         if (!Invalid &&
@@ -3172,9 +3169,6 @@ 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).
@@ -4482,9 +4476,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
     VarTemplatePartialSpecializationDecl *Partial =
         VarTemplatePartialSpecializationDecl::Create(
             Context, VarTemplate->getDeclContext(), TemplateKWLoc,
-            TemplateNameLoc, TemplateParams,
-            ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
-            VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
+            TemplateNameLoc, TemplateParams, VarTemplate, TSI->getType(), TSI,
+            SC, CTAI.CanonicalConverted);
+    Partial->setTemplateArgsAsWritten(TemplateArgs);
 
     if (!PrevPartial)
       VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4497,9 +4491,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
     Specialization = VarTemplateSpecializationDecl::Create(
         Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
         VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
-    Specialization->setExplicitSpecializationInfo(
-        TemplateParams,
-        ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
+    Specialization->setTemplateArgsAsWritten(TemplateArgs);
 
     if (!PrevDecl)
       VarTemplate->AddSpecialization(Specialization, InsertPos);
@@ -4585,7 +4577,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
 DeclResult
 Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
                          SourceLocation TemplateNameLoc,
-                         const TemplateArgumentListInfo &TemplateArgs) {
+                         const TemplateArgumentListInfo &TemplateArgs,
+                         bool SetWrittenArgs) {
   assert(Template && "A variable template id without template?");
 
   // Check that the template argument list is well-formed for this template.
@@ -4784,6 +4777,8 @@ 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))
@@ -4801,7 +4796,7 @@ ExprResult Sema::CheckVarTemplateId(
     const TemplateArgumentListInfo *TemplateArgs) {
 
   DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
-                                       *TemplateArgs);
+                                       *TemplateArgs, /*SetWrittenArgs=*/false);
   if (Decl.isInvalid())
     return ExprError();
 
@@ -6193,8 +6188,7 @@ bool Sema::CheckTemplateArgumentList(
   if (UpdateArgsWithConversions)
     TemplateArgs = std::move(NewArgs);
 
-  // Template template parameters can never have their constraints checked.
-  if (!PartialTemplateArgs && !isa<TemplateTemplateParmDecl>(Template)) {
+  if (!PartialTemplateArgs) {
     // Setup the context/ThisScope for the case where we are needing to
     // re-instantiate constraints outside of normal instantiation.
     DeclContext *NewContext = Template->getDeclContext();
@@ -6213,8 +6207,11 @@ bool Sema::CheckTemplateArgumentList(
     ContextRAII Context(*this, NewContext);
     CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
 
-    MultiLevelTemplateArgumentList MLTAL =
-        getTemplateInstantiationArgs(Template, CTAI.SugaredConverted);
+    MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+        Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
+        /*RelativeToPrimary=*/true,
+        /*Pattern=*/nullptr,
+        /*ForConceptInstantiation=*/true);
     if (!isa<ConceptDecl>(Template) &&
         EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
@@ -8205,8 +8202,9 @@ Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
 
 /// Match two template parameters within template parameter lists.
 static bool MatchTemplateParameterKind(
-    Sema &S, NamedDecl *New, const Decl *NewInstFrom, NamedDecl *Old,
-    const Decl *OldInstFrom, bool Complain,
+    Sema &S, NamedDecl *New,
+    const Sema::TemplateCompareNewDeclInfo &NewInstFrom, NamedDecl *Old,
+    const NamedDecl *OldInstFrom, bool Complain,
     Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
   // Check the actual kind (type, non-type, template).
   if (Old->getKind() != New->getKind()) {
@@ -8294,7 +8292,7 @@ static bool MatchTemplateParameterKind(
     if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
       return false;
     if (!S.TemplateParameterListsAreEqual(
-            NewTTP, NewTTP->getTemplateParameters(), OldTTP,
+            NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
             OldTTP->getTemplateParameters(), Complain,
             (Kind == Sema::TPL_TemplateMatch
                  ? Sema::TPL_TemplateTemplateParmMatch
@@ -8372,8 +8370,8 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
 }
 
 bool Sema::TemplateParameterListsAreEqual(
-    const Decl *NewInstFrom, TemplateParameterList *New,
-    const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+    const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
+    const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
     TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
   if (Old->size() != New->size()) {
     if (Complain)
@@ -8755,7 +8753,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;
@@ -8953,13 +8951,15 @@ 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(
@@ -8995,8 +8995,13 @@ 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);
@@ -9006,18 +9011,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
     // template specialization, make a note of that.
     if (isMemberSpecialization)
       Partial->setMemberSpecialization();
-  }
 
-  SetNestedNameSpecifier(*this, Specialization, SS);
-  if (TemplateParameterLists.size() > 1 && SS.isSet()) {
-    Specialization->setTemplateParameterListsInfo(
-        Context, TemplateParameterLists.drop_back(1));
+    CheckTemplatePartialSpecialization(Partial);
   }
 
-  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
@@ -9377,7 +9374,6 @@ 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!");
@@ -9392,7 +9388,6 @@ 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
@@ -9439,7 +9434,6 @@ 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.
@@ -9475,7 +9469,6 @@ 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.
@@ -9535,8 +9528,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
 }
 
 bool Sema::CheckDependentFunctionTemplateSpecialization(
-    FunctionDecl *FD, const TemplateParameterList *TemplateParams,
-    const TemplateArgumentListInfo *ExplicitTemplateArgs,
+    FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
     LookupResult &Previous) {
   // Remove anything from Previous that isn't a function template in
   // the correct context.
@@ -9573,14 +9565,13 @@ bool Sema::CheckDependentFunctionTemplateSpecialization(
   }
 
   FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
-                                         TemplateParams, ExplicitTemplateArgs);
+                                         ExplicitTemplateArgs);
   return false;
 }
 
 bool Sema::CheckFunctionTemplateSpecialization(
-    FunctionDecl *FD, const TemplateParameterList *TemplateParams,
-    TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
-    bool QualifiedFriend) {
+    FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
+    LookupResult &Previous, bool QualifiedFriend) {
   // The set of function template specializations that could match this
   // explicit function template specialization.
   UnresolvedSet<8> Candidates;
@@ -9830,11 +9821,9 @@ bool Sema::CheckFunctionTemplateSpecialization(
   TemplateArgumentList *TemplArgs = TemplateArgumentList::CreateCopy(
       Context, Specialization->getTemplateSpecializationArgs()->asArray());
   FD->setFunctionTemplateSpecialization(
-      Context, Specialization->getPrimaryTemplate(), TemplArgs,
-      /*InsertPos=*/nullptr, SpecInfo->getTemplateSpecializationKind(),
-      TemplateParams,
-      ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr,
-      /*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
+      Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
+      SpecInfo->getTemplateSpecializationKind(),
+      ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr);
 
   // A function template specialization inherits the target attributes
   // of its template.  (We require the attributes explicitly in the
@@ -9984,13 +9973,14 @@ 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) {
-      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);
+    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());
     }
 
     Previous.clear();
@@ -10077,8 +10067,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
 template<typename DeclT>
 static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
                                              SourceLocation Loc) {
-  if (auto Kind = OrigD->getTemplateSpecializationKind();
-      Kind != TSK_ImplicitInstantiation && Kind != TSK_FriendDeclaration)
+  if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
     return;
 
   // FIXME: Inform AST mutation listeners of this AST mutation.
@@ -10408,6 +10397,7 @@ 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.
@@ -10426,19 +10416,22 @@ DeclResult Sema::ActOnExplicitInstantiation(
     }
   }
 
-  Specialization->setExplicitInstantiationInfo(
-      ExternLoc, TemplateLoc,
-      ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
+  Specialization->setTemplateArgsAsWritten(TemplateArgs);
+
+  // Set source locations for keywords.
+  Specialization->setExternKeywordLoc(ExternLoc);
+  Specialization->setTemplateKeywordLoc(TemplateLoc);
   Specialization->setBraceRange(SourceRange());
 
   bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
   ProcessDeclAttributeList(S, Specialization, Attr);
   ProcessAPINotes(Specialization);
 
-  // Add the explicit instantiation into its lexical context.
-  auto *LexicalDC = ClassTemplate->getLexicalDeclContext();
-  Specialization->setLexicalDeclContext(LexicalDC);
-  LexicalDC->addDecl(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);
 
   // Syntax is now OK, so return if it has no other effect on semantics.
   if (HasNoEffect) {
@@ -10767,15 +10760,6 @@ 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
@@ -10825,7 +10809,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
         return true;
       }
 
-      if (!HasExplicitTemplateArgs) {
+      if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
         // C++1y [temp.explicit]p3:
         //   If the explicit instantiation is for a variable, the unqualified-id
         //   in the declaration shall be a template-id.
@@ -10837,8 +10821,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
         return true;
       }
 
-      DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
-                                          D.getIdentifierLoc(), TemplateArgs);
+      // 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);
       if (Res.isInvalid())
         return true;
 
@@ -10886,10 +10875,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
       // Instantiate static data member or variable template.
       Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
       if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Prev)) {
-        assert(HasExplicitTemplateArgs);
-        VTSD->setExplicitInstantiationInfo(
-            ExternLoc, TemplateLoc,
-            ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
+        VTSD->setExternKeywordLoc(ExternLoc);
+        VTSD->setTemplateKeywordLoc(TemplateLoc);
       }
 
       // Merge attributes.
@@ -10918,6 +10905,15 @@ 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 b75abecefafd6..26c397afdd6ef 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3182,16 +3182,36 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
                                 ArrayRef<TemplateArgument> CanonicalDeducedArgs,
                                 TemplateDeductionInfo &Info) {
   llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
-  if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
+  bool DeducedArgsNeedReplacement = false;
+  if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) {
     TD->getAssociatedConstraints(AssociatedConstraints);
-  else if (auto *TD = dyn_cast<VarTemplatePartialSpecializationDecl>(Template))
+    DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
+  } else if (auto *TD =
+                 dyn_cast<VarTemplatePartialSpecializationDecl>(Template)) {
     TD->getAssociatedConstraints(AssociatedConstraints);
-  else
+    DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
+  } 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, 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);
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
@@ -3952,8 +3972,9 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
   if (!IsLambda && !IsIncomplete) {
     if (CheckFunctionTemplateConstraints(
-            Info.getLocation(), FunctionTemplate, CTAI.CanonicalConverted,
-            Info.AssociatedConstraintsSatisfaction))
+            Info.getLocation(),
+            FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
+            CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
       return TemplateDeductionResult::MiscellaneousDeductionFailure;
     if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
       Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
@@ -3999,8 +4020,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   //   ([temp.constr.constr]). If the constraints are not satisfied, type
   //   deduction fails.
   if (IsLambda && !IsIncomplete) {
-    if (CheckFunctionSpecializationConstraints(
-            Info.getLocation(), Specialization,
+    if (CheckFunctionTemplateConstraints(
+            Info.getLocation(), Specialization, CTAI.CanonicalConverted,
             Info.AssociatedConstraintsSatisfaction))
       return TemplateDeductionResult::MiscellaneousDeductionFailure;
 
@@ -6007,7 +6028,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(FT1, TPL1, FT2, TPL2, false,
+  if (!TemplateParameterListsAreEqual(TPL1, TPL2, false,
                                       Sema::TPL_TemplateParamsEquivalent))
     return nullptr;
 
@@ -6362,7 +6383,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(P1, TPL1, P2, TPL2, false,
+  if (!S.TemplateParameterListsAreEqual(TPL1, TPL2, false,
                                         Sema::TPL_TemplateParamsEquivalent))
     return nullptr;
 

diff  --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 15b6aea749584..fa740d5581e5f 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -65,9 +65,10 @@ 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,
-                                               New, NewACs[I].ConstraintExpr))
+    if (!SemaRef.AreConstraintExpressionsEqual(
+            Old, OldACs[I].ConstraintExpr, NewInfo, NewACs[I].ConstraintExpr))
       return false;
 
   return true;
@@ -502,7 +503,6 @@ 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(
-          Decl::castFromDeclContext(Template->getDeclContext()));
+      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
   }
 
   Sema &SemaRef;
@@ -1053,9 +1053,52 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
     }
   }
 
-  MultiLevelTemplateArgumentList ArgsForBuildingRC =
-      SemaRef.getTemplateInstantiationArgs(F, TemplateArgsForBuildingRC);
+  // A list of template arguments for transforming the require-clause of F.
+  // It must contain the entire set of template argument lists.
+  MultiLevelTemplateArgumentList ArgsForBuildingRC;
   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 6df6d5505c61c..5309ec4430e9e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -49,6 +49,38 @@ 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.
@@ -136,197 +168,397 @@ bool isLambdaEnclosedByTypeAliasDecl(
               .TraverseType(Underlying);
 }
 
-} // namespace
+// 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);
+}
 
-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;
+// 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);
+}
+
+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;
         }
-      } 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());
+  }
 
-    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;
-      }
-      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();
+  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();
       }
-      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;
+      Result.addOuterTemplateArguments(
+          TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
+          /*Final=*/false);
     }
+  }
 
-    // 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;
-    }
+  return Response::ChangeDecl(FTD->getLexicalDeclContext());
+}
 
-    if (!Innermost)
-      continue;
+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);
+  }
 
-    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;
+  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());
+      }
     }
+  }
+
+  return Response::UseNextDecl(Rec);
+}
+
+Response HandleImplicitConceptSpecializationDecl(
+    const ImplicitConceptSpecializationDecl *CSD,
+    MultiLevelTemplateArgumentList &Result) {
+  Result.addOuterTemplateArguments(
+      const_cast<ImplicitConceptSpecializationDecl *>(CSD),
+      CSD->getTemplateArguments(),
+      /*Final=*/false);
+  return Response::UseNextDecl(CSD);
+}
+
+Response HandleGenericDeclContext(const Decl *CurDecl) {
+  return Response::UseNextDecl(CurDecl);
+}
+} // namespace TemplateInstArgsHelpers
+} // namespace
 
-    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;
+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);
       }
-      for (unsigned I = 0; I < ExtraLevels; ++I)
-        TemplateArgs.addOuterTemplateArguments(std::nullopt);
+    } else {
+      R = HandleGenericDeclContext(CurDecl);
     }
+
+    if (R.IsDone)
+      return Result;
+    if (R.ClearRelativeToPrimary)
+      RelativeToPrimary = false;
+    assert(R.NextDecl);
+    CurDecl = R.NextDecl;
   }
-  return TemplateArgs;
+  return Result;
 }
 
 bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@@ -1509,8 +1741,10 @@ namespace {
 
     CXXRecordDecl::LambdaDependencyKind
     ComputeLambdaDependency(LambdaScopeInfo *LSI) {
-      if (auto TypeAlias = ::getEnclosingTypeAliasTemplateDecl(getSema());
-          TypeAlias && ::isLambdaEnclosedByTypeAliasDecl(
+      if (auto TypeAlias =
+              TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
+                  getSema());
+          TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
                            LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
         unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
         if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@@ -3851,9 +4085,6 @@ 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());
@@ -3877,12 +4108,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
   if (!Pattern.isUsable())
     return Pattern.isInvalid();
 
-  MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-      ClassTemplateSpec, /*Innermost=*/std::nullopt,
-      /*NumLevels=*/Pattern.get()->getTemplateDepth());
-
-  bool Err = InstantiateClassImpl(PointOfInstantiation, ClassTemplateSpec,
-                                  Pattern.get(), TemplateArgs, TSK, Complain);
+  bool Err = InstantiateClassImpl(
+      PointOfInstantiation, ClassTemplateSpec, Pattern.get(),
+      getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);
 
   // If we haven't already warn on avaibility, consider the avaibility
   // attributes of the partial specialization.
@@ -4244,7 +4472,14 @@ ExprResult Sema::SubstConceptTemplateArguments(
       [](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); });
 
   MultiLevelTemplateArgumentList MLTALForConstraint =
-      getTemplateInstantiationArgs(CSE->getNamedConcept(), NewArgList);
+      getTemplateInstantiationArgs(
+          CSE->getNamedConcept(),
+          CSE->getNamedConcept()->getLexicalDeclContext(),
+          /*Final=*/false,
+          /*Innermost=*/NewArgList,
+          /*RelativeToPrimary=*/true,
+          /*Pattern=*/nullptr,
+          /*ForConstraintInstantiation=*/true);
 
   // 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 c3277748ab1f6..c9bc613a7c4ea 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -49,63 +49,40 @@ 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,
-                           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()));
+                           const MultiLevelTemplateArgumentList &TemplateArgs) {
+  if (!OldDecl->getQualifierLoc())
+    return false;
 
-    NestedNameSpecifierLoc NewQualifierLoc =
-        SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+  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(),
                                             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, Owner);
+  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
 }
 
 bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
                                               TagDecl *NewDecl) {
-  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
+  return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
 }
 
 // Include attribute instantiation code.
@@ -1782,10 +1759,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(),
@@ -2419,8 +2396,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
 
       // Make sure the parameter lists match.
       if (!SemaRef.TemplateParameterListsAreEqual(
-              RecordInst, InstParams, MostRecentPrevCT, PrevParams, true,
-              Sema::TPL_TemplateMatch))
+              RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
+              PrevParams, true, Sema::TPL_TemplateMatch))
         return nullptr;
 
       // Do some additional validation, then merge default arguments
@@ -2778,21 +2755,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     }
   }
 
-  FunctionDecl *PrevDecl = nullptr;
   if (FunctionTemplate && !TemplateParams) {
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
 
     void *InsertPos = nullptr;
-    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;
-    }
+    FunctionDecl *SpecFunc
+      = FunctionTemplate->findSpecialization(Innermost, InsertPos);
+
+    // If we already have a function template specialization, return it.
+    if (SpecFunc)
+      return SpecFunc;
   }
 
   bool MergeWithParentScope = (TemplateParams != nullptr) ||
@@ -2885,9 +2857,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         D->FriendConstraintRefersToEnclosingTemplate());
     Function->setRangeEnd(D->getSourceRange().getEnd());
   }
-  Function->setPreviousDeclaration(PrevDecl);
-  if (PrevDecl)
-    SemaRef.mergeDeclAttributes(Function, PrevDecl);
 
   if (D->isInlined())
     Function->setImplicitlyInline();
@@ -2944,10 +2913,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
 
     FunctionTemplate->setLexicalDeclContext(LexicalDC);
 
-    if (PrevDecl)
-      FunctionTemplate->setPreviousDecl(
-          PrevDecl->getDescribedFunctionTemplate());
-
     if (isFriend && D->isThisDeclarationADefinition()) {
       FunctionTemplate->setInstantiatedFromMemberTemplate(
                                            D->getDescribedFunctionTemplate());
@@ -2957,14 +2922,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
                  Sema::CodeSynthesisContext::BuildingDeductionGuides) {
     // Record this function template specialization.
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
-    Function->setFunctionTemplateSpecialization(
-        SemaRef.Context, FunctionTemplate,
-        TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
-        /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
-        /*TemplateParams=*/nullptr,
-        /*TemplateArgsAsWritten=*/nullptr,
-        /*PointOfInstantiation=*/SourceLocation(),
-        /*AddSpecialization=*/PrevDecl == nullptr);
+    Function->setFunctionTemplateSpecialization(FunctionTemplate,
+                            TemplateArgumentList::CreateCopy(SemaRef.Context,
+                                                             Innermost),
+                                                /*InsertPos=*/nullptr);
   } else if (FunctionRewriteKind == RewriteKind::None) {
     if (isFriend && D->isThisDeclarationADefinition()) {
       // Do not connect the friend to the template unless it's actually a
@@ -3022,7 +2983,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     }
 
     if (SemaRef.CheckFunctionTemplateSpecialization(
-            Function, DFTSI->TemplateParameters ? TemplateParams : nullptr,
+            Function,
             DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
             Previous))
       Function->setInvalidDecl();
@@ -3040,8 +3001,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
                                        ExplicitArgs))
       return nullptr;
 
-    if (SemaRef.CheckFunctionTemplateSpecialization(Function, TemplateParams,
-                                                    &ExplicitArgs, Previous))
+    if (SemaRef.CheckFunctionTemplateSpecialization(Function,
+                                                    &ExplicitArgs,
+                                                    Previous))
       Function->setInvalidDecl();
 
     IsExplicitSpecialization = true;
@@ -3158,8 +3120,6 @@ 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
@@ -3167,16 +3127,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
 
     void *InsertPos = nullptr;
-    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;
-    }
+    FunctionDecl *SpecFunc
+      = FunctionTemplate->findSpecialization(Innermost, InsertPos);
+
+    // If we already have a function template specialization, return it.
+    if (SpecFunc)
+      return SpecFunc;
   }
 
   bool isFriend;
@@ -3193,6 +3149,19 @@ 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 =
@@ -3318,9 +3287,6 @@ 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();
@@ -3352,33 +3318,25 @@ 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(
-        SemaRef.Context, FunctionTemplate,
-        TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
-        /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
-        /*TemplateParams=*/nullptr,
-        /*TemplateArgsAsWritten=*/nullptr,
-        /*PointOfInstantiation=*/SourceLocation(),
-        /*AddSpecialization=*/PrevDecl == nullptr);
+    Method->setFunctionTemplateSpecialization(FunctionTemplate,
+                         TemplateArgumentList::CreateCopy(SemaRef.Context,
+                                                          Innermost),
+                                              /*InsertPos=*/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())
@@ -3421,8 +3379,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     }
 
     if (SemaRef.CheckFunctionTemplateSpecialization(
-            Method, DFTSI->TemplateParameters,
-            DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
+            Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
             Previous))
       Method->setInvalidDecl();
 
@@ -3438,8 +3395,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
                                        ExplicitArgs))
       return nullptr;
 
-    if (SemaRef.CheckFunctionTemplateSpecialization(Method, TemplateParams,
-                                                    &ExplicitArgs, Previous))
+    if (SemaRef.CheckFunctionTemplateSpecialization(Method,
+                                                    &ExplicitArgs,
+                                                    Previous))
       Method->setInvalidDecl();
 
     IsExplicitSpecialization = true;
@@ -4569,22 +4527,16 @@ 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;
-  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))
+  if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
+          D->getTemplateArgsAsWritten()) {
+    InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
+    InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
+
+    if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->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.
@@ -4639,14 +4591,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
           SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
           D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
           CTAI.StrictPackMatch, PrevDecl);
-  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);
+  InstD->setTemplateArgsAsWritten(InstTemplateArgs);
 
   // Add this partial specialization to the set of class template partial
   // specializations.
@@ -4660,6 +4605,8 @@ 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);
 
@@ -4679,6 +4626,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
 Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
     VarTemplateSpecializationDecl *D) {
 
+  TemplateArgumentListInfo VarTemplateArgsInfo;
   VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
   assert(VarTemplate &&
          "A template specialization without specialized template?");
@@ -4689,15 +4637,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
   if (!InstVarTemplate)
     return nullptr;
 
-  assert(!D->getExplicitInstantiationInfo());
-  const auto *ExplicitSpecializationInfo = D->getExplicitSpecializationInfo();
   // Substitute the current template arguments.
-  TemplateArgumentListInfo VarTemplateArgsInfo;
-  if (ExplicitSpecializationInfo) {
-    // The template parameters for an explicit specialization are empty and
-    // never need to be transformed.
-    const auto *TemplateArgsInfo =
-        ExplicitSpecializationInfo->TemplateArgsAsWritten;
+  if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
+          D->getTemplateArgsAsWritten()) {
     VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
     VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
 
@@ -4728,17 +4670,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
                       PrevDecl->getPointOfInstantiation(), Ignored))
     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;
+  if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
+          InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
+    VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
+    return VTSD;
+  }
+  return nullptr;
 }
 
 VarTemplateSpecializationDecl *
@@ -4747,8 +4684,6 @@ 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,
@@ -5004,17 +4939,16 @@ 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;
@@ -5131,11 +5065,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
   VarTemplatePartialSpecializationDecl *InstPartialSpec =
       VarTemplatePartialSpecializationDecl::Create(
           SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
-          PartialSpec->getLocation(), InstParams,
-          ASTTemplateArgumentListInfo::Create(SemaRef.Context,
-                                              InstTemplateArgs),
-          VarTemplate, TSI->getType(), TSI, PartialSpec->getStorageClass(),
-          CTAI.CanonicalConverted);
+          PartialSpec->getLocation(), InstParams, VarTemplate, TSI->getType(),
+          TSI, PartialSpec->getStorageClass(), CTAI.CanonicalConverted);
+
+  InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
 
   // Substitute the nested name specifier, if any.
   if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -5370,11 +5303,8 @@ 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
@@ -5382,31 +5312,34 @@ 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 (!PatternDecl)
+  if (FD->getFriendObjectKind() != Decl::FOK_None &&
+      !FD->getTemplateInstantiationPattern())
     return 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.
+  //
+  // 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);
+
   if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
     return true;
 
@@ -5447,22 +5380,16 @@ 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: 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();
-  unsigned NumLevels = Template->getTemplateDepth();
-  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);
-
   if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
     UpdateExceptionSpec(Decl, EST_None);
     return;
@@ -5627,10 +5554,7 @@ FunctionDecl *Sema::InstantiateFunctionDeclaration(
   MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
                                        /*Final=*/false);
 
-  return cast_or_null<FunctionDecl>(SubstDecl(
-      FD,
-      isa<CXXMethodDecl>(FD) ? FD->getParent() : FD->getLexicalDeclContext(),
-      MArgs));
+  return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
 }
 
 void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
@@ -5985,52 +5909,36 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     RebuildTypeSourceInfoForDefaultSpecialMembers();
     SetDeclDefaulted(Function, PatternDecl->getLocation());
   } else {
-    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");
+    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());
     }
     MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-        Function, /*Innermost=*/std::nullopt,
-        /*NumLevels=*/PatternDecl->getTemplateDepth(),
-        /*SkipInnerNonInstantiated=*/true);
+        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);
 
     ActOnStartOfFunctionDef(nullptr, Function);
 
@@ -6396,8 +6304,6 @@ 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;
 
@@ -6415,9 +6321,8 @@ 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, /*Innermost=*/std::nullopt,
-      /*NumLevels=*/PatternDecl->getTemplateDepth());
+  MultiLevelTemplateArgumentList TemplateArgs =
+      getTemplateInstantiationArgs(Var);
 
   VarTemplateSpecializationDecl *VarSpec =
       dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -6578,6 +6483,15 @@ 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,
@@ -6585,13 +6499,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
     Var = VTSD;
 
     if (Var) {
-      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);
+      VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
 
       llvm::PointerUnion<VarTemplateDecl *,
                          VarTemplatePartialSpecializationDecl *> PatternPtr =
@@ -7381,7 +7289,6 @@ 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 ea4e3f9204175..fb291a4b0f2c5 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -905,10 +905,9 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
   if (Record.readInt()) { // hasExtInfo
     auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
     Record.readQualifierInfo(*Info);
-    Expr *ConstraintExpr = Record.readExpr();
-    UnsignedOrNone ArgPackSubstIndex = Record.readUnsignedOrNone();
-    Info->TrailingRequiresClause =
-        AssociatedConstraint(ConstraintExpr, ArgPackSubstIndex);
+    Info->TrailingRequiresClause = AssociatedConstraint(
+        Record.readExpr(),
+        UnsignedOrNone::fromInternalRepresentation(Record.readUInt32()));
     DD->DeclInfo = Info;
   }
   QualType TSIType = Record.readType();
@@ -950,9 +949,6 @@ 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();
@@ -977,7 +973,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
 
     FunctionTemplateSpecializationInfo *FTInfo =
         FunctionTemplateSpecializationInfo::Create(
-            C, FD, Template, TSK, TemplArgList, TemplateParams,
+            C, FD, Template, TSK, TemplArgList,
             HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI,
             MSInfo);
     FD->TemplateOrSpecialization = FTInfo;
@@ -1012,9 +1008,6 @@ 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();
@@ -1022,7 +1015,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
       Record.readTemplateArgumentListInfo(TemplArgsWritten);
 
     FD->setDependentTemplateSpecialization(
-        Reader.getContext(), Candidates, TemplateParams,
+        Reader.getContext(), Candidates,
         HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr);
     // These are not merged; we don't need to merge redeclarations of dependent
     // template friends.
@@ -2555,20 +2548,6 @@ 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>();
@@ -2599,11 +2578,27 @@ 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) {
+                                    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;
+
   RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
 
   // These are read/set from/to the first declaration.
@@ -2649,6 +2644,17 @@ 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);
@@ -2656,20 +2662,6 @@ 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();
@@ -2700,6 +2692,9 @@ 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 1390bc7c8dc9a..7f5005aa666c7 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -805,10 +805,6 @@ 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)
@@ -843,10 +839,6 @@ 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)
@@ -1754,7 +1746,6 @@ 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());
@@ -1763,8 +1754,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
                FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
       DependentFunctionTemplateSpecializationInfo *DFTSInfo =
           D->getDependentSpecializationInfo();
-      if (!DFTSInfo->TemplateArgumentsAsWritten &&
-          !DFTSInfo->TemplateParameters)
+      if (!DFTSInfo->TemplateArgumentsAsWritten)
         AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
     }
   }
@@ -1945,36 +1935,29 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
   Record.AddSourceLocation(D->getPointOfInstantiation());
   Record.push_back(D->getSpecializationKind());
   Record.push_back(D->hasStrictPackMatch());
-
-  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.
   //
@@ -1996,7 +1979,9 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
 }
 
 void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
-    ClassTemplatePartialSpecializationDecl *D) {
+                                    ClassTemplatePartialSpecializationDecl *D) {
+  Record.AddTemplateParameterList(D->getTemplateParameters());
+
   VisitClassTemplateSpecializationDecl(D);
 
   // These are read/set from/to the first declaration.
@@ -2029,34 +2014,27 @@ 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());
@@ -2075,6 +2053,8 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
 
 void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
     VarTemplatePartialSpecializationDecl *D) {
+  Record.AddTemplateParameterList(D->getTemplateParameters());
+
   VisitVarTemplateSpecializationDecl(D);
 
   // These are read/set from/to the first declaration.
@@ -2451,7 +2431,6 @@ 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));
@@ -2461,7 +2440,6 @@ 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 abc4b4179204b..6c1a55f79b908 100644
--- a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -166,6 +166,55 @@ 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
@@ -180,19 +229,41 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
 // attribute.
 //
 // The function handles specializations (and partial specializations) of
-// class templates.
-// For any other decl, it returns the input unchanged.
+// class and function templates.
+// For any other decl, it returns the input unchagned.
 static const Decl *
 preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
-  const auto *RD = dyn_cast<CXXRecordDecl>(D);
-  if (!RD)
+  // 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;
-  if (const CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
-    RD = Pattern;
-  RD = RD->getDefinitionOrSelf();
-  if (const auto *CTD = RD->getDescribedClassTemplate())
-    return CTD;
-  return RD;
+
+  auto InstantiatedFrom = SpecializationDecl->getInstantiatedFrom();
+  if (!InstantiatedFrom)
+    return D;
+
+  if (const auto *Tmpl = InstantiatedFrom.dyn_cast<ClassTemplateDecl *>()) {
+    // Interestingly, the source template might be a forward declaration, so we
+    // need to find the definition redeclaration.
+    return chooseDefinitionRedecl(walkInstantiatedFromChain(Tmpl));
+  }
+  return chooseDefinitionRedecl(walkInstantiatedFromChain(
+      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 c8088f622e185..3d3acea89d170 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;
-    const auto *Info = C->getExplicitInstantiationInfo();
-    if (!Info)
+    if (C->isExplicitSpecialization())
       return true; // we are only interested in explicit instantiations.
     auto *Declaration =
         cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C));
     foldExplicitTemplateInstantiation(
-        Builder.getTemplateRange(C), Builder.findToken(Info->ExternKeywordLoc),
-        Builder.findToken(Info->TemplateKeywordLoc), Declaration, C);
+        Builder.getTemplateRange(C),
+        Builder.findToken(C->getExternKeywordLoc()),
+        Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C);
     return true;
   }
 
@@ -778,9 +778,8 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
           foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
       DeclarationRange = R;
     };
-    if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(C))
-      if (const auto *Info = S->getExplicitSpecializationInfo())
-        ConsumeTemplateParameters(*Info->TemplateParams);
+    if (auto *S = dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
+      ConsumeTemplateParameters(*S->getTemplateParameters());
     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 c16e0870639af..aec86664f9988 100644
--- a/clang/test/AST/ast-dump-templates-pattern.cpp
+++ b/clang/test/AST/ast-dump-templates-pattern.cpp
@@ -32,12 +32,11 @@ 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 {{.+}} 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_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 0x[[TestFunctionRedecl_D2]] prev 0x[[TestFunctionRedecl_D1]] {{.+}} f 'void ()'
 // CHECK: | `-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
-// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-9]]:{{.+}} 'f'
+// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-8]]:{{.+}} 'f'
 // CHECK:   |-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
 // CHECK:   |-FunctionProtoTypeLoc {{.+}} 'void ()' cdecl
 // CHECK:   | `-BuiltinTypeLoc {{.+}} 'void'
@@ -77,15 +76,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: |   `-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: |   `-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: | |-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-15]]:{{.+}} B external-linkage
+// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-14]]:{{.+}} 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/basic/basic.link/p11.cpp b/clang/test/CXX/basic/basic.link/p11.cpp
index ab7b6cf99d0f6..7f6a88d4a63f1 100644
--- a/clang/test/CXX/basic/basic.link/p11.cpp
+++ b/clang/test/CXX/basic/basic.link/p11.cpp
@@ -5,6 +5,7 @@ namespace MemberSpecialization {
   struct A {
     template<bool B>
     void f() noexcept(B);
+    // FIXME expected-note at -1 {{previous declaration is here}}
 
     template<bool B>
     void g() noexcept(B); // expected-note {{previous declaration is here}}
@@ -13,6 +14,7 @@ namespace MemberSpecialization {
   template<>
   template<bool B>
   void A<int>::f() noexcept(B);
+  // FIXME expected-error at -1 {{exception specification in declaration does not match previous declaration}}
 
   template<>
   template<bool 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 ae8d5917a9664..342ffba53dbfa 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,15 +73,18 @@ template <class> struct S {};
 template<template<True T> typename Wrapper>
 using Test = Wrapper<int>;
 
-template<template<False 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 <typename U, template<False> typename T>
 void foo(T<U>); // #foo
 
 void bar() {
-  // FIXME: CWG2980: There is no way to check the constraints on the template template parameter.
-  foo<int>(S<int>{});
+  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]}}
 }
 
 }

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 70064f867e18e..fefe86a448b18 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,11 +1,10 @@
 // RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
 
 template<typename T>
 concept D = true;
 
 template<typename T>
-struct A {
+struct A { // expected-note {{defined here}}
   template<typename U, bool V>
   void f() requires V;
 
@@ -17,6 +16,7 @@ struct A {
 
   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,12 +26,14 @@ struct A {
 
   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>;
@@ -41,6 +43,7 @@ struct A {
 
   template<D U>
   static int y;
+  // expected-note at -2 {{previous template declaration is here}}
 
   template<D U>
   static int y<U*>;
@@ -94,9 +97,11 @@ 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<>
@@ -110,9 +115,11 @@ 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 
diff ers in template redeclaration}}
 
 template<>
 template<>
@@ -130,9 +137,11 @@ 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 
diff ers in template redeclaration}}
 
 template<>
 template<D U>
@@ -142,9 +151,11 @@ 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 
diff ers in template redeclaration}}
 
 template<>
 template<>
@@ -162,9 +173,11 @@ 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 
diff ers in template redeclaration}}
 
 template<>
 template<D U>

diff  --git a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
index a39d3a8fea15d..20121d6cf5743 100644
--- a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 // expected-no-diagnostics
 

diff  --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
index e7e4738032f64..af07024cb7af5 100644
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
@@ -180,20 +180,28 @@ namespace Defined {
 namespace Constrained {
   template<typename T>
   struct A {
+    // FIXME expected-note at -1 2{{defined here}}
     template<typename U, bool V> requires V
     static constexpr int f(); // expected-note {{declared here}}
+    // FIXME expected-note at -1 {{declared here}}
 
     template<typename U, bool V> requires V
     static const int x; // expected-note {{declared here}}
+    // FIXME expected-note at -2 2{{previous template declaration is here}}
+    // FIXME expected-note at -2 {{declared here}}
 
     template<typename U, bool V> requires V
     static const int x<U*, V>; // expected-note {{declared here}}
+    // FIXME expected-note at -1 {{partial specialization matches}}
 
     template<typename U, bool V> requires V
     struct B; // expected-note {{template is declared here}}
+    // FIXME expected-note at -2 2{{previous template declaration is here}}
+    // FIXME expected-note at -2 {{template is declared here}}
 
     template<typename U, bool V> requires V
     struct B<U*, V>; // expected-note {{template is declared here}}
+    // FIXME expected-note at -1 {{partial specialization matches}}
   };
 
   template<>
@@ -201,36 +209,43 @@ namespace Constrained {
   constexpr int A<short>::f() {
     return A<long>::f<U, V>();
   }
+  // FIXME expected-error at -3 {{out-of-line definition of 'f' does not match any declaration in 'Constrained::A<short>'}}
 
   template<>
   template<typename U, bool V> requires V
   constexpr int A<short>::x = A<long>::x<U, V>;
+  // FIXME expected-error at -2 {{requires clause 
diff ers in template redeclaration}}
 
   template<>
   template<typename U, bool V> requires V
   constexpr int A<short>::x<U*, V> = A<long>::x<U*, V>;
+  // FIXME expected-note at -1 {{partial specialization matches}}
 
   template<>
   template<typename U, bool V> requires V
   struct A<short>::B<U*, V> {
     static constexpr int y = A<long>::B<U*, V>::y;
   };
+    // FIXME expected-note at -3 {{partial specialization matches}}
 
   template<>
   template<typename U, bool V> requires V
   struct A<short>::B {
     static constexpr int y = A<long>::B<U, V>::y;
   };
+  // FIXME expected-error at -4 {{requires clause 
diff ers in template redeclaration}}
 
   template<>
   template<typename U, bool V> requires V
   constexpr int A<long>::f() {
     return 1;
   }
+  // FIXME expected-error at -3 {{out-of-line definition of 'f' does not match any declaration in 'Constrained::A<long>'}}
 
   template<>
   template<typename U, bool V> requires V
   constexpr int A<long>::x = 1;
+  // FIXME expected-error at -2 {{requires clause 
diff ers in template redeclaration}}
 
   template<>
   template<typename U, bool V> requires V
@@ -241,6 +256,7 @@ namespace Constrained {
   struct A<long>::B {
     static constexpr int y = 1;
   };
+  // FIXME expected-error at -4 {{requires clause 
diff ers in template redeclaration}}
 
   template<>
   template<typename U, bool V> requires V
@@ -258,10 +274,17 @@ namespace Constrained {
   static_assert(A<int>::B<int*, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int *, true>'}}
 
   static_assert(A<short>::f<int, true>() == 1);
+  // FIXME expected-error at -1 {{static assertion expression is not an integral constant expression}}
+  // FIXME expected-note at -2 {{undefined function 'f<int, true>' cannot be used in a constant expression}}
   static_assert(A<short>::x<int, true> == 1);
+  // FIXME expected-error at -1 {{static assertion expression is not an integral constant expression}}
+  // FIXME expected-note at -2 {{initializer of 'x<int, true>' is unknown}}
   static_assert(A<short>::x<int*, true> == 2);
+  // FIXME expected-error at -1 {{ambiguous partial specializations of 'x'}}
   static_assert(A<short>::B<int, true>::y == 1);
+  // FIXME expected-error at -1 {{implicit instantiation of undefined template 'Constrained::A<short>::B<int, true>'}}
   static_assert(A<short>::B<int*, true>::y == 2);
+  // FIXME expected-error at -1 {{ambiguous partial specializations of 'B<int *, true>'}}
 } // namespace Constrained
 
 namespace Dependent {

diff  --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 01db2a54ae381..6c41853cf3b4f 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 {
+template <typename...> struct TplClass { // #PackIndexExpr1-TplClassDef
   template <int... Ts>
   requires C<Ts...[0]>
   static auto buggy() -> void;
@@ -850,6 +850,9 @@ 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 {
@@ -900,16 +903,18 @@ namespace FuncTemplateInClass {
   template <int T> concept C = true;
 
   namespace t1 {
-    template <int> struct TplClass {
+    template <int> struct TplClass { // expected-note {{defined here}}
       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/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 4321f1f073c77..2b5a226c3b33c 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -338,11 +338,3 @@ class Foo {
   bool aux;
 };
 }
-
-namespace GH101330 {
-  template <class T> struct A {
-    template <int N> friend void f() noexcept(N == 0);
-  };
-  template <int N> void f() noexcept(N == 0) {}
-  template struct A<int>;
-} // namespace GH101330

diff  --git a/clang/test/SemaTemplate/instantiate-scope.cpp b/clang/test/SemaTemplate/instantiate-scope.cpp
index 7dca971470e6a..733105674b7a4 100644
--- a/clang/test/SemaTemplate/instantiate-scope.cpp
+++ b/clang/test/SemaTemplate/instantiate-scope.cpp
@@ -8,9 +8,10 @@ template<typename ...T> struct X {
 
 template<typename T, typename U> using A = T;
 
-// FIXME: These definitions are not OK, X<A<T, decltype(...)>...> is not equivalent to X<T...>.
+// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
+// so this defines the member of the primary template.
 template<typename ...T>
-void X<A<T, decltype(f(T()))>...>::f(int) {}
+void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
 
 template<typename ...T>
 int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
@@ -22,7 +23,8 @@ void g() {
   X<Y>().f(0);
   X<Y>::n = 1;
 
-  // FIXME: There should be no substitutiton failure since the out-of-line definitions were not valid.
-  X<void>().f(0);
+  // 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}}
   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 f2533bffb9b99..19e6039379724 100644
--- a/clang/test/Templight/templight-default-func-arg.cpp
+++ b/clang/test/Templight/templight-default-func-arg.cpp
@@ -10,77 +10,64 @@ int main()
 // 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: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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: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: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72: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:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
   foo<int>();
 }

diff  --git a/clang/test/Templight/templight-empty-entries-fix.cpp b/clang/test/Templight/templight-empty-entries-fix.cpp
index 43fcf2f50bbbc..7f34b10134929 100644
--- a/clang/test/Templight/templight-empty-entries-fix.cpp
+++ b/clang/test/Templight/templight-empty-entries-fix.cpp
@@ -207,18 +207,6 @@ 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$}}
@@ -237,41 +225,41 @@ void e() {
 }
 
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
 // CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
 // CHECK: {{^kind:[ ]+Memoization$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
 
 
 template <template<typename> class>
@@ -287,71 +275,71 @@ void foo() {
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271: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:277:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265: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:277:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265: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:277:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271: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:277:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+d$}}
 // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'d<C>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
 // CHECK-LABEL: {{^---$}}
 // CHECK: {{^name:[ ]+'d<C>'$}}
 // CHECK: {{^kind:[ ]+TemplateInstantiation$}}
 // CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271: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:283:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271: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:283:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 0577c442e38d6..85760968cdbde 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -732,7 +732,6 @@ 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 aa92ee1173414..92085e30ace74 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -5289,13 +5289,11 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
   Decl *FromTU = getTuDecl(Code, Lang_CXX03);
   auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU,
       functionDecl(hasName("f"), isExplicitTemplateSpecialization()));
-  ASSERT_EQ(FromD->getTemplateSpecializationInfo()->TemplateParameters->size(),
-            0u);
+  ASSERT_EQ(FromD->getTemplateParameterLists().size(), 1u);
 
   auto *ToD = Import(FromD, Lang_CXX03);
   // The template parameter list should exist.
-  ASSERT_EQ(ToD->getTemplateSpecializationInfo()->TemplateParameters->size(),
-            0u);
+  EXPECT_EQ(ToD->getTemplateParameterLists().size(), 1u);
 }
 
 const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 35d169fb1234d..a3281f948fdb7 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(declaresSameEntityAsNode(FunDecl)),
+                        callExpr(forCallable(equalsNode(FunDecl)),
                                  callee(cxxMethodDecl().bind("callee")))
                             .bind("call"),
                         FunDecl);
 
     ExpectCorrectResult("ForCallable second",
                         callExpr(callee(cxxMethodDecl().bind("callee")),
-                                 forCallable(declaresSameEntityAsNode(FunDecl)))
+                                 forCallable(equalsNode(FunDecl)))
                             .bind("call"),
                         FunDecl);
 

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 112901a05d641..74a5a414de67b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1154,7 +1154,9 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                 "libc++ std::chrono::sys_seconds summary provider",
                 "^std::__[[:alnum:]]+::chrono::time_point<"
                 "std::__[[:alnum:]]+::chrono::system_clock, "
-                "std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
+                "std::__[[:alnum:]]+::chrono::duration<.*, "
+                "std::__[[:alnum:]]+::ratio<1, 1> "
+                "> >$",
                 eTypeOptionHideChildren | eTypeOptionHideValue |
                     eTypeOptionCascade,
                 true);
@@ -1164,7 +1166,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                 "^std::__[[:alnum:]]+::chrono::time_point<"
                 "std::__[[:alnum:]]+::chrono::system_clock, "
                 "std::__[[:alnum:]]+::chrono::duration<int, "
-                "std::__[[:alnum:]]+::ratio<86400> "
+                "std::__[[:alnum:]]+::ratio<86400, 1> "
                 "> >$",
                 eTypeOptionHideChildren | eTypeOptionHideValue |
                     eTypeOptionCascade,
@@ -1176,7 +1178,9 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
       "libc++ std::chrono::local_seconds summary provider",
       "^std::__[[:alnum:]]+::chrono::time_point<"
       "std::__[[:alnum:]]+::chrono::local_t, "
-      "std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
+      "std::__[[:alnum:]]+::chrono::duration<.*, "
+      "std::__[[:alnum:]]+::ratio<1, 1> "
+      "> >$",
       eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
       true);
   AddCXXSummary(cpp_category_sp,
@@ -1185,7 +1189,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                 "^std::__[[:alnum:]]+::chrono::time_point<"
                 "std::__[[:alnum:]]+::chrono::local_t, "
                 "std::__[[:alnum:]]+::chrono::duration<int, "
-                "std::__[[:alnum:]]+::ratio<86400> "
+                "std::__[[:alnum:]]+::ratio<86400, 1> "
                 "> >$",
                 eTypeOptionHideChildren | eTypeOptionHideValue |
                     eTypeOptionCascade,

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 22ba62af26f3a..82fd9844cf96a 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1449,11 +1449,8 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo(
   TemplateArgumentList *template_args_ptr = TemplateArgumentList::CreateCopy(
       func_decl->getASTContext(), infos.GetArgs());
 
-  func_decl->setFunctionTemplateSpecialization(
-      func_decl->getASTContext(), func_tmpl_decl, template_args_ptr,
-      /*InsertPos=*/nullptr, TSK_ImplicitInstantiation,
-      /*TemplateParams=*/nullptr, /*TemplateArgsAsWritten=*/nullptr,
-      /*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
+  func_decl->setFunctionTemplateSpecialization(func_tmpl_decl,
+                                               template_args_ptr, nullptr);
 }
 
 /// Returns true if the given template parameter can represent the given value.
@@ -1652,40 +1649,6 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
       template_param_list);
 }
 
-static const ASTTemplateArgumentListInfo *getTrivialTemplateArgumentListInfo(
-    ASTContext &ast, ArrayRef<TemplateArgument> args, SourceLocation Loc) {
-  TemplateArgumentListInfo Args(/*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc);
-  for (const auto &arg : args) {
-    if (arg.getIsDefaulted())
-      break;
-    switch (arg.getKind()) {
-    case TemplateArgument::Type:
-      Args.addArgument(TemplateArgumentLoc(
-          arg.getAsType(), ast.getTrivialTypeSourceInfo(arg.getAsType(), Loc)));
-      break;
-    case TemplateArgument::Expression:
-      Args.addArgument(TemplateArgumentLoc(arg, arg.getAsExpr()));
-      break;
-    case TemplateArgument::Template:
-    case TemplateArgument::TemplateExpansion:
-      Args.addArgument(
-          TemplateArgumentLoc(ast, arg, Loc, NestedNameSpecifierLoc(), Loc));
-      break;
-    case TemplateArgument::Declaration:
-    case TemplateArgument::Integral:
-    case TemplateArgument::NullPtr:
-    case TemplateArgument::Pack:
-    case TemplateArgument::StructuralValue:
-      Args.addArgument(
-          TemplateArgumentLoc(arg, TemplateArgumentLocInfo(ast, Loc)));
-      break;
-    case TemplateArgument::Null:
-      llvm_unreachable("unexpected null template argument");
-    }
-  }
-  return ASTTemplateArgumentListInfo::Create(ast, Args);
-}
-
 ClassTemplateSpecializationDecl *
 TypeSystemClang::CreateClassTemplateSpecializationDecl(
     DeclContext *decl_ctx, OptionalClangModuleID owning_module,
@@ -1728,13 +1691,6 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
 
   class_template_specialization_decl->setSpecializationKind(
       TSK_ExplicitSpecialization);
-  SourceLocation FakeLoc = class_template_specialization_decl->getLocation();
-  auto *TemplateParams = TemplateParameterList::Create(
-      ast, /*TemplateLoc=*/FakeLoc, /*LAngleLoc=*/FakeLoc,
-      /*Params=*/ArrayRef<NamedDecl *>(), /*RAngleLoc=*/FakeLoc,
-      /*RequiresClause=*/nullptr);
-  class_template_specialization_decl->setExplicitSpecializationInfo(
-      TemplateParams, ::getTrivialTemplateArgumentListInfo(ast, args, FakeLoc));
 
   return class_template_specialization_decl;
 }


        


More information about the llvm-branch-commits mailing list