[clang] [Clang][Sema] Refactor collection of multi-level template argument lists (PR #106585)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 20 08:57:07 PDT 2024


https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/106585

>From 2cca9d25091c49b9a412af1d7585574c77754752 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 1 Aug 2024 13:13:57 -0400
Subject: [PATCH 01/31] [WIP] set isMemberSpecialization early

---
 clang/include/clang/AST/DeclTemplate.h     | 30 ++++----------
 clang/include/clang/Sema/Sema.h            |  7 ++--
 clang/lib/AST/DeclTemplate.cpp             | 28 ++++++-------
 clang/lib/Sema/SemaDecl.cpp                | 23 +++++------
 clang/lib/Sema/SemaDeclCXX.cpp             |  3 +-
 clang/lib/Sema/SemaTemplate.cpp            | 48 +++++++++++-----------
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 18 ++++++++
 clang/lib/Serialization/ASTReaderDecl.cpp  | 14 +++----
 clang/lib/Serialization/ASTWriterDecl.cpp  |  9 ++--
 clang/test/PCH/cxx-templates.cpp           |  6 +--
 10 files changed, 94 insertions(+), 92 deletions(-)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 687715a22e9fd3..3ad31243d5e559 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -809,8 +809,8 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   };
 
   /// Pointer to the common data shared by all declarations of this
-  /// template.
-  mutable CommonBase *Common = nullptr;
+  /// template, and a flag indicating if the template is a member specialization.
+  mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
 
   /// Retrieves the "common" pointer shared by all (re-)declarations of
   /// the same template. Calling this routine may implicitly allocate memory
@@ -858,14 +858,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// struct X<int>::Inner { /* ... */ };
   /// \endcode
   bool isMemberSpecialization() const {
-    return getCommonPtr()->InstantiatedFromMember.getInt();
+    return Common.getInt();
   }
 
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
-    assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
-           "Only member templates can be member template specializations");
-    getCommonPtr()->InstantiatedFromMember.setInt(true);
+    Common.setInt(true);
   }
 
   /// Retrieve the member template from which this template was
@@ -2187,17 +2185,12 @@ class ClassTemplatePartialSpecializationDecl
   /// struct X<int>::Inner<T*> { /* ... */ };
   /// \endcode
   bool isMemberSpecialization() const {
-    const auto *First =
-        cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
-    return First->InstantiatedFromMember.getInt();
+    return InstantiatedFromMember.getInt();
   }
 
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
-    auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
-    assert(First->InstantiatedFromMember.getPointer() &&
-           "Only member templates can be member template specializations");
-    return First->InstantiatedFromMember.setInt(true);
+    return InstantiatedFromMember.setInt(true);
   }
 
   /// Retrieves the injected specialization type for this partial
@@ -2269,7 +2262,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
   }
 
   void setCommonPtr(Common *C) {
-    RedeclarableTemplateDecl::Common = C;
+    RedeclarableTemplateDecl::Common.setPointer(C);
   }
 
 public:
@@ -2949,17 +2942,12 @@ class VarTemplatePartialSpecializationDecl
   /// U* X<int>::Inner<T*> = (T*)(0) + 1;
   /// \endcode
   bool isMemberSpecialization() const {
-    const auto *First =
-        cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
-    return First->InstantiatedFromMember.getInt();
+    return InstantiatedFromMember.getInt();
   }
 
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
-    auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
-    assert(First->InstantiatedFromMember.getPointer() &&
-           "Only member templates can be member template specializations");
-    return First->InstantiatedFromMember.setInt(true);
+    return 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 0358259945c796..99b8b17c2b0578 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11392,9 +11392,8 @@ class Sema final : public SemaBase {
       CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
       const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
       AccessSpecifier AS, SourceLocation ModulePrivateLoc,
-      SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
-      TemplateParameterList **OuterTemplateParamLists,
-      SkipBodyInfo *SkipBody = nullptr);
+      SourceLocation FriendLoc, ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
+      bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
 
   /// Translates template arguments as provided by the parser
   /// into template arguments used by semantic analysis.
@@ -11433,7 +11432,7 @@ class Sema final : public SemaBase {
   DeclResult ActOnVarTemplateSpecialization(
       Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
       SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
-      StorageClass SC, bool IsPartialSpecialization);
+      StorageClass SC, bool IsPartialSpecialization, bool IsMemberSpecialization);
 
   /// Get the specialization of the given variable template corresponding to
   /// the specified argument list, or a null-but-valid result if the arguments
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 976b3a3e1ecedb..58ce956f4b916a 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 (Common)
-    return Common;
+  if (CommonBase *C = Common.getPointer())
+    return C;
 
   // 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 (Prev->Common) {
-      Common = Prev->Common;
+    if (CommonBase *C = Prev->Common.getPointer()) {
+      Common.setPointer(C);
       break;
     }
 
@@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
   }
 
   // If we never found a common pointer, allocate one now.
-  if (!Common) {
+  if (!Common.getPointer()) {
     // FIXME: If any of the declarations is from an AST file, we probably
     // need an update record to add the common data.
 
-    Common = newCommon(getASTContext());
+    Common.setPointer(newCommon(getASTContext()));
   }
 
   // Update any previous declarations we saw with the common pointer.
   for (const RedeclarableTemplateDecl *Prev : PrevDecls)
-    Prev->Common = Common;
+    Prev->Common.setPointer(Common.getPointer());
 
-  return Common;
+  return Common.getPointer();
 }
 
 void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
@@ -467,15 +467,15 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
 
   // If we haven't created a common pointer yet, then it can just be created
   // with the usual method.
-  if (!Base::Common)
+  if (!Base::Common.getPointer())
     return;
 
-  Common *ThisCommon = static_cast<Common *>(Base::Common);
+  Common *ThisCommon = static_cast<Common *>(Base::Common.getPointer());
   Common *PrevCommon = nullptr;
   SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
   for (; Prev; Prev = Prev->getPreviousDecl()) {
-    if (Prev->Base::Common) {
-      PrevCommon = static_cast<Common *>(Prev->Base::Common);
+    if (CommonBase *C = Prev->Base::Common.getPointer()) {
+      PrevCommon = static_cast<Common *>(C);
       break;
     }
     PreviousDecls.push_back(Prev);
@@ -485,7 +485,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
   // use this common pointer.
   if (!PrevCommon) {
     for (auto *D : PreviousDecls)
-      D->Base::Common = ThisCommon;
+      D->Base::Common.setPointer(ThisCommon);
     return;
   }
 
@@ -493,7 +493,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
   assert(ThisCommon->Specializations.size() == 0 &&
          "Can't merge incompatible declarations!");
 
-  Base::Common = PrevCommon;
+  Base::Common.setPointer(PrevCommon);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0f63c764536ecb..9d1927680146b5 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7655,7 +7655,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
               : SourceLocation();
       DeclResult Res = ActOnVarTemplateSpecialization(
           S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
-          IsPartialSpecialization);
+          IsPartialSpecialization, IsMemberSpecialization);
       if (Res.isInvalid())
         return nullptr;
       NewVD = cast<VarDecl>(Res.get());
@@ -7674,6 +7674,10 @@ 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
@@ -8049,12 +8053,6 @@ 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();
     }
   }
 
@@ -9858,6 +9856,8 @@ 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) {
@@ -12004,10 +12004,9 @@ 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 &&
-          NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+      if (IsMemberSpecialization) {
         NewTemplateDecl->setMemberSpecialization();
-        assert(OldTemplateDecl->isMemberSpecialization());
+        // 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()) {
@@ -17066,8 +17065,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.size() - 1,
-            TemplateParameterLists.data(), SkipBody);
+            /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
+            isMemberSpecialization, 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 3044f1218f5b23..8d0dfa4da33e4f 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17411,8 +17411,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
       return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
                                 Name, NameLoc, Attr, TemplateParams, AS_public,
                                 /*ModulePrivateLoc=*/SourceLocation(),
-                                FriendLoc, TempParamLists.size() - 1,
-                                TempParamLists.data())
+                                FriendLoc, TempParamLists.drop_back(), IsMemberSpecialization)
           .get();
     } else {
       // The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index bf6b53700d90eb..7bdc87b8c7439f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1793,8 +1793,8 @@ DeclResult Sema::CheckClassTemplate(
     CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
     const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
     AccessSpecifier AS, SourceLocation ModulePrivateLoc,
-    SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
-    TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) {
+    SourceLocation FriendLoc, ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
+    bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
   assert(TemplateParams && TemplateParams->size() > 0 &&
          "No template parameters");
   assert(TUK != TagUseKind::Reference &&
@@ -2087,10 +2087,9 @@ DeclResult Sema::CheckClassTemplate(
                             PrevClassTemplate->getTemplatedDecl() : nullptr,
                           /*DelayTypeCreation=*/true);
   SetNestedNameSpecifier(*this, NewClass, SS);
-  if (NumOuterTemplateParamLists > 0)
+  if (!OuterTemplateParamLists.empty())
     NewClass->setTemplateParameterListsInfo(
-        Context,
-        llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
+        Context, OuterTemplateParamLists);
 
   // Add alignment attributes if necessary; these attributes are checked when
   // the ASTContext lays out the structure.
@@ -2103,7 +2102,10 @@ 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);
 
@@ -2118,12 +2120,6 @@ 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())
@@ -3970,7 +3966,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) {
+    StorageClass SC, bool IsPartialSpecialization, bool IsMemberSpecialization) {
   // D must be variable template id.
   assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
          "Variable template specialization is declared with a template id.");
@@ -4087,16 +4083,18 @@ 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();
+    //if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+    //  PrevPartial->setMemberSpecialization();
 
     CheckTemplatePartialSpecialization(Partial);
   } else {
@@ -8304,8 +8302,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
                                 TemplateParams,
                                 AS_none, /*ModulePrivateLoc=*/SourceLocation(),
                                 /*FriendLoc*/SourceLocation(),
-                                TemplateParameterLists.size() - 1,
-                                TemplateParameterLists.data());
+                                TemplateParameterLists.drop_back(),
+                                isMemberSpecialization);
     }
 
     // Create a new class template partial specialization declaration node.
@@ -8315,6 +8313,11 @@ 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()) {
@@ -8326,11 +8329,6 @@ 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
@@ -11127,7 +11125,7 @@ class ExplicitSpecializationVisibilityChecker {
 
   template<typename TemplDecl>
   void checkTemplate(TemplDecl *TD) {
-    if (TD->isMemberSpecialization()) {
+    if (TD->getMostRecentDecl()->isMemberSpecialization()) {
       if (!CheckMemberSpecialization(TD))
         diagnose(TD->getMostRecentDecl(), false);
     }
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index c42cc250bb904a..c27bc4690d10e8 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -332,12 +332,15 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
 
 Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
                                     MultiLevelTemplateArgumentList &Result) {
+  #if 0
   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) {
@@ -381,6 +384,21 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
   }
 
   return Response::ChangeDecl(FTD->getLexicalDeclContext());
+  #else
+  if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
+    Result.addOuterTemplateArguments(
+        const_cast<FunctionTemplateDecl *>(FTD),
+        const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
+        /*Final=*/false);
+  }
+
+  if (FTD->isMemberSpecialization())
+    return Response::Done();
+
+  if (FTD->getFriendObjectKind())
+    return Response::ChangeDecl(FTD->getLexicalDeclContext());
+  return Response::UseNextDecl(FTD);
+  #endif
 }
 
 Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 9272e23c7da3fc..d9556dc4ce731a 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2416,11 +2416,13 @@ 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->Common) {
-    CanonD->Common = CanonD->newCommon(Reader.getContext());
+  if (!CanonD->Common.getPointer()) {
+    CanonD->Common.setPointer(CanonD->newCommon(Reader.getContext()));
     Reader.PendingDefinitions.insert(CanonD);
   }
-  D->Common = CanonD->Common;
+  D->Common.setPointer(CanonD->Common.getPointer());
+  if (Record.readInt())
+    D->setMemberSpecialization();
 
   // If this is the first declaration of the template, fill in the information
   // for the 'common' pointer.
@@ -2429,8 +2431,6 @@ 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>());
-    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());
   }
 }
 
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 555f6325da646b..eb45124f911475 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1707,13 +1707,14 @@ void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
 void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   VisitRedeclarable(D);
 
+  // if (D->getInstantiatedFromMemberTemplate())
+  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()) {
     // 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);
@@ -1788,10 +1789,10 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
 
   VisitClassTemplateSpecializationDecl(D);
 
+  Record.push_back(D->isMemberSpecialization());
   // These are read/set from/to the first declaration.
   if (D->getPreviousDecl() == nullptr) {
     Record.AddDeclRef(D->getInstantiatedFromMember());
-    Record.push_back(D->isMemberSpecialization());
   }
 
   Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
@@ -1856,11 +1857,11 @@ 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->getPreviousDecl() == nullptr) {
     Record.AddDeclRef(D->getInstantiatedFromMember());
-    Record.push_back(D->isMemberSpecialization());
   }
 
   Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
diff --git a/clang/test/PCH/cxx-templates.cpp b/clang/test/PCH/cxx-templates.cpp
index 11ad401de23a8c..bbe8c79bec374c 100644
--- a/clang/test/PCH/cxx-templates.cpp
+++ b/clang/test/PCH/cxx-templates.cpp
@@ -34,15 +34,15 @@ struct A {
 
 void test(const int (&a6)[17]) {
   int x = templ_f<int, 5>(3);
-  
+
   S<char, float>::templ();
   S<int, char>::partial();
   S<int, float>::explicit_special();
-  
+
   Dep<A>::Ty ty;
   Dep<A> a;
   a.f();
-  
+
   S3<int> s3;
   s3.m();
 

>From 4d696213bfb23e36d6d71e2dd1b70ad37bf6f3eb Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 8 Aug 2024 09:58:22 -0400
Subject: [PATCH 02/31] [WIP] set isMemberSpecialization before comparing
 template parameter lists of class templates

---
 clang/lib/Sema/SemaTemplate.cpp               | 45 +++++++++++--------
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 11 ++++-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 30 ++++++++++---
 clang/lib/Serialization/ASTReaderDecl.cpp     |  2 +-
 4 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7bdc87b8c7439f..1d06d75ab6a076 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1982,6 +1982,7 @@ DeclResult Sema::CheckClassTemplate(
   }
 
   if (PrevClassTemplate) {
+    #if 0
     // 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.
@@ -1994,6 +1995,7 @@ DeclResult Sema::CheckClassTemplate(
             PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
             TPL_TemplateMatch))
       return true;
+    #endif
 
     // C++ [temp.class]p4:
     //   In a redeclaration, partial specialization, explicit
@@ -2044,23 +2046,6 @@ 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.
@@ -2129,6 +2114,30 @@ DeclResult Sema::CheckClassTemplate(
   NewClass->setLexicalDeclContext(CurContext);
   NewTemplate->setLexicalDeclContext(CurContext);
 
+
+  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 ? GetTemplateParameterList(PrevClassTemplate)
+                        : nullptr,
+      (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
+       SemanticContext->isDependentContext())
+          ? TPC_ClassTemplateMember
+      : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
+                                  : TPC_ClassTemplate,
+      SkipBody))
+    Invalid = true;
+
   if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
     NewClass->startDefinition();
 
@@ -11126,7 +11135,7 @@ class ExplicitSpecializationVisibilityChecker {
   template<typename TemplDecl>
   void checkTemplate(TemplDecl *TD) {
     if (TD->getMostRecentDecl()->isMemberSpecialization()) {
-      if (!CheckMemberSpecialization(TD))
+      if (!CheckMemberSpecialization(TD->getMostRecentDecl()))
         diagnose(TD->getMostRecentDecl(), false);
     }
   }
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 545da21183c3c4..d09b7a807f700f 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -802,8 +802,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
 
   // A list of template arguments for transforming the require-clause of F.
   // It must contain the entire set of template argument lists.
-  MultiLevelTemplateArgumentList ArgsForBuildingRC;
+  MultiLevelTemplateArgumentList ArgsForBuildingRC =
+      SemaRef.getTemplateInstantiationArgs(
+        F, F->getLexicalDeclContext(),
+        /*Final=*/false, /*Innermost=*/TemplateArgsForBuildingRC,
+        /*RelativeToPrimary=*/true,
+        /*Pattern=*/nullptr,
+        /*ForConstraintInstantiation=*/true);;
   ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
+  #if 0
   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
@@ -846,6 +853,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
     for (auto It : OuterLevelArgs)
       ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
   }
+  #endif
+
 
   ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
   if (E.isInvalid())
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index c27bc4690d10e8..095dfebafe076e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -385,12 +385,10 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
 
   return Response::ChangeDecl(FTD->getLexicalDeclContext());
   #else
-  if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
-    Result.addOuterTemplateArguments(
-        const_cast<FunctionTemplateDecl *>(FTD),
-        const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
-        /*Final=*/false);
-  }
+  Result.addOuterTemplateArguments(
+      const_cast<FunctionTemplateDecl *>(FTD),
+      const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
+      /*Final=*/false);
 
   if (FTD->isMemberSpecialization())
     return Response::Done();
@@ -401,6 +399,24 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
   #endif
 }
 
+Response HandleClassTemplateDecl(const ClassTemplateDecl *CTD,
+                                    MultiLevelTemplateArgumentList &Result) {
+  #if 0
+  Result.addOuterTemplateArguments(
+      const_cast<ClassTemplateDecl *>(CTD),
+      const_cast<ClassTemplateDecl *>(CTD)->getInjectedTemplateArgs(),
+      /*Final=*/false);
+
+  if (CTD->isMemberSpecialization())
+    return Response::Done();
+
+  if (CTD->getFriendObjectKind())
+    return Response::ChangeDecl(CTD->getLexicalDeclContext());
+  return Response::UseNextDecl(CTD);
+  #endif
+  return Response::ChangeDecl(CTD->getLexicalDeclContext());
+}
+
 Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
                           MultiLevelTemplateArgumentList &Result,
                           ASTContext &Context,
@@ -539,7 +555,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     } 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());
+      R = HandleClassTemplateDecl(CTD, Result);
     } else if (!isa<DeclContext>(CurDecl)) {
       R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
       if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index d9556dc4ce731a..5a893515de9cc6 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -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->Common = D->getCanonicalDecl()->Common;
+  D->Common.setPointer(D->getCanonicalDecl()->Common.getPointer());
 }
 
 /// "Cast" to type T, asserting if we don't have an implicit conversion.

