[clang] Revert "Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585)" (#111173)" (PR #111766)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 9 14:49:16 PDT 2024


https://github.com/sdkrystian created https://github.com/llvm/llvm-project/pull/111766

This reverts commit 4da8ac34f76e707ab94380b94f616457cfd2cb83.

>From 88925f844c22b9c8b4f0bfce1ebc467d24a8854d Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 9 Oct 2024 17:48:37 -0400
Subject: [PATCH] Revert "Reapply "[Clang][Sema] Refactor collection of
 multi-level template argument lists (#106585)" (#111173)"

This reverts commit 4da8ac34f76e707ab94380b94f616457cfd2cb83.
---
 clang/docs/ReleaseNotes.rst                   |   3 -
 clang/include/clang/AST/DeclTemplate.h        |  66 +-
 clang/include/clang/Sema/Sema.h               |  25 +-
 clang/lib/AST/Decl.cpp                        |  49 +-
 clang/lib/AST/DeclCXX.cpp                     |  20 +-
 clang/lib/AST/DeclTemplate.cpp                |  30 +-
 clang/lib/Sema/SemaConcept.cpp                |  29 +-
 clang/lib/Sema/SemaDecl.cpp                   |  31 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |   4 +-
 clang/lib/Sema/SemaTemplate.cpp               | 179 +++--
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  33 +-
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  45 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 752 +++++++++---------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  46 +-
 clang/lib/Serialization/ASTReader.cpp         |   3 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |  18 +-
 clang/lib/Serialization/ASTWriterDecl.cpp     |  17 +-
 .../temp/temp.constr/temp.constr.decl/p4.cpp  | 175 ----
 .../CXX/temp/temp.spec/temp.expl.spec/p7.cpp  | 178 -----
 clang/test/Modules/cxx-templates.cpp          |   4 +-
 20 files changed, 702 insertions(+), 1005 deletions(-)
 delete mode 100644 clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
 delete mode 100644 clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 29b9fe07f545f9..16e6a230ef428e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -477,9 +477,6 @@ Bug Fixes to C++ Support
   in certain friend declarations. (#GH93099)
 - Clang now instantiates the correct lambda call operator when a lambda's class type is
   merged across modules. (#GH110401)
-- Clang now uses the correct set of template argument lists when comparing the constraints of
-  out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
-  a class template. (#GH102320)
 - Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
 
 Bug Fixes to AST Handling
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 05739f39d2a496..687715a22e9fd3 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -781,11 +781,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
                              EntryType *Entry, void *InsertPos);
 
   struct CommonBase {
-    CommonBase() {}
+    CommonBase() : InstantiatedFromMember(nullptr, false) {}
 
     /// The template from which this was most
     /// directly instantiated (or null).
-    RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
+    ///
+    /// The boolean value indicates whether this template
+    /// was explicitly specialized.
+    llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
+      InstantiatedFromMember;
 
     /// If non-null, points to an array of specializations (including
     /// partial specializations) known only by their external declaration IDs.
@@ -805,19 +809,14 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   };
 
   /// Pointer to the common data shared by all declarations of this
-  /// template, and a flag indicating if the template is a member
-  /// specialization.
-  mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
-
-  CommonBase *getCommonPtrInternal() const { return Common.getPointer(); }
+  /// template.
+  mutable CommonBase *Common = nullptr;
 
   /// Retrieves the "common" pointer shared by all (re-)declarations of
   /// the same template. Calling this routine may implicitly allocate memory
   /// for the common pointer.
   CommonBase *getCommonPtr() const;
 
-  void setCommonPtr(CommonBase *C) const { Common.setPointer(C); }
-
   virtual CommonBase *newCommon(ASTContext &C) const = 0;
 
   // Construct a template decl with name, parameters, and templated element.
@@ -858,12 +857,15 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// template<> template<typename T>
   /// struct X<int>::Inner { /* ... */ };
   /// \endcode
-  bool isMemberSpecialization() const { return Common.getInt(); }
+  bool isMemberSpecialization() const {
+    return getCommonPtr()->InstantiatedFromMember.getInt();
+  }
 
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
-    assert(!isMemberSpecialization() && "already a member specialization");
-    Common.setInt(true);
+    assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
+           "Only member templates can be member template specializations");
+    getCommonPtr()->InstantiatedFromMember.setInt(true);
   }
 
   /// Retrieve the member template from which this template was
@@ -903,12 +905,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// void X<T>::f(T, U);
   /// \endcode
   RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
-    return getCommonPtr()->InstantiatedFromMember;
+    return getCommonPtr()->InstantiatedFromMember.getPointer();
   }
 
   void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
-    assert(!getCommonPtr()->InstantiatedFromMember);
-    getCommonPtr()->InstantiatedFromMember = TD;
+    assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
+    getCommonPtr()->InstantiatedFromMember.setPointer(TD);
   }
 
   /// Retrieve the "injected" template arguments that correspond to the
@@ -1987,8 +1989,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
   /// template arguments have been deduced.
   void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
                           const TemplateArgumentList *TemplateArgs) {
-    assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
-           "A partial specialization cannot be instantiated from a template");
     assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
            "Already set to a class template partial specialization!");
     auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2000,8 +2000,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
   /// Note that this class template specialization is an instantiation
   /// of the given class template.
   void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
-    assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
-           "A partial specialization cannot be instantiated from a template");
     assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
            "Previously set to a class template partial specialization!");
     SpecializedTemplate = TemplDecl;
@@ -2189,11 +2187,18 @@ class ClassTemplatePartialSpecializationDecl
   /// struct X<int>::Inner<T*> { /* ... */ };
   /// \endcode
   bool isMemberSpecialization() const {
-    return InstantiatedFromMember.getInt();
+    const auto *First =
+        cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
+    return First->InstantiatedFromMember.getInt();
   }
 
   /// Note that this member template is a specialization.
-  void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
+  void setMemberSpecialization() {
+    auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
+    assert(First->InstantiatedFromMember.getPointer() &&
+           "Only member templates can be member template specializations");
+    return First->InstantiatedFromMember.setInt(true);
+  }
 
   /// Retrieves the injected specialization type for this partial
   /// specialization.  This is not the same as the type-decl-type for
@@ -2263,6 +2268,10 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
     return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
   }
 
+  void setCommonPtr(Common *C) {
+    RedeclarableTemplateDecl::Common = C;
+  }
+
 public:
 
   friend class ASTDeclReader;
@@ -2745,8 +2754,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
   /// template arguments have been deduced.
   void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
                           const TemplateArgumentList *TemplateArgs) {
-    assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
-           "A partial specialization cannot be instantiated from a template");
     assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
            "Already set to a variable template partial specialization!");
     auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2758,8 +2765,6 @@ class VarTemplateSpecializationDecl : public VarDecl,
   /// Note that this variable template specialization is an instantiation
   /// of the given variable template.
   void setInstantiationOf(VarTemplateDecl *TemplDecl) {
-    assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
-           "A partial specialization cannot be instantiated from a template");
     assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
            "Previously set to a variable template partial specialization!");
     SpecializedTemplate = TemplDecl;
@@ -2944,11 +2949,18 @@ class VarTemplatePartialSpecializationDecl
   /// U* X<int>::Inner<T*> = (T*)(0) + 1;
   /// \endcode
   bool isMemberSpecialization() const {
-    return InstantiatedFromMember.getInt();
+    const auto *First =
+        cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+    return First->InstantiatedFromMember.getInt();
   }
 
   /// Note that this member template is a specialization.
-  void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
+  void setMemberSpecialization() {
+    auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
+    assert(First->InstantiatedFromMember.getPointer() &&
+           "Only member templates can be member template specializations");
+    return First->InstantiatedFromMember.setInt(true);
+  }
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 67a6dbeb520a89..51f38a90f3ea05 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11325,9 +11325,9 @@ class Sema final : public SemaBase {
       CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
       const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
       AccessSpecifier AS, SourceLocation ModulePrivateLoc,
-      SourceLocation FriendLoc,
-      ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
-      bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
+      SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
+      TemplateParameterList **OuterTemplateParamLists,
+      SkipBodyInfo *SkipBody = nullptr);
 
   /// Translates template arguments as provided by the parser
   /// into template arguments used by semantic analysis.
