[clang] [libcxx] [Clang] Implement CWG2369 "Ordering between constraints and substitution" (PR #102857)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 18 18:54:06 PDT 2024


https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/102857

>From 1119f0a8d180e482bff45c999d488827ac5ae49e Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 12 Aug 2024 23:32:34 +0800
Subject: [PATCH 01/12] [Clang][NFCI] Slightly refactor
 getTemplateInstantiationArgs()

---
 clang/include/clang/Sema/Sema.h            | 12 +++++++++---
 clang/lib/Sema/SemaConcept.cpp             |  2 +-
 clang/lib/Sema/SemaTemplate.cpp            |  2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 15 +++++++--------
 4 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 2ec6367eccea01..352b26b0739ffb 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13033,11 +13033,14 @@ class Sema final : public SemaBase {
   /// instantiation arguments.
   ///
   /// \param DC In the event we don't HAVE a declaration yet, we instead provide
-  ///  the decl context where it will be created.  In this case, the `Innermost`
-  ///  should likely be provided.  If ND is non-null, this is ignored.
+  ///  the decl context where it will be created.  In this case, the \p
+  ///  Innermost should likely be provided.  If \p ND is non-null and \p
+  ///  Innermost is NULL, this is ignored.
   ///
   /// \param Innermost if non-NULL, specifies a template argument list for the
-  /// template declaration passed as ND.
+  /// template declaration passed as \p ND. The next declaration context would
+  /// be switched to \p DC if present; otherwise, it would be the semantic
+  /// declaration context of \p ND.
   ///
   /// \param RelativeToPrimary true if we should get the template
   /// arguments relative to the primary template, even when we're
@@ -13053,6 +13056,9 @@ class Sema final : public SemaBase {
   /// ForConstraintInstantiation indicates we should continue looking when
   /// encountering a lambda generic call operator, and continue looking for
   /// arguments on an enclosing class template.
+  ///
+  /// \param SkipForSpecialization when specified, any template specializations
+  /// in a traversal would be ignored.
   MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
       const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d4c9d044985e34..929555e94dc35d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1482,7 +1482,7 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N,
 static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
                                         const ConceptSpecializationExpr *CSE) {
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
+      CSE->getNamedConcept(), CSE->getNamedConcept()->getDeclContext(),
       /*Final=*/true, CSE->getTemplateArguments(),
       /*RelativeToPrimary=*/true,
       /*Pattern=*/nullptr,
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1346a4a3f0012a..e6191c8c1397bd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5582,7 +5582,7 @@ bool Sema::CheckTemplateArgumentList(
     CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
 
     MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
-        Template, NewContext, /*Final=*/true, SugaredConverted,
+        Template, Template->getDeclContext(), /*Final=*/true, SugaredConverted,
         /*RelativeToPrimary=*/true,
         /*Pattern=*/nullptr,
         /*ForConceptInstantiation=*/true);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index de470739ab78e7..6cc9fb0ef04b65 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -491,7 +491,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
     // has a depth of 0.
     if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
       HandleDefaultTempArgIntoTempTempParam(TTP, Result);
-    CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
+    CurDecl = DC ? Decl::castFromDeclContext(DC)
+                 : Response::UseNextDecl(CurDecl).NextDecl;
   }
 
   while (!CurDecl->isFileContextDecl()) {
@@ -3242,15 +3243,13 @@ bool Sema::SubstDefaultArgument(
           /*ForDefinition*/ false);
       if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
         return true;
-      const FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
-      if (PrimaryTemplate && PrimaryTemplate->isOutOfLine()) {
-        TemplateArgumentList *CurrentTemplateArgumentList =
-            TemplateArgumentList::CreateCopy(getASTContext(),
-                                             TemplateArgs.getInnermost());
+      // FIXME: Investigate if we shall validate every FunctionTemplateDecl
+      // along the getInstantiatedFromMemberTemplate() chain.
+      if (auto *PrimaryTemplate = FD->getPrimaryTemplate();
+          PrimaryTemplate && PrimaryTemplate->isOutOfLine())
         NewTemplateArgs = getTemplateInstantiationArgs(
             FD, FD->getDeclContext(), /*Final=*/false,
-            CurrentTemplateArgumentList->asArray(), /*RelativeToPrimary=*/true);
-      }
+            TemplateArgs.getInnermost(), /*RelativeToPrimary=*/true);
     }
 
     runWithSufficientStackSpace(Loc, [&] {

>From 2dd772d47a7330476173e0a34fb3176bd5c8d384 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 13 Aug 2024 09:41:13 +0800
Subject: [PATCH 02/12] Resolve a merge conflict

---
 clang/lib/Sema/SemaTemplate.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ff29cf05dccff4..d2b1bc0e463ade 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5582,11 +5582,12 @@ bool Sema::CheckTemplateArgumentList(
     ContextRAII Context(*this, NewContext);
     CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
 
-    MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
-        Template, Template->getDeclContext(), /*Final=*/false, SugaredConverted,
-        /*RelativeToPrimary=*/true,
-        /*Pattern=*/nullptr,
-        /*ForConceptInstantiation=*/true);
+    MultiLevelTemplateArgumentList MLTAL =
+        getTemplateInstantiationArgs(Template, Template->getDeclContext(),
+                                     /*Final=*/false, CanonicalConverted,
+                                     /*RelativeToPrimary=*/true,
+                                     /*Pattern=*/nullptr,
+                                     /*ForConceptInstantiation=*/true);
     if (EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {

>From 96bf64c230b3a854ff09b2f7f32340bf17679746 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 11 Aug 2024 16:51:34 +0800
Subject: [PATCH 03/12] CWG 2369

---
 clang/include/clang/Sema/Sema.h               |  3 +-
 clang/lib/Sema/SemaConcept.cpp                |  2 +-
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 94 ++++++++++++++++---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  5 +-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 48 +++++++---
 5 files changed, 122 insertions(+), 30 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c1912343cf43b8..48901ded906ee8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13064,7 +13064,8 @@ class Sema final : public SemaBase {
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
       bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
       bool ForConstraintInstantiation = false,
-      bool SkipForSpecialization = false);
+      bool SkipForSpecialization = false,
+      MultiLevelTemplateArgumentList *Merged = nullptr);
 
   /// 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 f4dd0648781b61..79057e0e3e8138 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -847,7 +847,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
                                     bool ForOverloadResolution) {
   // Don't check constraints if the function is dependent. Also don't check if
   // this is a function template specialization, as the call to
-  // CheckinstantiatedFunctionTemplateConstraints after this will check it
+  // CheckInstantiatedFunctionTemplateConstraints after this will check it
   // better.
   if (FD->isDependentContext() ||
       FD->getTemplatedKind() ==
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index ec951d5ac06dbc..9bb215fe66c5a6 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3834,18 +3834,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
       Result != TemplateDeductionResult::Success)
     return Result;
 
-  // C++ [temp.deduct.call]p10: [DR1391]
-  //   If deduction succeeds for all parameters that contain
-  //   template-parameters that participate in template argument deduction,
-  //   and all template arguments are explicitly specified, deduced, or
-  //   obtained from default template arguments, remaining parameters are then
-  //   compared with the corresponding arguments. For each remaining parameter
-  //   P with a type that was non-dependent before substitution of any
-  //   explicitly-specified template arguments, if the corresponding argument
-  //   A cannot be implicitly converted to P, deduction fails.
-  if (CheckNonDependent())
-    return TemplateDeductionResult::NonDependentConversionFailure;
-
   // Form the template argument list from the deduced template arguments.
   TemplateArgumentList *SugaredDeducedArgumentList =
       TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
@@ -3875,6 +3863,76 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
     FD = const_cast<FunctionDecl *>(FDFriend);
     Owner = FD->getLexicalDeclContext();
   }
+#if 1
+  // FIXME: We have to partially instantiate lambda's captures for constraint
+  // evaluation.
+  if (!isLambdaCallOperator(FD) && !isLambdaConversionOperator(FD) &&
+      (!PartialOverloading ||
+       (CanonicalBuilder.size() ==
+        FunctionTemplate->getTemplateParameters()->size()))) {
+    FunctionTemplateDecl *Template = FunctionTemplate->getCanonicalDecl();
+    FunctionDecl *FD = Template->getTemplatedDecl();
+    SmallVector<const Expr *, 3> TemplateAC;
+    Template->getAssociatedConstraints(TemplateAC);
+    if (!TemplateAC.empty()) {
+
+      // Enter the scope of this instantiation. We don't use
+      // PushDeclContext because we don't have a scope.
+      LocalInstantiationScope Scope(*this);
+
+      // Collect the list of template arguments relative to the 'primary'
+      // template. We need the entire list, since the constraint is completely
+      // uninstantiated at this point.
+
+      MultiLevelTemplateArgumentList MLTAL(FD, SugaredBuilder, /*Final=*/false);
+      getTemplateInstantiationArgs(nullptr, FD->getLexicalDeclContext(),
+                                   /*Final=*/false,
+                                   /*Innermost=*/std::nullopt,
+                                   /*RelativeToPrimary=*/true,
+                                   /*Pattern=*/nullptr,
+                                   /*ForConstraintInstantiation=*/true,
+                                   /*SkipForSpecialization=*/false,
+                                   /*Merged=*/&MLTAL);
+
+      // if (SetupConstraintScope(FD, SugaredBuilder, MLTAL, Scope))
+      //   return TemplateDeductionResult::MiscellaneousDeductionFailure;
+
+      MultiLevelTemplateArgumentList JustTemplArgs(
+          Template, CanonicalDeducedArgumentList->asArray(),
+          /*Final=*/false);
+      if (addInstantiatedParametersToScope(nullptr, FD, Scope, JustTemplArgs))
+        return TemplateDeductionResult::MiscellaneousDeductionFailure;
+
+      if (FunctionTemplateDecl *FromMemTempl =
+              Template->getInstantiatedFromMemberTemplate()) {
+        while (FromMemTempl->getInstantiatedFromMemberTemplate())
+          FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
+        if (addInstantiatedParametersToScope(
+                nullptr, FromMemTempl->getTemplatedDecl(), Scope, MLTAL))
+          return TemplateDeductionResult::MiscellaneousDeductionFailure;
+      }
+
+      Qualifiers ThisQuals;
+      CXXRecordDecl *Record = nullptr;
+      if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+        ThisQuals = Method->getMethodQualifiers();
+        Record = Method->getParent();
+      }
+      CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+      llvm::SmallVector<Expr *, 1> Converted;
+      if (CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
+                                      Template->getSourceRange(),
+                                      Info.AssociatedConstraintsSatisfaction))
+        return TemplateDeductionResult::MiscellaneousDeductionFailure;
+      if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+        Info.reset(TemplateArgumentList::CreateCopy(Context, SugaredBuilder),
+                   Info.takeCanonical());
+        return TemplateDeductionResult::ConstraintsNotSatisfied;
+      }
+    }
+  }
+#endif
+
   MultiLevelTemplateArgumentList SubstArgs(
       FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
       /*Final=*/false);