>From b04d89f1e46d34cbd70b2c47a653eaa2a014b61b Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 8 Aug 2024 15:00:23 -0400
Subject: [PATCH 03/31] [FOLD]

---
 clang/lib/Sema/SemaTemplate.cpp               |  2 +-
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 73 +++++++++++++++----
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  5 ++
 4 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1d06d75ab6a076..e09e1f854fb590 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2128,7 +2128,7 @@ DeclResult Sema::CheckClassTemplate(
   // context, because the template parameter list might be dependent.
   if (ShouldAddRedecl && CheckTemplateParameterList(
       TemplateParams,
-      PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate)
+      PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
                         : nullptr,
       (SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
        SemanticContext->isDependentContext())
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index d09b7a807f700f..ea02e979c4270f 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -317,7 +317,7 @@ struct ConvertConstructorToDeductionGuideTransform {
     }
 
     if (NestedPattern)
-      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
+      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(/*D=*/nullptr, Template->getDeclContext());
   }
 
   Sema &SemaRef;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 095dfebafe076e..92b2c2d2337279 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -52,7 +52,6 @@ using namespace sema;
 //===----------------------------------------------------------------------===/
 
 namespace {
-namespace TemplateInstArgsHelpers {
 struct Response {
   const Decl *NextDecl = nullptr;
   bool IsDone = false;
@@ -84,6 +83,7 @@ struct Response {
   }
 };
 
+namespace TemplateInstArgsHelpers {
 // 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.
@@ -331,7 +331,8 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
 }
 
 Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
-                                    MultiLevelTemplateArgumentList &Result) {
+                                    MultiLevelTemplateArgumentList &Result,
+                                    bool ForConstraintInstantiation) {
   #if 0
   if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
     Result.addOuterTemplateArguments(
@@ -385,10 +386,11 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
 
   return Response::ChangeDecl(FTD->getLexicalDeclContext());
   #else
-  Result.addOuterTemplateArguments(
-      const_cast<FunctionTemplateDecl *>(FTD),
-      const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
-      /*Final=*/false);
+  if (ForConstraintInstantiation)
+    Result.addOuterTemplateArguments(
+        const_cast<FunctionTemplateDecl *>(FTD),
+        const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
+        /*Final=*/false);
 
   if (FTD->isMemberSpecialization())
     return Response::Done();
@@ -400,12 +402,15 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
 }
 
 Response HandleClassTemplateDecl(const ClassTemplateDecl *CTD,
-                                    MultiLevelTemplateArgumentList &Result) {
-  #if 0
-  Result.addOuterTemplateArguments(
-      const_cast<ClassTemplateDecl *>(CTD),
-      const_cast<ClassTemplateDecl *>(CTD)->getInjectedTemplateArgs(),
-      /*Final=*/false);
+                                 MultiLevelTemplateArgumentList &Result,
+                                 bool ForConstraintInstantiation,
+                                 bool SkipForSpecialization) {
+  #if 1
+  if (!SkipForSpecialization && ForConstraintInstantiation)
+    Result.addOuterTemplateArguments(
+        const_cast<ClassTemplateDecl *>(CTD),
+        const_cast<ClassTemplateDecl *>(CTD)->getInjectedTemplateArgs(),
+        /*Final=*/false);
 
   if (CTD->isMemberSpecialization())
     return Response::Done();
@@ -496,6 +501,38 @@ Response HandleGenericDeclContext(const Decl *CurDecl) {
   return Response::UseNextDecl(CurDecl);
 }
 } // namespace TemplateInstArgsHelpers
+
+
+struct TemplateInstantiationArgumentCollecter
+    : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl*> {
+  MultiLevelTemplateArgumentList &Result;
+  bool RelativeToPrimary;
+  bool ForConstraintInstantiation;
+  bool SkipForSpecialization;
+
+  TemplateInstantiationArgumentCollecter(
+      MultiLevelTemplateArgumentList &Result,
+      bool RelativeToPrimary,
+      bool ForConstraintInstantiation,
+      bool SkipForSpecialization) :
+          Result(Result), RelativeToPrimary(RelativeToPrimary),
+          ForConstraintInstantiation(ForConstraintInstantiation),
+          SkipForSpecialization(SkipForSpecialization) { }
+  //using inherited = DeclVisitor<TemplateInstantiationArgumentCollecter>;
+
+
+
+  Decl *VisitDecl(Decl *D) {
+    if (D->isFileContextDecl())
+      return nullptr;
+
+    if (isa<DeclContext>(D))
+      RelativeToPrimary = false;
+
+    return Decl::castFromDeclContext(D->getDeclContext());
+  }
+};
+
 } // namespace
 
 MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
@@ -529,6 +566,14 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
   }
 
+  TemplateInstantiationArgumentCollecter Collecter(
+      Result, RelativeToPrimary,
+      ForConstraintInstantiation,
+      SkipForSpecialization);
+  do {
+    CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
+  } while (CurDecl);
+
   while (!CurDecl->isFileContextDecl()) {
     Response R;
     if (const auto *VarTemplSpec =
@@ -553,9 +598,9 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
                    dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
       R = HandleImplicitConceptSpecializationDecl(CSD, Result);
     } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) {
-      R = HandleFunctionTemplateDecl(FTD, Result);
+      R = HandleFunctionTemplateDecl(FTD, Result, ForConstraintInstantiation);
     } else if (const auto *CTD = dyn_cast<ClassTemplateDecl>(CurDecl)) {
-      R = HandleClassTemplateDecl(CTD, Result);
+      R = HandleClassTemplateDecl(CTD, Result, ForConstraintInstantiation, SkipForSpecialization);
     } else if (!isa<DeclContext>(CurDecl)) {
       R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
       if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 51109b092d7568..97c240d58c0709 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5183,9 +5183,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     RebuildTypeSourceInfoForDefaultSpecialMembers();
     SetDeclDefaulted(Function, PatternDecl->getLocation());
   } else {
+    #if 0
     MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
         Function, Function->getLexicalDeclContext(), /*Final=*/false,
         /*Innermost=*/std::nullopt, false, PatternDecl);
+    #else
+    MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+        Function, Function->getLexicalDeclContext());
+    #endif
 
     // Substitute into the qualifier; we can get a substitution failure here
     // through evil use of alias templates.

>From 8d099394ca7e2ec1d258aa41da6822441deea693 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 12 Aug 2024 08:30:01 -0400
Subject: [PATCH 04/31] [FOLD] pass old and new declarations to
 TemplateParameterListsAreEqual when comparing variable templates

---
 clang/lib/Sema/SemaDecl.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9d1927680146b5..0eb58eb4339bc7 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4506,8 +4506,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
 
   // Ensure the template parameters are compatible.
   if (NewTemplate &&
-      !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
-                                      OldTemplate->getTemplateParameters(),
+      !TemplateParameterListsAreEqual(NewTemplate, NewTemplate->getTemplateParameters(),
+                                      OldTemplate, OldTemplate->getTemplateParameters(),
                                       /*Complain=*/true, TPL_TemplateMatch))
     return New->setInvalidDecl();
 

>From 3861eab6df1382277b8b106f907c9412addc6159 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 12 Aug 2024 08:30:36 -0400
Subject: [PATCH 05/31] [FOLD] implement TemplateInstantiationArgumentCollecter

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 320 +++++++++++++++++++--
 1 file changed, 299 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 92b2c2d2337279..481d32a310e260 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -82,8 +82,6 @@ struct Response {
     return R;
   }
 };
-
-namespace TemplateInstArgsHelpers {
 // 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.
@@ -171,6 +169,23 @@ bool isLambdaEnclosedByTypeAliasDecl(
               .TraverseType(Underlying);
 }
 
+namespace TemplateInstArgsHelpers {
+
+// 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();
+}
+
+#if 0
 // Add template arguments from a variable template instantiation.
 Response
 HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
@@ -211,20 +226,6 @@ HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
   return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
 }
 
-// If we have a template template parameter with translation unit context,
-// then we're performing substitution into a default template argument of
-// this template template parameter before we've constructed the template
-// that will own this template template parameter. In this case, we
-// use empty template parameter lists for all of the outer templates
-// to avoid performing any substitutions.
-Response
-HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
-                                      MultiLevelTemplateArgumentList &Result) {
-  for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
-    Result.addOuterTemplateArguments(std::nullopt);
-  return Response::Done();
-}
-
 Response HandlePartialClassTemplateSpec(
     const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
     MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
@@ -500,36 +501,310 @@ Response HandleImplicitConceptSpecializationDecl(
 Response HandleGenericDeclContext(const Decl *CurDecl) {
   return Response::UseNextDecl(CurDecl);
 }
+#endif
 } // namespace TemplateInstArgsHelpers
 
 
 struct TemplateInstantiationArgumentCollecter
     : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl*> {
+  Sema &S;
   MultiLevelTemplateArgumentList &Result;
   bool RelativeToPrimary;
   bool ForConstraintInstantiation;
   bool SkipForSpecialization;
 
   TemplateInstantiationArgumentCollecter(
+      Sema &S,
       MultiLevelTemplateArgumentList &Result,
       bool RelativeToPrimary,
       bool ForConstraintInstantiation,
       bool SkipForSpecialization) :
-          Result(Result), RelativeToPrimary(RelativeToPrimary),
+          S(S), Result(Result), RelativeToPrimary(RelativeToPrimary),
           ForConstraintInstantiation(ForConstraintInstantiation),
           SkipForSpecialization(SkipForSpecialization) { }
-  //using inherited = DeclVisitor<TemplateInstantiationArgumentCollecter>;
 
+  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());
+  }
+
+  Decl *DontClearRelativeToPrimaryNextDecl(const Decl* D) {
+    return const_cast<Decl *>(
+        Decl::castFromDeclContext(D->getDeclContext()));
+  }
+
+  Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
+    for (unsigned I = 0, N = TTPD->getDepth() + 1; I != N; ++I)
+      Result.addOuterTemplateArguments(std::nullopt);
+    return Done();
+  }
+
+  Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
+    if (ForConstraintInstantiation)
+      Result.addOuterTemplateArguments(
+          FTD, FTD->getInjectedTemplateArgs(), /*Final=*/false);
+
+    if (FTD->isMemberSpecialization())
+      return Done();
+
+    if (FTD->getFriendObjectKind())
+      return ChangeDecl(FTD->getLexicalDeclContext());
+    return UseNextDecl(FTD);
+  }
+
+  Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
+    if (!SkipForSpecialization && ForConstraintInstantiation)
+      Result.addOuterTemplateArguments(
+          VTD, VTD->getInjectedTemplateArgs(), /*Final=*/false);
+
+    if (VTD->isMemberSpecialization())
+      return Done();
+
+    return UseNextDecl(VTD);
+  }
+
+  Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
+    if (!SkipForSpecialization && ForConstraintInstantiation)
+      Result.addOuterTemplateArguments(
+          CTD, CTD->getInjectedTemplateArgs(), /*Final=*/false);
+
+    if (CTD->isMemberSpecialization())
+      return Done();
+
+    if (CTD->getFriendObjectKind())
+      return ChangeDecl(CTD->getLexicalDeclContext());
+    return UseNextDecl(CTD);
+  }
+
+  Decl *VisitClassTemplatePartialSpecializationDecl(ClassTemplatePartialSpecializationDecl *CTPSD) {
+    if (!SkipForSpecialization)
+        Result.addOuterRetainedLevels(CTPSD->getTemplateDepth());
+    return Done();
+  }
+
+  Decl *VisitFunctionDecl(FunctionDecl *FD) {
+    // Add template arguments from a function template specialization.
+    if (!RelativeToPrimary &&
+        FD->getTemplateSpecializationKindForInstantiation() ==
+            TSK_ExplicitSpecialization)
+      return Done();
+
+    if (!RelativeToPrimary &&
+        FD->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 UseNextDecl(FD);
+    } else if (const TemplateArgumentList *TemplateArgs =
+                   FD->getTemplateSpecializationArgs()) {
+      // Add the template arguments for this specialization.
+      Result.addOuterTemplateArguments(
+          FD, TemplateArgs->asArray(), /*Final=*/false);
+
+      if (RelativeToPrimary &&
+          (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)) {
+        // TypeAliasTemplateDecls should be taken into account, e.g.
+        // when we're deducing the return type of a lambda.
+        //
+        // template <class> int Value = 0;
+        // template <class T>
+        // using T = decltype([]<int U = 0>() { return Value<T>; }());
+        //
+        if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S)) {
+          if (isLambdaEnclosedByTypeAliasDecl(
+                  /*PrimaryLambdaCallOperator=*/getPrimaryTemplateOfGenericLambda(FD),
+                  /*PrimaryTypeAliasDecl=*/TypeAlias.PrimaryTypeAliasDecl))
+            return UseNextDecl(FD);
+        }
+        return Done();
+      }
+
+    } else if (FD->getDescribedFunctionTemplate()) {
+      assert(
+          (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+          "Outer template not instantiated?");
+    }
+    // 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);
+  }
+
+  Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
+    if (ClassTemplateDecl *ClassTemplate = RD->getDescribedClassTemplate()) {
+      assert(
+          (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+          "Outer template not instantiated?");
+      if (ClassTemplate->isMemberSpecialization())
+        return Done();
+      if (ForConstraintInstantiation)
+        Result.addOuterTemplateArguments(
+            RD, ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false);
+    }
 
+    if (const MemberSpecializationInfo *MSInfo =
+            RD->getMemberSpecializationInfo())
+      if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        return Done();
+
+    bool IsFriend = RD->getFriendObjectKind() ||
+                    (RD->getDescribedClassTemplate() &&
+                     RD->getDescribedClassTemplate()->getFriendObjectKind());
+    if (ForConstraintInstantiation && IsFriend &&
+        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)) {
+        const FunctionDecl *PrimaryLambdaCallOperator =
+            getPrimaryTemplateOfGenericLambda(RD->getLambdaCallOperator());
+        if (isLambdaEnclosedByTypeAliasDecl(PrimaryLambdaCallOperator,
+                                            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 ChangeDecl(TypeAlias.Template->getDeclContext());
+        }
+      }
+    }
+
+    return UseNextDecl(RD);
+  }
+
+  Decl *VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
+    if (!CTSD->isClassScopeExplicitSpecialization()) {
+      // We're done when we hit an explicit specialization.
+      if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
+          !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
+        return Done();
+
+      if (!SkipForSpecialization)
+        Result.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?");
+      if (CTSD->getSpecializedTemplate()->isMemberSpecialization())
+        return 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 *CTPSD = CTSD->getSpecializedTemplateOrPartial()
+                        .dyn_cast<ClassTemplatePartialSpecializationDecl *>())
+        return ChangeDecl(CTPSD->getLexicalDeclContext());
+    }
+    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 DontClearRelativeToPrimaryNextDecl(VTSD);
+
+    // We're done when we hit an explicit specialization.
+    if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
+        !isa<VarTemplatePartialSpecializationDecl>(VTSD))
+      return Done();
+
+    // 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 (VarTemplatePartialSpecializationDecl *VTPSD =
+            Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+      if (!SkipForSpecialization)
+        Result.addOuterTemplateArguments(
+            VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
+            /*Final=*/false);
+      if (VTPSD->isMemberSpecialization())
+        return Done();
+    } else {
+      VarTemplateDecl *VTD = Specialized.get<VarTemplateDecl *>();
+      if (!SkipForSpecialization)
+        Result.addOuterTemplateArguments(
+            VTD, VTSD->getTemplateInstantiationArgs().asArray(),
+            /*Final=*/false);
+      if (VTD->isMemberSpecialization())
+        return Done();
+    }
+    return DontClearRelativeToPrimaryNextDecl(VTSD);
+  }
+
+  Decl *VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl *ICSD) {
+    Result.addOuterTemplateArguments(
+        ICSD, ICSD->getTemplateArguments(),
+        /*Final=*/false);
+    return UseNextDecl(ICSD);
+  }
 
   Decl *VisitDecl(Decl *D) {
     if (D->isFileContextDecl())
-      return nullptr;
+      return Done();
 
     if (isa<DeclContext>(D))
       RelativeToPrimary = false;
 
-    return Decl::castFromDeclContext(D->getDeclContext());
+    return UseNextDecl(D);
   }
 };
 
@@ -567,13 +842,15 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   }
 
   TemplateInstantiationArgumentCollecter Collecter(
-      Result, RelativeToPrimary,
+      *this, Result, RelativeToPrimary,
       ForConstraintInstantiation,
       SkipForSpecialization);
   do {
     CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
   } while (CurDecl);
+  return Result;
 
+  #if 0
   while (!CurDecl->isFileContextDecl()) {
     Response R;
     if (const auto *VarTemplSpec =
@@ -619,6 +896,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   }
 
   return Result;
+  #endif
 }
 
 bool Sema::CodeSynthesisContext::isInstantiationRecord() const {

>From b0da1f06c3bd80136015d0660f7bae04ebfbbc6d Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 12 Aug 2024 08:52:11 -0400
Subject: [PATCH 06/31] [FOLD] update test

---
 .../class-template-partial-specializations.cpp             | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
index 7772eecc69be8b..3358869b95e370 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -33,11 +33,12 @@ class D{}; // expected-note{{previous definition is here}}
 template<typename T>
 class D<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} expected-error{{redefinition of 'D'}}
 
-template<typename T> requires C1<T> // expected-note{{previous template declaration is here}}
-class E{};
+template<typename T> requires C1<T>
+class E{}; // expected-note{{previous definition is here}}
 
-template<typename T> // expected-error{{requires clause differs in template redeclaration}}
+template<typename T>
 class E<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+              // expected-error at -1{{redefinition of 'E'}}
 
 template<typename T>
 struct F{ enum{ value = 1 }; };

>From 0c9e6c3d5b052b083948735f118f6bda14e4c636 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 12 Aug 2024 12:25:45 -0400
Subject: [PATCH 07/31] [FOLD] further simplify getTemplateInstantiationArgs

---
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  30 +++++
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 107 ++++++++++++++++--
 clang/test/SemaCXX/friend.cpp                 |   4 +-
 .../SemaTemplate/default-expr-arguments.cpp   |  26 ++---
 4 files changed, 142 insertions(+), 25 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 01f18e5a325197..db1f7177f514f2 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3170,6 +3170,8 @@ template<>
 struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
   static constexpr bool value = true;
 };
+
+#if 0
 template <typename TemplateDeclT>
 static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
   return false;
@@ -3184,6 +3186,7 @@ bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
     ClassTemplatePartialSpecializationDecl *Spec) {
   return !Spec->isClassScopeExplicitSpecialization();
 }