@@ -11366,8 +11366,7 @@ class Sema final : public SemaBase {
   DeclResult ActOnVarTemplateSpecialization(
       Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
       SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
-      StorageClass SC, bool IsPartialSpecialization,
-      bool IsMemberSpecialization);
+      StorageClass SC, bool IsPartialSpecialization);
 
   /// Get the specialization of the given variable template corresponding to
   /// the specified argument list, or a null-but-valid result if the arguments
@@ -13008,14 +13007,28 @@ class Sema final : public SemaBase {
   /// dealing with a specialization. This is only relevant for function
   /// template specializations.
   ///
+  /// \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 NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
-      bool RelativeToPrimary = false, bool ForConstraintInstantiation = 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.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 58d11a0312c505..84ef9f74582ef6 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2696,27 +2696,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
     if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
       auto From = VDTemplSpec->getInstantiatedFrom();
       if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
-        while (true) {
-          VTD = VTD->getMostRecentDecl();
-          if (VTD->isMemberSpecialization())
-            break;
-          if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
-            VTD = NewVTD;
-          else
+        while (!VTD->isMemberSpecialization()) {
+          auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
+          if (!NewVTD)
             break;
+          VTD = NewVTD;
         }
         return getDefinitionOrSelf(VTD->getTemplatedDecl());
       }
       if (auto *VTPSD =
               From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-        while (true) {
-          VTPSD = VTPSD->getMostRecentDecl();
-          if (VTPSD->isMemberSpecialization())
-            break;
-          if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
-            VTPSD = NewVTPSD;
-          else
+        while (!VTPSD->isMemberSpecialization()) {
+          auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
+          if (!NewVTPSD)
             break;
+          VTPSD = NewVTPSD;
         }
         return getDefinitionOrSelf<VarDecl>(VTPSD);
       }
@@ -2725,17 +2719,15 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
 
   // If this is the pattern of a variable template, find where it was
   // instantiated from. FIXME: Is this necessary?
-  if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
-    while (true) {
-      VTD = VTD->getMostRecentDecl();
-      if (VTD->isMemberSpecialization())
-        break;
-      if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
-        VTD = NewVTD;
-      else
+  if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
+    while (!VarTemplate->isMemberSpecialization()) {
+      auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
+      if (!NewVT)
         break;
+      VarTemplate = NewVT;
     }
-    return getDefinitionOrSelf(VTD->getTemplatedDecl());
+
+    return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
   }
 
   if (VD == this)
@@ -4150,14 +4142,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
   if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
     // If we hit a point where the user provided a specialization of this
     // template, we're done looking.
-    while (true) {
-      Primary = Primary->getMostRecentDecl();
-      if (ForDefinition && Primary->isMemberSpecialization())
-        break;
-      if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
-        Primary = NewPrimary;
-      else
+    while (!ForDefinition || !Primary->isMemberSpecialization()) {
+      auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
+      if (!NewPrimary)
         break;
+      Primary = NewPrimary;
     }
 
     return getDefinitionOrSelf(Primary->getTemplatedDecl());
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index cfc7a9a218f251..1364ccc745ba01 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2023,27 +2023,19 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
   if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
     auto From = TD->getInstantiatedFrom();
     if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
-      while (true) {
-        CTD = CTD->getMostRecentDecl();
-        if (CTD->isMemberSpecialization())
-          break;
-        if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
-          CTD = NewCTD;
-        else
+      while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
+        if (NewCTD->isMemberSpecialization())
           break;
+        CTD = NewCTD;
       }
       return GetDefinitionOrSelf(CTD->getTemplatedDecl());
     }
     if (auto *CTPSD =
             From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      while (true) {
-        CTPSD = CTPSD->getMostRecentDecl();
-        if (CTPSD->isMemberSpecialization())
-          break;
-        if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
-          CTPSD = NewCTPSD;
-        else
+      while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
+        if (NewCTPSD->isMemberSpecialization())
           break;
+        CTPSD = NewCTPSD;
       }
       return GetDefinitionOrSelf(CTPSD);
     }
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index d9b67b7bedf5a5..6fe817c5ef1c6b 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -309,16 +309,16 @@ bool TemplateDecl::isTypeAlias() const {
 void RedeclarableTemplateDecl::anchor() {}
 
 RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
-  if (CommonBase *C = getCommonPtrInternal())
-    return C;
+  if (Common)
+    return Common;
 
   // Walk the previous-declaration chain until we either find a declaration
   // with a common pointer or we run out of previous declarations.
   SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
   for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
        Prev = Prev->getPreviousDecl()) {
-    if (CommonBase *C = Prev->getCommonPtrInternal()) {
-      setCommonPtr(C);
+    if (Prev->Common) {
+      Common = Prev->Common;
       break;
     }
 
@@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
   }
 
   // If we never found a common pointer, allocate one now.
-  if (!getCommonPtrInternal()) {
+  if (!Common) {
     // FIXME: If any of the declarations is from an AST file, we probably
     // need an update record to add the common data.
 
-    setCommonPtr(newCommon(getASTContext()));
+    Common = newCommon(getASTContext());
   }
 
   // Update any previous declarations we saw with the common pointer.
   for (const RedeclarableTemplateDecl *Prev : PrevDecls)
-    Prev->setCommonPtr(getCommonPtrInternal());
+    Prev->Common = Common;
 
-  return getCommonPtrInternal();
+  return Common;
 }
 
 void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
@@ -463,17 +463,19 @@ void FunctionTemplateDecl::addSpecialization(
 }
 
 void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
+  using Base = RedeclarableTemplateDecl;
+
   // If we haven't created a common pointer yet, then it can just be created
   // with the usual method.
-  if (!getCommonPtrInternal())
+  if (!Base::Common)
     return;
 
-  Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
+  Common *ThisCommon = static_cast<Common *>(Base::Common);
   Common *PrevCommon = nullptr;
   SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
   for (; Prev; Prev = Prev->getPreviousDecl()) {
-    if (CommonBase *C = Prev->getCommonPtrInternal()) {
-      PrevCommon = static_cast<Common *>(C);
+    if (Prev->Base::Common) {
+      PrevCommon = static_cast<Common *>(Prev->Base::Common);
       break;
     }
     PreviousDecls.push_back(Prev);
@@ -483,7 +485,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
   // use this common pointer.
   if (!PrevCommon) {
     for (auto *D : PreviousDecls)
-      D->setCommonPtr(ThisCommon);
+      D->Base::Common = ThisCommon;
     return;
   }
 
@@ -491,7 +493,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
   assert(ThisCommon->Specializations.size() == 0 &&
          "Can't merge incompatible declarations!");
 
-  setCommonPtr(PrevCommon);
+  Base::Common = PrevCommon;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index e36ee062213716..998a148a7d24a1 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -585,8 +585,8 @@ static bool CheckConstraintSatisfaction(
 
   ArrayRef<TemplateArgument> TemplateArgs =
       TemplateArgsLists.getNumSubstitutedLevels() > 0
-          ? TemplateArgsLists.getInnermost()
-          : ArrayRef<TemplateArgument>{};
+          ? TemplateArgsLists.getOutermost()
+          : ArrayRef<TemplateArgument> {};
   Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
       Sema::InstantiatingTemplate::ConstraintsCheck{},
       const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
@@ -834,6 +834,7 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
       getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
                                    /*Final=*/false, /*Innermost=*/std::nullopt,
                                    /*RelativeToPrimary=*/true,
+                                   /*Pattern=*/nullptr,
                                    /*ForConstraintInstantiation=*/true);
   if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
     return std::nullopt;
@@ -909,13 +910,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
 // Figure out the to-translation-unit depth for this function declaration for
 // the purpose of seeing if they differ by constraints. This isn't the same as
 // getTemplateDepth, because it includes already instantiated parents.
-static unsigned CalculateTemplateDepthForConstraints(Sema &S,
-                                                     const NamedDecl *ND) {
+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,
-      /*ForConstraintInstantiation=*/true);
+      /*Pattern=*/nullptr,
+      /*ForConstraintInstantiation=*/true, SkipForSpecialization);
   return MLTAL.getNumLevels();
 }
 
@@ -954,7 +957,8 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
       DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
       /*RelativeToPrimary=*/true,
-      /*ForConstraintInstantiation=*/true);
+      /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
+      /*SkipForSpecialization*/ false);
 
   if (MLTAL.getNumSubstitutedLevels() == 0)
     return ConstrExpr;
@@ -1064,16 +1068,16 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
 bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
   assert(FD->getFriendObjectKind() && "Must be a friend!");
 
-  FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate();
   // 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(FTD && "Non-function templates don't need to be checked");
+  assert(FD->getDescribedFunctionTemplate() &&
+         "Non-function templates don't need to be checked");
 
   SmallVector<const Expr *, 3> ACs;
-  FTD->getAssociatedConstraints(ACs);
+  FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
 
-  unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
+  unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
   for (const Expr *Constraint : ACs)
     if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
                                                        Constraint))