@@ -3924,6 +3982,18 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
     }
   }
 
+  // C++ [temp.deduct.call]p10: [DR1391]
+  //   If deduction succeeds for all parameters that contain
+  //   template-parameters that participate in template argument deduction,
+  //   and all template arguments are explicitly specified, deduced, or
+  //   obtained from default template arguments, remaining parameters are then
+  //   compared with the corresponding arguments. For each remaining parameter
+  //   P with a type that was non-dependent before substitution of any
+  //   explicitly-specified template arguments, if the corresponding argument
+  //   A cannot be implicitly converted to P, deduction fails.
+  if (CheckNonDependent())
+    return TemplateDeductionResult::NonDependentConversionFailure;
+
   // We skipped the instantiation of the explicit-specifier during the
   // substitution of `FD` before. So, we try to instantiate it back if
   // `Specialization` is either a constructor or a conversion function.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index efae547b21c715..6a6ea8849badc8 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -468,10 +468,11 @@ 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 SkipForSpecialization, MultiLevelTemplateArgumentList *Merged) {
   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;
+  MultiLevelTemplateArgumentList Ret;
+  MultiLevelTemplateArgumentList &Result = Merged ? *Merged : Ret;
 
   using namespace TemplateInstArgsHelpers;
   const Decl *CurDecl = ND;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f93cd113988ae4..5a7cb294a1c86d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4577,17 +4577,17 @@ void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function,
   }
 }
 
-bool Sema::addInstantiatedParametersToScope(
-    FunctionDecl *Function, const FunctionDecl *PatternDecl,
-    LocalInstantiationScope &Scope,
+static bool addInstantiatedParametersToScope(
+    Sema &SemaRef, MutableArrayRef<ParmVarDecl *> InstantiatedParamDecls,
+    const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope,
     const MultiLevelTemplateArgumentList &TemplateArgs) {
   unsigned FParamIdx = 0;
   for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
     const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
     if (!PatternParam->isParameterPack()) {
       // Simple case: not a parameter pack.
-      assert(FParamIdx < Function->getNumParams());
-      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+      assert(FParamIdx < InstantiatedParamDecls.size());
+      ParmVarDecl *FunctionParam = InstantiatedParamDecls[FParamIdx];
       FunctionParam->setDeclName(PatternParam->getDeclName());
       // If the parameter's type is not dependent, update it to match the type
       // in the pattern. They can differ in top-level cv-qualifiers, and we want
@@ -4596,9 +4596,9 @@ bool Sema::addInstantiatedParametersToScope(
       // it's instantiation-dependent.
       // FIXME: Updating the type to work around this is at best fragile.
       if (!PatternDecl->getType()->isDependentType()) {
-        QualType T = SubstType(PatternParam->getType(), TemplateArgs,
-                               FunctionParam->getLocation(),
-                               FunctionParam->getDeclName());
+        QualType T = SemaRef.SubstType(PatternParam->getType(), TemplateArgs,
+                                       FunctionParam->getLocation(),
+                                       FunctionParam->getDeclName());
         if (T.isNull())
           return true;
         FunctionParam->setType(T);
@@ -4612,18 +4612,19 @@ bool Sema::addInstantiatedParametersToScope(
     // Expand the parameter pack.
     Scope.MakeInstantiatedLocalArgPack(PatternParam);
     std::optional<unsigned> NumArgumentsInExpansion =
-        getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
+        SemaRef.getNumArgumentsInExpansion(PatternParam->getType(),
+                                           TemplateArgs);
     if (NumArgumentsInExpansion) {
       QualType PatternType =
           PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
       for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
-        ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+        ParmVarDecl *FunctionParam = InstantiatedParamDecls[FParamIdx];
         FunctionParam->setDeclName(PatternParam->getDeclName());
         if (!PatternDecl->getType()->isDependentType()) {
-          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, Arg);
-          QualType T =
-              SubstType(PatternType, TemplateArgs, FunctionParam->getLocation(),
-                        FunctionParam->getDeclName());
+          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, Arg);
+          QualType T = SemaRef.SubstType(PatternType, TemplateArgs,
+                                         FunctionParam->getLocation(),
+                                         FunctionParam->getDeclName());
           if (T.isNull())
             return true;
           FunctionParam->setType(T);
@@ -4638,6 +4639,25 @@ bool Sema::addInstantiatedParametersToScope(
   return false;
 }
 
+bool Sema::addInstantiatedParametersToScope(
+    FunctionDecl *Function, const FunctionDecl *PatternDecl,
+    LocalInstantiationScope &Scope,
+    const MultiLevelTemplateArgumentList &TemplateArgs) {
+  if (Function)
+    return ::addInstantiatedParametersToScope(*this, Function->parameters(),
+                                              PatternDecl, Scope, TemplateArgs);
+  FunctionTypeLoc TypeLoc = PatternDecl->getFunctionTypeLoc();
+  assert(!TypeLoc.isNull() && "Invalid function TypeLoc?");
+  SmallVector<QualType> ParamTypes;
+  SmallVector<ParmVarDecl *> OutParams;
+  Sema::ExtParameterInfoBuilder ExtParamInfos;
+  if (SubstParmTypes(PatternDecl->getLocation(), TypeLoc.getParams(), nullptr,
+                     TemplateArgs, ParamTypes, &OutParams, ExtParamInfos))
+    return true;
+  return ::addInstantiatedParametersToScope(*this, OutParams, PatternDecl,
+                                            Scope, TemplateArgs);
+}
+
 bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());

>From 6b7072d713c163e0459fdd5493c25009f990ec09 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 12 Aug 2024 15:22:42 +0800
Subject: [PATCH 04/12] Rectify diagnostics

---
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 32 ++++++++-----------
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp |  8 +++--
 clang/test/CXX/drs/cwg23xx.cpp                | 32 +++++++++++++++++++
 clang/test/CXX/drs/cwg26xx.cpp                |  2 +-
 .../expr.prim.req/nested-requirement.cpp      |  2 +-
 .../constrant-satisfaction-conversions.cpp    |  6 ++--
 .../SemaCXX/concept-crash-on-diagnostic.cpp   |  2 +-
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  |  2 +-
 clang/test/SemaCXX/cxx23-assume.cpp           |  6 ++--
 clang/test/SemaCXX/cxx2c-fold-exprs.cpp       |  2 +-
 clang/test/SemaCXX/lambda-unevaluated.cpp     |  4 +--
 .../SemaTemplate/concepts-recursive-inst.cpp  |  4 +--
 .../SemaTemplate/cxx2a-constraint-exprs.cpp   |  2 +-
 clang/test/SemaTemplate/deduction-guide.cpp   |  5 ---
 .../nested-implicit-deduction-guides.cpp      |  8 +++--
 15 files changed, 72 insertions(+), 45 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9bb215fe66c5a6..1d475084afe846 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3863,7 +3863,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
     FD = const_cast<FunctionDecl *>(FDFriend);
     Owner = FD->getLexicalDeclContext();
   }
-#if 1
+  // [DR2369]
   // FIXME: We have to partially instantiate lambda's captures for constraint
   // evaluation.
   if (!isLambdaCallOperator(FD) && !isLambdaConversionOperator(FD) &&
@@ -3894,9 +3894,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
                                    /*SkipForSpecialization=*/false,
                                    /*Merged=*/&MLTAL);
 
-      // if (SetupConstraintScope(FD, SugaredBuilder, MLTAL, Scope))
-      //   return TemplateDeductionResult::MiscellaneousDeductionFailure;
-
       MultiLevelTemplateArgumentList JustTemplArgs(
           Template, CanonicalDeducedArgumentList->asArray(),
           /*Final=*/false);
@@ -3921,7 +3918,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
       CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
       llvm::SmallVector<Expr *, 1> Converted;
       if (CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
-                                      Template->getSourceRange(),
+                                      Info.getLocation(),
                                       Info.AssociatedConstraintsSatisfaction))
         return TemplateDeductionResult::MiscellaneousDeductionFailure;
       if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
@@ -3931,7 +3928,18 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
       }
     }
   }
-#endif
+
+  // C++ [temp.deduct.call]p10: [DR1391]
+  //   If deduction succeeds for all parameters that contain
+  //   template-parameters that participate in template argument deduction,
+  //   and all template arguments are explicitly specified, deduced, or
+  //   obtained from default template arguments, remaining parameters are then
+  //   compared with the corresponding arguments. For each remaining parameter
+  //   P with a type that was non-dependent before substitution of any
+  //   explicitly-specified template arguments, if the corresponding argument
+  //   A cannot be implicitly converted to P, deduction fails.
+  if (CheckNonDependent())
+    return TemplateDeductionResult::NonDependentConversionFailure;
 
   MultiLevelTemplateArgumentList SubstArgs(
       FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
@@ -3982,18 +3990,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
     }
   }
 