+#endif
 
 template <typename TemplateDeclT>
 static TemplateDeductionResult
@@ -3194,6 +3197,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
   llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
   Template->getAssociatedConstraints(AssociatedConstraints);
 
+  #if 0
   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.
@@ -3211,6 +3215,32 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
   // instead of adding to inner-most.
   if (!Innermost)
     MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
+  #endif
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+      Template, Template->getDeclContext(), /*Final=*/false,
+      /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
+      /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
+
+  #if 0
+  if (DeducedArgsNeedReplacement(Template)) {
+    MultiLevelTemplateArgumentList WithReplacement = S.getTemplateInstantiationArgs(
+      Template, Template->getDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt,
+      /*RelativeToPrimary=*/true, /*Pattern=*/
+      nullptr, /*ForConstraintInstantiation=*/true);
+
+    WithReplacement.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
+
+    assert(MLTAL.getNumLevels() == WithReplacement.getNumLevels());
+    assert(MLTAL.getNumSubstitutedLevels() == WithReplacement.getNumSubstitutedLevels());
+    auto First0 = MLTAL.begin(), Last0 = MLTAL.end();
+    auto First1 = WithReplacement.begin(), Last1 = WithReplacement.end();
+
+    while (First0 != Last0) {
+      assert(First0->Args.data() == First1->Args.data());
+      ++First0, ++First1;
+    }
+  }
+  #endif
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 481d32a310e260..74149273b06fd0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -546,12 +546,21 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
+    #if 0
     for (unsigned I = 0, N = TTPD->getDepth() + 1; I != N; ++I)
       Result.addOuterTemplateArguments(std::nullopt);
     return Done();
+    #endif
+    if (ForConstraintInstantiation)
+      Result.addOuterTemplateArguments(std::nullopt);
+
+    return UseNextDecl(TTPD);
   }
 
   Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
+    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+          "outer template not instantiated?");
+
     if (ForConstraintInstantiation)
       Result.addOuterTemplateArguments(
           FTD, FTD->getInjectedTemplateArgs(), /*Final=*/false);
@@ -565,6 +574,9 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
+    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+          "outer template not instantiated?");
+
     if (!SkipForSpecialization && ForConstraintInstantiation)
       Result.addOuterTemplateArguments(
           VTD, VTD->getInjectedTemplateArgs(), /*Final=*/false);
@@ -576,6 +588,9 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
+    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+          "outer template not instantiated?");
+
     if (!SkipForSpecialization && ForConstraintInstantiation)
       Result.addOuterTemplateArguments(
           CTD, CTD->getInjectedTemplateArgs(), /*Final=*/false);
@@ -588,13 +603,24 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(CTD);
   }
 
+  #if 0
   Decl *VisitClassTemplatePartialSpecializationDecl(ClassTemplatePartialSpecializationDecl *CTPSD) {
     if (!SkipForSpecialization)
         Result.addOuterRetainedLevels(CTPSD->getTemplateDepth());
     return Done();
   }
+  #endif
 
   Decl *VisitFunctionDecl(FunctionDecl *FD) {
+    if (!RelativeToPrimary) {
+      if (const MemberSpecializationInfo *MSI = FD->getMemberSpecializationInfo();
+          MSI && MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        return Done();
+
+      if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        return UseNextDecl(FD);
+    }
+    #if 0
     // Add template arguments from a function template specialization.
     if (!RelativeToPrimary &&
         FD->getTemplateSpecializationKindForInstantiation() ==
@@ -607,13 +633,15 @@ struct TemplateInstantiationArgumentCollecter
       // don't get any template arguments from this function but might get
       // some from an enclosing template.
       return UseNextDecl(FD);
-    } else if (const TemplateArgumentList *TemplateArgs =
+    } else
+    #endif
+    if (const TemplateArgumentList *TemplateArgs =
                    FD->getTemplateSpecializationArgs()) {
       // Add the template arguments for this specialization.
       Result.addOuterTemplateArguments(
           FD, TemplateArgs->asArray(), /*Final=*/false);
 
-      if (RelativeToPrimary &&
+      if ( // RelativeToPrimary &&
           (FD->getTemplateSpecializationKind() ==
                TSK_ExplicitSpecialization ||
            (FD->getFriendObjectKind() &&
@@ -676,10 +704,9 @@ struct TemplateInstantiationArgumentCollecter
             RD, ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false);
     }
 
-    if (const MemberSpecializationInfo *MSInfo =
-            RD->getMemberSpecializationInfo())
-      if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-        return Done();
+    if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
+        MSI &&MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+      return Done();
 
     bool IsFriend = RD->getFriendObjectKind() ||
                     (RD->getDescribedClassTemplate() &&
@@ -727,6 +754,7 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
+    #if 0
     if (!CTSD->isClassScopeExplicitSpecialization()) {
       // We're done when we hit an explicit specialization.
       if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
@@ -752,10 +780,60 @@ struct TemplateInstantiationArgumentCollecter
         return ChangeDecl(CTPSD->getLexicalDeclContext());
     }
     return UseNextDecl(CTSD);
+    #else
+    // 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 DontClearRelativeToPrimaryNextDecl(CTSD);
+
+    // We're done when we hit an explicit specialization.
+    if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
+        !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
+      return Done();
+
+    // 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 0
+    if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+      if (!SkipForSpecialization)
+        Result.addOuterTemplateArguments(
+            CTPSD, CTSD->getTemplateInstantiationArgs().asArray(),
+            /*Final=*/false);
+      if (CTPSD->isMemberSpecialization())
+        return Done();
+    } else {
+      auto *CTD = Specialized.get<ClassTemplateDecl *>();
+      if (!SkipForSpecialization)
+        Result.addOuterTemplateArguments(
+            CTD, CTSD->getTemplateInstantiationArgs().asArray(),
+            /*Final=*/false);
+      if (CTD->isMemberSpecialization())
+        return Done();
+    }
+    #else
+    if (!SkipForSpecialization)
+      Result.addOuterTemplateArguments(
+          CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
+    if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+      if (CTPSD->isMemberSpecialization())
+        return Done();
+    } else {
+      auto *CTD = Specialized.get<ClassTemplateDecl *>();
+      if (CTD->isMemberSpecialization())
+        return Done();
+    }
+    #endif
+
+    return DontClearRelativeToPrimaryNextDecl(CTSD);
+    #endif
   }
 
   Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) {
-      // For a class-scope explicit specialization, there are no template arguments
+    // 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 DontClearRelativeToPrimaryNextDecl(VTSD);
@@ -770,8 +848,7 @@ struct TemplateInstantiationArgumentCollecter
     assert(VTSD->getSpecializedTemplate() && "No variable template?");
     llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
         Specialized = VTSD->getSpecializedTemplateOrPartial();
-    if (VarTemplatePartialSpecializationDecl *VTPSD =
-            Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+    if (auto *VTPSD = Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
       if (!SkipForSpecialization)
         Result.addOuterTemplateArguments(
             VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
@@ -779,7 +856,7 @@ struct TemplateInstantiationArgumentCollecter
       if (VTPSD->isMemberSpecialization())
         return Done();
     } else {
-      VarTemplateDecl *VTD = Specialized.get<VarTemplateDecl *>();
+      auto *VTD = Specialized.get<VarTemplateDecl *>();
       if (!SkipForSpecialization)
         Result.addOuterTemplateArguments(
             VTD, VTSD->getTemplateInstantiationArgs().asArray(),
@@ -806,6 +883,14 @@ struct TemplateInstantiationArgumentCollecter
 
     return UseNextDecl(D);
   }
+
+  Decl *Visit(Decl *D) {
+    #if 0
+    if (TemplateDecl *TD = D->getDescribedTemplate())
+      D = TD;
+    #endif
+    return DeclVisitor::Visit(D);
+  }
 };
 
 } // namespace
@@ -819,6 +904,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   // Accumulate the set of template argument lists in this structure.
   MultiLevelTemplateArgumentList Result;
 
+  SkipForSpecialization = false;
+
   using namespace TemplateInstArgsHelpers;
   const Decl *CurDecl = ND;
 
diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 53e6bbfcf42a8e..0283fa1f7b2122 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -52,14 +52,14 @@ namespace test3 {
 namespace test4 {
   class T4A {
     friend class T4B;
-  
+
   public:
     T4A(class T4B *);
 
   protected:
     T4B *mB;          // error here
   };
- 
+
   class T4B {};
 }
 
diff --git a/clang/test/SemaTemplate/default-expr-arguments.cpp b/clang/test/SemaTemplate/default-expr-arguments.cpp
index 438f5b1aa95f74..7570110caae81b 100644
--- a/clang/test/SemaTemplate/default-expr-arguments.cpp
+++ b/clang/test/SemaTemplate/default-expr-arguments.cpp
@@ -23,10 +23,10 @@ template<typename T> void f3(T a, T b = T() + T()); // expected-error{{invalid o
 void g() {
   f1(10);
   f1(S()); // expected-note{{in instantiation of default function argument expression for 'f1<S>' required here}}
-  
+
   f2(10);
   f2(S());
-  
+
   f3(10);
   f3(S()); // expected-note{{in instantiation of default function argument expression for 'f3<S>' required here}}
 }
@@ -48,7 +48,7 @@ void g2() {
 void g3(F<int> f, F<struct S> s) {
   f.f();
   s.f(); // expected-note{{in instantiation of default function argument expression for 'f<S>' required here}}
-  
+
   F<int> f2;
   F<S> s2; // expected-note{{in instantiation of default function argument expression for 'F<S>' required here}}
 }
@@ -115,7 +115,7 @@ template<typename T> struct A {
   // expected-note 3{{passing argument to parameter here}}
 };
 
-struct B : A<int*> { 
+struct B : A<int*> {
   B();
 };
 B::B() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}}
@@ -127,7 +127,7 @@ C::C() { } // expected-note {{in instantiation of default function argument expr
 
 struct D {
   D();
-  
+
   A<int*> a;
 };
 D::D() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}}
@@ -162,12 +162,12 @@ namespace PR5810 {
   struct allocator {
     allocator() { int a[sizeof(T) ? -1 : -1]; } // expected-error2 {{array with a negative size}}
   };
-  
+
   template<typename T>
   struct vector {
     vector(const allocator<T>& = allocator<T>()) {} // expected-note2 {{instantiation of}}
   };
-  
+
   struct A { };
   struct B { };
 
@@ -175,7 +175,7 @@ namespace PR5810 {
   void FilterVTs() {
     vector<A> Result;
   }
-  
+
   void f() {
     vector<A> Result;
   }
@@ -229,8 +229,8 @@ namespace PR5810b {
 
 namespace PR5810c {
   template<typename T>
-  struct X { 
-    X() { 
+  struct X {
+    X() {
       T t;
       double *****p = t; // expected-error{{cannot initialize a variable of type 'double *****' with an lvalue of type 'int'}}
     }
@@ -251,7 +251,7 @@ namespace PR8127 {
     PointerClass( T * object_p ) : p_( object_p ) {
       p_->acquire();
     }
-  private:    
+  private:
     T * p_;
   };
 
@@ -285,8 +285,8 @@ namespace rdar8427926 {
 }
 
 namespace PR8401 {
-  template<typename T> 
-  struct A { 
+  template<typename T>
+  struct A {
     A() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
   };
 

>From f525cbd16c11713d8c5400d1bd636173f6fe8005 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 12 Aug 2024 14:17:08 -0400
Subject: [PATCH 08/31] [FOLD] add tests

---
 .../temp/temp.constr/temp.constr.decl/p4.cpp  | 108 ++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp

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
new file mode 100644
index 00000000000000..f6e0d45334c0f7
--- /dev/null
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+
+template<typename T>
+struct A {
+  template<typename U, bool V>
+  void f() requires V;
+
+  template<>
+  void f<short, true>();
+
+  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<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<typename T>
+template<typename U, bool V>
+void A<T>::f() requires V { }
+
+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<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<>
+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<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<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>;

>From 8e470b52d1e18f229987a42515a4486388ad1d02 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 12 Aug 2024 14:59:26 -0400
Subject: [PATCH 09/31] [FOLD]

---
 clang/lib/Sema/SemaConcept.cpp             | 12 ++++++++----
 clang/lib/Sema/SemaTemplateInstantiate.cpp |  9 ++++++++-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 6a1b32598bb4a6..5fd2b998c7fc8c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -585,7 +585,7 @@ static bool CheckConstraintSatisfaction(
 
   ArrayRef<TemplateArgument> TemplateArgs =
       TemplateArgsLists.getNumSubstitutedLevels() > 0
-          ? TemplateArgsLists.getOutermost()
+          ? TemplateArgsLists.getInnermost()
           : ArrayRef<TemplateArgument> {};
   Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
       Sema::InstantiatingTemplate::ConstraintsCheck{},
@@ -1063,16 +1063,20 @@ 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(FD->getDescribedFunctionTemplate() &&
-         "Non-function templates don't need to be checked");
+  assert(FTD && "Non-function templates don't need to be checked");
 
   SmallVector<const Expr *, 3> ACs;
-  FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+  FTD->getAssociatedConstraints(ACs);
 
+  #if 0
   unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+  #else
+  unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
+  #endif
   for (const Expr *Constraint : ACs)
     if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
                                                        Constraint))
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 74149273b06fd0..83f87cc8b07ffa 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -705,7 +705,7 @@ struct TemplateInstantiationArgumentCollecter
     }
 
     if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
-        MSI &&MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        MSI && MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
       return Done();
 
     bool IsFriend = RD->getFriendObjectKind() ||
@@ -912,6 +912,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   if (!CurDecl)
     CurDecl = Decl::castFromDeclContext(DC);
 
+  #if 1
   if (Innermost) {
     Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
                                      Final);
@@ -927,6 +928,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
       HandleDefaultTempArgIntoTempTempParam(TTP, Result);
     CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
   }
+  #endif
 
   TemplateInstantiationArgumentCollecter Collecter(
       *this, Result, RelativeToPrimary,
@@ -935,6 +937,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   do {
     CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
   } while (CurDecl);
+
+  #if 0
+  if (Innermost)
+    Result.replaceInnermostTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost);
+  #endif
   return Result;
 
   #if 0

>From 9a7be77f6ffeddff49e80315fbb035760bef1304 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 13 Aug 2024 09:27:34 -0400
Subject: [PATCH 10/31] [FOLD] remove SkipForSpecialization and Pattern
 parameters from getTemplateInstantiationArgs

---
 clang/include/clang/Sema/Sema.h               |  5 +-
 clang/lib/Sema/SemaConcept.cpp                | 15 ++---
 clang/lib/Sema/SemaTemplate.cpp               |  4 +-
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  2 +-
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  1 -
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 57 ++++++++-----------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  2 +-
 7 files changed, 32 insertions(+), 54 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 99b8b17c2b0578..e8fea08a5783d5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13087,10 +13087,7 @@ class Sema final : public SemaBase {
   MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
       const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
-      bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
-      bool ForConstraintInstantiation = false,
-      bool SkipForSpecialization = false,
-      bool ForDefaultArgumentSubstitution = false);
+      bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
 
   /// RAII object to handle the state changes required to synthesize
   /// a function body.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 5fd2b998c7fc8c..bff98e21564cdd 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -833,7 +833,6 @@ 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;
@@ -910,14 +909,12 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
 // the purpose of seeing if they differ by constraints. This isn't the same as
 // getTemplateDepth, because it includes already instantiated parents.
 static unsigned
-CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
-                                     bool SkipForSpecialization = false) {
+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND) {
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
       ND, ND->getLexicalDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
       /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+      /*ForConstraintInstantiation=*/true);
   return MLTAL.getNumLevels();
 }
 
@@ -956,8 +953,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
       DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
       /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
-      /*SkipForSpecialization*/ false);
+      /*ForConstraintInstantiation=*/true);
 
   if (MLTAL.getNumSubstitutedLevels() == 0)
     return ConstrExpr;
@@ -1523,7 +1519,6 @@ 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,
@@ -1804,8 +1799,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
     return false;
   }
 
-  unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
-  unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
+  unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
+  unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
 
   for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
     if (Depth2 > Depth1) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index e09e1f854fb590..398c0dac45cb53 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5615,9 +5615,7 @@ bool Sema::CheckTemplateArgumentList(
 
     MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
         Template, NewContext, /*Final=*/false, CanonicalConverted,
-        /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
-        /*ForConceptInstantiation=*/true);
+        /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true);
     if (EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index db1f7177f514f2..4507a2204f78ce 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3219,7 +3219,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
       Template, Template->getDeclContext(), /*Final=*/false,
       /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
+      /*ForConstraintInstantiation=*/true);
 
   #if 0
   if (DeducedArgsNeedReplacement(Template)) {
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index ea02e979c4270f..e74f9abb3ea413 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -807,7 +807,6 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
         F, F->getLexicalDeclContext(),
         /*Final=*/false, /*Innermost=*/TemplateArgsForBuildingRC,
         /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
         /*ForConstraintInstantiation=*/true);;
   ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
   #if 0
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 83f87cc8b07ffa..a0159e369a248f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -511,17 +511,15 @@ struct TemplateInstantiationArgumentCollecter
   MultiLevelTemplateArgumentList &Result;
   bool RelativeToPrimary;
   bool ForConstraintInstantiation;
-  bool SkipForSpecialization;
 
   TemplateInstantiationArgumentCollecter(
       Sema &S,
       MultiLevelTemplateArgumentList &Result,
       bool RelativeToPrimary,
-      bool ForConstraintInstantiation,
-      bool SkipForSpecialization) :
+      bool ForConstraintInstantiation) :
           S(S), Result(Result), RelativeToPrimary(RelativeToPrimary),
-          ForConstraintInstantiation(ForConstraintInstantiation),
-          SkipForSpecialization(SkipForSpecialization) { }
+          ForConstraintInstantiation(ForConstraintInstantiation) {
+  }
 
   Decl *Done() {
     return nullptr;
@@ -577,7 +575,7 @@ struct TemplateInstantiationArgumentCollecter
     assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
           "outer template not instantiated?");
 
-    if (!SkipForSpecialization && ForConstraintInstantiation)
+    if (ForConstraintInstantiation)
       Result.addOuterTemplateArguments(
           VTD, VTD->getInjectedTemplateArgs(), /*Final=*/false);
 
@@ -591,7 +589,7 @@ struct TemplateInstantiationArgumentCollecter
     assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
           "outer template not instantiated?");
 
-    if (!SkipForSpecialization && ForConstraintInstantiation)
+    if (ForConstraintInstantiation)
       Result.addOuterTemplateArguments(
           CTD, CTD->getInjectedTemplateArgs(), /*Final=*/false);
 
@@ -798,26 +796,23 @@ struct TemplateInstantiationArgumentCollecter
         Specialized = CTSD->getSpecializedTemplateOrPartial();
     #if 0
     if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      if (!SkipForSpecialization)
-        Result.addOuterTemplateArguments(
-            CTPSD, CTSD->getTemplateInstantiationArgs().asArray(),
-            /*Final=*/false);
+      Result.addOuterTemplateArguments(
+          CTPSD, CTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
       if (CTPSD->isMemberSpecialization())
         return Done();
     } else {
       auto *CTD = Specialized.get<ClassTemplateDecl *>();
-      if (!SkipForSpecialization)
-        Result.addOuterTemplateArguments(
-            CTD, CTSD->getTemplateInstantiationArgs().asArray(),
-            /*Final=*/false);
+      Result.addOuterTemplateArguments(
+          CTD, CTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
       if (CTD->isMemberSpecialization())
         return Done();
     }
     #else
-    if (!SkipForSpecialization)
-      Result.addOuterTemplateArguments(
-          CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
+    Result.addOuterTemplateArguments(
+        CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
+        /*Final=*/false);
     if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
       if (CTPSD->isMemberSpecialization())
         return Done();
@@ -849,18 +844,16 @@ struct TemplateInstantiationArgumentCollecter
     llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
         Specialized = VTSD->getSpecializedTemplateOrPartial();
     if (auto *VTPSD = Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-      if (!SkipForSpecialization)
-        Result.addOuterTemplateArguments(
-            VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
-            /*Final=*/false);
+      Result.addOuterTemplateArguments(
+          VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
       if (VTPSD->isMemberSpecialization())
         return Done();
     } else {
       auto *VTD = Specialized.get<VarTemplateDecl *>();
-      if (!SkipForSpecialization)
-        Result.addOuterTemplateArguments(
-            VTD, VTSD->getTemplateInstantiationArgs().asArray(),
-            /*Final=*/false);
+      Result.addOuterTemplateArguments(
+          VTD, VTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
       if (VTD->isMemberSpecialization())
         return Done();
     }
@@ -897,15 +890,12 @@ struct TemplateInstantiationArgumentCollecter
 
 MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     const NamedDecl *ND, const DeclContext *DC, bool Final,
-    std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
-    const FunctionDecl *Pattern, bool ForConstraintInstantiation,
-    bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
+    std::optional<ArrayRef<TemplateArgument>> Innermost,
+    bool RelativeToPrimary, bool ForConstraintInstantiation) {
   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;
 
-  SkipForSpecialization = false;
-
   using namespace TemplateInstArgsHelpers;
   const Decl *CurDecl = ND;
 
@@ -932,8 +922,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
 
   TemplateInstantiationArgumentCollecter Collecter(
       *this, Result, RelativeToPrimary,
-      ForConstraintInstantiation,
-      SkipForSpecialization);
+      ForConstraintInstantiation);
   do {
     CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
   } while (CurDecl);
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 97c240d58c0709..8a609d6d23830f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4746,7 +4746,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,

>From 63e2cf877dd5ead67dc940de60ecc6afa198ca2f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 14 Aug 2024 07:53:18 -0400
Subject: [PATCH 11/31] [FOLD] using the right next decl after adding innermost
 template arguments

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 172 +++++++++++++-----
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  25 ++-
 .../temp/temp.constr/temp.constr.decl/p4.cpp  |   1 +
 .../SemaTemplate/default-arguments-cxx0x.cpp  |   2 +-
 4 files changed, 147 insertions(+), 53 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a0159e369a248f..aeeb6d303e859c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -509,15 +509,17 @@ 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), RelativeToPrimary(RelativeToPrimary),
+          S(S), Result(Result), Innermost(Innermost), RelativeToPrimary(RelativeToPrimary),
           ForConstraintInstantiation(ForConstraintInstantiation) {
   }
 
@@ -543,14 +545,34 @@ struct TemplateInstantiationArgumentCollecter
         Decl::castFromDeclContext(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) {
+    #if 0
+    if (Innermost) {
+      Args = *Innermost;
+      Innermost.reset();
+    }
+    #endif
+    Result.addOuterTemplateArguments(const_cast<Decl*>(D), Args, Final);
+  }
+
   Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
     #if 0
     for (unsigned I = 0, N = TTPD->getDepth() + 1; I != N; ++I)
       Result.addOuterTemplateArguments(std::nullopt);
     return Done();
     #endif
+    if (Innermost)
+      AddInnermostTemplateArguments(TTPD);
+
+    // else if (ForConstraintInstantiation)
     if (ForConstraintInstantiation)
-      Result.addOuterTemplateArguments(std::nullopt);
+      AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
 
     return UseNextDecl(TTPD);
   }
@@ -559,8 +581,10 @@ struct TemplateInstantiationArgumentCollecter
     assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
           "outer template not instantiated?");
 
-    if (ForConstraintInstantiation)
-      Result.addOuterTemplateArguments(
+    if (Innermost)
+      AddInnermostTemplateArguments(FTD);
+    else if (ForConstraintInstantiation)
+      AddOuterTemplateArguments(
           FTD, FTD->getInjectedTemplateArgs(), /*Final=*/false);
 
     if (FTD->isMemberSpecialization())
@@ -575,8 +599,10 @@ struct TemplateInstantiationArgumentCollecter
     assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
           "outer template not instantiated?");
 
-    if (ForConstraintInstantiation)
-      Result.addOuterTemplateArguments(
+    if (Innermost)
+      AddInnermostTemplateArguments(VTD);
+    else if (ForConstraintInstantiation)
+      AddOuterTemplateArguments(
           VTD, VTD->getInjectedTemplateArgs(), /*Final=*/false);
 
     if (VTD->isMemberSpecialization())
@@ -589,8 +615,10 @@ struct TemplateInstantiationArgumentCollecter
     assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
           "outer template not instantiated?");
 
-    if (ForConstraintInstantiation)
-      Result.addOuterTemplateArguments(
+    if (Innermost)
+      AddInnermostTemplateArguments(CTD);
+    else if (ForConstraintInstantiation)
+      AddOuterTemplateArguments(
           CTD, CTD->getInjectedTemplateArgs(), /*Final=*/false);
 
     if (CTD->isMemberSpecialization())
@@ -601,6 +629,27 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(CTD);
   }
 
+  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);
+  }
+
+  Decl *VisitConceptDecl(ConceptDecl *CD) {
+    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+          "outer template not instantiated?");
+    if (Innermost)
+      AddInnermostTemplateArguments(CD);
+
+    return UseNextDecl(CD);
+  }
+
   #if 0
   Decl *VisitClassTemplatePartialSpecializationDecl(ClassTemplatePartialSpecializationDecl *CTPSD) {
     if (!SkipForSpecialization)
@@ -636,8 +685,11 @@ struct TemplateInstantiationArgumentCollecter
     if (const TemplateArgumentList *TemplateArgs =
                    FD->getTemplateSpecializationArgs()) {
       // Add the template arguments for this specialization.
-      Result.addOuterTemplateArguments(
-          FD, TemplateArgs->asArray(), /*Final=*/false);
+      if (Innermost)
+        AddInnermostTemplateArguments(FD);
+      else
+        AddOuterTemplateArguments(
+            FD, TemplateArgs->asArray(), /*Final=*/false);
 
       if ( // RelativeToPrimary &&
           (FD->getTemplateSpecializationKind() ==
@@ -698,7 +750,7 @@ struct TemplateInstantiationArgumentCollecter
       if (ClassTemplate->isMemberSpecialization())
         return Done();
       if (ForConstraintInstantiation)
-        Result.addOuterTemplateArguments(
+        AddOuterTemplateArguments(
             RD, ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false);
     }
 
@@ -727,9 +779,9 @@ struct TemplateInstantiationArgumentCollecter
             getPrimaryTemplateOfGenericLambda(RD->getLambdaCallOperator());
         if (isLambdaEnclosedByTypeAliasDecl(PrimaryLambdaCallOperator,
                                             TypeAlias.PrimaryTypeAliasDecl)) {
-          Result.addOuterTemplateArguments(TypeAlias.Template,
-                                           TypeAlias.AssociatedTemplateArguments,
-                                           /*Final=*/false);
+          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:
@@ -781,7 +833,8 @@ struct TemplateInstantiationArgumentCollecter
     #else
     // For a class-scope explicit specialization, there are no template arguments
     // at this level, but there may be enclosing template arguments.
-    if (CTSD->isClassScopeExplicitSpecialization())
+    if (CTSD->isClassScopeExplicitSpecialization() &&
+        !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
       return DontClearRelativeToPrimaryNextDecl(CTSD);
 
     // We're done when we hit an explicit specialization.
@@ -810,9 +863,12 @@ struct TemplateInstantiationArgumentCollecter
         return Done();
     }
     #else
-    Result.addOuterTemplateArguments(
-        CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
-        /*Final=*/false);
+    if (Innermost)
+        AddInnermostTemplateArguments(CTSD);
+    else
+      AddOuterTemplateArguments(
+          CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
     if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
       if (CTPSD->isMemberSpecialization())
         return Done();
@@ -830,7 +886,8 @@ struct TemplateInstantiationArgumentCollecter
   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())
+    if (VTSD->isClassScopeExplicitSpecialization() &&
+        !isa<VarTemplatePartialSpecializationDecl>(VTSD))
       return DontClearRelativeToPrimaryNextDecl(VTSD);
 
     // We're done when we hit an explicit specialization.
@@ -844,16 +901,22 @@ struct TemplateInstantiationArgumentCollecter
     llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
         Specialized = VTSD->getSpecializedTemplateOrPartial();
     if (auto *VTPSD = Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-      Result.addOuterTemplateArguments(
-          VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
+      if (Innermost)
+        AddInnermostTemplateArguments(VTPSD);
+      else
+        AddOuterTemplateArguments(
+            VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
+            /*Final=*/false);
       if (VTPSD->isMemberSpecialization())
         return Done();
     } else {
       auto *VTD = Specialized.get<VarTemplateDecl *>();
-      Result.addOuterTemplateArguments(
-          VTD, VTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
+      if (Innermost)
+        AddInnermostTemplateArguments(VTD);
+      else
+        AddOuterTemplateArguments(
+            VTD, VTSD->getTemplateInstantiationArgs().asArray(),
+            /*Final=*/false);
       if (VTD->isMemberSpecialization())
         return Done();
     }
@@ -861,7 +924,7 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl *ICSD) {
-    Result.addOuterTemplateArguments(
+    AddOuterTemplateArguments(
         ICSD, ICSD->getTemplateArguments(),
         /*Final=*/false);
     return UseNextDecl(ICSD);
@@ -877,13 +940,13 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(D);
   }
 
-  Decl *Visit(Decl *D) {
     #if 0
+  Decl *Visit(Decl *D) {
     if (TemplateDecl *TD = D->getDescribedTemplate())
       D = TD;
-    #endif
     return DeclVisitor::Visit(D);
   }
+    #endif
 };
 
 } // namespace
@@ -902,7 +965,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   if (!CurDecl)
     CurDecl = Decl::castFromDeclContext(DC);
 
-  #if 1
+  #if 0
   if (Innermost) {
     Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
                                      Final);
@@ -921,7 +984,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   #endif
 
   TemplateInstantiationArgumentCollecter Collecter(
-      *this, Result, RelativeToPrimary,
+      *this, Result, Innermost, RelativeToPrimary,
       ForConstraintInstantiation);
   do {
     CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
@@ -2121,25 +2184,42 @@ namespace {
 
     ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
                                  LambdaScopeInfo *LSI) {
+      #if 1
       CXXMethodDecl *MD = LSI->CallOperator;
-      for (ParmVarDecl *PVD : MD->parameters()) {
-        assert(PVD && "null in a parameter list");
-        if (!PVD->hasDefaultArg())
-          continue;
-        Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
-        // FIXME: Obtain the source location for the '=' token.
-        SourceLocation EqualLoc = UninstExpr->getBeginLoc();
-        if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
-          // If substitution fails, the default argument is set to a
-          // RecoveryExpr that wraps the uninstantiated default argument so
-          // that downstream diagnostics are omitted.
-          ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
-              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
-              { UninstExpr }, UninstExpr->getType());
-          if (ErrorResult.isUsable())
-            PVD->setDefaultArg(ErrorResult.get());
+      if (MD->getParentFunctionOrMethod()) {
+      #if 0
+        NamedDecl *Pattern = MD;
+          std::optional<ArrayRef<TemplateArgument>> Innermost;
+        if (FunctionTemplateDecl *FTD = MD->getDescribedFunctionTemplate()) {
+          Pattern = FTD;
+          Innermost = FTD->getInjectedTemplateArgs();
+        }
+        MultiLevelTemplateArgumentList MLTAL =
+            SemaRef.getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
+                                                 /*Final=*/false, Innermost,
+                                                 /*RelativeToPrimary=*/true);
+        #endif
+;
+        for (ParmVarDecl *PVD : MD->parameters()) {
+          assert(PVD && "null in a parameter list");
+          if (!PVD->hasDefaultArg())
+            continue;
+          Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+          // FIXME: Obtain the source location for the '=' token.
+          SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+          if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+            // If substitution fails, the default argument is set to a
+            // RecoveryExpr that wraps the uninstantiated default argument so
+            // that downstream diagnostics are omitted.
+            ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+                UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+                { UninstExpr }, UninstExpr->getType());
+            if (ErrorResult.isUsable())
+              PVD->setDefaultArg(ErrorResult.get());
+          }
         }
       }
+      #endif
       return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
     }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8a609d6d23830f..e70edd0ef66f9d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4683,6 +4683,21 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());
 
+  NamedDecl *Pattern = nullptr;
+  std::optional<ArrayRef<TemplateArgument>> Innermost;
+  #if 1
+  if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
+    Pattern = FTD->isCXXClassMember() ? FTD->getFirstDecl() : FTD;
+    Innermost = FD->getTemplateSpecializationArgs()->asArray();
+  } else if (FD->isCXXClassMember()) {
+    Pattern = FD->getFirstDecl();
+  } else {
+    Pattern = FD;
+  }
+  #else
+  Pattern = FD;
+  #endif
+
   // Instantiate the expression.
   //
   // FIXME: Pass in a correct Pattern argument, otherwise
@@ -4700,12 +4715,10 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   //
   // template<typename T>
   // A<T> Foo(int a = A<T>::FooImpl());
-  MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-      FD, FD->getLexicalDeclContext(),
-      /*Final=*/false, /*Innermost=*/std::nullopt,
-      /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
-      /*ForDefaultArgumentSubstitution=*/true);
+  MultiLevelTemplateArgumentList TemplateArgs =
+      getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
+                                   /*Final=*/false, Innermost,
+                                   /*RelativeToPrimary=*/true);
 
   if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
     return true;
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
index f6e0d45334c0f7..c39d13c47c8a15 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
 
 template<typename T>
 struct A {
diff --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
index 4972c57a719229..bd9388eede316f 100644
--- a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -12,7 +12,7 @@ void f0();
 
 void g0() {
   f0(); // okay!
-} 
+}
 
 template<typename T, int N = T::value>
 int &f1(T);