@@ -1520,6 +1524,7 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
       CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
       /*Final=*/false, CSE->getTemplateArguments(),
       /*RelativeToPrimary=*/true,
+      /*Pattern=*/nullptr,
       /*ForConstraintInstantiation=*/true);
 
   return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
@@ -1800,8 +1805,8 @@ bool Sema::IsAtLeastAsConstrained(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 072f43d360ee1c..118873bc93ad4b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4510,10 +4510,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:
@@ -7663,7 +7663,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
               : SourceLocation();
       DeclResult Res = ActOnVarTemplateSpecialization(
           S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
-          IsPartialSpecialization, IsMemberSpecialization);
+          IsPartialSpecialization);
       if (Res.isInvalid())
         return nullptr;
       NewVD = cast<VarDecl>(Res.get());
@@ -7682,10 +7682,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
           VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
                                   TemplateParams, NewVD);
       NewVD->setDescribedVarTemplate(NewTemplate);
-      // If we are providing an explicit specialization of a static variable
-      // template, make a note of that.
-      if (IsMemberSpecialization)
-        NewTemplate->setMemberSpecialization();
     }
 
     // If this decl has an auto type in need of deduction, make a note of the
@@ -8063,6 +8059,12 @@ NamedDecl *Sema::ActOnVariableDeclarator(
                   ? TPC_ClassTemplateMember
                   : TPC_VarTemplate))
         NewVD->setInvalidDecl();
+
+      // If we are providing an explicit specialization of a static variable
+      // template, make a note of that.
+      if (PrevVarTemplate &&
+          PrevVarTemplate->getInstantiatedFromMemberTemplate())
+        PrevVarTemplate->setMemberSpecialization();
     }
   }
 
@@ -9869,8 +9871,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                                                         NewFD);
         FunctionTemplate->setLexicalDeclContext(CurContext);
         NewFD->setDescribedFunctionTemplate(FunctionTemplate);
-        if (isMemberSpecialization)
-          FunctionTemplate->setMemberSpecialization();
 
         // For source fidelity, store the other template param lists.
         if (TemplateParamLists.size() > 1) {
@@ -12028,7 +12028,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
 
       // If this is an explicit specialization of a member that is a function
       // template, mark it as a member specialization.
-      if (IsMemberSpecialization) {
+      if (IsMemberSpecialization &&
+          NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+        NewTemplateDecl->setMemberSpecialization();
+        assert(OldTemplateDecl->isMemberSpecialization());
         // Explicit specializations of a member template do not inherit deleted
         // status from the parent member template that they are specializing.
         if (OldFD->isDeleted()) {
@@ -17090,8 +17093,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
         DeclResult Result = CheckClassTemplate(
             S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams,
             AS, ModulePrivateLoc,
-            /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
-            isMemberSpecialization, SkipBody);
+            /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
+            TemplateParameterLists.data(), SkipBody);
         return Result.get();
       } else {
         // The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 75d82c12e0c1f3..9cb2ed02a3f764 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17416,8 +17416,8 @@ DeclResult Sema::ActOnTemplatedFriendTag(
       return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
                                 Name, NameLoc, Attr, TemplateParams, AS_public,
                                 /*ModulePrivateLoc=*/SourceLocation(),
-                                FriendLoc, TempParamLists.drop_back(),
-                                IsMemberSpecialization)
+                                FriendLoc, TempParamLists.size() - 1,
+                                TempParamLists.data())
           .get();
     } else {
       // The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index dfd56debc75e99..c7d48b81bc0347 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1795,9 +1795,8 @@ DeclResult Sema::CheckClassTemplate(
     CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
     const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
     AccessSpecifier AS, SourceLocation ModulePrivateLoc,
-    SourceLocation FriendLoc,
-    ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
-    bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
+    SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
+    TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) {
   assert(TemplateParams && TemplateParams->size() > 0 &&
          "No template parameters");
   assert(TUK != TagUseKind::Reference &&
@@ -1985,6 +1984,19 @@ DeclResult Sema::CheckClassTemplate(
   }
 
   if (PrevClassTemplate) {
+    // Ensure that the template parameter lists are compatible. Skip this check
+    // for a friend in a dependent context: the template parameter list itself
+    // could be dependent.
+    if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
+        !TemplateParameterListsAreEqual(
+            TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
+                                                       : CurContext,
+                                       CurContext, KWLoc),
+            TemplateParams, PrevClassTemplate,
+            PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
+            TPL_TemplateMatch))
+      return true;
+
     // C++ [temp.class]p4:
     //   In a redeclaration, partial specialization, explicit
     //   specialization or explicit instantiation of a class template,
@@ -1999,6 +2011,30 @@ DeclResult Sema::CheckClassTemplate(
       Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
       Kind = PrevRecordDecl->getTagKind();
     }
+
+    // Check for redefinition of this class template.
+    if (TUK == TagUseKind::Definition) {
+      if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
+        // If we have a prior definition that is not visible, treat this as
+        // simply making that previous definition visible.
+        NamedDecl *Hidden = nullptr;
+        if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+          SkipBody->ShouldSkip = true;
+          SkipBody->Previous = Def;
+          auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
+          assert(Tmpl && "original definition of a class template is not a "
+                         "class template?");
+          makeMergedDefinitionVisible(Hidden);
+          makeMergedDefinitionVisible(Tmpl);
+        } else {
+          Diag(NameLoc, diag::err_redefinition) << Name;
+          Diag(Def->getLocation(), diag::note_previous_definition);
+          // FIXME: Would it make sense to try to "forget" the previous
+          // definition, as part of error recovery?
+          return true;
+        }
+      }
+    }
   } else if (PrevDecl) {
     // C++ [temp]p5:
     //   A class template shall not have the same name as any other
@@ -2010,6 +2046,23 @@ DeclResult Sema::CheckClassTemplate(
     return true;
   }
 
+  // Check the template parameter list of this declaration, possibly
+  // merging in the template parameter list from the previous class
+  // template declaration. Skip this check for a friend in a dependent
+  // context, because the template parameter list might be dependent.
+  if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
+      CheckTemplateParameterList(
+          TemplateParams,
+          PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate)
+                            : nullptr,
+          (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
+           SemanticContext->isDependentContext())
+              ? TPC_ClassTemplateMember
+          : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
+                                      : TPC_ClassTemplate,
+          SkipBody))
+    Invalid = true;
+
   if (SS.isSet()) {
     // If the name of the template was qualified, we must be defining the
     // template out-of-line.
@@ -2036,8 +2089,10 @@ DeclResult Sema::CheckClassTemplate(
                             PrevClassTemplate->getTemplatedDecl() : nullptr,
                           /*DelayTypeCreation=*/true);
   SetNestedNameSpecifier(*this, NewClass, SS);
-  if (!OuterTemplateParamLists.empty())
-    NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists);
+  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.
@@ -2050,10 +2105,7 @@ DeclResult Sema::CheckClassTemplate(
     = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
                                 DeclarationName(Name), TemplateParams,
                                 NewClass);
-  // If we are providing an explicit specialization of a member that is a
-  // class template, make a note of that.
-  if (IsMemberSpecialization)
-    NewTemplate->setMemberSpecialization();
+
   if (ShouldAddRedecl)
     NewTemplate->setPreviousDecl(PrevClassTemplate);
 