-  // C++ [temp.deduct.call]p10: [DR1391]
-  //   If deduction succeeds for all parameters that contain
-  //   template-parameters that participate in template argument deduction,
-  //   and all template arguments are explicitly specified, deduced, or
-  //   obtained from default template arguments, remaining parameters are then
-  //   compared with the corresponding arguments. For each remaining parameter
-  //   P with a type that was non-dependent before substitution of any
-  //   explicitly-specified template arguments, if the corresponding argument
-  //   A cannot be implicitly converted to P, deduction fails.
-  if (CheckNonDependent())
-    return TemplateDeductionResult::NonDependentConversionFailure;
-
   // We skipped the instantiation of the explicit-specifier during the
   // substitution of `FD` before. So, we try to instantiate it back if
   // `Specialization` is either a constructor or a conversion function.
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 545da21183c3c4..405a733550fd54 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -904,10 +904,12 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
       Context.getTrivialTypeSourceInfo(
           Context.getDeducedTemplateSpecializationType(
               TemplateName(AliasTemplate), /*DeducedType=*/QualType(),
-              /*IsDependent=*/true)), // template specialization type whose
-                                      // arguments will be deduced.
+              /*IsDependent=*/true),
+          AliasTemplate->getLocation()), // template specialization type whose
+                                         // arguments will be deduced.
       Context.getTrivialTypeSourceInfo(
-          ReturnType), // type from which template arguments are deduced.
+          ReturnType, AliasTemplate->getLocation()), // type from which template
+                                                     // arguments are deduced.
   };
   return TypeTraitExpr::Create(
       Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(),
diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp
index 77fd6a337436e3..4685f2fec2c749 100644
--- a/clang/test/CXX/drs/cwg23xx.cpp
+++ b/clang/test/CXX/drs/cwg23xx.cpp
@@ -491,3 +491,35 @@ namespace cwg2397 { // cwg2397: 17
 } // namespace cwg2397
 
 #endif
+
+#if __cplusplus >= 202002L
+
+namespace cwg2369 { // cwg2369: 20
+
+template <class T> struct Z {
+  typedef typename T::x xx;
+};
+
+template <class T>
+concept C = requires { typename T::A; };
+template <C T> typename Z<T>::xx f(void *, T); // #1
+template <class T> void f(int, T);             // #2
+
+struct A {
+} a;
+
+struct ZZ {
+  template <class T, class = typename Z<T>::xx> operator T *();
+  operator int();
+};
+
+void foo() {
+  ZZ zz;
+  f(1, a); // OK, deduction fails for #1 because there is no conversion from int
+           // to void*
+  f(zz, 42); // OK, deduction fails for #1 because C<int> is not satisfied
+}
+
+} // namespace cwg2369
+
+#endif
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 63a954c803b77a..35814ca9a26a39 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -319,7 +319,7 @@ void f(T) requires requires { []() { T::invalid; } (); };
 //   since-cxx20-note at -3 {{in instantiation of requirement here}}
 //   since-cxx20-note at -4 {{while substituting template arguments into constraint expression here}}
 //   since-cxx20-note@#cwg2672-f-0 {{while checking constraint satisfaction for template 'f<int>' required here}}
-//   since-cxx20-note@#cwg2672-f-0 {{in instantiation of function template specialization 'cwg2672::f<int>' requested here}}
+//   since-cxx20-note@#cwg2672-f-0 {{while substituting deduced template arguments into function template 'f' [with T = int]}}
 void f(...);
 
 template <class T>
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
index 763d983d20f615..a23f7dc595171e 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -154,7 +154,7 @@ void func() {
 
   bar<int>();
   // expected-note at -1 {{while checking constraint satisfaction for template 'bar<int>' required here}} \
-  // expected-note at -1 {{in instantiation of function template specialization}}
+  // expected-note at -1 {{while substituting deduced template arguments into function template 'bar' [with T = int]}}
   // expected-note@#bar {{in instantiation of static data member}}
   // expected-note@#bar {{in instantiation of requirement here}}
   // expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
index ba8e2dc372e984..c41de77986bcae 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
@@ -11,7 +11,7 @@ template<typename T> struct S {
 
 // expected-error at +3{{atomic constraint must be of type 'bool' (found 'S<int>')}}
 // expected-note@#FINST{{while checking constraint satisfaction}}
-// expected-note@#FINST{{in instantiation of function template specialization}}
+// expected-note@#FINST{{while substituting deduced template arguments into function template 'f' [with T = int]}}
 template<typename T> requires (S<T>{})
 void f(T);
 void f(int);
@@ -19,7 +19,7 @@ void f(int);
 // Ensure this applies to operator && as well.
 // expected-error at +3{{atomic constraint must be of type 'bool' (found 'S<int>')}}
 // expected-note@#F2INST{{while checking constraint satisfaction}}
-// expected-note@#F2INST{{in instantiation of function template specialization}}
+// expected-note@#F2INST{{while substituting deduced template arguments into function template 'f2' [with T = int]}}
 template<typename T> requires (S<T>{} && true)
 void f2(T);
 void f2(int);
@@ -32,7 +32,7 @@ template<typename T> requires requires {
   // expected-note at -4{{while checking the satisfaction}}
   // expected-note at -6{{while substituting template arguments}}
   // expected-note@#F3INST{{while checking constraint satisfaction}}
-  // expected-note@#F3INST{{in instantiation of function template specialization}}
+  // expected-note@#F3INST{{while substituting deduced template arguments into function template 'f3' [with T = int]}}
   //
 }
 void f3(T);
diff --git a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
index 71e55c8290ee4a..ccc109cbca0f19 100644
--- a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
+++ b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -31,7 +31,7 @@ void function() {
 // expected-note@#3 {{checking the satisfaction of concept 'convertible_to<bool, bool>'}}
 // expected-note@#2 {{substituting template arguments into constraint expression here}}
 // expected-note@#5 {{checking constraint satisfaction for template 'compare<Object *, Object *>'}}
-// expected-note@#5 {{in instantiation of function template specialization 'compare<Object *, Object *>' requested here}}
+// expected-note@#5 {{while substituting deduced template arguments into function template 'compare' [with IteratorL = Object *, IteratorR = Object *]}}
 
 // expected-note@#4 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
 // We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 5392573fcdb9d5..dff7f611635582 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -196,7 +196,7 @@ struct Foo {
 
 template <int K>
 using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
-// expected-note at -1 {{candidate template ignored: could not match}}
+// expected-note at -1 {{candidate template ignored: could not match}} expected-note at -1 {{candidate template ignored: constraints not satisfied}}
 // expected-note at -2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(Foo<double, K>) -> Foo<double, K>'}}
 // expected-note at -3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(const double (&)[K]) -> Foo<double, K>'}}
 double abc[3];
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index 9138501d726dd6..35971a58331ff3 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -127,12 +127,12 @@ constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while che
 
 static_assert(f5<int>() == 1);
 static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
-                             // expected-note at -1 3 {{in instantiation of}}
+                             // expected-note at -1 3 {{while substituting deduced template arguments}}
                              // expected-error at -2 {{no matching function for call}}
 
 static_assert(f5<double>() == 2);
-static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
-static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
+static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{while substituting deduced template arguments}}
+static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{while substituting deduced template arguments}}
 
 // Do not validate assumptions whose evaluation would have side-effects.
 constexpr int foo() {
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 0674135aac483f..70644e3aef8a71 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -233,7 +233,7 @@ void g() {
     A<Thingy, Thingy> *ap;
     f(ap, ap); // expected-error{{no matching function for call to 'f'}} \
                // expected-note {{while checking constraint satisfaction}} \
-               // expected-note {{in instantiation of function template specialization}}
+               // expected-note {{while substituting deduced template arguments}}
 }
 
 }
diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 39ee89bc797f84..242d1fc0c1219d 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -172,7 +172,7 @@ int* func(T) requires requires { []() { T::foo(); }; }; // expected-error{{type
 double* func(...);
 
 static_assert(__is_same(decltype(func(0)), double*)); // expected-note {{while checking constraint satisfaction for template 'func<int>' required here}}
-                                                      // expected-note at -1 {{in instantiation of function template specialization 'lambda_in_constraints::func<int>'}}
+                                                      // expected-note at -1 {{while substituting deduced template arguments into function template 'func' [with T = int]}}
 static_assert(__is_same(decltype(func(WithFoo())), int*));
 
 template <class T>
@@ -250,7 +250,7 @@ S s("a"); // #use
 // expected-note@#S-requires {{substituting template arguments into constraint expression here}}
 // expected-note@#S-requires {{in instantiation of requirement here}}
 // expected-note@#use {{checking constraint satisfaction for template 'S<const char *>' required here}}
-// expected-note@#use {{requested here}}
+// expected-note@#use {{while substituting deduced template arguments into function template 'S' [with value:auto = const char *]}}
 // expected-note-re@#S 2{{candidate constructor {{.*}} not viable}}
 // expected-note@#S-ctor {{constraints not satisfied}}
 // expected-note-re@#S-requires {{because {{.*}} would be invalid}}
diff --git a/clang/test/SemaTemplate/concepts-recursive-inst.cpp b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
index 9330df8cdd0398..30a410cef91ee9 100644
--- a/clang/test/SemaTemplate/concepts-recursive-inst.cpp
+++ b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
@@ -76,7 +76,7 @@ auto it = begin(rng); // #BEGIN_CALL
 // expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
 // expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
 // expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
-// expected-note@#BEGIN_CALL {{in instantiation of function template specialization}}
+// expected-note@#BEGIN_CALL {{while substituting deduced template arguments into function template}}
 
 // Fallout of the failure is failed lookup, which is necessary to stop odd
 // cascading errors.
@@ -103,7 +103,7 @@ namespace GH50891 {
   // expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
   // expected-note@#OP_TO {{while substituting template arguments into constraint expression here}}
   // expected-note@#FOO_CALL {{while checking constraint satisfaction for template}}
-  // expected-note@#FOO_CALL {{in instantiation of function template specialization}}
+  // expected-note@#FOO_CALL {{while substituting deduced template arguments into function template}}
   // expected-note@#FOO_CALL {{in instantiation of requirement here}}
   // expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
 
diff --git a/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp b/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp
index f4403587a62594..5809ef684bbf3b 100644
--- a/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp
+++ b/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp
@@ -34,7 +34,7 @@ namespace constant_evaluated {
      expected-note at -1{{candidate template ignored}}
   int a = (foo<int>(), 0);
   // expected-note at -1 {{while checking}} expected-error at -1{{no matching function}} \
-     expected-note at -1 {{in instantiation}}
+     expected-note at -1 {{while substituting}}
   template<typename T> void bar() requires requires { requires f<int[2]>; } { };
   // expected-note at -1{{in instantiation}} \
      expected-note at -1{{while substituting}} \
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index d03c783313dd71..67d00bb49f77d7 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -234,11 +234,6 @@ F s(0);
 // CHECK: | `-CXXBoolLiteralExpr {{.*}} 'bool' false
 // CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (U) -> F<>'
 // CHECK: | `-ParmVarDecl {{.*}} 'U'
-// CHECK: `-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (int) -> F<>'
-// CHECK:   |-TemplateArgument integral ''x''
-// CHECK:   |-TemplateArgument type 'int'
-// CHECK:   | `-BuiltinType {{.*}} 'int'
-// CHECK:   `-ParmVarDecl {{.*}} 'int'
 // CHECK: FunctionProtoType {{.*}} 'auto (U) -> F<>' dependent trailing_return cdecl
 // CHECK: |-InjectedClassNameType {{.*}} 'F<>' dependent
 // CHECK: | `-CXXRecord {{.*}} 'F'
diff --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
index af3e3358f61382..5c7a90273d0e0f 100644
--- a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
@@ -38,7 +38,7 @@ template<typename A, typename T>
 concept True = true;
 
 template<typename T>
-concept False = false;
+concept False = false; // #False
 
 template<class X> struct concepts {
     template<class Y> struct B {
@@ -68,7 +68,7 @@ template<typename X> struct nested_init_list {
         Y y;
     };
 
-    template<False F>
+    template<False F>  // #INIT_LIST_INNER_INVALID_HEADER
     struct concept_fail { // #INIT_LIST_INNER_INVALID
         X x;
         F f;
@@ -81,7 +81,9 @@ using NIL = nested_init_list<int>::B<int>;
 
 // expected-error at +1 {{no viable constructor or deduction guide for deduction of template arguments of 'nested_init_list<int>::concept_fail'}}
 nested_init_list<int>::concept_fail nil_invalid{1, ""};
-// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
+// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: constraints not satisfied [with F = const char *]}}
+// expected-note@#INIT_LIST_INNER_INVALID_HEADER {{because 'const char *' does not satisfy 'False'}}
+// expected-note@#False {{because 'false' evaluated to false}}
 // expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(int, F) -> concept_fail<F>'}}
 // expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
 // expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(concept_fail<F>) -> concept_fail<F>'}}

>From bb31d36a92fb821d551ea8465941b93f590af00f Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 12 Aug 2024 23:34:33 +0800
Subject: [PATCH 05/12] Instantiate function parameters as needed

---
 clang/include/clang/Sema/Sema.h               |   5 +
 clang/lib/Sema/SemaConcept.cpp                | 137 ++++++++++++++++++
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  82 +++--------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  53 +++----
 clang/lib/Sema/TreeTransform.h                |   2 +-
 libcxx/include/__chrono/leap_second.h         |   2 +-
 6 files changed, 179 insertions(+), 102 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 48901ded906ee8..33eff47a8707bf 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14450,6 +14450,11 @@ class Sema final : public SemaBase {
       ArrayRef<TemplateArgument> TemplateArgs,
       ConstraintSatisfaction &Satisfaction);
 
+  bool CheckFunctionConstraintsWithoutInstantiation(
+      SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
+      ArrayRef<TemplateArgument> TemplateArgs,
+      ConstraintSatisfaction &Satisfaction);
+
   /// \brief Emit diagnostics explaining why a constraint expression was deemed
   /// unsatisfied.
   /// \param First whether this is the first time an unsatisfied constraint is
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 79057e0e3e8138..ad17d714037ed0 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -461,13 +461,17 @@ static ExprResult calculateConstraintSatisfaction(
           return ExprError();
 
         llvm::FoldingSetNodeID ID;
+        // llvm::errs() << "Preparing for checking " << Template << "\n";
         if (Template &&
             DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
+          // Template->dump();
           Satisfaction.IsSatisfied = false;
           Satisfaction.ContainsErrors = true;
+          // __builtin_trap();
           return ExprEmpty();
         }
 
+        // llvm::errs() << "Pushing " << Template << "\n";
         SatisfactionStackRAII StackRAII(S, Template, ID);
 
         // We do not want error diagnostics escaping here.
@@ -1122,6 +1126,139 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
                                      PointOfInstantiation, Satisfaction);
 }
 
+namespace {
+
+// We employ a TreeTransform because RAV couldn't recurse into a bunch of
+// Exprs e.g. SizeOfPackExpr, CXXFoldExpr, etc.
+// FIXME: Could we do the Decl instantiation as we substitute into
+// the constraint expressions?
+class InstantiateReferencedParameter
+    : public TreeTransform<InstantiateReferencedParameter> {
+  const MultiLevelTemplateArgumentList &TemplateArgs;
+
+  DeclContext *FunctionDC;
+
+  using inherited = TreeTransform<InstantiateReferencedParameter>;
+
+  bool instantiateParameterToScope(ParmVarDecl *OldParm,
+                                   LocalInstantiationScope &Scope) {
+    // Current context might have been changed by lambda expressions. So resume
+    // it before we substitute parameters.
+    Sema::ContextRAII Context(SemaRef, FunctionDC);
+    std::optional<unsigned> NumExpansions;
+    ParmVarDecl *NewParm = nullptr;
+    unsigned IndexAdjustment = 0;
+    if (OldParm->isParameterPack()) {
+      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+      TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
+      PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
+      TypeLoc Pattern = ExpansionTL.getPatternLoc();
+      SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+
+      assert(!Unexpanded.empty() &&
+             "A pack Decl doesn't contain anything unexpanded?");
+
+      bool ShouldExpand = false;
+      bool RetainExpansion = false;
+      std::optional<unsigned> OrigNumExpansions =
+          ExpansionTL.getTypePtr()->getNumExpansions();
+      NumExpansions = OrigNumExpansions;
+      if (SemaRef.CheckParameterPacksForExpansion(
+              ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(),
+              Unexpanded, TemplateArgs, ShouldExpand, RetainExpansion,
+              NumExpansions))
+        return true;
+
+      assert(ShouldExpand && !RetainExpansion &&
+             "Shouldn't retain an expansion here!");
+      Scope.MakeInstantiatedLocalArgPack(OldParm);
+
+      for (unsigned I = 0; I != *NumExpansions; ++I) {
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
+        ParmVarDecl *NewParm = SemaRef.SubstParmVarDecl(
+            OldParm, TemplateArgs, /*indexAdjustment=*/IndexAdjustment++,
+            NumExpansions, /*ExpectParameterPack=*/false,
+            /*EvaluateConstraints=*/false);
+        if (!NewParm)
+          return true;
+      }
+
+      return false;
+    }
+    NewParm = SemaRef.SubstParmVarDecl(OldParm, TemplateArgs,
+                                       /*indexAdjustment=*/IndexAdjustment,
+                                       std::nullopt,
+                                       /*ExpectParameterPack=*/false);
+    if (!NewParm)
+      return true;
+    Scope.InstantiatedLocal(OldParm, NewParm);
+    return false;
+  }
+
+public:
+  InstantiateReferencedParameter(
+      Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs,
+      DeclContext *FunctionDC)
+      : inherited(SemaRef), TemplateArgs(TemplateArgs), FunctionDC(FunctionDC) {
+  }
+
+  Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+    if (auto *PVD = dyn_cast<ParmVarDecl>(D))
+      instantiateParameterToScope(PVD, *SemaRef.CurrentInstantiationScope);
+    return D;
+  }
+
+  void TraverseConstraintExprs(ArrayRef<const Expr *> Exprs) {
+    for (auto *E : Exprs)
+      TransformExpr(const_cast<Expr *>(E));
+  }
+};
+
+} // namespace
+
+bool Sema::CheckFunctionConstraintsWithoutInstantiation(
+    SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
+    ArrayRef<TemplateArgument> TemplateArgs,
+    ConstraintSatisfaction &Satisfaction) {
+  FunctionDecl *FD = Template->getTemplatedDecl();
+  SmallVector<const Expr *, 3> TemplateAC;
+  Template->getAssociatedConstraints(TemplateAC);
+  if (TemplateAC.empty()) {
+    Satisfaction.IsSatisfied = true;
+    return false;
+  }
+
+  // Enter the scope of this instantiation. We don't use
+  // PushDeclContext because we don't have a scope.
+  LocalInstantiationScope Scope(*this);
+
+  // Collect the list of template arguments relative to the 'primary'
+  // template. We need the entire list, since the constraint is completely
+  // uninstantiated at this point.
+  DeclContext *NextDC = FD->getFriendObjectKind() ? FD->getLexicalDeclContext()
+                                                  : FD->getDeclContext();
+  MultiLevelTemplateArgumentList MLTAL =
+      getTemplateInstantiationArgs(FD, NextDC,
+                                   /*Final=*/false,
+                                   /*Innermost=*/TemplateArgs,
+                                   /*RelativeToPrimary=*/true,
+                                   /*Pattern=*/nullptr,
+                                   /*ForConstraintInstantiation=*/true);
+
+  InstantiateReferencedParameter(*this, MLTAL, FD)
+      .TraverseConstraintExprs(TemplateAC);
+
+  Qualifiers ThisQuals;
+  CXXRecordDecl *Record = nullptr;
+  if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+    ThisQuals = Method->getMethodQualifiers();
+    Record = Method->getParent();
+  }
+  CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+  return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
+                                     PointOfInstantiation, Satisfaction);
+}
+
 static void diagnoseUnsatisfiedRequirement(Sema &S,
                                            concepts::ExprRequirement *Req,
                                            bool First) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1d475084afe846..f1883882edc804 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3863,72 +3863,28 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
     FD = const_cast<FunctionDecl *>(FDFriend);
     Owner = FD->getLexicalDeclContext();
   }
+
   // [DR2369]
   // FIXME: We have to partially instantiate lambda's captures for constraint
   // evaluation.
-  if (!isLambdaCallOperator(FD) && !isLambdaConversionOperator(FD) &&
-      (!PartialOverloading ||
-       (CanonicalBuilder.size() ==
-        FunctionTemplate->getTemplateParameters()->size()))) {
-    FunctionTemplateDecl *Template = FunctionTemplate->getCanonicalDecl();
-    FunctionDecl *FD = Template->getTemplatedDecl();
-    SmallVector<const Expr *, 3> TemplateAC;
-    Template->getAssociatedConstraints(TemplateAC);
-    if (!TemplateAC.empty()) {
-
-      // Enter the scope of this instantiation. We don't use
-      // PushDeclContext because we don't have a scope.
-      LocalInstantiationScope Scope(*this);
-
-      // Collect the list of template arguments relative to the 'primary'
-      // template. We need the entire list, since the constraint is completely
-      // uninstantiated at this point.
-
-      MultiLevelTemplateArgumentList MLTAL(FD, SugaredBuilder, /*Final=*/false);
-      getTemplateInstantiationArgs(nullptr, FD->getLexicalDeclContext(),
-                                   /*Final=*/false,
-                                   /*Innermost=*/std::nullopt,
-                                   /*RelativeToPrimary=*/true,
-                                   /*Pattern=*/nullptr,
-                                   /*ForConstraintInstantiation=*/true,
-                                   /*SkipForSpecialization=*/false,
-                                   /*Merged=*/&MLTAL);
-
-      MultiLevelTemplateArgumentList JustTemplArgs(
-          Template, CanonicalDeducedArgumentList->asArray(),
-          /*Final=*/false);
-      if (addInstantiatedParametersToScope(nullptr, FD, Scope, JustTemplArgs))
-        return TemplateDeductionResult::MiscellaneousDeductionFailure;
-
-      if (FunctionTemplateDecl *FromMemTempl =
-              Template->getInstantiatedFromMemberTemplate()) {
-        while (FromMemTempl->getInstantiatedFromMemberTemplate())
-          FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
-        if (addInstantiatedParametersToScope(
-                nullptr, FromMemTempl->getTemplatedDecl(), Scope, MLTAL))
-          return TemplateDeductionResult::MiscellaneousDeductionFailure;
-      }
-
-      Qualifiers ThisQuals;
-      CXXRecordDecl *Record = nullptr;
-      if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
-        ThisQuals = Method->getMethodQualifiers();
-        Record = Method->getParent();
-      }
-      CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
-      llvm::SmallVector<Expr *, 1> Converted;
-      if (CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
-                                      Info.getLocation(),
-                                      Info.AssociatedConstraintsSatisfaction))
-        return TemplateDeductionResult::MiscellaneousDeductionFailure;
-      if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
-        Info.reset(TemplateArgumentList::CreateCopy(Context, SugaredBuilder),
-                   Info.takeCanonical());
-        return TemplateDeductionResult::ConstraintsNotSatisfied;
-      }
+  bool NeedConstraintChecking =
+      !PartialOverloading ||
+      CanonicalBuilder.size() ==
+          FunctionTemplate->getTemplateParameters()->size();
+  bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
+#if 1
+  if (!IsLambda && NeedConstraintChecking) {
+    if (CheckFunctionConstraintsWithoutInstantiation(
+            Info.getLocation(), FunctionTemplate->getCanonicalDecl(),
+            CanonicalBuilder, Info.AssociatedConstraintsSatisfaction))
+      return TemplateDeductionResult::MiscellaneousDeductionFailure;
+    if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+      Info.reset(Info.takeSugared(),
+                 TemplateArgumentList::CreateCopy(Context, CanonicalBuilder));
+      return TemplateDeductionResult::ConstraintsNotSatisfied;
     }
   }