>From e8c553f3cc0204b55ba18262861b4183d2756c64 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 20 Aug 2024 06:41:24 -0400
Subject: [PATCH 12/31] [FOLD] instantiate lambda default args correctly

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp     | 3 ++-
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 +++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index aeeb6d303e859c..48efc064f4701e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2186,7 +2186,8 @@ namespace {
                                  LambdaScopeInfo *LSI) {
       #if 1
       CXXMethodDecl *MD = LSI->CallOperator;
-      if (MD->getParentFunctionOrMethod()) {
+      // if (MD->getParentFunctionOrMethod()) {
+      if (true) {
       #if 0
         NamedDecl *Pattern = MD;
           std::optional<ArrayRef<TemplateArgument>> Innermost;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e70edd0ef66f9d..03cd9b5ffed303 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -12,6 +12,7 @@
 #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,6 +4687,7 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   NamedDecl *Pattern = nullptr;
   std::optional<ArrayRef<TemplateArgument>> Innermost;
   #if 1
+
   if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
     Pattern = FTD->isCXXClassMember() ? FTD->getFirstDecl() : FTD;
     Innermost = FD->getTemplateSpecializationArgs()->asArray();
@@ -4698,6 +4700,9 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   Pattern = FD;
   #endif
 
+  if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
+    Pattern = FD;
+
   // Instantiate the expression.
   //
   // FIXME: Pass in a correct Pattern argument, otherwise

>From 9f08b9bb37ba0d5ad1abad33d66a5e9a8e39b1bc Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 23 Aug 2024 11:51:49 -0400
Subject: [PATCH 13/31] [FOLD] handle template template params correctly and
 switch to described template

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 422 +-----------------
 .../namespace.udecl/p8-cxx0x.cpp              |   4 +-
 2 files changed, 20 insertions(+), 406 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 48efc064f4701e..2a956d488423d7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -185,323 +185,6 @@ HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
   return Response::Done();
 }
 
-#if 0
-// 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);
-}
-
-Response HandlePartialClassTemplateSpec(
-    const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
-    MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
-  if (!SkipForSpecialization)
-      Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
-  return Response::Done();
-}
-
-// Add template arguments from a class template instantiation.
-Response
-HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
-                        MultiLevelTemplateArgumentList &Result,
-                        bool SkipForSpecialization) {
-  if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
-    // We're done when we hit an explicit specialization.
-    if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
-        !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
-      return Response::Done();
-
-    if (!SkipForSpecialization)
-      Result.addOuterTemplateArguments(
-          const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
-          ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
-
-    // If this class template specialization was instantiated from a
-    // specialized member that is a class template, we're done.
-    assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
-    if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
-      return Response::Done();
-
-    // If this was instantiated from a partial template specialization, we need
-    // to get the next level of declaration context from the partial
-    // specialization, as the ClassTemplateSpecializationDecl's
-    // DeclContext/LexicalDeclContext will be for the primary template.
-    if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial()
-                      .dyn_cast<ClassTemplatePartialSpecializationDecl *>())
-      return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext());
-  }
-  return Response::UseNextDecl(ClassTemplSpec);
-}
-
-Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
-                        MultiLevelTemplateArgumentList &Result,
-                        const FunctionDecl *Pattern, bool RelativeToPrimary,
-                        bool ForConstraintInstantiation,
-                        bool ForDefaultArgumentSubstitution) {
-  // Add template arguments from a function template specialization.
-  if (!RelativeToPrimary &&
-      Function->getTemplateSpecializationKindForInstantiation() ==
-          TSK_ExplicitSpecialization)
-    return Response::Done();
-
-  if (!RelativeToPrimary &&
-      Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
-    // This is an implicit instantiation of an explicit specialization. We
-    // don't get any template arguments from this function but might get
-    // some from an enclosing template.
-    return Response::UseNextDecl(Function);
-  } else if (const TemplateArgumentList *TemplateArgs =
-                 Function->getTemplateSpecializationArgs()) {
-    // Add the template arguments for this specialization.
-    Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
-                                     TemplateArgs->asArray(),
-                                     /*Final=*/false);
-
-    if (RelativeToPrimary &&
-        (Function->getTemplateSpecializationKind() ==
-             TSK_ExplicitSpecialization ||
-         (Function->getFriendObjectKind() &&
-          !Function->getPrimaryTemplate()->getFriendObjectKind())))
-      return Response::UseNextDecl(Function);
-
-    // If this function was instantiated from a specialized member that is
-    // a function template, we're done.
-    assert(Function->getPrimaryTemplate() && "No function template?");
-    if (!ForDefaultArgumentSubstitution &&
-        Function->getPrimaryTemplate()->isMemberSpecialization())
-      return Response::Done();
-
-    // If this function is a generic lambda specialization, we are done.
-    if (!ForConstraintInstantiation &&
-        isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
-      return Response::Done();
-
-  } else if (Function->getDescribedFunctionTemplate()) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "Outer template not instantiated?");
-  }
-  // If this is a friend or local declaration and it declares an entity at
-  // namespace scope, take arguments from its lexical parent
-  // instead of its semantic parent, unless of course the pattern we're
-  // instantiating actually comes from the file's context!
-  if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
-      Function->getNonTransparentDeclContext()->isFileContext() &&
-      (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
-    return Response::ChangeDecl(Function->getLexicalDeclContext());
-  }
-
-  if (ForConstraintInstantiation && Function->getFriendObjectKind())
-    return Response::ChangeDecl(Function->getLexicalDeclContext());
-  return Response::UseNextDecl(Function);
-}
-
-Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
-                                    MultiLevelTemplateArgumentList &Result,
-                                    bool ForConstraintInstantiation) {
-  #if 0
-  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(
-              const_cast<FunctionTemplateDecl *>(FTD), Arguments,
-              /*Final=*/false);
-        }
-      }
-
-      NNS = NNS->getPrefix();
-    }
-  }
-
-  return Response::ChangeDecl(FTD->getLexicalDeclContext());
-  #else
-  if (ForConstraintInstantiation)
-    Result.addOuterTemplateArguments(
-        const_cast<FunctionTemplateDecl *>(FTD),
-        const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
-        /*Final=*/false);
-
-  if (FTD->isMemberSpecialization())
-    return Response::Done();
-
-  if (FTD->getFriendObjectKind())
-    return Response::ChangeDecl(FTD->getLexicalDeclContext());
-  return Response::UseNextDecl(FTD);
-  #endif
-}
-
-Response HandleClassTemplateDecl(const ClassTemplateDecl *CTD,
-                                 MultiLevelTemplateArgumentList &Result,
-                                 bool ForConstraintInstantiation,
-                                 bool SkipForSpecialization) {
-  #if 1
-  if (!SkipForSpecialization && ForConstraintInstantiation)
-    Result.addOuterTemplateArguments(
-        const_cast<ClassTemplateDecl *>(CTD),
-        const_cast<ClassTemplateDecl *>(CTD)->getInjectedTemplateArgs(),
-        /*Final=*/false);
-
-  if (CTD->isMemberSpecialization())
-    return Response::Done();
-
-  if (CTD->getFriendObjectKind())
-    return Response::ChangeDecl(CTD->getLexicalDeclContext());
-  return Response::UseNextDecl(CTD);
-  #endif
-  return Response::ChangeDecl(CTD->getLexicalDeclContext());
-}
-
-Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
-                          MultiLevelTemplateArgumentList &Result,
-                          ASTContext &Context,
-                          bool ForConstraintInstantiation) {
-  if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
-    assert(
-        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-        "Outer template not instantiated?");
-    if (ClassTemplate->isMemberSpecialization())
-      return Response::Done();
-    if (ForConstraintInstantiation)
-      Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
-                                       ClassTemplate->getInjectedTemplateArgs(),
-                                       /*Final=*/false);
-  }
-
-  if (const MemberSpecializationInfo *MSInfo =
-          Rec->getMemberSpecializationInfo())
-    if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-      return Response::Done();
-
-  bool IsFriend = Rec->getFriendObjectKind() ||
-                  (Rec->getDescribedClassTemplate() &&
-                   Rec->getDescribedClassTemplate()->getFriendObjectKind());
-  if (ForConstraintInstantiation && IsFriend &&
-      Rec->getNonTransparentDeclContext()->isFileContext()) {
-    return Response::ChangeDecl(Rec->getLexicalDeclContext());
-  }
-
-  // This is to make sure we pick up the VarTemplateSpecializationDecl or the
-  // TypeAliasTemplateDecl that this lambda is defined inside of.
-  if (Rec->isLambda()) {
-    if (const Decl *LCD = Rec->getLambdaContextDecl())
-      return Response::ChangeDecl(LCD);
-    // Retrieve the template arguments for a using alias declaration.
-    // This is necessary for constraint checking, since we always keep
-    // constraints relative to the primary template.
-    if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
-        ForConstraintInstantiation && TypeAlias) {
-      if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
-                                          TypeAlias.PrimaryTypeAliasDecl)) {
-        Result.addOuterTemplateArguments(TypeAlias.Template,
-                                         TypeAlias.AssociatedTemplateArguments,
-                                         /*Final=*/false);
-        // Visit the parent of the current type alias declaration rather than
-        // the lambda thereof.
-        // E.g., in the following example:
-        // struct S {
-        //  template <class> using T = decltype([]<Concept> {} ());
-        // };
-        // void foo() {
-        //   S::T var;
-        // }
-        // The instantiated lambda expression (which we're visiting at 'var')
-        // has a function DeclContext 'foo' rather than the Record DeclContext
-        // S. This seems to be an oversight to me that we may want to set a
-        // Sema Context from the CXXScopeSpec before substituting into T.
-        return Response::ChangeDecl(TypeAlias.Template->getDeclContext());
-      }
-    }
-  }
-
-  return Response::UseNextDecl(Rec);
-}
-
-Response HandleImplicitConceptSpecializationDecl(
-    const ImplicitConceptSpecializationDecl *CSD,
-    MultiLevelTemplateArgumentList &Result) {
-  Result.addOuterTemplateArguments(
-      const_cast<ImplicitConceptSpecializationDecl *>(CSD),
-      CSD->getTemplateArguments(),
-      /*Final=*/false);
-  return Response::UseNextDecl(CSD);
-}
-
-Response HandleGenericDeclContext(const Decl *CurDecl) {
-  return Response::UseNextDecl(CurDecl);
-}
-#endif
 } // namespace TemplateInstArgsHelpers
 
 