@@ -2068,6 +2120,12 @@ DeclResult Sema::CheckClassTemplate(
   assert(T->isDependentType() && "Class template type is not dependent?");
   (void)T;
 
+  // If we are providing an explicit specialization of a member that is a
+  // class template, make a note of that.
+  if (PrevClassTemplate &&
+      PrevClassTemplate->getInstantiatedFromMemberTemplate())
+    PrevClassTemplate->setMemberSpecialization();
+
   // Set the access specifier.
   if (!Invalid && TUK != TagUseKind::Friend &&
       NewTemplate->getDeclContext()->isRecord())
@@ -2077,62 +2135,8 @@ DeclResult Sema::CheckClassTemplate(
   NewClass->setLexicalDeclContext(CurContext);
   NewTemplate->setLexicalDeclContext(CurContext);
 
-  // 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 (ShouldAddRedecl && PrevClassTemplate &&
-      !TemplateParameterListsAreEqual(
-          NewTemplate, TemplateParams, PrevClassTemplate,
-          PrevClassTemplate->getTemplateParameters(),
-          /*Complain=*/true, TPL_TemplateMatch))
-    return true;
-
-  // Check the template parameter list of this declaration, possibly
-  // merging in the template parameter list from the previous class
-  // template declaration. Skip this check for a friend in a dependent
-  // context, because the template parameter list might be dependent.
-  if (ShouldAddRedecl &&
-      CheckTemplateParameterList(
-          TemplateParams,
-          PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
-                            : nullptr,
-          (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
-           SemanticContext->isDependentContext())
-              ? TPC_ClassTemplateMember
-          : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
-                                      : TPC_ClassTemplate,
-          SkipBody))
-    Invalid = true;
-
-  if (TUK == TagUseKind::Definition) {
-    if (PrevClassTemplate) {
-      // Check for redefinition of this class template.
-      if (TagDecl *Def =
-              PrevClassTemplate->getTemplatedDecl()->getDefinition()) {
-        // If we have a prior definition that is not visible, treat this as
-        // simply making that previous definition visible.
-        NamedDecl *Hidden = nullptr;
-        if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
-          SkipBody->ShouldSkip = true;
-          SkipBody->Previous = Def;
-          auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
-          assert(Tmpl && "original definition of a class template is not a "
-                         "class template?");
-          makeMergedDefinitionVisible(Hidden);
-          makeMergedDefinitionVisible(Tmpl);
-        } else {
-          Diag(NameLoc, diag::err_redefinition) << Name;
-          Diag(Def->getLocation(), diag::note_previous_definition);
-          // FIXME: Would it make sense to try to "forget" the previous
-          // definition, as part of error recovery?
-          return true;
-        }
-      }
-    }
-
-    if (!SkipBody || !SkipBody->ShouldSkip)
-      NewClass->startDefinition();
-  }
+  if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
+    NewClass->startDefinition();
 
   ProcessDeclAttributeList(S, NewClass, Attr);
   ProcessAPINotes(NewClass);
@@ -4129,8 +4133,7 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
 DeclResult Sema::ActOnVarTemplateSpecialization(
     Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
     SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
-    StorageClass SC, bool IsPartialSpecialization,
-    bool IsMemberSpecialization) {
+    StorageClass SC, bool IsPartialSpecialization) {
   // D must be variable template id.
   assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
          "Variable template specialization is declared with a template id.");
@@ -4248,16 +4251,17 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
             Context, VarTemplate->getDeclContext(), TemplateKWLoc,
             TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
             CanonicalConverted);
-    // If we are providing an explicit specialization of a member variable
-    // template specialization, make a note of that.
-    if (IsMemberSpecialization)
-      Partial->setMemberSpecialization();
     Partial->setTemplateArgsAsWritten(TemplateArgs);
 
     if (!PrevPartial)
       VarTemplate->AddPartialSpecialization(Partial, InsertPos);
     Specialization = Partial;
 
+    // If we are providing an explicit specialization of a member variable
+    // template specialization, make a note of that.
+    if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+      PrevPartial->setMemberSpecialization();
+
     CheckTemplatePartialSpecialization(Partial);
   } else {
     // Create a new class template specialization declaration node for
@@ -5772,7 +5776,9 @@ bool Sema::CheckTemplateArgumentList(
 
     MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
         Template, NewContext, /*Final=*/false, CanonicalConverted,
-        /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true);
+        /*RelativeToPrimary=*/true,
+        /*Pattern=*/nullptr,
+        /*ForConceptInstantiation=*/true);
     if (EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
@@ -8461,12 +8467,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
       Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
           << /*class template*/ 0 << (TUK == TagUseKind::Definition)
           << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
-      return CheckClassTemplate(
-          S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(),
-          TemplateNameLoc, Attr, TemplateParams, AS_none,
-          /*ModulePrivateLoc=*/SourceLocation(),
-          /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
-          isMemberSpecialization);
+      return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
+                                ClassTemplate->getIdentifier(),
+                                TemplateNameLoc,
+                                Attr,
+                                TemplateParams,
+                                AS_none, /*ModulePrivateLoc=*/SourceLocation(),
+                                /*FriendLoc*/SourceLocation(),
+                                TemplateParameterLists.size() - 1,
+                                TemplateParameterLists.data());
     }
 
     // Create a new class template partial specialization declaration node.
@@ -8476,11 +8485,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
         ClassTemplatePartialSpecializationDecl::Create(
             Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
             ClassTemplate, CanonicalConverted, CanonType, PrevPartial);
-
-    // If we are providing an explicit specialization of a member class
-    // template specialization, make a note of that.
-    if (isMemberSpecialization)
-      Partial->setMemberSpecialization();
     Partial->setTemplateArgsAsWritten(TemplateArgs);
     SetNestedNameSpecifier(*this, Partial, SS);
     if (TemplateParameterLists.size() > 1 && SS.isSet()) {
@@ -8492,6 +8496,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
       ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
     Specialization = Partial;
 
+    // If we are providing an explicit specialization of a member class
+    // template specialization, make a note of that.
+    if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+      PrevPartial->setMemberSpecialization();
+
     CheckTemplatePartialSpecialization(Partial);
   } else {
     // Create a new class template specialization declaration node for
@@ -11290,8 +11299,8 @@ class ExplicitSpecializationVisibilityChecker {
 
   template<typename TemplDecl>
   void checkTemplate(TemplDecl *TD) {
-    if (TD->getMostRecentDecl()->isMemberSpecialization()) {
-      if (!CheckMemberSpecialization(TD->getMostRecentDecl()))
+    if (TD->isMemberSpecialization()) {
+      if (!CheckMemberSpecialization(TD))
         diagnose(TD->getMostRecentDecl(), false);
     }
   }
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index aa62cfa7dcbd17..d106874c4c5bda 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3138,6 +3138,20 @@ template<>
 struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
   static constexpr bool value = true;
 };
+template <typename TemplateDeclT>
+static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
+  return false;
+}
+template <>
+bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
+    VarTemplatePartialSpecializationDecl *Spec) {
+  return !Spec->isClassScopeExplicitSpecialization();
+}
+template <>
+bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
+    ClassTemplatePartialSpecializationDecl *Spec) {
+  return !Spec->isClassScopeExplicitSpecialization();
+}
 
 template <typename TemplateDeclT>
 static TemplateDeductionResult
@@ -3148,10 +3162,23 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
   llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
   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(Template))
+    Innermost = CanonicalDeducedArgs;
+
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      Template, Template->getDeclContext(), /*Final=*/false,
-      /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
-      /*ForConstraintInstantiation=*/true);
+      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, CanonicalDeducedArgs);
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index ca93c840f03215..545da21183c3c4 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -765,7 +765,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
   }
   // Template arguments used to transform the template arguments in
   // DeducedResults.
-  SmallVector<TemplateArgument> InnerArgsForBuildingRC(
+  SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
       F->getTemplateParameters()->size());
   // Transform the transformed template args
   MultiLevelTemplateArgumentList Args;
@@ -778,30 +778,33 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
       NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
       MultiLevelTemplateArgumentList Args;
       Args.setKind(TemplateSubstitutionKind::Rewrite);
-      Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
+      Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
       // Rebuild the template parameter with updated depth and index.
       NamedDecl *NewParam =
           transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args,
                                      /*NewIndex=*/FirstUndeducedParamIdx,
                                      getDepthAndIndex(TP).first + AdjustDepth);
       FirstUndeducedParamIdx += 1;