-
+#endif
   // C++ [temp.deduct.call]p10: [DR1391]
   //   If deduction succeeds for all parameters that contain
   //   template-parameters that participate in template argument deduction,
@@ -3975,9 +3931,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   //   ([temp.constr.decl]), those constraints are checked for satisfaction
   //   ([temp.constr.constr]). If the constraints are not satisfied, type
   //   deduction fails.
-  if (!PartialOverloading ||
-      (CanonicalBuilder.size() ==
-       FunctionTemplate->getTemplateParameters()->size())) {
+  if (IsLambda && NeedConstraintChecking) {
     if (CheckInstantiatedFunctionTemplateConstraints(
             Info.getLocation(), Specialization, CanonicalBuilder,
             Info.AssociatedConstraintsSatisfaction))
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5a7cb294a1c86d..86a916cc3fc373 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -34,6 +34,7 @@
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/TimeProfiler.h"
 #include <optional>
 
@@ -2136,7 +2137,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     return nullptr;
   QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
 
-  if (TemplateParams && TemplateParams->size()) {
+  if (false && TemplateParams && TemplateParams->size()) {
     auto *LastParam =
         dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
     if (LastParam && LastParam->isImplicit() &&
@@ -2548,7 +2549,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
     return nullptr;
   QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
 
-  if (TemplateParams && TemplateParams->size()) {
+  if (false && TemplateParams && TemplateParams->size()) {
     auto *LastParam =
         dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
     if (LastParam && LastParam->isImplicit() &&
@@ -4577,17 +4578,17 @@ void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function,
   }
 }
 
-static bool addInstantiatedParametersToScope(
-    Sema &SemaRef, MutableArrayRef<ParmVarDecl *> InstantiatedParamDecls,
-    const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope,
+bool Sema::addInstantiatedParametersToScope(
+    FunctionDecl *Function, const FunctionDecl *PatternDecl,
+    LocalInstantiationScope &Scope,
     const MultiLevelTemplateArgumentList &TemplateArgs) {
   unsigned FParamIdx = 0;
   for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
     const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
     if (!PatternParam->isParameterPack()) {
       // Simple case: not a parameter pack.
-      assert(FParamIdx < InstantiatedParamDecls.size());
-      ParmVarDecl *FunctionParam = InstantiatedParamDecls[FParamIdx];
+      assert(FParamIdx < Function->getNumParams());
+      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
       FunctionParam->setDeclName(PatternParam->getDeclName());
       // If the parameter's type is not dependent, update it to match the type
       // in the pattern. They can differ in top-level cv-qualifiers, and we want
@@ -4596,9 +4597,9 @@ static bool addInstantiatedParametersToScope(
       // it's instantiation-dependent.
       // FIXME: Updating the type to work around this is at best fragile.
       if (!PatternDecl->getType()->isDependentType()) {
-        QualType T = SemaRef.SubstType(PatternParam->getType(), TemplateArgs,
-                                       FunctionParam->getLocation(),
-                                       FunctionParam->getDeclName());
+        QualType T = SubstType(PatternParam->getType(), TemplateArgs,
+                               FunctionParam->getLocation(),
+                               FunctionParam->getDeclName());
         if (T.isNull())
           return true;
         FunctionParam->setType(T);
@@ -4612,19 +4613,18 @@ static bool addInstantiatedParametersToScope(
     // Expand the parameter pack.
     Scope.MakeInstantiatedLocalArgPack(PatternParam);
     std::optional<unsigned> NumArgumentsInExpansion =
-        SemaRef.getNumArgumentsInExpansion(PatternParam->getType(),
-                                           TemplateArgs);
+        getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
     if (NumArgumentsInExpansion) {
       QualType PatternType =
           PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
       for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
-        ParmVarDecl *FunctionParam = InstantiatedParamDecls[FParamIdx];
+        ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
         FunctionParam->setDeclName(PatternParam->getDeclName());
         if (!PatternDecl->getType()->isDependentType()) {
-          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, Arg);
-          QualType T = SemaRef.SubstType(PatternType, TemplateArgs,
-                                         FunctionParam->getLocation(),
-                                         FunctionParam->getDeclName());
+          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, Arg);
+          QualType T =
+              SubstType(PatternType, TemplateArgs, FunctionParam->getLocation(),
+                        FunctionParam->getDeclName());
           if (T.isNull())
             return true;
           FunctionParam->setType(T);
@@ -4639,25 +4639,6 @@ static bool addInstantiatedParametersToScope(
   return false;
 }
 
-bool Sema::addInstantiatedParametersToScope(
-    FunctionDecl *Function, const FunctionDecl *PatternDecl,
-    LocalInstantiationScope &Scope,
-    const MultiLevelTemplateArgumentList &TemplateArgs) {
-  if (Function)
-    return ::addInstantiatedParametersToScope(*this, Function->parameters(),
-                                              PatternDecl, Scope, TemplateArgs);
-  FunctionTypeLoc TypeLoc = PatternDecl->getFunctionTypeLoc();
-  assert(!TypeLoc.isNull() && "Invalid function TypeLoc?");
-  SmallVector<QualType> ParamTypes;
-  SmallVector<ParmVarDecl *> OutParams;
-  Sema::ExtParameterInfoBuilder ExtParamInfos;
-  if (SubstParmTypes(PatternDecl->getLocation(), TypeLoc.getParams(), nullptr,
-                     TemplateArgs, ParamTypes, &OutParams, ExtParamInfos))
-    return true;
-  return ::addInstantiatedParametersToScope(*this, OutParams, PatternDecl,
-                                            Scope, TemplateArgs);
-}
-
 bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
                                       ParmVarDecl *Param) {
   assert(Param->hasUninstantiatedDefaultArg());
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 62287c2d26375c..5a9fc5ba6bc127 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -713,7 +713,7 @@ class TreeTransform {
   /// variables vector are acceptable.
   ///
   /// LastParamTransformed, if non-null, will be set to the index of the last
-  /// parameter on which transfromation was started. In the event of an error,
+  /// parameter on which transformation was started. In the event of an error,
   /// this will contain the parameter which failed to instantiate.
   ///
   /// Return true on error.
diff --git a/libcxx/include/__chrono/leap_second.h b/libcxx/include/__chrono/leap_second.h
index 1a0e7f3107de81..4e7f208acd3409 100644
--- a/libcxx/include/__chrono/leap_second.h
+++ b/libcxx/include/__chrono/leap_second.h
@@ -105,7 +105,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const sys_time<_Duration>& __x,
   return !(__x < __y);
 }
 
-#    ifndef _LIBCPP_COMPILER_GCC
+#    if 0
 // This requirement cause a compilation loop in GCC-13 and running out of memory.
 // TODO TZDB Test whether GCC-14 fixes this.
 template <class _Duration>

>From 631be750f4d80b766608457da7334eddddbd788b Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 17 Aug 2024 22:27:50 +0800
Subject: [PATCH 06/12] Remove debugging logs

---
 clang/lib/Sema/SemaConcept.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ad17d714037ed0..7c61606e5d83f5 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -461,17 +461,13 @@ static ExprResult calculateConstraintSatisfaction(
           return ExprError();
 
         llvm::FoldingSetNodeID ID;
-        // llvm::errs() << "Preparing for checking " << Template << "\n";
         if (Template &&
             DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
-          // Template->dump();
           Satisfaction.IsSatisfied = false;
           Satisfaction.ContainsErrors = true;
-          // __builtin_trap();
           return ExprEmpty();
         }
 
-        // llvm::errs() << "Pushing " << Template << "\n";
         SatisfactionStackRAII StackRAII(S, Template, ID);
 
         // We do not want error diagnostics escaping here.

>From 7d484e22555c46de9c820001311763a5df9ffb45 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 17 Aug 2024 22:30:09 +0800
Subject: [PATCH 07/12] Revert unrelated changes

---
 clang/include/clang/Sema/Sema.h            | 3 +--
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 ++---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 33eff47a8707bf..0c94ebfbe91c32 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13064,8 +13064,7 @@ class Sema final : public SemaBase {
       std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
       bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
       bool ForConstraintInstantiation = false,
-      bool SkipForSpecialization = false,
-      MultiLevelTemplateArgumentList *Merged = nullptr);
+      bool SkipForSpecialization = false);
 
   /// RAII object to handle the state changes required to synthesize
   /// a function body.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 6a6ea8849badc8..efae547b21c715 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -468,11 +468,10 @@ 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, MultiLevelTemplateArgumentList *Merged) {
+    bool SkipForSpecialization) {
   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 Ret;
-  MultiLevelTemplateArgumentList &Result = Merged ? *Merged : Ret;
+  MultiLevelTemplateArgumentList Result;
 
   using namespace TemplateInstArgsHelpers;
   const Decl *CurDecl = ND;

>From c5154079b9c41e841d0225fc4b2d77f5f6e7b2ea Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 17 Aug 2024 23:50:42 +0800
Subject: [PATCH 08/12] Fix tests

---
 clang/lib/Sema/SemaConcept.cpp | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 7c61606e5d83f5..a4cfd02caa014e 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1132,15 +1132,17 @@ class InstantiateReferencedParameter
     : public TreeTransform<InstantiateReferencedParameter> {
   const MultiLevelTemplateArgumentList &TemplateArgs;
 
-  DeclContext *FunctionDC;
+  llvm::SmallPtrSet<ParmVarDecl *, 4> InstantiatedDecls;
+
+  FunctionDecl *PrimaryTemplatedFunction;
 
   using inherited = TreeTransform<InstantiateReferencedParameter>;
 
   bool instantiateParameterToScope(ParmVarDecl *OldParm,
                                    LocalInstantiationScope &Scope) {
-    // Current context might have been changed by lambda expressions. So resume
-    // it before we substitute parameters.
-    Sema::ContextRAII Context(SemaRef, FunctionDC);
+    // The current context might have been changed by lambda expressions. So
+    // resume it before we substitute into parameters.
+    Sema::ContextRAII Context(SemaRef, PrimaryTemplatedFunction);
     std::optional<unsigned> NumExpansions;
     ParmVarDecl *NewParm = nullptr;
     unsigned IndexAdjustment = 0;
@@ -1194,13 +1196,17 @@ class InstantiateReferencedParameter
 public:
   InstantiateReferencedParameter(
       Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs,
-      DeclContext *FunctionDC)
-      : inherited(SemaRef), TemplateArgs(TemplateArgs), FunctionDC(FunctionDC) {
-  }
+      FunctionDecl *PrimaryTemplatedFunction)
+      : inherited(SemaRef), TemplateArgs(TemplateArgs),
+        PrimaryTemplatedFunction(PrimaryTemplatedFunction) {}
 
   Decl *TransformDecl(SourceLocation Loc, Decl *D) {
-    if (auto *PVD = dyn_cast<ParmVarDecl>(D))
+    if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(D);
+        PVD && PVD->getDeclContext() == PrimaryTemplatedFunction &&
+        !InstantiatedDecls.contains(PVD)) {
       instantiateParameterToScope(PVD, *SemaRef.CurrentInstantiationScope);
+      InstantiatedDecls.insert(PVD);
+    }
     return D;
   }
 
@@ -1241,7 +1247,16 @@ bool Sema::CheckFunctionConstraintsWithoutInstantiation(
                                    /*Pattern=*/nullptr,
                                    /*ForConstraintInstantiation=*/true);
 
-  InstantiateReferencedParameter(*this, MLTAL, FD)
+  FunctionDecl *PatternDecl = FD;
+
+  if (FunctionTemplateDecl *FromMemTempl =
+          Template->getInstantiatedFromMemberTemplate()) {
+    while (FromMemTempl->getInstantiatedFromMemberTemplate())
+      FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
+    PatternDecl = FromMemTempl->getTemplatedDecl();
+  }
+
+  InstantiateReferencedParameter(*this, MLTAL, PatternDecl)
       .TraverseConstraintExprs(TemplateAC);
 
   Qualifiers ThisQuals;

>From a9da5a3e53e0900aa60addb4eaefc213a96836cc Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 18 Aug 2024 00:30:32 +0800
Subject: [PATCH 09/12] Fix libcxx tests

---
 libcxx/include/__chrono/leap_second.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__chrono/leap_second.h b/libcxx/include/__chrono/leap_second.h
index 4e7f208acd3409..a439f3f5c6cc62 100644
--- a/libcxx/include/__chrono/leap_second.h
+++ b/libcxx/include/__chrono/leap_second.h
@@ -105,11 +105,11 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const sys_time<_Duration>& __x,
   return !(__x < __y);
 }
 
-#    if 0
+#    ifndef _LIBCPP_COMPILER_GCC
 // This requirement cause a compilation loop in GCC-13 and running out of memory.
 // TODO TZDB Test whether GCC-14 fixes this.
 template <class _Duration>
-  requires three_way_comparable_with<sys_seconds, sys_time<_Duration>>
+  requires(same_as<seconds, _Duration> || three_way_comparable_with<sys_seconds, sys_time<_Duration>>)
 _LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const leap_second& __x, const sys_time<_Duration>& __y) {
   return __x.date() <=> __y;
 }

>From cebe7063174a12dfedbe28185b7173b8826093ab Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 18 Aug 2024 18:41:08 +0800
Subject: [PATCH 10/12] Instantiate the decls as we substituting constraints

---
 clang/include/clang/Sema/Sema.h            |   4 +-
 clang/include/clang/Sema/Template.h        |   3 +
 clang/lib/Sema/SemaConcept.cpp             | 126 +++-----------------
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 129 +++++++++++++++++++--
 4 files changed, 141 insertions(+), 121 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0c94ebfbe91c32..0f186ac6aecccb 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13329,7 +13329,9 @@ class Sema final : public SemaBase {
   // Must be used instead of SubstExpr at 'constraint checking' time.
   ExprResult
   SubstConstraintExpr(Expr *E,
-                      const MultiLevelTemplateArgumentList &TemplateArgs);
+                      const MultiLevelTemplateArgumentList &TemplateArgs,
+                      DeclContext *InstantiatingFunctionDC = nullptr);
+
   // Unlike the above, this does not evaluates constraints.
   ExprResult SubstConstraintExprWithoutSatisfaction(
       Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs);
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 0340c23fd170d6..5de4bf0148652c 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -515,6 +515,9 @@ enum class TemplateSubstitutionKind : char {
     llvm::PointerUnion<Decl *, DeclArgumentPack *> *
     findInstantiationOf(const Decl *D);
 
+    llvm::PointerUnion<Decl *, DeclArgumentPack *> *
+    findInstantiationUnsafe(const Decl *D);
+
     void InstantiatedLocal(const Decl *D, Decl *Inst);
     void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst);
     void MakeInstantiatedLocalArgPack(const Decl *D);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index a4cfd02caa014e..99c1b4a6998544 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -470,10 +470,27 @@ static ExprResult calculateConstraintSatisfaction(
 
         SatisfactionStackRAII StackRAII(S, Template, ID);
 
+        DeclContext *FunctionDC = nullptr;
+        if (auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(Template)) {
+          FunctionDecl *FD = FTD->getTemplatedDecl();
+          FunctionDC = FD;
+          // The function has been instantiated. Don't bother to instantiate its
+          // parameters then.
+          if (FD->getTemplateInstantiationPattern(/*ForDefinition=*/false))
+            FunctionDC = nullptr;
+          else if (FunctionTemplateDecl *FromMemTempl =
+                       FTD->getInstantiatedFromMemberTemplate()) {
+            while (FromMemTempl->getInstantiatedFromMemberTemplate())
+              FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
+            FunctionDC = FromMemTempl->getTemplatedDecl();
+          }
+        }
+
         // We do not want error diagnostics escaping here.
         Sema::SFINAETrap Trap(S);
         SubstitutedExpression =
-            S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
+            S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL,
+                                  /*InstantiatingFunctionDC=*/FunctionDC);
 
         if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
           // C++2a [temp.constr.atomic]p1
@@ -1122,102 +1139,6 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
                                      PointOfInstantiation, Satisfaction);
 }
 
-namespace {
-
-// We employ a TreeTransform because RAV couldn't recurse into a bunch of
-// Exprs e.g. SizeOfPackExpr, CXXFoldExpr, etc.
-// FIXME: Could we do the Decl instantiation as we substitute into
-// the constraint expressions?
-class InstantiateReferencedParameter
-    : public TreeTransform<InstantiateReferencedParameter> {
-  const MultiLevelTemplateArgumentList &TemplateArgs;
-
-  llvm::SmallPtrSet<ParmVarDecl *, 4> InstantiatedDecls;
-
-  FunctionDecl *PrimaryTemplatedFunction;
-
-  using inherited = TreeTransform<InstantiateReferencedParameter>;
-
-  bool instantiateParameterToScope(ParmVarDecl *OldParm,
-                                   LocalInstantiationScope &Scope) {
-    // The current context might have been changed by lambda expressions. So
-    // resume it before we substitute into parameters.
-    Sema::ContextRAII Context(SemaRef, PrimaryTemplatedFunction);
-    std::optional<unsigned> NumExpansions;
-    ParmVarDecl *NewParm = nullptr;
-    unsigned IndexAdjustment = 0;
-    if (OldParm->isParameterPack()) {
-      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-      TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
-      PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
-      TypeLoc Pattern = ExpansionTL.getPatternLoc();
-      SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
-
-      assert(!Unexpanded.empty() &&
-             "A pack Decl doesn't contain anything unexpanded?");
-
-      bool ShouldExpand = false;
-      bool RetainExpansion = false;
-      std::optional<unsigned> OrigNumExpansions =
-          ExpansionTL.getTypePtr()->getNumExpansions();
-      NumExpansions = OrigNumExpansions;
-      if (SemaRef.CheckParameterPacksForExpansion(
-              ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(),
-              Unexpanded, TemplateArgs, ShouldExpand, RetainExpansion,
-              NumExpansions))
-        return true;
-
-      assert(ShouldExpand && !RetainExpansion &&
-             "Shouldn't retain an expansion here!");
-      Scope.MakeInstantiatedLocalArgPack(OldParm);
-
-      for (unsigned I = 0; I != *NumExpansions; ++I) {
-        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
-        ParmVarDecl *NewParm = SemaRef.SubstParmVarDecl(
-            OldParm, TemplateArgs, /*indexAdjustment=*/IndexAdjustment++,
-            NumExpansions, /*ExpectParameterPack=*/false,
-            /*EvaluateConstraints=*/false);
-        if (!NewParm)
-          return true;
-      }
-
-      return false;
-    }
-    NewParm = SemaRef.SubstParmVarDecl(OldParm, TemplateArgs,
-                                       /*indexAdjustment=*/IndexAdjustment,
-                                       std::nullopt,
-                                       /*ExpectParameterPack=*/false);
-    if (!NewParm)
-      return true;
-    Scope.InstantiatedLocal(OldParm, NewParm);
-    return false;
-  }
-
-public:
-  InstantiateReferencedParameter(
-      Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs,
-      FunctionDecl *PrimaryTemplatedFunction)
-      : inherited(SemaRef), TemplateArgs(TemplateArgs),
-        PrimaryTemplatedFunction(PrimaryTemplatedFunction) {}
-
-  Decl *TransformDecl(SourceLocation Loc, Decl *D) {
-    if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(D);
-        PVD && PVD->getDeclContext() == PrimaryTemplatedFunction &&
-        !InstantiatedDecls.contains(PVD)) {
-      instantiateParameterToScope(PVD, *SemaRef.CurrentInstantiationScope);
-      InstantiatedDecls.insert(PVD);
-    }
-    return D;
-  }
-
-  void TraverseConstraintExprs(ArrayRef<const Expr *> Exprs) {
-    for (auto *E : Exprs)
-      TransformExpr(const_cast<Expr *>(E));
-  }
-};
-
-} // namespace
-
 bool Sema::CheckFunctionConstraintsWithoutInstantiation(
     SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
     ArrayRef<TemplateArgument> TemplateArgs,
@@ -1247,17 +1168,6 @@ bool Sema::CheckFunctionConstraintsWithoutInstantiation(
                                    /*Pattern=*/nullptr,
                                    /*ForConstraintInstantiation=*/true);
 
-  FunctionDecl *PatternDecl = FD;
-
-  if (FunctionTemplateDecl *FromMemTempl =
-          Template->getInstantiatedFromMemberTemplate()) {
-    while (FromMemTempl->getInstantiatedFromMemberTemplate())
-      FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
-    PatternDecl = FromMemTempl->getTemplatedDecl();
-  }
-
-  InstantiateReferencedParameter(*this, MLTAL, PatternDecl)
-      .TraverseConstraintExprs(TemplateAC);
 
   Qualifiers ThisQuals;
   CXXRecordDecl *Record = nullptr;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index efae547b21c715..4f590fc1afc5b4 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1345,6 +1345,16 @@ namespace {
     // Whether to evaluate the C++20 constraints or simply substitute into them.
     bool EvaluateConstraints = true;
 
+    // Whether to instantiate function parameters in one transformation.
+    // The DeclContext is the context where the instantiated parameter would
+    // belong.
+    DeclContext *FunctionDCForParameterDeclInstantiation;
+
+    LocalInstantiationScope *ParameterInstantiationScope;
+  private:
+    bool instantiateParameterToScope(ParmVarDecl *OldParm,
+                                     LocalInstantiationScope &Scope);
+
   public:
     typedef TreeTransform<TemplateInstantiator> inherited;
 
@@ -1357,10 +1367,18 @@ namespace {
     void setEvaluateConstraints(bool B) {
       EvaluateConstraints = B;
     }
-    bool getEvaluateConstraints() {
+    bool getEvaluateConstraints() const {
       return EvaluateConstraints;
     }
 
+    void setInstantiatingFunctionDC(DeclContext *FunctionDC) {
+      FunctionDCForParameterDeclInstantiation = FunctionDC;
+    }
+
+    void setParameterInstantiationScope(LocalInstantiationScope *Scope) {
+      ParameterInstantiationScope = Scope;
+    }
+
     /// Determine whether the given type \p T has already been
     /// transformed.
     ///
@@ -1397,12 +1415,25 @@ namespace {
                                  ArrayRef<UnexpandedParameterPack> Unexpanded,
                                  bool &ShouldExpand, bool &RetainExpansion,
                                  std::optional<unsigned> &NumExpansions) {
-      return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
-                                                       PatternRange, Unexpanded,
-                                                       TemplateArgs,
-                                                       ShouldExpand,
-                                                       RetainExpansion,
-                                                       NumExpansions);
+      if (ParameterInstantiationScope) {
+        for (UnexpandedParameterPack ParmPack : Unexpanded) {
+          NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
+          if (!VD)
+            continue;
+          if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD);
+              PVD &&
+              PVD->getDeclContext() ==
+                  FunctionDCForParameterDeclInstantiation &&
+              !ParameterInstantiationScope->findInstantiationUnsafe(PVD)) {
+            // Fall through to the default lookup even if we have failed to
+            // instantiate anything. We're likely to crash thereafter.
+            instantiateParameterToScope(PVD, *ParameterInstantiationScope);
+          }
+        }
+      }
+      return getSema().CheckParameterPacksForExpansion(
+          EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, ShouldExpand,
+          RetainExpansion, NumExpansions);
     }
 
     void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
@@ -1836,9 +1867,68 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
     // template parameter.
   }
 
+  if (auto *PVD = dyn_cast<ParmVarDecl>(D);
+      PVD && PVD->getDeclContext() == FunctionDCForParameterDeclInstantiation &&
+      !ParameterInstantiationScope->findInstantiationUnsafe(PVD)) {
+    // Fall through to the default lookup even if we have failed to instantiate
+    // anything. We're likely to crash thereafter.
+    instantiateParameterToScope(PVD, *ParameterInstantiationScope);
+  }
+
   return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
 }
 
+bool TemplateInstantiator::instantiateParameterToScope(
+    ParmVarDecl *OldParm, LocalInstantiationScope &Scope) {
+  // The current context / instantiation scope might have been changed by lambda
+  // expressions. So resume them before we substitute into parameters.
+  llvm::SaveAndRestore CurrentScope(SemaRef.CurrentInstantiationScope, &Scope);
+  Sema::ContextRAII Context(SemaRef, FunctionDCForParameterDeclInstantiation);
+  std::optional<unsigned> NumExpansions;
+  unsigned IndexAdjustment = 0;
+  if (OldParm->isParameterPack()) {
+    SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+    TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
+    PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
+    TypeLoc Pattern = ExpansionTL.getPatternLoc();
+    SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+
+    assert(!Unexpanded.empty() &&
+           "A pack Decl doesn't contain anything unexpanded?");
+
+    bool ShouldExpand = false;
+    bool RetainExpansion = false;
+    std::optional<unsigned> OrigNumExpansions =
+        ExpansionTL.getTypePtr()->getNumExpansions();
+    NumExpansions = OrigNumExpansions;
+    if (SemaRef.CheckParameterPacksForExpansion(
+            ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(), Unexpanded,
+            TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions))
+      return true;
+
+    assert(ShouldExpand && !RetainExpansion &&
+           "Shouldn't retain an expansion here!");
+    Scope.MakeInstantiatedLocalArgPack(OldParm);
+
+    for (unsigned I = 0; I != *NumExpansions; ++I) {
+      Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
+      ParmVarDecl *NewParm = SemaRef.SubstParmVarDecl(
+          OldParm, TemplateArgs, /*indexAdjustment=*/IndexAdjustment++,
+          NumExpansions, /*ExpectParameterPack=*/false,
+          /*EvaluateConstraints=*/false);
+      if (!NewParm)
+        return true;
+    }
+
+    return false;
+  }
+  ParmVarDecl *NewParm = SemaRef.SubstParmVarDecl(
+      OldParm, TemplateArgs,
+      /*indexAdjustment=*/IndexAdjustment, std::nullopt,
+      /*ExpectParameterPack=*/false);
+  return !NewParm;
+}
+
 Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) {
   Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
   if (!Inst)
@@ -4259,10 +4349,17 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
 
 ExprResult
 Sema::SubstConstraintExpr(Expr *E,
-                          const MultiLevelTemplateArgumentList &TemplateArgs) {
-  // FIXME: should call SubstExpr directly if this function is equivalent or
-  //        should it be different?
-  return SubstExpr(E, TemplateArgs);
+                          const MultiLevelTemplateArgumentList &TemplateArgs,
+                          DeclContext *InstantiatingFunctionDC) {
+  if (!E)
+    return E;
+
+  TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+                                    DeclarationName());
+  Instantiator.setInstantiatingFunctionDC(InstantiatingFunctionDC);
+  Instantiator.setParameterInstantiationScope(CurrentInstantiationScope);
+
+  return Instantiator.TransformExpr(E);
 }
 
 ExprResult Sema::SubstConstraintExprWithoutSatisfaction(
@@ -4346,7 +4443,7 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) {
 
 
 llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
-LocalInstantiationScope::findInstantiationOf(const Decl *D) {
+LocalInstantiationScope::findInstantiationUnsafe(const Decl *D) {
   D = getCanonicalParmVarDecl(D);
   for (LocalInstantiationScope *Current = this; Current;
        Current = Current->Outer) {
@@ -4371,6 +4468,14 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
       break;
   }
 
+  return nullptr;
+}
+
+llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
+LocalInstantiationScope::findInstantiationOf(const Decl *D) {
+  auto *Result = findInstantiationUnsafe(D);
+  if (Result)
+    return Result;
   // If we're performing a partial substitution during template argument
   // deduction, we may not have values for template parameters yet.
   if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||

>From e0b21a546664b1c8324fb0bfe6ec871acb564a1a Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sun, 18 Aug 2024 17:09:40 +0200
Subject: [PATCH 11/12] [libc++][chono] Use hidden friends for leap_second
 comparison.

The function

    template<class Duration>
      requires three_way_comparable_with<sys_seconds, sys_time<Duration>>
      constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y) noexcept;

Has a recursive constrained. This caused an infinite loop in GCC and is
now hit by https://github.com/llvm/llvm-project/pull/102857.

A fix would be to make this function a hidden friend, this solution is
propsed in LWG4139.

For consistency all comparisons are made hidden friends.
Since the issue causes compilation failures no additional test are
needed.
---
 libcxx/docs/Status/Cxx2cIssues.csv    |   4 +-
 libcxx/include/__chrono/leap_second.h | 131 +++++++++++++-------------
 2 files changed, 70 insertions(+), 65 deletions(-)

diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index a92a1fef779800..82590d25336808 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -76,6 +76,6 @@
 "`LWG4105 <https://wg21.link/LWG4105>`__","``ranges::ends_with``\`s Returns misses difference casting","St. Louis June 2024","","","|ranges|"
 "`LWG4106 <https://wg21.link/LWG4106>`__","``basic_format_args`` should not be default-constructible","St. Louis June 2024","|Complete|","19.0","|format|"
 "","","","","",""
-"`LWG3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
-"XXXX","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0",""
+"`LWG3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Adopted Yet","|Complete|","16.0",""
+"`LWG4139 <https://wg21.link/LWG4139>`__","ยง[time.zone.leap] recursive constraint in <=>","Not Adopted Yet","|Complete|","20.0",""
 "","","","","",""
diff --git a/libcxx/include/__chrono/leap_second.h b/libcxx/include/__chrono/leap_second.h
index a439f3f5c6cc62..d79111ed8eecfc 100644
--- a/libcxx/include/__chrono/leap_second.h
+++ b/libcxx/include/__chrono/leap_second.h
@@ -50,70 +50,75 @@ class leap_second {
 private:
   sys_seconds __date_;
   seconds __value_;
-};
 
-_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const leap_second& __x, const leap_second& __y) {
-  return __x.date() == __y.date();
-}
-
-_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const leap_second& __x, const leap_second& __y) {
-  return __x.date() <=> __y.date();
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const leap_second& __x, const sys_time<_Duration>& __y) {
-  return __x.date() == __y;
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const leap_second& __x, const sys_time<_Duration>& __y) {
-  return __x.date() < __y;
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const sys_time<_Duration>& __x, const leap_second& __y) {
-  return __x < __y.date();
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const leap_second& __x, const sys_time<_Duration>& __y) {
-  return __y < __x;
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const sys_time<_Duration>& __x, const leap_second& __y) {
-  return __y < __x;
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const leap_second& __x, const sys_time<_Duration>& __y) {
-  return !(__y < __x);
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const sys_time<_Duration>& __x, const leap_second& __y) {
-  return !(__y < __x);
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const leap_second& __x, const sys_time<_Duration>& __y) {
-  return !(__x < __y);
-}
-
-template <class _Duration>
-_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const sys_time<_Duration>& __x, const leap_second& __y) {
-  return !(__x < __y);
-}
-
-#    ifndef _LIBCPP_COMPILER_GCC
-// This requirement cause a compilation loop in GCC-13 and running out of memory.
-// TODO TZDB Test whether GCC-14 fixes this.
-template <class _Duration>
-  requires(same_as<seconds, _Duration> || three_way_comparable_with<sys_seconds, sys_time<_Duration>>)
-_LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const leap_second& __x, const sys_time<_Duration>& __y) {
-  return __x.date() <=> __y;
-}
-#    endif
+  // The function
+  //   template<class Duration>
+  //    requires three_way_comparable_with<sys_seconds, sys_time<Duration>>
+  //    constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y) noexcept;
+  //
+  // Has constraints that are recursive (LWG4139). The proposed resolution is
+  // to make the funcion a hidden friend. For consistency make this change for
+  // all comparison functions.
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const leap_second& __x, const leap_second& __y) {
+    return __x.date() == __y.date();
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering operator<=>(const leap_second& __x, const leap_second& __y) {
+    return __x.date() <=> __y.date();
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const leap_second& __x, const sys_time<_Duration>& __y) {
+    return __x.date() == __y;
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const leap_second& __x, const sys_time<_Duration>& __y) {
+    return __x.date() < __y;
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const sys_time<_Duration>& __x, const leap_second& __y) {
+    return __x < __y.date();
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const leap_second& __x, const sys_time<_Duration>& __y) {
+    return __y < __x;
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const sys_time<_Duration>& __x, const leap_second& __y) {
+    return __y < __x;
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const leap_second& __x, const sys_time<_Duration>& __y) {
+    return !(__y < __x);
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const sys_time<_Duration>& __x, const leap_second& __y) {
+    return !(__y < __x);
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const leap_second& __x, const sys_time<_Duration>& __y) {
+    return !(__x < __y);
+  }
+
+  template <class _Duration>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const sys_time<_Duration>& __x, const leap_second& __y) {
+    return !(__x < __y);
+  }
+
+  template <class _Duration>
+    requires three_way_comparable_with<sys_seconds, sys_time<_Duration>>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const leap_second& __x, const sys_time<_Duration>& __y) {
+    return __x.date() <=> __y;
+  }
+};
 
 } // namespace chrono
 