@@ -529,6 +212,8 @@ struct TemplateInstantiationArgumentCollecter
 
   Decl *ChangeDecl(const Decl *D) {
     RelativeToPrimary = false;
+    if (const TemplateDecl *TD = D->getDescribedTemplate())
+      D = TD;
     return const_cast<Decl *>(D);
   }
 
@@ -541,8 +226,10 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *DontClearRelativeToPrimaryNextDecl(const Decl* D) {
-    return const_cast<Decl *>(
-        Decl::castFromDeclContext(D->getDeclContext()));
+    D = Decl::castFromDeclContext(D->getDeclContext());
+    if (const TemplateDecl *TD = D->getDescribedTemplate())
+      D = TD;
+    return const_cast<Decl *>(D);
   }
 
   void AddInnermostTemplateArguments(const Decl *D) {
@@ -562,19 +249,15 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
-    #if 0
-    for (unsigned I = 0, N = TTPD->getDepth() + 1; I != N; ++I)
-      Result.addOuterTemplateArguments(std::nullopt);
-    return Done();
-    #endif
     if (Innermost)
       AddInnermostTemplateArguments(TTPD);
+    else if (ForConstraintInstantiation)
+      AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
 
-    // else if (ForConstraintInstantiation)
-    if (ForConstraintInstantiation)
+    for (unsigned Depth = TTPD->getDepth() + 1; Depth--;)
       AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
 
-    return UseNextDecl(TTPD);
+    return Done();
   }
 
   Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
@@ -706,22 +389,8 @@ struct TemplateInstantiationArgumentCollecter
 
       // If this function is a generic lambda specialization, we are done.
       if (!ForConstraintInstantiation &&
-          isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
-        // TypeAliasTemplateDecls should be taken into account, e.g.
-        // when we're deducing the return type of a lambda.
-        //
-        // template <class> int Value = 0;
-        // template <class T>
-        // using T = decltype([]<int U = 0>() { return Value<T>; }());
-        //
-        if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S)) {
-          if (isLambdaEnclosedByTypeAliasDecl(
-                  /*PrimaryLambdaCallOperator=*/getPrimaryTemplateOfGenericLambda(FD),
-                  /*PrimaryTypeAliasDecl=*/TypeAlias.PrimaryTypeAliasDecl))
-            return UseNextDecl(FD);
-        }
+          isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
         return Done();
-      }
 
     } else if (FD->getDescribedFunctionTemplate()) {
       assert(
@@ -747,6 +416,7 @@ struct TemplateInstantiationArgumentCollecter
       assert(
           (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
           "Outer template not instantiated?");
+      // llvm_unreachable("shouldn't get here");
       if (ClassTemplate->isMemberSpecialization())
         return Done();
       if (ForConstraintInstantiation)
@@ -774,11 +444,10 @@ struct TemplateInstantiationArgumentCollecter
       // 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)) {
-        const FunctionDecl *PrimaryLambdaCallOperator =
-            getPrimaryTemplateOfGenericLambda(RD->getLambdaCallOperator());
-        if (isLambdaEnclosedByTypeAliasDecl(PrimaryLambdaCallOperator,
-                                            TypeAlias.PrimaryTypeAliasDecl)) {
+      if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S);
+          ForConstraintInstantiation && TypeAlias) {
+        if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(),
+                                          TypeAlias.PrimaryTypeAliasDecl)) {
           AddOuterTemplateArguments(TypeAlias.Template,
                                     TypeAlias.AssociatedTemplateArguments,
                                     /*Final=*/false);
@@ -989,60 +658,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   do {
     CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
   } while (CurDecl);
-
-  #if 0
-  if (Innermost)
-    Result.replaceInnermostTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost);
-  #endif
   return Result;
-
-  #if 0
-  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, ForConstraintInstantiation);
-    } else if (const auto *CTD = dyn_cast<ClassTemplateDecl>(CurDecl)) {
-      R = HandleClassTemplateDecl(CTD, Result, ForConstraintInstantiation, SkipForSpecialization);
-    } 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;
-  #endif
 }
 
 bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@@ -2160,10 +1776,8 @@ namespace {
 
     CXXRecordDecl::LambdaDependencyKind
     ComputeLambdaDependency(LambdaScopeInfo *LSI) {
-      if (auto TypeAlias =
-              TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
-                  getSema());
-          TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+      if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(getSema());
+          TypeAlias && isLambdaEnclosedByTypeAliasDecl(
                            LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
         unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
         if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
index 0ea4eeb1e9b08d..8361a35e96ec15 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
@@ -61,14 +61,14 @@ namespace PR21933 {
     }
   };
   template<typename T>
-  struct Y : T { 
+  struct Y : T {
     static void StaticFun() {
       using T::member; // expected-error 2{{class member}} expected-note {{use a reference instead}}
       (void)member;
     }
   };
 
-  void f() { 
+  void f() {
     X<A>::StaticFun(); // expected-note {{instantiation of}}
     X<B>::StaticFun(); // expected-note {{instantiation of}}
     X<C>::StaticFun();

>From f011c5a98ee0dc42c6d3a19776dcdce9630c55a4 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 23 Aug 2024 12:08:33 -0400
Subject: [PATCH 14/31] [FOLD] remove code for handling described templates

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 35 +++++-----------------
 1 file changed, 7 insertions(+), 28 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 2a956d488423d7..9a30e42f132128 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -212,8 +212,6 @@ struct TemplateInstantiationArgumentCollecter
 
   Decl *ChangeDecl(const Decl *D) {
     RelativeToPrimary = false;
-    if (const TemplateDecl *TD = D->getDescribedTemplate())
-      D = TD;
     return const_cast<Decl *>(D);
   }
 
@@ -226,10 +224,8 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *DontClearRelativeToPrimaryNextDecl(const Decl* D) {
-    D = Decl::castFromDeclContext(D->getDeclContext());
-    if (const TemplateDecl *TD = D->getDescribedTemplate())
-      D = TD;
-    return const_cast<Decl *>(D);
+    return const_cast<Decl *>(
+        Decl::castFromDeclContext(D->getDeclContext()));
   }
 
   void AddInnermostTemplateArguments(const Decl *D) {
@@ -239,12 +235,6 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args, bool Final) {
-    #if 0
-    if (Innermost) {
-      Args = *Innermost;
-      Innermost.reset();
-    }
-    #endif
     Result.addOuterTemplateArguments(const_cast<Decl*>(D), Args, Final);
   }
 
@@ -342,6 +332,8 @@ struct TemplateInstantiationArgumentCollecter
   #endif
 
   Decl *VisitFunctionDecl(FunctionDecl *FD) {
+    assert(!FD->getDescribedFunctionTemplate() && "not for templated declarations");
+
     if (!RelativeToPrimary) {
       if (const MemberSpecializationInfo *MSI = FD->getMemberSpecializationInfo();
           MSI && MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
@@ -392,11 +384,8 @@ struct TemplateInstantiationArgumentCollecter
           isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
         return Done();
 
-    } else if (FD->getDescribedFunctionTemplate()) {
-      assert(
-          (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "Outer template not instantiated?");
     }
+
     // 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
@@ -412,17 +401,7 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
-    if (ClassTemplateDecl *ClassTemplate = RD->getDescribedClassTemplate()) {
-      assert(
-          (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "Outer template not instantiated?");
-      // llvm_unreachable("shouldn't get here");
-      if (ClassTemplate->isMemberSpecialization())
-        return Done();
-      if (ForConstraintInstantiation)
-        AddOuterTemplateArguments(
-            RD, ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false);
-    }
+    assert(!RD->getDescribedClassTemplate() && "not for templated declarations");
 
     if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
         MSI && MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
@@ -609,7 +588,7 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(D);
   }
 
-    #if 0
+    #if 1
   Decl *Visit(Decl *D) {
     if (TemplateDecl *TD = D->getDescribedTemplate())
       D = TD;

>From c7e047928a3092486a73b140d10de7d476b2cc1f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 23 Aug 2024 12:37:40 -0400
Subject: [PATCH 15/31] [FOLD] handle partial specializations that are member
 specializations

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 43 +++++++++++++---------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 9a30e42f132128..ee20c538411f45 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -490,11 +490,6 @@ struct TemplateInstantiationArgumentCollecter
         !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
       return Done();
 
-    // 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 0
     if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
       Result.addOuterTemplateArguments(
@@ -511,12 +506,25 @@ struct TemplateInstantiationArgumentCollecter
         return Done();
     }
     #else
+
     if (Innermost)
         AddInnermostTemplateArguments(CTSD);
     else
       AddOuterTemplateArguments(
           CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
           /*Final=*/false);
+
+    if (auto *CTPSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(CTSD)) {
+      if (CTPSD->isMemberSpecialization())
+        return Done();
+    }
+
+    // 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();
@@ -526,7 +534,6 @@ struct TemplateInstantiationArgumentCollecter
         return Done();
     }
     #endif
-
     return DontClearRelativeToPrimaryNextDecl(CTSD);
     #endif
   }
@@ -543,28 +550,28 @@ struct TemplateInstantiationArgumentCollecter
         !isa<VarTemplatePartialSpecializationDecl>(VTSD))
       return Done();
 
+    if (Innermost)
+        AddInnermostTemplateArguments(VTSD);
+    else
+      AddOuterTemplateArguments(
+          VTSD, VTSD->getTemplateInstantiationArgs().asArray(),
+          /*Final=*/false);
+
+    if (auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(VTSD)) {
+      if (VTPSD->isMemberSpecialization())
+        return Done();
+    }
+
     // 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 (Innermost)
-        AddInnermostTemplateArguments(VTPSD);
-      else
-        AddOuterTemplateArguments(
-            VTPSD, VTSD->getTemplateInstantiationArgs().asArray(),
-            /*Final=*/false);
       if (VTPSD->isMemberSpecialization())
         return Done();
     } else {
       auto *VTD = Specialized.get<VarTemplateDecl *>();
-      if (Innermost)
-        AddInnermostTemplateArguments(VTD);
-      else
-        AddOuterTemplateArguments(
-            VTD, VTSD->getTemplateInstantiationArgs().asArray(),
-            /*Final=*/false);
       if (VTD->isMemberSpecialization())
         return Done();
     }

>From 27c0419f65dd6af9d0f4aff62330178f23c1dc59 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 23 Aug 2024 12:40:51 -0400
Subject: [PATCH 16/31] [FOLD] cleanups

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 92 +---------------------
 1 file changed, 4 insertions(+), 88 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index ee20c538411f45..a8dfea1771ab4d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -323,40 +323,22 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(CD);
   }
 
-  #if 0
-  Decl *VisitClassTemplatePartialSpecializationDecl(ClassTemplatePartialSpecializationDecl *CTPSD) {
-    if (!SkipForSpecialization)
-        Result.addOuterRetainedLevels(CTPSD->getTemplateDepth());
-    return Done();
-  }
-  #endif
-
   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 0
-    // Add template arguments from a function template specialization.
-    if (!RelativeToPrimary &&
-        FD->getTemplateSpecializationKindForInstantiation() ==
-            TSK_ExplicitSpecialization)
-      return Done();
 
-    if (!RelativeToPrimary &&
-        FD->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 UseNextDecl(FD);
-    } else
-    #endif
     if (const TemplateArgumentList *TemplateArgs =
                    FD->getTemplateSpecializationArgs()) {
       // Add the template arguments for this specialization.
@@ -452,33 +434,6 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
-    #if 0
-    if (!CTSD->isClassScopeExplicitSpecialization()) {
-      // We're done when we hit an explicit specialization.
-      if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
-          !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
-        return Done();
-
-      if (!SkipForSpecialization)
-        Result.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?");
-      if (CTSD->getSpecializedTemplate()->isMemberSpecialization())
-        return 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 *CTPSD = CTSD->getSpecializedTemplateOrPartial()
-                        .dyn_cast<ClassTemplatePartialSpecializationDecl *>())
-        return ChangeDecl(CTPSD->getLexicalDeclContext());
-    }
-    return UseNextDecl(CTSD);
-    #else
     // For a class-scope explicit specialization, there are no template arguments
     // at this level, but there may be enclosing template arguments.
     if (CTSD->isClassScopeExplicitSpecialization() &&
@@ -490,23 +445,6 @@ struct TemplateInstantiationArgumentCollecter
         !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
       return Done();
 
-    #if 0
-    if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      Result.addOuterTemplateArguments(
-          CTPSD, CTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
-      if (CTPSD->isMemberSpecialization())
-        return Done();
-    } else {
-      auto *CTD = Specialized.get<ClassTemplateDecl *>();
-      Result.addOuterTemplateArguments(
-          CTD, CTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
-      if (CTD->isMemberSpecialization())
-        return Done();
-    }
-    #else
-
     if (Innermost)
         AddInnermostTemplateArguments(CTSD);
     else
@@ -533,9 +471,7 @@ struct TemplateInstantiationArgumentCollecter
       if (CTD->isMemberSpecialization())
         return Done();
     }
-    #endif
     return DontClearRelativeToPrimaryNextDecl(CTSD);
-    #endif
   }
 
   Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) {
@@ -595,13 +531,11 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(D);
   }
 
-    #if 1
   Decl *Visit(Decl *D) {
     if (TemplateDecl *TD = D->getDescribedTemplate())
       D = TD;
     return DeclVisitor::Visit(D);
   }
-    #endif
 };
 
 } // namespace
@@ -620,24 +554,6 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   if (!CurDecl)
     CurDecl = Decl::castFromDeclContext(DC);
 
-  #if 0
-  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;
-  }
-  #endif
-
   TemplateInstantiationArgumentCollecter Collecter(
       *this, Result, Innermost, RelativeToPrimary,
       ForConstraintInstantiation);