-      assert(InnerArgsForBuildingRC[Index].isNull());
-      InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
+      assert(TemplateArgsForBuildingRC[Index].isNull());
+      TemplateArgsForBuildingRC[Index] =
+          Context.getInjectedTemplateArg(NewParam);
       continue;
     }
     TemplateArgumentLoc Input =
         SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
     TemplateArgumentLoc Output;
     if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
-      assert(InnerArgsForBuildingRC[Index].isNull() &&
+      assert(TemplateArgsForBuildingRC[Index].isNull() &&
              "InstantiatedArgs must be null before setting");
-      InnerArgsForBuildingRC[Index] = Output.getArgument();
+      TemplateArgsForBuildingRC[Index] = Output.getArgument();
     }
   }
 
-  // A list of template arguments for transforming the require-clause using
-  // the transformed template arguments as the template argument list of F.
-  //
+  // A list of template arguments for transforming the require-clause of F.
+  // It must contain the entire set of template argument lists.
+  MultiLevelTemplateArgumentList ArgsForBuildingRC;
+  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.
@@ -824,15 +827,25 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
   //   - 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.
-  MultiLevelTemplateArgumentList ArgsForBuildingRC =
-      SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
-                                           /*Final=*/false,
-                                           /*Innermost=*/InnerArgsForBuildingRC,
-                                           /*RelativeToPrimary=*/true,
-                                           /*ForConstraintInstantiation=*/true);
-  ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
+  // 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 5b5e50f668b25d..7d42cf6b8cced3 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -52,6 +52,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.
@@ -139,396 +171,374 @@ bool isLambdaEnclosedByTypeAliasDecl(
               .TraverseType(Underlying);
 }
 
-struct TemplateInstantiationArgumentCollecter
-    : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl *> {
-  Sema &S;
-  MultiLevelTemplateArgumentList &Result;
-  std::optional<ArrayRef<TemplateArgument>> Innermost;
-  bool RelativeToPrimary;
-  bool ForConstraintInstantiation;
-
-  TemplateInstantiationArgumentCollecter(
-      Sema &S, MultiLevelTemplateArgumentList &Result,
-      std::optional<ArrayRef<TemplateArgument>> Innermost,
-      bool RelativeToPrimary, bool ForConstraintInstantiation)
-      : S(S), Result(Result), Innermost(Innermost),
-        RelativeToPrimary(RelativeToPrimary),
-        ForConstraintInstantiation(ForConstraintInstantiation) {}
-
-  Decl *Done() { return nullptr; }
-
-  Decl *ChangeDecl(const Decl *D) {
-    RelativeToPrimary = false;
-    return const_cast<Decl *>(D);
-  }
-
-  Decl *ChangeDecl(const DeclContext *DC) {
-    return ChangeDecl(Decl::castFromDeclContext(DC));
-  }
-
-  Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); }
-
-  void AddInnermostTemplateArguments(const Decl *D) {
-    assert(Innermost);
-    Result.addOuterTemplateArguments(const_cast<Decl *>(D), *Innermost,
-                                     /*Final=*/false);
-    Innermost.reset();
-  }
-
-  void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args,
-                                 bool Final) {
-    Result.addOuterTemplateArguments(const_cast<Decl *>(D), Args, Final);
+// 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 =
+          Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+    if (!SkipForSpecialization)
+      Result.addOuterTemplateArguments(
+          Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
+    if (Partial->isMemberSpecialization())
+      return Response::Done();
+  } else {
+    VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+    if (!SkipForSpecialization)
+      Result.addOuterTemplateArguments(
+          Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
+    if (Tmpl->isMemberSpecialization())
+      return Response::Done();
   }
+  return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+}
 
-  Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
-    if (Innermost)
-      AddInnermostTemplateArguments(TTPD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
-
-    for (unsigned Depth = TTPD->getDepth() + 1; Depth--;)
-      AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
-
-    return Done();
-  }
+// 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();
+}
 
-  Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "outer template not instantiated?");
+Response HandlePartialClassTemplateSpec(
+    const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
+    MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
+  if (!SkipForSpecialization)
+      Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
+  return Response::Done();
+}
 
-    if (Innermost)
-      AddInnermostTemplateArguments(FTD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(),
-                                /*Final=*/false);
+// 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 (FTD->isMemberSpecialization())
-      return Done();
+    if (!SkipForSpecialization)
+      Result.addOuterTemplateArguments(
+          const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
+          ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
 
-    if (FTD->getFriendObjectKind())
-      return ChangeDecl(FTD->getLexicalDeclContext());
-    return UseNextDecl(FTD);
+    // 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);
+}
 
-  Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "outer template not instantiated?");
-
-    if (Innermost)
-      AddInnermostTemplateArguments(VTD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(),
-                                /*Final=*/false);
-
-    if (VTD->isMemberSpecialization())
-      return Done();
-
-    return UseNextDecl(VTD);
-  }
+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);
 
-  Decl *VisitVarTemplatePartialSpecializationDecl(
-      VarTemplatePartialSpecializationDecl *VTPSD) {
+    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 (Function->getDescribedFunctionTemplate()) {
     assert(
         (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "outer template not instantiated?");
-
-    if (Innermost)
-      AddInnermostTemplateArguments(VTPSD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(),
-                                /*Final=*/false);
-
-    if (VTPSD->isMemberSpecialization())
-      return Done();
-
-    return UseNextDecl(VTPSD);
+        "Outer template not instantiated?");
   }
-
-  Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "outer template not instantiated?");
-
-    if (Innermost)
-      AddInnermostTemplateArguments(CTD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(),
-                                /*Final=*/false);
-
-    if (CTD->isMemberSpecialization())
-      return Done();
-
-    if (CTD->getFriendObjectKind())
-      return ChangeDecl(CTD->getLexicalDeclContext());
-    return UseNextDecl(CTD);
+  // 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());
   }
 
-  Decl *VisitClassTemplatePartialSpecializationDecl(
-      ClassTemplatePartialSpecializationDecl *CTPSD) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "outer template not instantiated?");
-
-    if (Innermost)
-      AddInnermostTemplateArguments(CTPSD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(),
-                                /*Final=*/false);
+  if (ForConstraintInstantiation && Function->getFriendObjectKind())
+    return Response::ChangeDecl(Function->getLexicalDeclContext());
+  return Response::UseNextDecl(Function);
+}
 
-    if (CTPSD->isMemberSpecialization())
-      return Done();
+Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
+                                    MultiLevelTemplateArgumentList &Result) {
+  if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
+    Result.addOuterTemplateArguments(
+        const_cast<FunctionTemplateDecl *>(FTD),
+        const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
+        /*Final=*/false);
+
+    NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier();
+
+    while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
+      if (NNS->isInstantiationDependent()) {
+        if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
+          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();
+            else if (auto *Specialization =
+                         dyn_cast<ClassTemplateSpecializationDecl>(RD))
+              Arguments =
+                  Specialization->getTemplateInstantiationArgs().asArray();
+          }
+          Result.addOuterTemplateArguments(
+              TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
+              /*Final=*/false);
+        }
+      }
 
-    return UseNextDecl(CTPSD);
+      NNS = NNS->getPrefix();
+    }
   }
 
-  Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "outer template not instantiated?");
-    if (Innermost)
-      AddInnermostTemplateArguments(TATD);
-    else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(),
-                                /*Final=*/false);
-
-    return UseNextDecl(TATD);
-  }
+  return Response::ChangeDecl(FTD->getLexicalDeclContext());
+}
 
-  Decl *VisitConceptDecl(ConceptDecl *CD) {
+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 (Innermost)
-      AddInnermostTemplateArguments(CD);
-
-    return UseNextDecl(CD);
+        "Outer template not instantiated?");
+    if (ClassTemplate->isMemberSpecialization())
+      return Response::Done();
+    if (ForConstraintInstantiation)
+      Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
+                                       ClassTemplate->getInjectedTemplateArgs(),
+                                       /*Final=*/false);
   }
 