>From 30dc1d1b00fa6ae8c3fe1ddac4fde52253ec3cc2 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 19 Aug 2024 09:53:37 +0800
Subject: [PATCH 12/12] clang-format

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

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 99c1b4a6998544..f89dd6878b9695 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1168,7 +1168,6 @@ bool Sema::CheckFunctionConstraintsWithoutInstantiation(
                                    /*Pattern=*/nullptr,
                                    /*ForConstraintInstantiation=*/true);
 
-
   Qualifiers ThisQuals;
   CXXRecordDecl *Record = nullptr;
   if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 4f590fc1afc5b4..971dc65eb193cc 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1351,6 +1351,7 @@ namespace {
     DeclContext *FunctionDCForParameterDeclInstantiation;
 
     LocalInstantiationScope *ParameterInstantiationScope;
+
   private:
     bool instantiateParameterToScope(ParmVarDecl *OldParm,
                                      LocalInstantiationScope &Scope);
@@ -1367,9 +1368,7 @@ namespace {
     void setEvaluateConstraints(bool B) {
       EvaluateConstraints = B;
     }
-    bool getEvaluateConstraints() const {
-      return EvaluateConstraints;
-    }
+    bool getEvaluateConstraints() const { return EvaluateConstraints; }
 
     void setInstantiatingFunctionDC(DeclContext *FunctionDC) {
       FunctionDCForParameterDeclInstantiation = FunctionDC;
@@ -4441,7 +4440,6 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) {
   return D;
 }
 
-
 llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
 LocalInstantiationScope::findInstantiationUnsafe(const Decl *D) {
   D = getCanonicalParmVarDecl(D);



More information about the cfe-commits mailing list