>From 096eab19e70d0a20a536e79d6e973e5e0c8fda9a Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 27 Aug 2024 07:59:40 -0400
Subject: [PATCH 17/31] [FOLD] cleanup dead code

---
 clang/lib/Sema/SemaTemplate.cpp          | 23 ++--------
 clang/lib/Sema/SemaTemplateDeduction.cpp | 57 ------------------------
 2 files changed, 3 insertions(+), 77 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 398c0dac45cb53..b035f59ee395b8 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1982,21 +1982,6 @@ DeclResult Sema::CheckClassTemplate(
   }
 
   if (PrevClassTemplate) {
-    #if 0
-    // 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;
-    #endif
-
     // C++ [temp.class]p4:
     //   In a redeclaration, partial specialization, explicit
     //   specialization or explicit instantiation of a class template,
@@ -2114,14 +2099,15 @@ 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
@@ -4102,9 +4088,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
       VarTemplate->AddPartialSpecialization(Partial, InsertPos);
     Specialization = Partial;
 
-    //if (PrevPartial && PrevPartial->getInstantiatedFromMember())
-    //  PrevPartial->setMemberSpecialization();
-
     CheckTemplatePartialSpecialization(Partial);
   } else {
     // Create a new class template specialization declaration node for
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 4507a2204f78ce..d9dd2504cd92e9 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3171,23 +3171,6 @@ struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
   static constexpr bool value = true;
 };
 
-#if 0
-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();
-}
-#endif
-
 template <typename TemplateDeclT>
 static TemplateDeductionResult
 CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
@@ -3197,51 +3180,11 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
   llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
   Template->getAssociatedConstraints(AssociatedConstraints);
 
-  #if 0
-  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,
-      /*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);
-  #endif
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
       Template, Template->getDeclContext(), /*Final=*/false,
       /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
       /*ForConstraintInstantiation=*/true);
 
-  #if 0
-  if (DeducedArgsNeedReplacement(Template)) {
-    MultiLevelTemplateArgumentList WithReplacement = S.getTemplateInstantiationArgs(
-      Template, Template->getDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt,
-      /*RelativeToPrimary=*/true, /*Pattern=*/
-      nullptr, /*ForConstraintInstantiation=*/true);
-
-    WithReplacement.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
-
-    assert(MLTAL.getNumLevels() == WithReplacement.getNumLevels());
-    assert(MLTAL.getNumSubstitutedLevels() == WithReplacement.getNumSubstitutedLevels());
-    auto First0 = MLTAL.begin(), Last0 = MLTAL.end();
-    auto First1 = WithReplacement.begin(), Last1 = WithReplacement.end();
-
-    while (First0 != Last0) {
-      assert(First0->Args.data() == First1->Args.data());
-      ++First0, ++First1;
-    }
-  }
-  #endif
-
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
                                     Info.AssociatedConstraintsSatisfaction) ||

>From 46543dcda057786ed7f410bc2c82b4beb44eed18 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 27 Aug 2024 08:01:09 -0400
Subject: [PATCH 18/31] [FOLD] revert whitespace only changes

---
 .../namespace.udecl/p8-cxx0x.cpp              |  4 +--
 clang/test/PCH/cxx-templates.cpp              |  6 ++---
 clang/test/SemaCXX/friend.cpp                 |  4 +--
 .../SemaTemplate/default-arguments-cxx0x.cpp  |  2 +-
 .../SemaTemplate/default-expr-arguments.cpp   | 26 +++++++++----------
 5 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
index 8361a35e96ec15..0ea4eeb1e9b08d 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp
@@ -61,14 +61,14 @@ namespace PR21933 {
     }
   };
   template<typename T>
-  struct Y : T {
+  struct Y : T { 
     static void StaticFun() {
       using T::member; // expected-error 2{{class member}} expected-note {{use a reference instead}}
       (void)member;
     }
   };
 
-  void f() {
+  void f() { 
     X<A>::StaticFun(); // expected-note {{instantiation of}}
     X<B>::StaticFun(); // expected-note {{instantiation of}}
     X<C>::StaticFun();
diff --git a/clang/test/PCH/cxx-templates.cpp b/clang/test/PCH/cxx-templates.cpp
index bbe8c79bec374c..11ad401de23a8c 100644
--- a/clang/test/PCH/cxx-templates.cpp
+++ b/clang/test/PCH/cxx-templates.cpp
@@ -34,15 +34,15 @@ struct A {
 
 void test(const int (&a6)[17]) {
   int x = templ_f<int, 5>(3);
-
+  
   S<char, float>::templ();
   S<int, char>::partial();
   S<int, float>::explicit_special();
-
+  
   Dep<A>::Ty ty;
   Dep<A> a;
   a.f();
-
+  
   S3<int> s3;
   s3.m();
 
diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 0283fa1f7b2122..53e6bbfcf42a8e 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -52,14 +52,14 @@ namespace test3 {
 namespace test4 {
   class T4A {
     friend class T4B;
-
+  
   public:
     T4A(class T4B *);
 
   protected:
     T4B *mB;          // error here
   };
-
+ 
   class T4B {};
 }
 
diff --git a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
index bd9388eede316f..4972c57a719229 100644
--- a/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/clang/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -12,7 +12,7 @@ void f0();
 
 void g0() {
   f0(); // okay!
-}
+} 
 
 template<typename T, int N = T::value>
 int &f1(T);
diff --git a/clang/test/SemaTemplate/default-expr-arguments.cpp b/clang/test/SemaTemplate/default-expr-arguments.cpp
index 7570110caae81b..438f5b1aa95f74 100644
--- a/clang/test/SemaTemplate/default-expr-arguments.cpp
+++ b/clang/test/SemaTemplate/default-expr-arguments.cpp
@@ -23,10 +23,10 @@ template<typename T> void f3(T a, T b = T() + T()); // expected-error{{invalid o
 void g() {
   f1(10);
   f1(S()); // expected-note{{in instantiation of default function argument expression for 'f1<S>' required here}}
-
+  
   f2(10);
   f2(S());
-
+  
   f3(10);
   f3(S()); // expected-note{{in instantiation of default function argument expression for 'f3<S>' required here}}
 }
@@ -48,7 +48,7 @@ void g2() {
 void g3(F<int> f, F<struct S> s) {
   f.f();
   s.f(); // expected-note{{in instantiation of default function argument expression for 'f<S>' required here}}
-
+  
   F<int> f2;
   F<S> s2; // expected-note{{in instantiation of default function argument expression for 'F<S>' required here}}
 }
@@ -115,7 +115,7 @@ template<typename T> struct A {
   // expected-note 3{{passing argument to parameter here}}
 };
 
-struct B : A<int*> {
+struct B : A<int*> { 
   B();
 };
 B::B() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}}
@@ -127,7 +127,7 @@ C::C() { } // expected-note {{in instantiation of default function argument expr
 
 struct D {
   D();
-
+  
   A<int*> a;
 };
 D::D() { } // expected-note {{in instantiation of default function argument expression for 'A<int *>' required he}}
@@ -162,12 +162,12 @@ namespace PR5810 {
   struct allocator {
     allocator() { int a[sizeof(T) ? -1 : -1]; } // expected-error2 {{array with a negative size}}
   };
-
+  
   template<typename T>
   struct vector {
     vector(const allocator<T>& = allocator<T>()) {} // expected-note2 {{instantiation of}}
   };
-
+  
   struct A { };
   struct B { };
 
@@ -175,7 +175,7 @@ namespace PR5810 {
   void FilterVTs() {
     vector<A> Result;
   }
-
+  
   void f() {
     vector<A> Result;
   }
@@ -229,8 +229,8 @@ namespace PR5810b {
 
 namespace PR5810c {
   template<typename T>
-  struct X {
-    X() {
+  struct X { 
+    X() { 
       T t;
       double *****p = t; // expected-error{{cannot initialize a variable of type 'double *****' with an lvalue of type 'int'}}
     }
@@ -251,7 +251,7 @@ namespace PR8127 {
     PointerClass( T * object_p ) : p_( object_p ) {
       p_->acquire();
     }
-  private:
+  private:    
     T * p_;
   };
 
@@ -285,8 +285,8 @@ namespace rdar8427926 {
 }
 
 namespace PR8401 {
-  template<typename T>
-  struct A {
+  template<typename T> 
+  struct A { 
     A() { T* x = 1; } // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}}
   };
 

>From 9a334390b57deee279fcf4708dd93513584469ad Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 27 Aug 2024 09:13:06 -0400
Subject: [PATCH 19/31] [FOLD] remove some redundant checks

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a8dfea1771ab4d..a79750280c9956 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -348,11 +348,8 @@ struct TemplateInstantiationArgumentCollecter
         AddOuterTemplateArguments(
             FD, TemplateArgs->asArray(), /*Final=*/false);
 
-      if ( // RelativeToPrimary &&
-          (FD->getTemplateSpecializationKind() ==
-               TSK_ExplicitSpecialization ||
-           (FD->getFriendObjectKind() &&
-            !FD->getPrimaryTemplate()->getFriendObjectKind())))
+      if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization ||
+          (FD->getFriendObjectKind() && !FD->getPrimaryTemplate()->getFriendObjectKind()))
         return UseNextDecl(FD);
 
       // If this function was instantiated from a specialized member that is
@@ -365,7 +362,6 @@ struct TemplateInstantiationArgumentCollecter
       if (!ForConstraintInstantiation &&
           isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
         return Done();
-
     }
 
     // If this is a friend or local declaration and it declares an entity at
@@ -389,10 +385,7 @@ struct TemplateInstantiationArgumentCollecter
         MSI && MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
       return Done();
 
-    bool IsFriend = RD->getFriendObjectKind() ||
-                    (RD->getDescribedClassTemplate() &&
-                     RD->getDescribedClassTemplate()->getFriendObjectKind());
-    if (ForConstraintInstantiation && IsFriend &&
+    if (ForConstraintInstantiation && RD->getFriendObjectKind() &&
         RD->getNonTransparentDeclContext()->isFileContext()) {
       return ChangeDecl(RD->getLexicalDeclContext());
     }

>From 3791fe16ceb0075099ff255c3a1483ddd88f2c2e Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 28 Aug 2024 10:51:24 -0400
Subject: [PATCH 20/31] [FOLD] fix common pointer being overwritten when
 deserializing

---
 clang/lib/Serialization/ASTReader.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index e5a1e20a265616..cd6cdacc20970a 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9978,7 +9978,7 @@ void ASTReader::finishPendingActions() {
 
     auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
     for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
-      cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
+      cast<RedeclarableTemplateDecl>(R)->Common.setPointer(RTD->Common.getPointer());
   }
   PendingDefinitions.clear();
 

>From 08e551ac85e680a9010009661d5599f4d7603918 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 29 Aug 2024 12:18:24 -0400
Subject: [PATCH 21/31] [FOLD] more cleanup

---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 48 +++++------------
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 51 -------------------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 27 +++++-----
 clang/lib/Serialization/ASTWriterDecl.cpp     | 10 ++--
 4 files changed, 30 insertions(+), 106 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index e74f9abb3ea413..7415e1e15375c1 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> TemplateArgsForBuildingRC(
+  SmallVector<TemplateArgument> InnerArgsForBuildingRC(
       F->getTemplateParameters()->size());
   // Transform the transformed template args
   MultiLevelTemplateArgumentList Args;
@@ -778,15 +778,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
       NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
       MultiLevelTemplateArgumentList Args;
       Args.setKind(TemplateSubstitutionKind::Rewrite);
-      Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
+      Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
       // 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(TemplateArgsForBuildingRC[Index].isNull());
-      TemplateArgsForBuildingRC[Index] =
+      assert(InnerArgsForBuildingRC[Index].isNull());
+      InnerArgsForBuildingRC[Index] =
           Context.getInjectedTemplateArg(NewParam);
       continue;
     }
@@ -794,23 +794,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
         SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
     TemplateArgumentLoc Output;
     if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
-      assert(TemplateArgsForBuildingRC[Index].isNull() &&
+      assert(InnerArgsForBuildingRC[Index].isNull() &&
              "InstantiatedArgs must be null before setting");
-      TemplateArgsForBuildingRC[Index] = Output.getArgument();
+      InnerArgsForBuildingRC[Index] = Output.getArgument();
     }
   }
 
-  // A list of template arguments for transforming the require-clause of F.
-  // It must contain the entire set of template argument lists.
-  MultiLevelTemplateArgumentList ArgsForBuildingRC =
-      SemaRef.getTemplateInstantiationArgs(
-        F, F->getLexicalDeclContext(),
-        /*Final=*/false, /*Innermost=*/TemplateArgsForBuildingRC,
-        /*RelativeToPrimary=*/true,
-        /*ForConstraintInstantiation=*/true);;
-  ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
-  #if 0
-  ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
+  // A list of template arguments for transforming the require-clause using
+  // the transformed template arguments as the template argument list of F.
+  //
   // 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.
@@ -833,27 +825,15 @@ 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.
-  // getInstantiatedFromMemberTemplate() can only handle the former case, so we
-  // check the DeclContext kind.
-  if (F->getLexicalDeclContext()->getDeclKind() ==
-      clang::Decl::ClassTemplateSpecialization) {
-    auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
+  MultiLevelTemplateArgumentList ArgsForBuildingRC =
+      SemaRef.getTemplateInstantiationArgs(
         F, F->getLexicalDeclContext(),
-        /*Final=*/false, /*Innermost=*/std::nullopt,
+        /*Final=*/false, /*Innermost=*/InnerArgsForBuildingRC,
         /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
-        /*ForConstraintInstantiation=*/true);
-    for (auto It : OuterLevelArgs)
-      ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
-  }
-  #endif
-
+        /*ForConstraintInstantiation=*/true);;
+  ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
 
   ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
   if (E.isInvalid())
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a79750280c9956..24e8f8b5f488ee 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -52,36 +52,6 @@ using namespace sema;
 //===----------------------------------------------------------------------===/
 
 namespace {
-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.
@@ -169,25 +139,6 @@ bool isLambdaEnclosedByTypeAliasDecl(
               .TraverseType(Underlying);
 }
 
-namespace TemplateInstArgsHelpers {
-
-// 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();
-}
-
-} // namespace TemplateInstArgsHelpers
-
-
 struct TemplateInstantiationArgumentCollecter
     : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl*> {
   Sema &S;
@@ -540,8 +491,6 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
   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)
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 03cd9b5ffed303..1030fd571ecd13 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4684,25 +4684,30 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());
 
-  NamedDecl *Pattern = nullptr;
+  NamedDecl *Pattern = FD;
   std::optional<ArrayRef<TemplateArgument>> Innermost;
-  #if 1
 
-  if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
+  if (FD->isCXXClassMember() && !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
+    if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
+      Pattern = FTD->getFirstDecl();
+      Innermost = FD->getTemplateSpecializationArgs()->asArray();
+    }
+  }
+  #if 0
+
     Pattern = FTD->isCXXClassMember() ? FTD->getFirstDecl() : FTD;
-    Innermost = FD->getTemplateSpecializationArgs()->asArray();
   } else if (FD->isCXXClassMember()) {
     Pattern = FD->getFirstDecl();
   } else {
     Pattern = FD;
   }
-  #else
+  #elif 0
   Pattern = FD;
+  #elif 0
+  Pattern = FD->getTemplateInstantiationPattern(/*ForDefinition=*/true);
+  #elif 1
   #endif
 
-  if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
-    Pattern = FD;
-
   // Instantiate the expression.
   //
   // FIXME: Pass in a correct Pattern argument, otherwise
@@ -5201,14 +5206,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     RebuildTypeSourceInfoForDefaultSpecialMembers();
     SetDeclDefaulted(Function, PatternDecl->getLocation());
   } else {
-    #if 0
-    MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
-        Function, Function->getLexicalDeclContext(), /*Final=*/false,
-        /*Innermost=*/std::nullopt, false, PatternDecl);
-    #else
     MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
         Function, Function->getLexicalDeclContext());
-    #endif
 
     // Substitute into the qualifier; we can get a substitution failure here
     // through evil use of alias templates.
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index eb45124f911475..020f82ef3ac47f 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1707,15 +1707,13 @@ void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
 void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   VisitRedeclarable(D);
 
-  // if (D->getInstantiatedFromMemberTemplate())
   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());
-  }
 
   VisitTemplateDecl(D);
   Record.push_back(D->getIdentifierNamespace());
@@ -1791,9 +1789,8 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
 
   Record.push_back(D->isMemberSpecialization());
   // These are read/set from/to the first declaration.
-  if (D->getPreviousDecl() == nullptr) {
+  if (D->isFirstDecl())
     Record.AddDeclRef(D->getInstantiatedFromMember());
-  }
 
   Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
 }
@@ -1860,9 +1857,8 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
   Record.push_back(D->isMemberSpecialization());
 
   // These are read/set from/to the first declaration.
-  if (D->getPreviousDecl() == nullptr) {
+  if (D->isFirstDecl())
     Record.AddDeclRef(D->getInstantiatedFromMember());
-  }
 
   Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
 }

>From a85342898b26bd44b46816bfcb2b3e3f70f9d400 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 29 Aug 2024 12:29:21 -0400
Subject: [PATCH 22/31] [FOLD] more cleanups

---
 clang/include/clang/AST/DeclTemplate.h         |  1 +
 clang/lib/Sema/SemaDecl.cpp                    |  2 --
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 --------------
 3 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 3ad31243d5e559..6e6e075ac93d57 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -863,6 +863,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
 
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
+    assert(!isMemberSpecialization() && "already a member specialization");
     Common.setInt(true);
   }
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0eb58eb4339bc7..66dc4c318fcb83 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12005,8 +12005,6 @@ 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) {
-        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()) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1030fd571ecd13..5a5edfc87dff61 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4693,20 +4693,6 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
       Innermost = FD->getTemplateSpecializationArgs()->asArray();
     }
   }