-  Decl *VisitFunctionDecl(FunctionDecl *FD) {
-    assert(!FD->getDescribedFunctionTemplate() &&
-           "not for templated declarations");
-
-    if (!RelativeToPrimary) {
-      // Add template arguments from a function template specialization.
-      if (const MemberSpecializationInfo *MSI =
-              FD->getMemberSpecializationInfo();
-          MSI &&
-          MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-        return Done();
-
-      // 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.
-      if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-        return UseNextDecl(FD);
-    }
-
-    if (const TemplateArgumentList *TemplateArgs =
-            FD->getTemplateSpecializationArgs()) {
-      // Add the template arguments for this specialization.
-      if (Innermost)
-        AddInnermostTemplateArguments(FD);
-      else
-        AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false);
-
-      if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization ||
-          (FD->getFriendObjectKind() &&
-           !FD->getPrimaryTemplate()->getFriendObjectKind()))
-        return UseNextDecl(FD);
-
-      // If this function was instantiated from a specialized member that is
-      // a function template, we're done.
-      assert(FD->getPrimaryTemplate() && "No function template?");
-      if (FD->getPrimaryTemplate()->isMemberSpecialization())
-        return Done();
-
-      // If this function is a generic lambda specialization, we are done.
-      if (!ForConstraintInstantiation &&
-          isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
-        return Done();
-    }
-
-    // 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 ((FD->getFriendObjectKind() || FD->isLocalExternDecl()) &&
-        FD->getNonTransparentDeclContext()->isFileContext()) {
-      return ChangeDecl(FD->getLexicalDeclContext());
-    }
-
-    if (ForConstraintInstantiation && FD->getFriendObjectKind())
-      return ChangeDecl(FD->getLexicalDeclContext());
-    return UseNextDecl(FD);
+  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());
   }
 
-  Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
-    assert(!RD->getDescribedClassTemplate() &&
-           "not for templated declarations");
-
-    if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
-        MSI &&
-        MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-      return Done();
-
-    if (ForConstraintInstantiation && RD->getFriendObjectKind() &&
-        RD->getNonTransparentDeclContext()->isFileContext()) {
-      return ChangeDecl(RD->getLexicalDeclContext());
-    }
-
-    // This is to make sure we pick up the VarTemplateSpecializationDecl or the
-    // TypeAliasTemplateDecl that this lambda is defined inside of.
-    if (RD->isLambda()) {
-      if (Decl *LCD = RD->getLambdaContextDecl())
-        return 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(S);
-          ForConstraintInstantiation && TypeAlias) {
-        if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(),
-                                            TypeAlias.PrimaryTypeAliasDecl)) {
-          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 ChangeDecl(TypeAlias.Template->getDeclContext());
-        }
+  // 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 UseNextDecl(RD);
-  }
-
-  Decl *
-  VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
-    // For a class-scope explicit specialization, there are no template
-    // arguments at this level, but there may be enclosing template arguments.
-    if (CTSD->isClassScopeExplicitSpecialization())
-      return UseNextDecl(CTSD);
-
-    // We're done when we hit an explicit specialization.
-    if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
-      return Done();
-
-    if (Innermost)
-      AddInnermostTemplateArguments(CTSD);
-    else
-      AddOuterTemplateArguments(CTSD,
-                                CTSD->getTemplateInstantiationArgs().asArray(),
-                                /*Final=*/false);
-
-    // If this class template specialization was instantiated from a
-    // specialized member that is a class template, we're done.
-    assert(CTSD->getSpecializedTemplate() && "No class template?");
-    llvm::PointerUnion<ClassTemplateDecl *,
-                       ClassTemplatePartialSpecializationDecl *>
-        Specialized = CTSD->getSpecializedTemplateOrPartial();
-    if (auto *CTPSD =
-            Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      if (CTPSD->isMemberSpecialization())
-        return Done();
-    } else {
-      auto *CTD = Specialized.get<ClassTemplateDecl *>();
-      if (CTD->isMemberSpecialization())
-        return Done();
-    }
-    return UseNextDecl(CTSD);
-  }
-
-  Decl *
-  VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) {
-    // For a class-scope explicit specialization, there are no template
-    // arguments at this level, but there may be enclosing template arguments.
-    if (VTSD->isClassScopeExplicitSpecialization())
-      return UseNextDecl(VTSD);
-
-    // We're done when we hit an explicit specialization.
-    if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
-      return Done();
-
-    if (Innermost)
-      AddInnermostTemplateArguments(VTSD);
-    else
-      AddOuterTemplateArguments(VTSD,
-                                VTSD->getTemplateInstantiationArgs().asArray(),
-                                /*Final=*/false);
-
-    // If this variable template specialization was instantiated from a
-    // specialized member that is a variable template, we're done.
-    assert(VTSD->getSpecializedTemplate() && "No variable template?");
-    llvm::PointerUnion<VarTemplateDecl *,
-                       VarTemplatePartialSpecializationDecl *>
-        Specialized = VTSD->getSpecializedTemplateOrPartial();
-    if (auto *VTPSD =
-            Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-      if (VTPSD->isMemberSpecialization())
-        return Done();
-    } else {
-      auto *VTD = Specialized.get<VarTemplateDecl *>();
-      if (VTD->isMemberSpecialization())
-        return Done();
-    }
-    return UseNextDecl(VTSD);
-  }
-
-  Decl *VisitImplicitConceptSpecializationDecl(
-      ImplicitConceptSpecializationDecl *ICSD) {
-    AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(),
-                              /*Final=*/false);
-    return UseNextDecl(ICSD);
   }
 
-  Decl *VisitDecl(Decl *D) {
-    if (D->isFileContextDecl())
-      return Done();
-
-    if (isa<DeclContext>(D))
-      RelativeToPrimary = false;
-
-    return UseNextDecl(D);
-  }
+  return Response::UseNextDecl(Rec);
+}
 
-  Decl *Visit(Decl *D) {
-    if (TemplateDecl *TD = D->getDescribedTemplate())
-      D = TD;
-    return DeclVisitor::Visit(D);
-  }
-};
+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
 
 MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     const NamedDecl *ND, const DeclContext *DC, bool Final,
     std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
-    bool ForConstraintInstantiation) {
+    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 (!CurDecl)
     CurDecl = Decl::castFromDeclContext(DC);
 
-  TemplateInstantiationArgumentCollecter Collecter(
-      *this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation);
-  do {
-    CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
-  } while (CurDecl);
+  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 = Response::UseNextDecl(CurDecl).NextDecl;
+  }
+
+  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(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);
+      }
+    } else {
+      R = HandleGenericDeclContext(CurDecl);
+    }
+
+    if (R.IsDone)
+      return Result;
+    if (R.ClearRelativeToPrimary)
+      RelativeToPrimary = false;
+    assert(R.NextDecl);
+    CurDecl = R.NextDecl;
+  }
+
   return Result;
 }
 
@@ -1662,8 +1672,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())
@@ -1702,8 +1714,8 @@ namespace {
           // RecoveryExpr that wraps the uninstantiated default argument so
           // that downstream diagnostics are omitted.
           ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
-              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
-              UninstExpr->getType());
+              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+              { UninstExpr }, UninstExpr->getType());
           if (ErrorResult.isUsable())
             PVD->setDefaultArg(ErrorResult.get());
         }