-  #if 0
-
-    Pattern = FTD->isCXXClassMember() ? FTD->getFirstDecl() : FTD;
-  } else if (FD->isCXXClassMember()) {
-    Pattern = FD->getFirstDecl();
-  } else {
-    Pattern = FD;
-  }
-  #elif 0
-  Pattern = FD;
-  #elif 0
-  Pattern = FD->getTemplateInstantiationPattern(/*ForDefinition=*/true);
-  #elif 1
-  #endif
 
   // Instantiate the expression.
   //

>From 21c0d6351b18048efff890f3d8fac997ca4b717f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 29 Aug 2024 12:55:52 -0400
Subject: [PATCH 23/31] [FOLD] format

---
 clang/include/clang/AST/DeclTemplate.h        |  15 +-
 clang/include/clang/Sema/Sema.h               |   6 +-
 clang/lib/Sema/SemaConcept.cpp                |  12 +-
 clang/lib/Sema/SemaDecl.cpp                   |   8 +-
 clang/lib/Sema/SemaDeclCXX.cpp                |   3 +-
 clang/lib/Sema/SemaTemplate.cpp               |  54 +++---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  17 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 170 +++++++++---------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   3 +-
 clang/lib/Serialization/ASTReader.cpp         |   3 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |   4 +-
 11 files changed, 153 insertions(+), 142 deletions(-)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 6e6e075ac93d57..0e1f1f8b48cabe 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -809,7 +809,8 @@ 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.
+  /// template, and a flag indicating if the template is a member
+  /// specialization.
   mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
 
   /// Retrieves the "common" pointer shared by all (re-)declarations of
@@ -857,9 +858,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// template<> template<typename T>
   /// struct X<int>::Inner { /* ... */ };
   /// \endcode
-  bool isMemberSpecialization() const {
-    return Common.getInt();
-  }
+  bool isMemberSpecialization() const { return Common.getInt(); }
 
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
@@ -2190,9 +2189,7 @@ class ClassTemplatePartialSpecializationDecl
   }
 
   /// Note that this member template is a specialization.
-  void setMemberSpecialization() {
-    return InstantiatedFromMember.setInt(true);
-  }
+  void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
 
   /// Retrieves the injected specialization type for this partial
   /// specialization.  This is not the same as the type-decl-type for
@@ -2947,9 +2944,7 @@ class VarTemplatePartialSpecializationDecl
   }
 
   /// Note that this member template is a specialization.
-  void setMemberSpecialization() {
-    return InstantiatedFromMember.setInt(true);
-  }
+  void setMemberSpecialization() { return 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 e8fea08a5783d5..ab00d8c8aa13a2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11392,7 +11392,8 @@ 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,
+      SourceLocation FriendLoc,
+      ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
       bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
 
   /// Translates template arguments as provided by the parser
@@ -11432,7 +11433,8 @@ 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,
+      bool IsMemberSpecialization);
 
   /// Get the specialization of the given variable template corresponding to
   /// the specified argument list, or a null-but-valid result if the arguments
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index bff98e21564cdd..f953ad19a4130e 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -586,7 +586,7 @@ static bool CheckConstraintSatisfaction(
   ArrayRef<TemplateArgument> TemplateArgs =
       TemplateArgsLists.getNumSubstitutedLevels() > 0
           ? TemplateArgsLists.getInnermost()
-          : ArrayRef<TemplateArgument> {};
+          : ArrayRef<TemplateArgument>{};
   Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
       Sema::InstantiatingTemplate::ConstraintsCheck{},
       const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
@@ -908,8 +908,8 @@ 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) {
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
       ND, ND->getLexicalDeclContext(), /*Final=*/false,
       /*Innermost=*/std::nullopt,
@@ -1068,11 +1068,11 @@ bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
   SmallVector<const Expr *, 3> ACs;
   FTD->getAssociatedConstraints(ACs);
 
-  #if 0
+#if 0
   unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
-  #else
+#else
   unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
-  #endif
+#endif
   for (const Expr *Constraint : ACs)
     if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
                                                        Constraint))
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 66dc4c318fcb83..4b44cf15522011 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4505,10 +4505,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, NewTemplate->getTemplateParameters(),
+                         OldTemplate, OldTemplate->getTemplateParameters(),
+                         /*Complain=*/true, TPL_TemplateMatch))
     return New->setInvalidDecl();
 
   // C++ [class.mem]p1:
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8d0dfa4da33e4f..90f3bf1f8cf1f7 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17411,7 +17411,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.drop_back(),
+                                IsMemberSpecialization)
           .get();
     } else {
       // The "template<>" header is extraneous.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b035f59ee395b8..a19c201be35929 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1793,7 +1793,8 @@ DeclResult Sema::CheckClassTemplate(
     CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
     const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
     AccessSpecifier AS, SourceLocation ModulePrivateLoc,
-    SourceLocation FriendLoc, ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
+    SourceLocation FriendLoc,
+    ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
     bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
   assert(TemplateParams && TemplateParams->size() > 0 &&
          "No template parameters");
@@ -2058,8 +2059,7 @@ DeclResult Sema::CheckClassTemplate(
                           /*DelayTypeCreation=*/true);
   SetNestedNameSpecifier(*this, NewClass, SS);
   if (!OuterTemplateParamLists.empty())
-    NewClass->setTemplateParameterListsInfo(
-        Context, OuterTemplateParamLists);
+    NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists);
 
   // Add alignment attributes if necessary; these attributes are checked when
   // the ASTContext lays out the structure.
@@ -2102,26 +2102,28 @@ DeclResult Sema::CheckClassTemplate(
   // 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))
+  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))
+  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 && (!SkipBody || !SkipBody->ShouldSkip))
@@ -3961,7 +3963,8 @@ 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,
+    bool IsMemberSpecialization) {
   // D must be variable template id.
   assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
          "Variable template specialization is declared with a template id.");
@@ -8285,15 +8288,12 @@ 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.drop_back(),
+          isMemberSpecialization);
     }
 
     // Create a new class template partial specialization declaration node.
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 7415e1e15375c1..10ca5d6664b83a 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -317,7 +317,8 @@ struct ConvertConstructorToDeductionGuideTransform {
     }
 
     if (NestedPattern)
-      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(/*D=*/nullptr, Template->getDeclContext());
+      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(
+          /*D=*/nullptr, Template->getDeclContext());
   }
 
   Sema &SemaRef;
@@ -786,8 +787,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
                                      getDepthAndIndex(TP).first + AdjustDepth);
       FirstUndeducedParamIdx += 1;
       assert(InnerArgsForBuildingRC[Index].isNull());
-      InnerArgsForBuildingRC[Index] =
-          Context.getInjectedTemplateArg(NewParam);
+      InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
       continue;
     }
     TemplateArgumentLoc Input =
@@ -828,11 +828,12 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
   // 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);;
+      SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
+                                           /*Final=*/false,
+                                           /*Innermost=*/InnerArgsForBuildingRC,
+                                           /*RelativeToPrimary=*/true,
+                                           /*ForConstraintInstantiation=*/true);
+  ;
   ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
 
   ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 24e8f8b5f488ee..f44bd839d32261 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -140,7 +140,7 @@ bool isLambdaEnclosedByTypeAliasDecl(
 }
 
 struct TemplateInstantiationArgumentCollecter
-    : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl*> {
+    : DeclVisitor<TemplateInstantiationArgumentCollecter, Decl *> {
   Sema &S;
   MultiLevelTemplateArgumentList &Result;
   std::optional<ArrayRef<TemplateArgument>> Innermost;
@@ -148,18 +148,14 @@ struct TemplateInstantiationArgumentCollecter
   bool ForConstraintInstantiation;
 
   TemplateInstantiationArgumentCollecter(
-      Sema &S,
-      MultiLevelTemplateArgumentList &Result,
+      Sema &S, MultiLevelTemplateArgumentList &Result,
       std::optional<ArrayRef<TemplateArgument>> Innermost,
-      bool RelativeToPrimary,
-      bool ForConstraintInstantiation) :
-          S(S), Result(Result), Innermost(Innermost), RelativeToPrimary(RelativeToPrimary),
-          ForConstraintInstantiation(ForConstraintInstantiation) {
-  }
+      bool RelativeToPrimary, bool ForConstraintInstantiation)
+      : S(S), Result(Result), Innermost(Innermost),
+        RelativeToPrimary(RelativeToPrimary),
+        ForConstraintInstantiation(ForConstraintInstantiation) {}
 
-  Decl *Done() {
-    return nullptr;
-  }
+  Decl *Done() { return nullptr; }
 
   Decl *ChangeDecl(const Decl *D) {
     RelativeToPrimary = false;
@@ -170,23 +166,22 @@ struct TemplateInstantiationArgumentCollecter
     return ChangeDecl(Decl::castFromDeclContext(DC));
   }
 
-  Decl *UseNextDecl(const Decl *D) {
-    return ChangeDecl(D->getDeclContext());
-  }
+  Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); }
 
-  Decl *DontClearRelativeToPrimaryNextDecl(const Decl* D) {
-    return const_cast<Decl *>(
-        Decl::castFromDeclContext(D->getDeclContext()));
+  Decl *DontClearRelativeToPrimaryNextDecl(const Decl *D) {
+    return const_cast<Decl *>(Decl::castFromDeclContext(D->getDeclContext()));
   }
 
   void AddInnermostTemplateArguments(const Decl *D) {
     assert(Innermost);
-    Result.addOuterTemplateArguments(const_cast<Decl*>(D), *Innermost, /*Final=*/false);
+    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);
+  void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args,
+                                 bool Final) {
+    Result.addOuterTemplateArguments(const_cast<Decl *>(D), Args, Final);
   }
 
   Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
@@ -202,14 +197,15 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
-    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "outer template not instantiated?");
+    assert(
+        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+        "outer template not instantiated?");
 
     if (Innermost)
       AddInnermostTemplateArguments(FTD);
     else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(
-          FTD, FTD->getInjectedTemplateArgs(), /*Final=*/false);
+      AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(),
+                                /*Final=*/false);
 
     if (FTD->isMemberSpecialization())
       return Done();
@@ -220,14 +216,15 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
-    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "outer template not instantiated?");
+    assert(
+        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+        "outer template not instantiated?");
 
     if (Innermost)
       AddInnermostTemplateArguments(VTD);
     else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(
-          VTD, VTD->getInjectedTemplateArgs(), /*Final=*/false);
+      AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(),
+                                /*Final=*/false);
 
     if (VTD->isMemberSpecialization())
       return Done();
@@ -236,14 +233,15 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
-    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "outer template not instantiated?");
+    assert(
+        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+        "outer template not instantiated?");
 
     if (Innermost)
       AddInnermostTemplateArguments(CTD);
     else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(
-          CTD, CTD->getInjectedTemplateArgs(), /*Final=*/false);
+      AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(),
+                                /*Final=*/false);
 
     if (CTD->isMemberSpecialization())
       return Done();
@@ -254,20 +252,22 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) {
-    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "outer template not instantiated?");
+    assert(
+        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+        "outer template not instantiated?");
     if (Innermost)
       AddInnermostTemplateArguments(TATD);
     else if (ForConstraintInstantiation)
-      AddOuterTemplateArguments(
-          TATD, TATD->getInjectedTemplateArgs(), /*Final=*/false);
+      AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(),
+                                /*Final=*/false);
 
     return UseNextDecl(TATD);
   }
 
   Decl *VisitConceptDecl(ConceptDecl *CD) {
-    assert((ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
-          "outer template not instantiated?");
+    assert(
+        (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+        "outer template not instantiated?");
     if (Innermost)
       AddInnermostTemplateArguments(CD);
 
@@ -275,12 +275,15 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitFunctionDecl(FunctionDecl *FD) {
-    assert(!FD->getDescribedFunctionTemplate() && "not for templated declarations");
+    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)
+      if (const MemberSpecializationInfo *MSI =
+              FD->getMemberSpecializationInfo();
+          MSI &&
+          MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
         return Done();
 
       // This is an implicit instantiation of an explicit specialization. We
@@ -291,16 +294,16 @@ struct TemplateInstantiationArgumentCollecter
     }
 
     if (const TemplateArgumentList *TemplateArgs =
-                   FD->getTemplateSpecializationArgs()) {
+            FD->getTemplateSpecializationArgs()) {
       // Add the template arguments for this specialization.
       if (Innermost)
         AddInnermostTemplateArguments(FD);
       else
-        AddOuterTemplateArguments(
-            FD, TemplateArgs->asArray(), /*Final=*/false);
+        AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false);
 
       if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization ||
-          (FD->getFriendObjectKind() && !FD->getPrimaryTemplate()->getFriendObjectKind()))
+          (FD->getFriendObjectKind() &&
+           !FD->getPrimaryTemplate()->getFriendObjectKind()))
         return UseNextDecl(FD);
 
       // If this function was instantiated from a specialized member that is
@@ -330,10 +333,12 @@ struct TemplateInstantiationArgumentCollecter
   }
 
   Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
-    assert(!RD->getDescribedClassTemplate() && "not for templated declarations");
+    assert(!RD->getDescribedClassTemplate() &&
+           "not for templated declarations");
 
     if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