@@ -4097,31 +4109,31 @@ getPatternForClassTemplateSpecialization(
 
   CXXRecordDecl *Pattern = nullptr;
   Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
-  if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
-    while (true) {
-      CTD = CTD->getMostRecentDecl();
-      if (CTD->isMemberSpecialization())
-        break;
-      if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
-        CTD = NewCTD;
-      else
+  if (auto *PartialSpec =
+          Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+    // Instantiate using the best class template partial specialization.
+    while (PartialSpec->getInstantiatedFromMember()) {
+      // If we've found an explicit specialization of this class template,
+      // stop here and use that as the pattern.
+      if (PartialSpec->isMemberSpecialization())
         break;
+
+      PartialSpec = PartialSpec->getInstantiatedFromMember();
     }
-    Pattern = CTD->getTemplatedDecl();
-  } else if (auto *CTPSD =
-                 Specialized
-                     .dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-    while (true) {
-      CTPSD = CTPSD->getMostRecentDecl();
-      if (CTPSD->isMemberSpecialization())
-        break;
-      if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
-        CTPSD = NewCTPSD;
-      else
+    Pattern = PartialSpec;
+  } else {
+    ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
+    while (Template->getInstantiatedFromMemberTemplate()) {
+      // If we've found an explicit specialization of this class template,
+      // stop here and use that as the pattern.
+      if (Template->isMemberSpecialization())
         break;
+
+      Template = Template->getInstantiatedFromMemberTemplate();
     }
-    Pattern = CTPSD;
+    Pattern = Template->getTemplatedDecl();
   }
+
   return Pattern;
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 74f2152e441e18..34558e1a005d5a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -12,7 +12,6 @@
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclVisitor.h"
@@ -4686,36 +4685,6 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());
 
-  NamedDecl *Pattern = FD;
-  std::optional<ArrayRef<TemplateArgument>> Innermost;
-
-  // C++ [dcl.fct.default]p4
-  //   For non-template functions, default arguments can be added in later
-  //   declarations of a function that inhabit the same scope.
-  //
-  // C++ [dcl.fct.default]p6
-  //   Except for member functions of templated classes, the default arguments
-  //   in a member function definition that appears outside of the class
-  //   definition are added to the set of default arguments provided by the
-  //   member function declaration in the class definition; the program is
-  //   ill-formed if a default constructor, copy or move constructor, or copy
-  //   or move assignment operator is so declared. Default arguments for a
-  //   member function of a templated class shall be specified on the initial
-  //   declaration of the member function within the templated class.
-  //
-  // We need to collect the template arguments from the context of the function
-  // where the default argument was defined. For a specialization of a function
-  // template explicitly specialized for an implicit instantiation of a class
-  // template, that context is the (implicitly instantiated) declaration in the
-  // definition of the class template specialization.
-  if (FD->isCXXClassMember() &&
-      !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
-    if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
-      Pattern = FTD->getFirstDecl();
-      Innermost = FD->getTemplateSpecializationArgs()->asArray();
-    }
-  }
-
   // Instantiate the expression.
   //
   // FIXME: Pass in a correct Pattern argument, otherwise
@@ -4733,10 +4702,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   //
   // template<typename T>
   // A<T> Foo(int a = A<T>::FooImpl());
-  MultiLevelTemplateArgumentList TemplateArgs =
-      getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
-                                   /*Final=*/false, Innermost,
-                                   /*RelativeToPrimary=*/true);
+  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;
@@ -4777,7 +4748,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
   MultiLevelTemplateArgumentList TemplateArgs =
       getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
                                    /*Final=*/false, /*Innermost=*/std::nullopt,
-                                   /*RelativeToPrimary=*/true);
+                                   /*RelativeToPrimary*/ true);
 
   // FIXME: We can't use getTemplateInstantiationPattern(false) in general
   // here, because for a non-defining friend declaration in a class template,
@@ -5225,7 +5196,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     SetDeclDefaulted(Function, PatternDecl->getLocation());
   } else {
     MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-        Function, Function->getLexicalDeclContext());
+        Function, Function->getLexicalDeclContext(), /*Final=*/false,
+        /*Innermost=*/std::nullopt, false, PatternDecl);
 
     // Substitute into the qualifier; we can get a substitution failure here
     // through evil use of alias templates.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 5c4f8d0e9c46cd..e638129897692f 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -10003,8 +10003,7 @@ void ASTReader::finishPendingActions() {
 
     auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
     for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
-      cast<RedeclarableTemplateDecl>(R)->setCommonPtr(
-          RTD->getCommonPtrInternal());
+      cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
   }
   PendingDefinitions.clear();
 
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 1ccc810f415eb4..7cead2728ca938 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2416,13 +2416,11 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   // Make sure we've allocated the Common pointer first. We do this before
   // VisitTemplateDecl so that getCommonPtr() can be used during initialization.
   RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
-  if (!CanonD->getCommonPtrInternal()) {
-    CanonD->setCommonPtr(CanonD->newCommon(Reader.getContext()));
+  if (!CanonD->Common) {
+    CanonD->Common = CanonD->newCommon(Reader.getContext());
     Reader.PendingDefinitions.insert(CanonD);
   }
-  D->setCommonPtr(CanonD->getCommonPtrInternal());
-  if (Record.readInt())
-    D->setMemberSpecialization();
+  D->Common = CanonD->Common;
 
   // If this is the first declaration of the template, fill in the information
   // for the 'common' pointer.
@@ -2431,6 +2429,8 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
       assert(RTD->getKind() == D->getKind() &&
              "InstantiatedFromMemberTemplate kind mismatch");
       D->setInstantiatedFromMemberTemplate(RTD);
+      if (Record.readInt())
+        D->setMemberSpecialization();
     }
   }
 
@@ -2562,12 +2562,12 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
   D->TemplateParams = Params;
 
   RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
-  D->InstantiatedFromMember.setInt(Record.readInt());
 
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {
     D->InstantiatedFromMember.setPointer(
-        readDeclAs<ClassTemplatePartialSpecializationDecl>());
+      readDeclAs<ClassTemplatePartialSpecializationDecl>());
+    D->InstantiatedFromMember.setInt(Record.readInt());
   }
 }
 
@@ -2660,12 +2660,12 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
   D->TemplateParams = Params;
 
   RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
-  D->InstantiatedFromMember.setInt(Record.readInt());
 
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {
     D->InstantiatedFromMember.setPointer(
         readDeclAs<VarTemplatePartialSpecializationDecl>());
+    D->InstantiatedFromMember.setInt(Record.readInt());
   }
 }
 
@@ -2888,7 +2888,7 @@ void ASTDeclReader::mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
   // If we merged the template with a prior declaration chain, merge the
   // common pointer.
   // FIXME: Actually merge here, don't just overwrite.
-  D->setCommonPtr(D->getCanonicalDecl()->getCommonPtrInternal());
+  D->Common = D->getCanonicalDecl()->Common;
 }
 
 /// "Cast" to type T, asserting if we don't have an implicit conversion.
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f21cbd11b6ab89..b71684569609ac 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1713,13 +1713,14 @@ void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
 void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   VisitRedeclarable(D);
 
-  Record.push_back(D->isMemberSpecialization());
-
   // Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
   // getCommonPtr() can be used while this is still initializing.
-  if (D->isFirstDecl())
+  if (D->isFirstDecl()) {
     // This declaration owns the 'common' pointer, so serialize that data now.
     Record.AddDeclRef(D->getInstantiatedFromMemberTemplate());
+    if (D->getInstantiatedFromMemberTemplate())
+      Record.push_back(D->isMemberSpecialization());
+  }
 
   VisitTemplateDecl(D);
   Record.push_back(D->getIdentifierNamespace());
@@ -1805,10 +1806,11 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
 
   VisitClassTemplateSpecializationDecl(D);
 
-  Record.push_back(D->isMemberSpecialization());
   // These are read/set from/to the first declaration.
-  if (D->isFirstDecl())
+  if (D->getPreviousDecl() == nullptr) {
     Record.AddDeclRef(D->getInstantiatedFromMember());
+    Record.push_back(D->isMemberSpecialization());
+  }
 
   Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
 }
@@ -1872,11 +1874,12 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
   Record.AddTemplateParameterList(D->getTemplateParameters());
 
   VisitVarTemplateSpecializationDecl(D);
-  Record.push_back(D->isMemberSpecialization());
 
   // These are read/set from/to the first declaration.
-  if (D->isFirstDecl())
+  if (D->getPreviousDecl() == nullptr) {
     Record.AddDeclRef(D->getInstantiatedFromMember());
+    Record.push_back(D->isMemberSpecialization());
+  }
 
   Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
 }
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
deleted file mode 100644
index 70064f867e18e3..00000000000000
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
-
-template<typename T>
-concept D = true;
-
-template<typename T>
-struct A {
-  template<typename U, bool V>
-  void f() requires V;
-
-  template<>
-  void f<short, true>();
-
-  template<D U>
-  void g();
-
-  template<typename U, bool V> requires V
-  struct B;
-
-  template<typename U, bool V> requires V
-  struct B<U*, V>;
-
-  template<>
-  struct B<short, true>;
-
-  template<D U>
-  struct C;
-
-  template<D U>
-  struct C<U*>;
-
-  template<typename U, bool V> requires V
-  static int x;
-
-  template<typename U, bool V> requires V
-  static int x<U*, V>;
-
-  template<>
-  int x<short, true>;
-
-  template<D U>
-  static int y;
-
-  template<D U>
-  static int y<U*>;
-};
-
-template<typename T>
-template<typename U, bool V>
-void A<T>::f() requires V { }
-
-template<typename T>
-template<D U>
-void A<T>::g() { }
-
-template<typename T>
-template<typename U, bool V> requires V
-struct A<T>::B { };
-
-template<typename T>
-template<typename U, bool V> requires V
-struct A<T>::B<U*, V> { };
-
-template<typename T>
-template<typename U, bool V> requires V
-struct A<T>::B<U&, V> { };
-
-template<typename T>
-template<D U>
-struct A<T>::C { };
-
-template<typename T>
-template<D U>
-struct A<T>::C<U*> { };
-
-template<typename T>
-template<typename U, bool V> requires V
-int A<T>::x = 0;
-
-template<typename T>
-template<typename U, bool V> requires V
-int A<T>::x<U*, V> = 0;
-
-template<typename T>
-template<typename U, bool V> requires V
-int A<T>::x<U&, V> = 0;
-
-template<typename T>
-template<D U>
-int A<T>::y = 0;
-
-template<typename T>
-template<D U>
-int A<T>::y<U*> = 0;
-
-template<>
-template<typename U, bool V>
-void A<short>::f() requires V;
-
-template<>
-template<>
-void A<short>::f<int, true>();
-
-template<>
-template<>
-void A<void>::f<int, true>();
-
-template<>
-template<D U>
-void A<short>::g();
-
-template<>
-template<typename U, bool V> requires V
-struct A<int>::B;
-
-template<>
-template<>
-struct A<int>::B<int, true>;
-
-template<>
-template<>
-struct A<void>::B<int, true>;
-
-template<>
-template<typename U, bool V> requires V
-struct A<int>::B<U*, V>;
-
-template<>
-template<typename U, bool V> requires V
-struct A<int>::B<U&, V>;
-
-template<>
-template<D U>
-struct A<int>::C;
-
-template<>
-template<D U>
-struct A<int>::C<U*>;
-
-template<>
-template<D U>
-struct A<int>::C<U&>;
-
-template<>
-template<typename U, bool V> requires V
-int A<long>::x;
-
-template<>
-template<>
-int A<long>::x<int, true>;
-
-template<>
-template<>
-int A<void>::x<int, true>;
-
-template<>
-template<typename U, bool V> requires V
-int A<long>::x<U*, V>;
-
-template<>
-template<typename U, bool V> requires V
-int A<long>::x<U&, V>;
-
-template<>
-template<D U>
-int A<long>::y;
-
-template<>
-template<D U>
-int A<long>::y<U*>;
-
-template<>
-template<D U>
-int A<long>::y<U&>;
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
deleted file mode 100644
index 1df449293bad82..00000000000000
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-
-namespace Undefined {
-  template<typename T>
-  struct A {
-    template<typename U>
-    static constexpr int f(); // expected-note {{declared here}}
-
-    template<typename U>
-    static const int x; // expected-note {{declared here}}
-
-    template<typename U>
-    static const int x<U*>; // expected-note {{declared here}}
-
-    template<typename U>
-    struct B; // expected-note {{template is declared here}}
-
-    template<typename U>
-    struct B<U*>; // expected-note {{template is declared here}}
-  };
-
-  template<>
-  template<typename U>
-  constexpr int A<short>::f() {
-    return A<long>::f<U>();
-  }
-
-  template<>
-  template<typename U>
-  constexpr int A<short>::x = A<long>::x<U>;
-
-  template<>
-  template<typename U>
-  constexpr int A<short>::x<U*> = A<long>::x<U*>;
-
-  template<>
-  template<typename U>
-  struct A<short>::B<U*> {
-    static constexpr int y = A<long>::B<U*>::y;
-  };
-
-  template<>
-  template<typename U>
-  struct A<short>::B {
-    static constexpr int y = A<long>::B<U>::y;
-  };
-
-  template<>
-  template<typename U>
-  constexpr int A<long>::f() {
-    return 1;
-  }
-
-  template<>
-  template<typename U>
-  constexpr int A<long>::x = 1;
-
-  template<>
-  template<typename U>
-  constexpr int A<long>::x<U*> = 2;
-
-  template<>
-  template<typename U>
-  struct A<long>::B {
-    static constexpr int y = 1;
-  };
-
-  template<>
-  template<typename U>
-  struct A<long>::B<U*> {
-    static constexpr int y = 2;
-  };
-
-  static_assert(A<int>::f<int>() == 0); // expected-error {{static assertion expression is not an integral constant expression}}
-                                        // expected-note at -1 {{undefined function 'f<int>' cannot be used in a constant expression}}
-  static_assert(A<int>::x<int> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
-                                      // expected-note at -1 {{initializer of 'x<int>' is unknown}}
-  static_assert(A<int>::x<int*> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
-                                       // expected-note at -1 {{initializer of 'x<int *>' is unknown}}
-  static_assert(A<int>::B<int>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int>'}}
-  static_assert(A<int>::B<int*>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int *>'}}
-
-  static_assert(A<short>::f<int>() == 1);
-  static_assert(A<short>::x<int> == 1);
-  static_assert(A<short>::x<int*> == 2);
-  static_assert(A<short>::B<int>::y == 1);
-  static_assert(A<short>::B<int*>::y == 2);
-} // namespace Undefined
-
-namespace Defined {
-  template<typename T>
-  struct A {
-    template<typename U>
-    static constexpr int f() {
-      return 0;
-    };
-
-    template<typename U>
-    static const int x = 0;
-
-    template<typename U>
-    static const int x<U*> = 0;
-
-    template<typename U>
-    struct B {
-      static constexpr int y = 0;
-    };
-
-    template<typename U>
-    struct B<U*> {
-      static constexpr int y = 0;
-    };
-  };
-
-  template<>
-  template<typename U>
-  constexpr int A<short>::f() {
-    return A<long>::f<U>();
-  }
-
-  template<>
-  template<typename U>
-  constexpr int A<short>::x = A<long>::x<U>;
-
-  template<>
-  template<typename U>
-  constexpr int A<short>::x<U*> = A<long>::x<U*>;
-
-  template<>
-  template<typename U>
-  struct A<short>::B<U*> {
-    static constexpr int y = A<long>::B<U*>::y;
-  };
-
-  template<>
-  template<typename U>
-  struct A<short>::B {
-    static constexpr int y = A<long>::B<U>::y;
-  };
-
-  template<>
-  template<typename U>
-  constexpr int A<long>::f() {
-    return 1;
-  }
-
-  template<>
-  template<typename U>
-  constexpr int A<long>::x = 1;
-
-  template<>
-  template<typename U>
-  constexpr int A<long>::x<U*> = 2;
-
-  template<>
-  template<typename U>
-  struct A<long>::B {
-    static constexpr int y = 1;
-  };
-
-  template<>
-  template<typename U>
-  struct A<long>::B<U*> {
-    static constexpr int y = 2;
-  };
-
-  static_assert(A<int>::f<int>() == 0);
-  static_assert(A<int>::x<int> == 0);
-  static_assert(A<int>::x<int*> == 0);
-  static_assert(A<int>::B<int>::y == 0);
-  static_assert(A<int>::B<int*>::y == 0);
-
-  static_assert(A<short>::f<int>() == 1);
-  static_assert(A<short>::x<int> == 1);
-  static_assert(A<short>::x<int*> == 2);
-  static_assert(A<short>::B<int>::y == 1);
-  static_assert(A<short>::B<int*>::y == 2);
-} // namespace Defined
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index 44b02ad3ec748c..b7d5741e69af61 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -199,7 +199,9 @@ namespace hidden_specializations {
     cls<char*> uk4; // expected-error 1+{{partial specialization of 'cls<T *>' must be imported}} expected-error 1+{{definition of}}
     cls<void>::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}}
     cls<void>::nested_cls_t<int> unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
-    cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
+    // expected-error at cxx-templates-unimported.h:29 {{explicit specialization of 'nested_cls_t' must be imported}}
+    // expected-note at -2 {{in evaluation of exception specification}}
+    cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}}
 
     // For enums, uses that would trigger instantiations of definitions are not
     // allowed.



More information about the cfe-commits mailing list