-        MSI && MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+        MSI &&
+        MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
       return Done();
 
     if (ForConstraintInstantiation && RD->getFriendObjectKind() &&
@@ -352,7 +357,7 @@ struct TemplateInstantiationArgumentCollecter
       if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S);
           ForConstraintInstantiation && TypeAlias) {
         if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(),
-                                          TypeAlias.PrimaryTypeAliasDecl)) {
+                                            TypeAlias.PrimaryTypeAliasDecl)) {
           AddOuterTemplateArguments(TypeAlias.Template,
                                     TypeAlias.AssociatedTemplateArguments,
                                     /*Final=*/false);
@@ -377,9 +382,10 @@ struct TemplateInstantiationArgumentCollecter
     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.
+  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() &&
         !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
       return DontClearRelativeToPrimaryNextDecl(CTSD);
@@ -390,11 +396,11 @@ struct TemplateInstantiationArgumentCollecter
       return Done();
 
     if (Innermost)
-        AddInnermostTemplateArguments(CTSD);
+      AddInnermostTemplateArguments(CTSD);
     else
-      AddOuterTemplateArguments(
-          CTSD, CTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
+      AddOuterTemplateArguments(CTSD,
+                                CTSD->getTemplateInstantiationArgs().asArray(),
+                                /*Final=*/false);
 
     if (auto *CTPSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(CTSD)) {
       if (CTPSD->isMemberSpecialization())
@@ -404,10 +410,12 @@ struct TemplateInstantiationArgumentCollecter
     // 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 *>
+    llvm::PointerUnion<ClassTemplateDecl *,
+                       ClassTemplatePartialSpecializationDecl *>
         Specialized = CTSD->getSpecializedTemplateOrPartial();
 
-    if (auto *CTPSD = Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+    if (auto *CTPSD =
+            Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
       if (CTPSD->isMemberSpecialization())
         return Done();
     } else {
@@ -418,9 +426,10 @@ struct TemplateInstantiationArgumentCollecter
     return DontClearRelativeToPrimaryNextDecl(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.
+  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() &&
         !isa<VarTemplatePartialSpecializationDecl>(VTSD))
       return DontClearRelativeToPrimaryNextDecl(VTSD);
@@ -431,11 +440,11 @@ struct TemplateInstantiationArgumentCollecter
       return Done();
 
     if (Innermost)
-        AddInnermostTemplateArguments(VTSD);
+      AddInnermostTemplateArguments(VTSD);
     else
-      AddOuterTemplateArguments(
-          VTSD, VTSD->getTemplateInstantiationArgs().asArray(),
-          /*Final=*/false);
+      AddOuterTemplateArguments(VTSD,
+                                VTSD->getTemplateInstantiationArgs().asArray(),
+                                /*Final=*/false);
 
     if (auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(VTSD)) {
       if (VTPSD->isMemberSpecialization())
@@ -445,9 +454,11 @@ struct TemplateInstantiationArgumentCollecter
     // 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 *>
+    llvm::PointerUnion<VarTemplateDecl *,
+                       VarTemplatePartialSpecializationDecl *>
         Specialized = VTSD->getSpecializedTemplateOrPartial();
-    if (auto *VTPSD = Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+    if (auto *VTPSD =
+            Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
       if (VTPSD->isMemberSpecialization())
         return Done();
     } else {
@@ -458,10 +469,10 @@ struct TemplateInstantiationArgumentCollecter
     return DontClearRelativeToPrimaryNextDecl(VTSD);
   }
 
-  Decl *VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl *ICSD) {
-    AddOuterTemplateArguments(
-        ICSD, ICSD->getTemplateArguments(),
-        /*Final=*/false);
+  Decl *VisitImplicitConceptSpecializationDecl(
+      ImplicitConceptSpecializationDecl *ICSD) {
+    AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(),
+                              /*Final=*/false);
     return UseNextDecl(ICSD);
   }
 
@@ -486,8 +497,8 @@ struct TemplateInstantiationArgumentCollecter
 
 MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     const NamedDecl *ND, const DeclContext *DC, bool Final,
-    std::optional<ArrayRef<TemplateArgument>> Innermost,
-    bool RelativeToPrimary, bool ForConstraintInstantiation) {
+    std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
+    bool ForConstraintInstantiation) {
   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;
@@ -497,8 +508,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     CurDecl = Decl::castFromDeclContext(DC);
 
   TemplateInstantiationArgumentCollecter Collecter(
-      *this, Result, Innermost, RelativeToPrimary,
-      ForConstraintInstantiation);
+      *this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation);
   do {
     CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
   } while (CurDecl);
@@ -1642,11 +1652,11 @@ namespace {
 
     ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
                                  LambdaScopeInfo *LSI) {
-      #if 1
+#if 1
       CXXMethodDecl *MD = LSI->CallOperator;
       // if (MD->getParentFunctionOrMethod()) {
       if (true) {
-      #if 0
+#if 0
         NamedDecl *Pattern = MD;
           std::optional<ArrayRef<TemplateArgument>> Innermost;
         if (FunctionTemplateDecl *FTD = MD->getDescribedFunctionTemplate()) {
@@ -1657,8 +1667,8 @@ namespace {
             SemaRef.getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
                                                  /*Final=*/false, Innermost,
                                                  /*RelativeToPrimary=*/true);
-        #endif
-;
+#endif
+        ;
         for (ParmVarDecl *PVD : MD->parameters()) {
           assert(PVD && "null in a parameter list");
           if (!PVD->hasDefaultArg())
@@ -1672,13 +1682,13 @@ namespace {
             // that downstream diagnostics are omitted.
             ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
                 UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
-                { UninstExpr }, UninstExpr->getType());
+                {UninstExpr}, UninstExpr->getType());
             if (ErrorResult.isUsable())
               PVD->setDefaultArg(ErrorResult.get());
           }
         }
       }
-      #endif
+#endif
       return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
     }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5a5edfc87dff61..6d8cec35cbc1bb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4687,7 +4687,8 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   NamedDecl *Pattern = FD;
   std::optional<ArrayRef<TemplateArgument>> Innermost;
 
-  if (FD->isCXXClassMember() && !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
+  if (FD->isCXXClassMember() &&
+      !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
     if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
       Pattern = FTD->getFirstDecl();
       Innermost = FD->getTemplateSpecializationArgs()->asArray();
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index cd6cdacc20970a..a37d853db6bc1b 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9978,7 +9978,8 @@ void ASTReader::finishPendingActions() {
 
     auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
     for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
-      cast<RedeclarableTemplateDecl>(R)->Common.setPointer(RTD->Common.getPointer());
+      cast<RedeclarableTemplateDecl>(R)->Common.setPointer(
+          RTD->Common.getPointer());
   }
   PendingDefinitions.clear();
 
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 5a893515de9cc6..4d9463535fef31 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2567,7 +2567,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {
     D->InstantiatedFromMember.setPointer(
-      readDeclAs<ClassTemplatePartialSpecializationDecl>());
+        readDeclAs<ClassTemplatePartialSpecializationDecl>());
   }
 }
 
@@ -2660,7 +2660,7 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
   D->TemplateParams = Params;
 
   RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
-    D->InstantiatedFromMember.setInt(Record.readInt());
+  D->InstantiatedFromMember.setInt(Record.readInt());
 
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {

>From 60a2ab23b1380966ea74b04b1fa1d034fe3f4b8f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 30 Aug 2024 09:50:14 -0400
Subject: [PATCH 24/31] [FOLD] address some review feedback

---
 clang/lib/Sema/SemaConcept.cpp                |  4 --
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  4 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 50 ++++++-------------
 3 files changed, 17 insertions(+), 41 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f953ad19a4130e..8b83418c897f8d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1068,11 +1068,7 @@ bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
   SmallVector<const Expr *, 3> ACs;
   FTD->getAssociatedConstraints(ACs);
 
-#if 0
-  unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
-#else
   unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
-#endif
   for (const Expr *Constraint : ACs)
     if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
                                                        Constraint))
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 10ca5d6664b83a..ca93c840f03215 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -317,8 +317,7 @@ struct ConvertConstructorToDeductionGuideTransform {
     }
 
     if (NestedPattern)
-      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(
-          /*D=*/nullptr, Template->getDeclContext());
+      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
   }
 
   Sema &SemaRef;
@@ -833,7 +832,6 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
                                            /*Innermost=*/InnerArgsForBuildingRC,
                                            /*RelativeToPrimary=*/true,
                                            /*ForConstraintInstantiation=*/true);
-  ;
   ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
 
   ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index f44bd839d32261..17e4cf7db3c6d3 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1652,43 +1652,25 @@ namespace {
 
     ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
                                  LambdaScopeInfo *LSI) {
-#if 1
       CXXMethodDecl *MD = LSI->CallOperator;
-      // if (MD->getParentFunctionOrMethod()) {
-      if (true) {
-#if 0
-        NamedDecl *Pattern = MD;
-          std::optional<ArrayRef<TemplateArgument>> Innermost;
-        if (FunctionTemplateDecl *FTD = MD->getDescribedFunctionTemplate()) {
-          Pattern = FTD;
-          Innermost = FTD->getInjectedTemplateArgs();
-        }
-        MultiLevelTemplateArgumentList MLTAL =
-            SemaRef.getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
-                                                 /*Final=*/false, Innermost,
-                                                 /*RelativeToPrimary=*/true);
-#endif
-        ;
-        for (ParmVarDecl *PVD : MD->parameters()) {
-          assert(PVD && "null in a parameter list");
-          if (!PVD->hasDefaultArg())
-            continue;
-          Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
-          // FIXME: Obtain the source location for the '=' token.
-          SourceLocation EqualLoc = UninstExpr->getBeginLoc();
-          if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
-            // If substitution fails, the default argument is set to a
-            // RecoveryExpr that wraps the uninstantiated default argument so
-            // that downstream diagnostics are omitted.
-            ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
-                UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
-                {UninstExpr}, UninstExpr->getType());
-            if (ErrorResult.isUsable())
-              PVD->setDefaultArg(ErrorResult.get());
-          }
+      for (ParmVarDecl *PVD : MD->parameters()) {
+        assert(PVD && "null in a parameter list");
+        if (!PVD->hasDefaultArg())
+          continue;
+        Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+        // FIXME: Obtain the source location for the '=' token.
+        SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+        if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+          // If substitution fails, the default argument is set to a
+          // RecoveryExpr that wraps the uninstantiated default argument so
+          // that downstream diagnostics are omitted.
+          ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
+              UninstExpr->getType());
+          if (ErrorResult.isUsable())
+            PVD->setDefaultArg(ErrorResult.get());
         }
       }
-#endif
       return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
     }
 

>From a8e2c69b56ae56d45a3a5fb061051d9a1bb61ad2 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 30 Aug 2024 10:12:27 -0400
Subject: [PATCH 25/31] [FOLD] use pointer for InstantiatedFromMember

---
 clang/include/clang/AST/DeclTemplate.h | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 0e1f1f8b48cabe..90245a16ea3b59 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -781,15 +781,11 @@ class RedeclarableTemplateDecl : public TemplateDecl,
                              EntryType *Entry, void *InsertPos);
 
   struct CommonBase {
-    CommonBase() : InstantiatedFromMember(nullptr, false) {}
+    CommonBase() {}
 
     /// The template from which this was most
     /// directly instantiated (or null).
-    ///
-    /// The boolean value indicates whether this template
-    /// was explicitly specialized.
-    llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
-      InstantiatedFromMember;
+    RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
 
     /// If non-null, points to an array of specializations (including
     /// partial specializations) known only by their external declaration IDs.
@@ -903,12 +899,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// void X<T>::f(T, U);
   /// \endcode
   RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
-    return getCommonPtr()->InstantiatedFromMember.getPointer();
+    return getCommonPtr()->InstantiatedFromMember;
   }
 
   void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
-    assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
-    getCommonPtr()->InstantiatedFromMember.setPointer(TD);
+    assert(!getCommonPtr()->InstantiatedFromMember);
+    getCommonPtr()->InstantiatedFromMember = TD;
   }
 
   /// Retrieve the "injected" template arguments that correspond to the

>From 124d6d48ff280000ac7bacdb73f0ec2e0d5dfe3f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 30 Aug 2024 11:46:18 -0400
Subject: [PATCH 26/31] [FOLD] add comment

---
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6d8cec35cbc1bb..bae1c8a1d47108 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4687,6 +4687,25 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
   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()) {

>From fd20bd296e2fe53c234ada48e32b6187f88d76d2 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 3 Sep 2024 09:00:15 -0400
Subject: [PATCH 27/31] [FOLD] diagnose redefinitions after checking template
 parameter equivalence

---
 clang/lib/Sema/SemaTemplate.cpp               | 55 ++++++++++---------
 ...class-template-partial-specializations.cpp |  7 +--
 2 files changed, 32 insertions(+), 30 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index a19c201be35929..3d29d862edca23 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1997,30 +1997,6 @@ 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
@@ -2126,8 +2102,35 @@ DeclResult Sema::CheckClassTemplate(
           SkipBody))
     Invalid = true;
 
-  if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
-    NewClass->startDefinition();
+  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();
+  }
 
   ProcessDeclAttributeList(S, NewClass, Attr);
   ProcessAPINotes(NewClass);
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
index 3358869b95e370..7772eecc69be8b 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
@@ -33,12 +33,11 @@ class D{}; // expected-note{{previous definition is here}}
 template<typename T>
 class D<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}} expected-error{{redefinition of 'D'}}
 
-template<typename T> requires C1<T>
-class E{}; // expected-note{{previous definition is here}}
+template<typename T> requires C1<T> // expected-note{{previous template declaration is here}}
+class E{};
 
-template<typename T>
+template<typename T> // expected-error{{requires clause differs in template redeclaration}}
 class E<T>{}; // expected-error{{class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
-              // expected-error at -1{{redefinition of 'E'}}
 
 template<typename T>
 struct F{ enum{ value = 1 }; };

>From b7e0dd6792ce5479d7785e95bc57e19aa6e249d8 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 3 Sep 2024 09:31:16 -0400
Subject: [PATCH 28/31] [FOLD] more tests

---
 .../temp/temp.constr/temp.constr.decl/p4.cpp  | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
index c39d13c47c8a15..70064f867e18e3 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -1,6 +1,9 @@
 // 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>
@@ -9,6 +12,9 @@ struct A {
   template<>
   void f<short, true>();
 
+  template<D U>
+  void g();
+
   template<typename U, bool V> requires V
   struct B;
 
@@ -18,6 +24,12 @@ struct A {
   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;
 
@@ -26,12 +38,22 @@ struct A {
 
   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 { };
@@ -44,6 +66,14 @@ 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;
@@ -56,6 +86,14 @@ 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;
@@ -68,6 +106,10 @@ 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;
@@ -88,6 +130,18 @@ 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;
@@ -107,3 +161,15 @@ 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&>;

>From e3338a97b69e8c2a31dcaf5aed69f46814af5b53 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 20 Sep 2024 10:23:31 -0400
Subject: [PATCH 29/31] [FOLD] add getCommonPtrInternal

---
 clang/include/clang/AST/DeclTemplate.h    |  2 ++
 clang/lib/AST/DeclTemplate.cpp            | 21 +++++++++++++--------
 clang/lib/Serialization/ASTReader.cpp     |  2 +-
 clang/lib/Serialization/ASTReaderDecl.cpp |  6 +++---
 4 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 90245a16ea3b59..7d0002afe31ee6 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -809,6 +809,8 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// specialization.
   mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
 
+  CommonBase *getCommonPtrInternal() const;
+
   /// Retrieves the "common" pointer shared by all (re-)declarations of
   /// the same template. Calling this routine may implicitly allocate memory
   /// for the common pointer.
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 58ce956f4b916a..fb258195529eab 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -308,8 +308,13 @@ bool TemplateDecl::isTypeAlias() const {
 
 void RedeclarableTemplateDecl::anchor() {}
 
+RedeclarableTemplateDecl::CommonBase *
+RedeclarableTemplateDecl::getCommonPtrInternal() const {
+  return Common.getPointer();
+}
+
 RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
-  if (CommonBase *C = Common.getPointer())
+  if (CommonBase *C = getCommonPtrInternal())
     return C;
 
   // Walk the previous-declaration chain until we either find a declaration
@@ -317,7 +322,7 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
   SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
   for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
        Prev = Prev->getPreviousDecl()) {
-    if (CommonBase *C = Prev->Common.getPointer()) {
+    if (CommonBase *C = Prev->getCommonPtrInternal()) {
       Common.setPointer(C);
       break;
     }
@@ -326,7 +331,7 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
   }
 
   // If we never found a common pointer, allocate one now.
-  if (!Common.getPointer()) {
+  if (!getCommonPtrInternal()) {
     // FIXME: If any of the declarations is from an AST file, we probably
     // need an update record to add the common data.
 
@@ -335,9 +340,9 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
 
   // Update any previous declarations we saw with the common pointer.
   for (const RedeclarableTemplateDecl *Prev : PrevDecls)
-    Prev->Common.setPointer(Common.getPointer());
+    Prev->Common.setPointer(getCommonPtrInternal());
 
-  return Common.getPointer();
+  return getCommonPtrInternal();
 }
 
 void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
@@ -467,14 +472,14 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
 
   // If we haven't created a common pointer yet, then it can just be created
   // with the usual method.
-  if (!Base::Common.getPointer())
+  if (!getCommonPtrInternal())
     return;
 
-  Common *ThisCommon = static_cast<Common *>(Base::Common.getPointer());
+  Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
   Common *PrevCommon = nullptr;
   SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
   for (; Prev; Prev = Prev->getPreviousDecl()) {
-    if (CommonBase *C = Prev->Base::Common.getPointer()) {
+    if (CommonBase *C = Prev->getCommonPtrInternal()) {
       PrevCommon = static_cast<Common *>(C);
       break;
     }
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index a37d853db6bc1b..5ee2446404b3e6 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9979,7 +9979,7 @@ void ASTReader::finishPendingActions() {
     auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
     for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
       cast<RedeclarableTemplateDecl>(R)->Common.setPointer(
-          RTD->Common.getPointer());
+          RTD->getCommonPtrInternal());
   }
   PendingDefinitions.clear();
 
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 4d9463535fef31..af8daaec938c18 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2416,11 +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->Common.getPointer()) {
+  if (!CanonD->getCommonPtrInternal()) {
     CanonD->Common.setPointer(CanonD->newCommon(Reader.getContext()));
     Reader.PendingDefinitions.insert(CanonD);
   }
-  D->Common.setPointer(CanonD->Common.getPointer());
+  D->Common.setPointer(CanonD->getCommonPtrInternal());
   if (Record.readInt())
     D->setMemberSpecialization();
 
@@ -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->Common.setPointer(D->getCanonicalDecl()->Common.getPointer());
+  D->Common.setPointer(D->getCanonicalDecl()->getCommonPtrInternal());
 }
 
 /// "Cast" to type T, asserting if we don't have an implicit conversion.

>From 9cf97e4fddbf247ea3bae9c2d13987079724ce46 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 20 Sep 2024 10:40:26 -0400
Subject: [PATCH 30/31] [FOLD] add asserts in setInstantiationOf

---
 clang/include/clang/AST/DeclTemplate.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 7d0002afe31ee6..2911473cac0318 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1985,6 +1985,8 @@ 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();
@@ -1996,6 +1998,8 @@ 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;
@@ -2743,6 +2747,8 @@ 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();
@@ -2754,6 +2760,8 @@ 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;

>From 334a522218e65b8f386bc0ec7583752da0c20265 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 20 Sep 2024 11:56:37 -0400
Subject: [PATCH 31/31] [FOLD] split up template argument collection for
 class/variable template specializations

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 58 +++++++++++++++-------
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 17e4cf7db3c6d3..3e6e2633550782 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -232,6 +232,24 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(VTD);
   }
 
+  Decl *VisitVarTemplatePartialSpecializationDecl(
+      VarTemplatePartialSpecializationDecl *VTPSD) {
+    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);
+  }
+
   Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
     assert(
         (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
@@ -251,6 +269,24 @@ struct TemplateInstantiationArgumentCollecter
     return UseNextDecl(CTD);
   }
 
+  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 (CTPSD->isMemberSpecialization())
+      return Done();
+
+    return UseNextDecl(CTPSD);
+  }
+
   Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) {
     assert(
         (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
@@ -386,13 +422,11 @@ struct TemplateInstantiationArgumentCollecter
   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() &&
-        !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
+    if (CTSD->isClassScopeExplicitSpecialization())
       return DontClearRelativeToPrimaryNextDecl(CTSD);
 
     // We're done when we hit an explicit specialization.
-    if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
-        !isa<ClassTemplatePartialSpecializationDecl>(CTSD))
+    if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
       return Done();
 
     if (Innermost)
@@ -402,11 +436,6 @@ struct TemplateInstantiationArgumentCollecter
                                 CTSD->getTemplateInstantiationArgs().asArray(),
                                 /*Final=*/false);
 
-    if (auto *CTPSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(CTSD)) {
-      if (CTPSD->isMemberSpecialization())
-        return Done();
-    }
-
     // 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?");
@@ -430,13 +459,11 @@ struct TemplateInstantiationArgumentCollecter
   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() &&
-        !isa<VarTemplatePartialSpecializationDecl>(VTSD))
+    if (VTSD->isClassScopeExplicitSpecialization())
       return DontClearRelativeToPrimaryNextDecl(VTSD);
 
     // We're done when we hit an explicit specialization.
-    if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
-        !isa<VarTemplatePartialSpecializationDecl>(VTSD))
+    if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
       return Done();
 
     if (Innermost)
@@ -446,11 +473,6 @@ struct TemplateInstantiationArgumentCollecter
                                 VTSD->getTemplateInstantiationArgs().asArray(),
                                 /*Final=*/false);
 
-    if (auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(VTSD)) {
-      if (VTPSD->isMemberSpecialization())
-        return Done();
-    }
-
     // 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?");



More information about the cfe-commits mailing list