[libcxx-commits] [clang] [libcxx] [Clang] Normalize constraints before checking for satisfaction (PR #141776)

Corentin Jabot via libcxx-commits libcxx-commits at lists.llvm.org
Fri Sep 19 03:07:15 PDT 2025


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/141776

>From a8c391c8509f18037d9b4f82dfa1d88d4c91ec05 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Sep 2025 16:07:52 +0200
Subject: [PATCH 01/29] Use normalization for concept satisfaction

---
 clang/include/clang/AST/ASTConcept.h          |   29 +-
 clang/include/clang/AST/ASTContext.h          |   21 +
 clang/include/clang/AST/TemplateBase.h        |    1 -
 clang/include/clang/Sema/Sema.h               |   84 +-
 clang/include/clang/Sema/SemaConcept.h        |  413 +++-
 clang/include/clang/Sema/Template.h           |   28 +-
 clang/lib/AST/ASTConcept.cpp                  |   27 +-
 clang/lib/AST/ASTContext.cpp                  |    1 +
 clang/lib/AST/ASTImporter.cpp                 |    2 +-
 clang/lib/Sema/SemaConcept.cpp                | 1966 +++++++++++------
 clang/lib/Sema/SemaDeclCXX.cpp                |   12 +-
 clang/lib/Sema/SemaExprCXX.cpp                |   16 +-
 clang/lib/Sema/SemaOverload.cpp               |    3 +-
 clang/lib/Sema/SemaTemplate.cpp               |  108 +-
 clang/lib/Sema/SemaTemplateDeduction.cpp      |   37 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  234 +-
 clang/lib/Sema/TreeTransform.h                |   25 +-
 clang/lib/Serialization/ASTReaderDecl.cpp     |    2 +-
 clang/lib/Serialization/ASTReaderStmt.cpp     |    9 +-
 clang/lib/Serialization/ASTWriterStmt.cpp     |   19 +-
 clang/test/AST/ast-dump-concepts.cpp          |   10 +-
 clang/test/AST/ast-dump-ctad-alias.cpp        |   21 +-
 clang/test/CXX/drs/cwg25xx.cpp                |   14 +-
 .../CXX/expr/expr.prim/expr.prim.id/p3.cpp    |    3 +-
 .../expr.prim.req/compound-requirement.cpp    |   14 +-
 .../expr.prim.req/nested-requirement.cpp      |   35 +-
 .../expr.prim.req/simple-requirement.cpp      |    4 +-
 .../expr.prim.req/type-requirement.cpp        |   12 +-
 .../constrant-satisfaction-conversions.cpp    |    5 +-
 .../temp.constr/temp.constr.normal/p1.cpp     |   59 +-
 clang/test/CXX/temp/temp.param/p10-2a.cpp     |   23 +-
 clang/test/SemaCXX/cxx23-assume.cpp           |    9 +-
 clang/test/SemaCXX/cxx2b-deducing-this.cpp    |    8 +-
 clang/test/SemaCXX/cxx2c-fold-exprs.cpp       |  202 +-
 .../SemaCXX/cxx2c-template-template-param.cpp |    4 +-
 .../invalid-requirement-requires-expr.cpp     |    7 +-
 ...overload-resolution-deferred-templates.cpp |    3 +-
 clang/test/SemaCXX/type-traits.cpp            |    4 +-
 clang/test/SemaHLSL/BuiltIns/Buffers.hlsl     |    6 +-
 clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl   |    6 +-
 .../SemaTemplate/concepts-recovery-expr.cpp   |   32 +-
 .../SemaTemplate/concepts-recursive-inst.cpp  |   27 +-
 clang/test/SemaTemplate/concepts.cpp          |   14 +-
 clang/test/SemaTemplate/deduction-guide.cpp   |   15 +-
 .../instantiate-abbreviated-template.cpp      |    1 +
 .../instantiate-expanded-type-constraint.cpp  |    4 +-
 .../instantiate-requires-expr.cpp             |   20 +-
 .../instantiate-template-argument.cpp         |   14 +-
 clang/test/SemaTemplate/pr52970.cpp           |    2 +-
 49 files changed, 2437 insertions(+), 1178 deletions(-)

diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index 72da0059744f2..9babfd39dd668 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -28,13 +28,23 @@ namespace clang {
 
 class ConceptDecl;
 class TemplateDecl;
+class ConceptReference;
 class Expr;
 class NamedDecl;
 struct PrintingPolicy;
 
+/// Pairs of unsatisfied atomic constraint expressions along with the
+/// substituted constraint expr, if the template arguments could be
+/// substituted into them, or a diagnostic if substitution resulted in
+/// an invalid expression.
+using UnsatisfiedConstraintRecord =
+    llvm::PointerUnion<const Expr *, const ConceptReference *,
+                       std::pair<SourceLocation, StringRef> *>;
+
 /// The result of a constraint satisfaction check, containing the necessary
 /// information to diagnose an unsatisfied constraint.
 class ConstraintSatisfaction : public llvm::FoldingSetNode {
+private:
   // The template-like entity that 'owns' the constraint checked here (can be a
   // constrained entity or a concept).
   const NamedDecl *ConstraintOwner = nullptr;
@@ -49,7 +59,6 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
       : ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}
 
   using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
-  using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
 
   bool IsSatisfied = false;
   bool ContainsErrors = false;
@@ -57,7 +66,7 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
   /// \brief The substituted constraint expr, if the template arguments could be
   /// substituted into them, or a diagnostic if substitution resulted in an
   /// invalid expression.
-  llvm::SmallVector<Detail, 4> Details;
+  llvm::SmallVector<UnsatisfiedConstraintRecord, 4> Details;
 
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
     Profile(ID, C, ConstraintOwner, TemplateArgs);
@@ -75,13 +84,6 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
   }
 };
 
-/// Pairs of unsatisfied atomic constraint expressions along with the
-/// substituted constraint expr, if the template arguments could be
-/// substituted into them, or a diagnostic if substitution resulted in
-/// an invalid expression.
-using UnsatisfiedConstraintRecord =
-    llvm::PointerUnion<Expr *, std::pair<SourceLocation, StringRef> *>;
-
 /// \brief The result of a constraint satisfaction check, containing the
 /// necessary information to diagnose an unsatisfied constraint.
 ///
@@ -101,6 +103,10 @@ struct ASTConstraintSatisfaction final :
     return getTrailingObjects() + NumRecords;
   }
 
+  ArrayRef<UnsatisfiedConstraintRecord> records() const {
+    return {begin(), end()};
+  }
+
   ASTConstraintSatisfaction(const ASTContext &C,
                             const ConstraintSatisfaction &Satisfaction);
   ASTConstraintSatisfaction(const ASTContext &C,
@@ -282,6 +288,11 @@ class TypeConstraint {
   }
 };
 
+/// Insertion operator for diagnostics.  This allows sending TemplateName's
+/// into a diagnostic with <<.
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      const ConceptReference *C);
+
 } // clang
 
 #endif // LLVM_CLANG_AST_ASTCONCEPT_H
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index a2c55c71e09ae..655c8522b67c4 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -51,6 +51,27 @@ class FixedPointSemantics;
 struct fltSemantics;
 template <typename T, unsigned N> class SmallPtrSet;
 
+template <> struct DenseMapInfo<llvm::FoldingSetNodeID> {
+  static FoldingSetNodeID getEmptyKey() { return FoldingSetNodeID{}; }
+
+  static FoldingSetNodeID getTombstoneKey() {
+    FoldingSetNodeID id;
+    for (size_t i = 0; i < sizeof(id) / sizeof(unsigned); ++i) {
+      id.AddInteger(std::numeric_limits<unsigned>::max());
+    }
+    return id;
+  }
+
+  static unsigned getHashValue(const FoldingSetNodeID &Val) {
+    return Val.ComputeHash();
+  }
+
+  static bool isEqual(const FoldingSetNodeID &LHS,
+                      const FoldingSetNodeID &RHS) {
+    return LHS == RHS;
+  }
+};
+
 } // namespace llvm
 
 namespace clang {
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index de248ac3cf703..0359f4beb6309 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -475,7 +475,6 @@ class TemplateArgument {
   /// Used to insert TemplateArguments into FoldingSets.
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
 };
-
 /// Location information for a TemplateArgument.
 struct TemplateArgumentLocInfo {
   struct TemplateTemplateArgLocInfo {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d017d1f829015..4c4b07be1b31e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -65,6 +65,7 @@
 #include "clang/Sema/Redeclaration.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/SemaBase.h"
+#include "clang/Sema/SemaConcept.h"
 #include "clang/Sema/TypoCorrection.h"
 #include "clang/Sema/Weak.h"
 #include "llvm/ADT/APInt.h"
@@ -11695,8 +11696,9 @@ class Sema final : public SemaBase {
   ExprResult
   CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
                          const DeclarationNameInfo &ConceptNameInfo,
-                         NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
-                         const TemplateArgumentListInfo *TemplateArgs);
+                         NamedDecl *FoundDecl, TemplateDecl *NamedConcept,
+                         const TemplateArgumentListInfo *TemplateArgs,
+                         bool DoCheckConstraintSatisfaction = true);
 
   void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
   void diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
@@ -12009,6 +12011,13 @@ class Sema final : public SemaBase {
                                  bool UpdateArgsWithConversions = true,
                                  bool *ConstraintsNotSatisfied = nullptr);
 
+  bool CheckTemplateArgumentList(
+      TemplateDecl *Template, TemplateParameterList *Params,
+      SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs,
+      const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
+      CheckTemplateArgumentInfo &CTAI, bool UpdateArgsWithConversions = true,
+      bool *ConstraintsNotSatisfied = nullptr);
+
   bool CheckTemplateTypeArgument(
       TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
       SmallVectorImpl<TemplateArgument> &SugaredConverted,
@@ -12783,6 +12792,9 @@ class Sema final : public SemaBase {
   void MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
                                   unsigned Depth, llvm::SmallBitVector &Used);
 
+  void MarkUsedTemplateParameters(ArrayRef<TemplateArgumentLoc> TemplateArgs,
+                                  unsigned Depth, llvm::SmallBitVector &Used);
+
   void
   MarkDeducedTemplateParameters(const FunctionTemplateDecl *FunctionTemplate,
                                 llvm::SmallBitVector &Deduced) {
@@ -13080,6 +13092,8 @@ class Sema final : public SemaBase {
     /// Whether we're substituting into constraints.
     bool InConstraintSubstitution;
 
+    bool InParameterMappingSubstitution;
+
     /// The point of instantiation or synthesis within the source code.
     SourceLocation PointOfInstantiation;
 
@@ -13345,6 +13359,11 @@ class Sema final : public SemaBase {
                          const MultiLevelTemplateArgumentList &TemplateArgs,
                          TemplateArgumentListInfo &Outputs);
 
+  bool SubstTemplateArgumentsInParameterMapping(
+      ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
+      const MultiLevelTemplateArgumentList &TemplateArgs,
+      TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes);
+
   /// Retrieve the template argument list(s) that should be used to
   /// instantiate the definition of the given declaration.
   ///
@@ -13806,6 +13825,12 @@ class Sema final : public SemaBase {
            CodeSynthesisContexts.back().InConstraintSubstitution;
   }
 
+  bool inParameterMappingSubstitution() const {
+    return !CodeSynthesisContexts.empty() &&
+           CodeSynthesisContexts.back().InParameterMappingSubstitution &&
+           !inConstraintSubstitution();
+  }
+
   using EntityPrinter = llvm::function_ref<void(llvm::raw_ostream &)>;
 
   /// \brief create a Requirement::SubstitutionDiagnostic with only a
@@ -14690,6 +14715,10 @@ class Sema final : public SemaBase {
     SatisfactionStack.swap(NewSS);
   }
 
+  using ConstrainedDeclOrNestedRequirement =
+      llvm::PointerUnion<const NamedDecl *,
+                         const concepts::NestedRequirement *>;
+
   /// Check whether the given expression is a valid constraint expression.
   /// A diagnostic is emitted if it is not, false is returned, and
   /// PossibleNonPrimary will be set to true if the failure might be due to a
@@ -14714,44 +14743,12 @@ class Sema final : public SemaBase {
   /// \returns true if an error occurred and satisfaction could not be checked,
   /// false otherwise.
   bool CheckConstraintSatisfaction(
-      const NamedDecl *Template,
+      ConstrainedDeclOrNestedRequirement Entity,
       ArrayRef<AssociatedConstraint> AssociatedConstraints,
       const MultiLevelTemplateArgumentList &TemplateArgLists,
-      SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
-    llvm::SmallVector<Expr *, 4> Converted;
-    return CheckConstraintSatisfaction(Template, AssociatedConstraints,
-                                       Converted, TemplateArgLists,
-                                       TemplateIDRange, Satisfaction);
-  }
-
-  /// \brief Check whether the given list of constraint expressions are
-  /// satisfied (as if in a 'conjunction') given template arguments.
-  /// Additionally, takes an empty list of Expressions which is populated with
-  /// the instantiated versions of the ConstraintExprs.
-  /// \param Template the template-like entity that triggered the constraints
-  /// check (either a concept or a constrained entity).
-  /// \param ConstraintExprs a list of constraint expressions, treated as if
-  /// they were 'AND'ed together.
-  /// \param ConvertedConstraints a out parameter that will get populated with
-  /// the instantiated version of the ConstraintExprs if we successfully checked
-  /// satisfaction.
-  /// \param TemplateArgList the multi-level list of template arguments to
-  /// substitute into the constraint expression. This should be relative to the
-  /// top-level (hence multi-level), since we need to instantiate fully at the
-  /// time of checking.
-  /// \param TemplateIDRange The source range of the template id that
-  /// caused the constraints check.
-  /// \param Satisfaction if true is returned, will contain details of the
-  /// satisfaction, with enough information to diagnose an unsatisfied
-  /// expression.
-  /// \returns true if an error occurred and satisfaction could not be checked,
-  /// false otherwise.
-  bool CheckConstraintSatisfaction(
-      const NamedDecl *Template,
-      ArrayRef<AssociatedConstraint> AssociatedConstraints,
-      llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
-      const MultiLevelTemplateArgumentList &TemplateArgList,
-      SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction);
+      SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction,
+      const ConceptReference *TopLevelConceptId = nullptr,
+      Expr **ConvertedExpr = nullptr);
 
   /// \brief Check whether the given non-dependent constraint expression is
   /// satisfied. Returns false and updates Satisfaction with the satisfaction
@@ -14817,16 +14814,17 @@ class Sema final : public SemaBase {
   /// \param First whether this is the first time an unsatisfied constraint is
   /// diagnosed for this error.
   void DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction,
+                                     SourceLocation Loc = {},
                                      bool First = true);
 
   /// \brief Emit diagnostics explaining why a constraint expression was deemed
   /// unsatisfied.
   void
-  DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction,
+  DiagnoseUnsatisfiedConstraint(const ConceptSpecializationExpr *ConstraintExpr,
                                 bool First = true);
 
   const NormalizedConstraint *getNormalizedAssociatedConstraints(
-      const NamedDecl *ConstrainedDecl,
+      ConstrainedDeclOrNestedRequirement Entity,
       ArrayRef<AssociatedConstraint> AssociatedConstraints);
 
   /// \brief Check whether the given declaration's associated constraints are
@@ -14851,6 +14849,9 @@ class Sema final : public SemaBase {
       const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1,
       const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2);
 
+  llvm::DenseMap<llvm::FoldingSetNodeID, CachedConceptIdConstraint>
+      ConceptIdSatisfactionCache;
+
 private:
   /// Caches pairs of template-like decls whose associated constraints were
   /// checked for subsumption and whether or not the first's constraints did in
@@ -14861,7 +14862,8 @@ class Sema final : public SemaBase {
   /// constrained declarations). If an error occurred while normalizing the
   /// associated constraints of the template or concept, nullptr will be cached
   /// here.
-  llvm::DenseMap<const NamedDecl *, NormalizedConstraint *> NormalizationCache;
+  llvm::DenseMap<ConstrainedDeclOrNestedRequirement, NormalizedConstraint *>
+      NormalizationCache;
 
   llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
       SatisfactionCache;
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index 648a9c51ae6c1..3ba48b75c1286 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -16,130 +16,387 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/UnsignedOrNone.h"
+#include "clang/Sema/Ownership.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
 #include <optional>
 #include <utility>
 
 namespace clang {
 class Sema;
+class MultiLevelTemplateArgumentList;
 
-enum { ConstraintAlignment = 8 };
+/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
+/// either an atomic constraint, a conjunction of normalized constraints or a
+/// disjunction of normalized constraints.
+
+struct NormalizedConstraint {
+
+  enum class ConstraintKind {
+    Atomic = 0,
+    ConceptId,
+    FoldExpanded,
+    Compound,
+  };
+
+  enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
+  enum class FoldOperatorKind : unsigned int { And, Or };
+
+  using OccurenceList = llvm::SmallBitVector;
+
+  friend bool
+  substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+                              const MultiLevelTemplateArgumentList &MLTAL,
+                              const ASTTemplateArgumentListInfo *ArgsAsWritten,
+                              TemplateParameterList *TemplateParams,
+                              const NamedDecl *D);
+
+protected:
+  using ExprOrConcept =
+      llvm::PointerUnion<const Expr *, const ConceptReference *>;
+
+  struct AtomicBits {
+    LLVM_PREFERRED_TYPE(ConstraintKind)
+    unsigned Kind : 5;
+    unsigned Placeholder : 1;
+    unsigned PackSubstitutionIndex : 26;
+    OccurenceList Indexes;
+    TemplateArgumentLoc *Args;
+    TemplateParameterList *ParamList;
+    ExprOrConcept ConstraintExpr;
+    const NamedDecl *ConstraintDecl;
+  };
+
+  struct FoldExpandedBits {
+    LLVM_PREFERRED_TYPE(ConstraintKind)
+    unsigned Kind : 5;
+    LLVM_PREFERRED_TYPE(FoldOperatorKind)
+    unsigned FoldOperator : 1;
+    unsigned Placeholder : 26;
+    OccurenceList Indexes;
+    TemplateArgumentLoc *Args;
+    TemplateParameterList *ParamList;
+    const Expr *Pattern;
+    const NamedDecl *ConstraintDecl;
+    NormalizedConstraint *Constraint;
+  };
+
+  struct ConceptIdBits : AtomicBits {
+    NormalizedConstraint *Sub;
+
+    // Only used for parameter mapping.
+    const ConceptSpecializationExpr *CSE;
+  };
+
+  struct CompoundBits {
+    LLVM_PREFERRED_TYPE(ConstraintKind)
+    unsigned Kind : 5;
+    LLVM_PREFERRED_TYPE(CompoundConstraintKind)
+    unsigned CCK : 1;
+    NormalizedConstraint *LHS;
+    NormalizedConstraint *RHS;
+  };
+
+  union {
+    AtomicBits Atomic;
+    FoldExpandedBits FoldExpanded;
+    ConceptIdBits ConceptId;
+    CompoundBits Compound;
+  };
+
+  ~NormalizedConstraint() {
+    if (getKind() != ConstraintKind::Compound)
+      Atomic.Indexes.llvm::SmallBitVector::~SmallBitVector();
+  }
+
+  NormalizedConstraint(const Expr *ConstraintExpr,
+                       const NamedDecl *ConstraintDecl,
+                       UnsignedOrNone PackIndex)
+      : Atomic{llvm::to_underlying(ConstraintKind::Atomic),
+               /*Placeholder=*/0,
+               PackIndex.toInternalRepresentation(),
+               /*Indexes=*/{},
+               /*Args=*/nullptr,
+               /*ParamList=*/nullptr,
+               ConstraintExpr,
+               ConstraintDecl} {}
+
+  NormalizedConstraint(const Expr *Pattern, FoldOperatorKind OpKind,
+                       NormalizedConstraint *Constraint,
+                       const NamedDecl *ConstraintDecl)
+      : FoldExpanded{llvm::to_underlying(ConstraintKind::FoldExpanded),
+                     llvm::to_underlying(OpKind),
+                     /*Placeholder=*/0,
+                     /*Indexes=*/{},
+                     /*Args=*/nullptr,
+                     /*ParamList=*/nullptr,
+                     Pattern,
+                     ConstraintDecl,
+                     Constraint} {}
+
+  NormalizedConstraint(const ConceptReference *ConceptId,
+                       const NamedDecl *ConstraintDecl,
+                       NormalizedConstraint *SubConstraint,
+                       const ConceptSpecializationExpr *CSE,
+                       UnsignedOrNone PackIndex)
+      : ConceptId{{llvm::to_underlying(ConstraintKind::ConceptId),
+                   /*Placeholder=*/0, PackIndex.toInternalRepresentation(),
+                   /*Indexes=*/{},
+                   /*Args=*/nullptr, /*ParamList=*/nullptr, ConceptId,
+                   ConstraintDecl},
+                  SubConstraint,
+                  CSE} {}
+
+  NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK,
+                       NormalizedConstraint *RHS)
+      : Compound{llvm::to_underlying(ConstraintKind::Compound), CCK, LHS, RHS} {
+  }
 
-struct alignas(ConstraintAlignment) AtomicConstraint {
-  const Expr *ConstraintExpr;
-  const NamedDecl *ConstraintDecl;
-  std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping;
+  bool hasParameterMapping() const {
+    return getKind() != ConstraintKind::Compound
+                            && Atomic.Args != nullptr;
+  }
+
+  const OccurenceList &mappingOccurenceList() const {
+    assert(hasParameterMapping() && "This constraint has no parameter mapping");
+    return Atomic.Indexes;
+  }
+
+  llvm::MutableArrayRef<TemplateArgumentLoc> getParameterMapping() const {
+    return {Atomic.Args, Atomic.Indexes.count()};
+  }
+
+  TemplateParameterList *getUsedTemplateParamList() const {
+    return Atomic.ParamList;
+  }
 
-  AtomicConstraint(const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl)
-      : ConstraintExpr(ConstraintExpr), ConstraintDecl(ConstraintDecl) {};
+  void updateParameterMapping(OccurenceList Indexes,
+                              llvm::MutableArrayRef<TemplateArgumentLoc> Args,
+                              TemplateParameterList *ParamList) {
+    assert(getKind() != ConstraintKind::Compound);
+    assert(Indexes.count() == Args.size());
+    Atomic.Indexes = Indexes;
+    Atomic.Args = Args.data();
+    Atomic.ParamList = ParamList;
+  }
 
   bool hasMatchingParameterMapping(ASTContext &C,
-                                   const AtomicConstraint &Other) const {
-    if (!ParameterMapping != !Other.ParameterMapping)
+                                   const NormalizedConstraint &Other) const {
+    assert(getKind() != ConstraintKind::Compound);
+
+    if (hasParameterMapping() != Other.hasParameterMapping())
       return false;
-    if (!ParameterMapping)
+    if (!hasParameterMapping())
       return true;
-    if (ParameterMapping->size() != Other.ParameterMapping->size())
+
+    llvm::ArrayRef<TemplateArgumentLoc> ParameterMapping =
+        getParameterMapping();
+    llvm::ArrayRef<TemplateArgumentLoc> OtherParameterMapping =
+        Other.getParameterMapping();
+
+    if (ParameterMapping.size() != OtherParameterMapping.size())
       return false;
 
-    for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
+    for (unsigned I = 0, S = ParameterMapping.size(); I < S; ++I) {
       llvm::FoldingSetNodeID IDA, IDB;
-      C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
+      C.getCanonicalTemplateArgument(ParameterMapping[I].getArgument())
           .Profile(IDA, C);
-      C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
+      C.getCanonicalTemplateArgument(OtherParameterMapping[I].getArgument())
           .Profile(IDB, C);
       if (IDA != IDB)
         return false;
     }
     return true;
   }
-};
 
-struct alignas(ConstraintAlignment) NormalizedConstraintPair;
-struct alignas(ConstraintAlignment) FoldExpandedConstraint;
+public:
+  ConstraintKind getKind() const {
+    return static_cast<ConstraintKind>(Atomic.Kind);
+  }
 
-/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
-/// either an atomic constraint, a conjunction of normalized constraints or a
-/// disjunction of normalized constraints.
-struct NormalizedConstraint {
+  SourceLocation getBeginLoc() const {
+    switch (getKind()) {
+    case ConstraintKind::Atomic:
+      return cast<const Expr *>(Atomic.ConstraintExpr)->getBeginLoc();
+    case ConstraintKind::ConceptId:
+      return cast<const ConceptReference *>(Atomic.ConstraintExpr)
+          ->getBeginLoc();
+    case ConstraintKind::Compound:
+      return Compound.LHS->getBeginLoc();
+    case ConstraintKind::FoldExpanded:
+      return FoldExpanded.Pattern->getBeginLoc();
+    }
+  }
+
+  SourceLocation getEndLoc() const {
+    switch (getKind()) {
+    case ConstraintKind::Atomic:
+      return cast<const Expr *>(Atomic.ConstraintExpr)->getEndLoc();
+    case ConstraintKind::ConceptId:
+      return cast<const ConceptReference *>(Atomic.ConstraintExpr)->getEndLoc();
+    case ConstraintKind::Compound:
+      return Compound.RHS->getEndLoc();
+    case ConstraintKind::FoldExpanded:
+      return FoldExpanded.Pattern->getEndLoc();
+    }
+  }
+
+  SourceRange getSourceRange() const { return {getBeginLoc(), getEndLoc()}; }
+
+private:
   friend class Sema;
+  static NormalizedConstraint *
+  fromAssociatedConstraints(Sema &S, const NamedDecl *D,
+                            ArrayRef<AssociatedConstraint> ACs);
+  static NormalizedConstraint *fromConstraintExpr(Sema &S, const NamedDecl *D,
+                                                  const Expr *E,
+                                                  UnsignedOrNone SubstIndex);
+};
 
-  enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
+class CompoundConstraint : public NormalizedConstraint {
+  using NormalizedConstraint::NormalizedConstraint;
+
+public:
+  static CompoundConstraint *Create(ASTContext &Ctx, NormalizedConstraint *LHS,
+                                    CompoundConstraintKind CCK,
+                                    NormalizedConstraint *RHS) {
+    return new (Ctx) CompoundConstraint(LHS, CCK, RHS);
+  }
+
+  static CompoundConstraint *CreateConjunction(ASTContext &Ctx,
+                                               NormalizedConstraint *LHS,
+                                               NormalizedConstraint *RHS) {
+    return new (Ctx) CompoundConstraint(LHS, CCK_Conjunction, RHS);
+  }
 
-  using CompoundConstraint = llvm::PointerIntPair<NormalizedConstraintPair *, 1,
-                                                  CompoundConstraintKind>;
+  const NormalizedConstraint &getLHS() const { return *Compound.LHS; }
 
-  llvm::PointerUnion<AtomicConstraint *, FoldExpandedConstraint *,
-                     CompoundConstraint>
-      Constraint;
+  NormalizedConstraint &getLHS() { return *Compound.LHS; }
 
-  NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
-  NormalizedConstraint(FoldExpandedConstraint *C) : Constraint{C} {};
+  const NormalizedConstraint &getRHS() const { return *Compound.RHS; }
 
-  NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
-                       NormalizedConstraint RHS, CompoundConstraintKind Kind);
+  NormalizedConstraint &getRHS() { return *Compound.RHS; }
 
-  NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other);
-  NormalizedConstraint(NormalizedConstraint &&Other):
-      Constraint(Other.Constraint) {
-    Other.Constraint = nullptr;
+  CompoundConstraintKind getCompoundKind() const {
+    return static_cast<CompoundConstraintKind>(Compound.CCK);
   }
-  NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete;
-  NormalizedConstraint &operator=(NormalizedConstraint &&Other) {
-    if (&Other != this) {
-      NormalizedConstraint Temp(std::move(Other));
-      std::swap(Constraint, Temp.Constraint);
-    }
-    return *this;
+};
+
+class NormalizedConstraintWithParamMapping : public NormalizedConstraint {
+protected:
+  using NormalizedConstraint::NormalizedConstraint;
+
+public:
+  using NormalizedConstraint::getParameterMapping;
+  using NormalizedConstraint::getUsedTemplateParamList;
+  using NormalizedConstraint::hasMatchingParameterMapping;
+  using NormalizedConstraint::hasParameterMapping;
+  using NormalizedConstraint::mappingOccurenceList;
+  using NormalizedConstraint::updateParameterMapping;
+
+  const NamedDecl *getConstraintDecl() const { return Atomic.ConstraintDecl; }
+
+  UnsignedOrNone getPackSubstitutionIndex() const {
+    return UnsignedOrNone::fromInternalRepresentation(
+        Atomic.PackSubstitutionIndex);
   }
+};
 
-  bool isAtomic() const { return llvm::isa<AtomicConstraint *>(Constraint); }
-  bool isFoldExpanded() const {
-    return llvm::isa<FoldExpandedConstraint *>(Constraint);
+class AtomicConstraint : public NormalizedConstraintWithParamMapping {
+  using NormalizedConstraintWithParamMapping::
+      NormalizedConstraintWithParamMapping;
+
+public:
+  static AtomicConstraint *Create(ASTContext &Ctx, const Expr *ConstraintExpr,
+                                  const NamedDecl *ConstraintDecl,
+                                  UnsignedOrNone PackIndex) {
+    return new (Ctx)
+        AtomicConstraint(ConstraintExpr, ConstraintDecl, PackIndex);
   }
-  bool isCompound() const { return llvm::isa<CompoundConstraint>(Constraint); }
 
-  CompoundConstraintKind getCompoundKind() const;
+  const Expr *getConstraintExpr() const {
+    return cast<const Expr *>(Atomic.ConstraintExpr);
+  }
+};
 
-  NormalizedConstraint &getLHS() const;
-  NormalizedConstraint &getRHS() const;
+class FoldExpandedConstraint : public NormalizedConstraintWithParamMapping {
+  using NormalizedConstraintWithParamMapping::
+      NormalizedConstraintWithParamMapping;
 
-  AtomicConstraint *getAtomicConstraint() const;
+public:
+  static FoldExpandedConstraint *Create(ASTContext &Ctx, const Expr *Pattern,
+                                        const NamedDecl *ConstraintDecl,
+                                        FoldOperatorKind OpKind,
+                                        NormalizedConstraint *Constraint) {
+    return new (Ctx)
+        FoldExpandedConstraint(Pattern, OpKind, Constraint, ConstraintDecl);
+  }
 
-  FoldExpandedConstraint *getFoldExpandedConstraint() const;
+  using NormalizedConstraint::hasMatchingParameterMapping;
 
-private:
-  static std::optional<NormalizedConstraint>
-  fromAssociatedConstraints(Sema &S, const NamedDecl *D,
-                            ArrayRef<AssociatedConstraint> ACs);
-  static std::optional<NormalizedConstraint>
-  fromConstraintExpr(Sema &S, const NamedDecl *D, const Expr *E);
-};
+  FoldOperatorKind getFoldOperator() const {
+    return static_cast<FoldOperatorKind>(FoldExpanded.FoldOperator);
+  }
 
-struct alignas(ConstraintAlignment) NormalizedConstraintPair {
-  NormalizedConstraint LHS, RHS;
-};
+  const Expr *getPattern() const { return FoldExpanded.Pattern; }
 
-struct alignas(ConstraintAlignment) FoldExpandedConstraint {
-  enum class FoldOperatorKind { And, Or } Kind;
-  NormalizedConstraint Constraint;
-  const Expr *Pattern;
+  const NormalizedConstraint &getNormalizedPattern() const {
+    return *FoldExpanded.Constraint;
+  }
 
-  FoldExpandedConstraint(FoldOperatorKind K, NormalizedConstraint C,
-                         const Expr *Pattern)
-      : Kind(K), Constraint(std::move(C)), Pattern(Pattern) {};
+  NormalizedConstraint &getNormalizedPattern() {
+    return *FoldExpanded.Constraint;
+  }
 
   static bool AreCompatibleForSubsumption(const FoldExpandedConstraint &A,
                                           const FoldExpandedConstraint &B);
 };
 
-const NormalizedConstraint *getNormalizedAssociatedConstraints(
-    Sema &S, const NamedDecl *ConstrainedDecl,
-    ArrayRef<AssociatedConstraint> AssociatedConstraints);
+class ConceptIdConstraint : public NormalizedConstraintWithParamMapping {
+  using NormalizedConstraintWithParamMapping::
+      NormalizedConstraintWithParamMapping;
+
+public:
+  static ConceptIdConstraint *Create(ASTContext &Ctx,
+                                     const ConceptReference *ConceptId,
+                                     NormalizedConstraint *SubConstraint,
+                                     const NamedDecl *ConstraintDecl,
+                                     const ConceptSpecializationExpr *CSE,
+                                     UnsignedOrNone PackIndex) {
+    return new (Ctx) ConceptIdConstraint(ConceptId, ConstraintDecl,
+                                         SubConstraint, CSE, PackIndex);
+  }
+
+  const ConceptSpecializationExpr *getConceptSpecializationExpr() const {
+    return ConceptId.CSE;
+  }
+
+  const ConceptReference *getConceptId() const {
+    return cast<const ConceptReference *>(ConceptId.ConstraintExpr);
+  }
+
+  const NormalizedConstraint &getNormalizedConstraint() const {
+    return *ConceptId.Sub;
+  }
+
+  NormalizedConstraint &getNormalizedConstraint() { return *ConceptId.Sub; }
+};
+
+struct CachedConceptIdConstraint {
+#ifndef NDEBUG
+  const Expr *E;
+#endif
+  ExprResult SubstExpr;
+  ConstraintSatisfaction Satisfaction;
+};
 
 /// \brief SubsumptionChecker establishes subsumption
 /// between two set of constraints.
@@ -189,13 +446,13 @@ class SubsumptionChecker {
   };
 
   struct MappedAtomicConstraint {
-    AtomicConstraint *Constraint;
+    const AtomicConstraint *Constraint;
     Literal ID;
   };
 
   struct FoldExpendedConstraintKey {
     FoldExpandedConstraint::FoldOperatorKind Kind;
-    AtomicConstraint *Constraint;
+    const AtomicConstraint *Constraint;
     Literal ID;
   };
 
@@ -207,7 +464,7 @@ class SubsumptionChecker {
 
   // A map from a literal to a corresponding associated constraint.
   // We do not have enough bits left for a pointer union here :(
-  llvm::DenseMap<uint16_t, void *> ReverseMap;
+  llvm::DenseMap<uint16_t, const void *> ReverseMap;
 
   // Fold expanded constraints ask us to recursively establish subsumption.
   // This caches the result.
@@ -234,12 +491,12 @@ class SubsumptionChecker {
   FormulaType Normalize(const NormalizedConstraint &C);
   void AddUniqueClauseToFormula(Formula &F, Clause C);
 
-  Literal find(AtomicConstraint *);
-  Literal find(FoldExpandedConstraint *);
+  Literal find(const AtomicConstraint *);
+  Literal find(const FoldExpandedConstraint *);
 
   uint16_t getNewLiteralId();
 };
 
-} // clang
+} // namespace clang
 
 #endif // LLVM_CLANG_SEMA_SEMACONCEPT_H
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 115c19d4f1540..5176e4ad5a362 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -234,23 +234,39 @@ enum class TemplateSubstitutionKind : char {
     /// Replaces the current 'innermost' level with the provided argument list.
     /// This is useful for type deduction cases where we need to get the entire
     /// list from the AST, but then add the deduced innermost list.
-    void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
+    void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args,
+                                           bool Final = false) {
       assert((!TemplateArgumentLists.empty() || NumRetainedOuterLevels) &&
              "Replacing in an empty list?");
 
       if (!TemplateArgumentLists.empty()) {
-        assert((TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ||
-                TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ==
-                    AssociatedDecl) &&
-               "Trying to change incorrect declaration?");
+        // assert((!TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer()
+        // ||
+        //         TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer()
+        //         ==
+        //             AssociatedDecl) &&
+        //         "Trying to change incorrect declaration?");
         TemplateArgumentLists[0].Args = Args;
       } else {
         --NumRetainedOuterLevels;
         TemplateArgumentLists.push_back(
-            {{AssociatedDecl, /*Final=*/false}, Args});
+            {{AssociatedDecl, /*Final=*/Final}, Args});
       }
     }
 
+    void replaceOutermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
+      assert((!TemplateArgumentLists.empty()) && "Replacing in an empty list?");
+      // assert((!TemplateArgumentLists.back().AssociatedDeclAndFinal.getPointer()
+      // ||
+      //         TemplateArgumentLists.back().AssociatedDeclAndFinal.getPointer()
+      //         ==
+      //             AssociatedDecl) &&
+      //        "Trying to change incorrect declaration?");
+      TemplateArgumentLists.back().AssociatedDeclAndFinal.setPointer(
+          AssociatedDecl);
+      TemplateArgumentLists.back().Args = Args;
+    }
+
     /// Add an outermost level that we are not substituting. We have no
     /// arguments at this level, and do not remove it from the depth of inner
     /// template parameters that we instantiate.
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index d658890e076c2..d533aac707cbc 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -24,8 +24,13 @@ static void
 CreateUnsatisfiedConstraintRecord(const ASTContext &C,
                                   const UnsatisfiedConstraintRecord &Detail,
                                   UnsatisfiedConstraintRecord *TrailingObject) {
-  if (auto *E = dyn_cast<Expr *>(Detail))
+  if (Detail.isNull())
+    new (TrailingObject) UnsatisfiedConstraintRecord(nullptr);
+  else if (const auto *E = llvm::dyn_cast<const Expr *>(Detail))
     new (TrailingObject) UnsatisfiedConstraintRecord(E);
+  else if (const auto *Concept =
+               llvm::dyn_cast<const ConceptReference *>(Detail))
+    new (TrailingObject) UnsatisfiedConstraintRecord(Concept);
   else {
     auto &SubstitutionDiagnostic =
         *cast<std::pair<SourceLocation, StringRef> *>(Detail);
@@ -74,9 +79,10 @@ ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild(
   return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
 }
 
-void ConstraintSatisfaction::Profile(
-    llvm::FoldingSetNodeID &ID, const ASTContext &C,
-    const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
+void ConstraintSatisfaction::Profile(llvm::FoldingSetNodeID &ID,
+                                     const ASTContext &C,
+                                     const NamedDecl *ConstraintOwner,
+                                     ArrayRef<TemplateArgument> TemplateArgs) {
   ID.AddPointer(ConstraintOwner);
   ID.AddInteger(TemplateArgs.size());
   for (auto &Arg : TemplateArgs)
@@ -116,6 +122,19 @@ void ConceptReference::print(llvm::raw_ostream &OS,
   }
 }
 
+const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
+                                             const ConceptReference *C) {
+  std::string NameStr;
+  llvm::raw_string_ostream OS(NameStr);
+  LangOptions LO;
+  LO.CPlusPlus = true;
+  LO.Bool = true;
+  OS << '\'';
+  C->print(OS, PrintingPolicy(LO));
+  OS << '\'';
+  return DB << NameStr;
+}
+
 concepts::ExprRequirement::ExprRequirement(
     Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
     ReturnTypeRequirement Req, SatisfactionStatus Status,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index e49ff9080571e..2a5e151e33a85 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5793,6 +5793,7 @@ QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
   llvm::FoldingSetNodeID ID;
   SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
                                      PackIndex, Final);
+
   void *InsertPos = nullptr;
   SubstTemplateTypeParmType *SubstParm =
       SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 1c8fd83feb7f8..7eaae4488d657 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1069,7 +1069,7 @@ Error ASTNodeImporter::ImportConstraintSatisfaction(
   ToSat.ContainsErrors = FromSat.ContainsErrors;
   if (!ToSat.IsSatisfied) {
     for (auto Record = FromSat.begin(); Record != FromSat.end(); ++Record) {
-      if (Expr *E = Record->dyn_cast<Expr *>()) {
+      if (const Expr *E = Record->dyn_cast<const Expr *>()) {
         ExpectedExpr ToSecondExpr = import(E);
         if (!ToSecondExpr)
           return ToSecondExpr.takeError();
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d238b7916a330..22b131f4d48c2 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -12,10 +12,18 @@
 
 #include "clang/Sema/SemaConcept.h"
 #include "TreeTransform.h"
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTLambda.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DependenceFlags.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TemplateBase.h"
 #include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Basic/UnsignedOrNone.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Overload.h"
@@ -24,9 +32,19 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
+#include <chrono>
+#include <cstddef>
+#include <iterator>
 #include <optional>
 
 using namespace clang;
@@ -85,7 +103,7 @@ class LogicalBinOp {
                                   OK_Ordinary, Loc, FPOptionsOverride{});
   }
 };
-}
+} // namespace
 
 bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
                                      Token NextToken, bool *PossibleNonPrimary,
@@ -146,14 +164,14 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
 
   if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
     Diag(ConstraintExpression->getExprLoc(),
-         diag::err_non_bool_atomic_constraint) << Type
-        << ConstraintExpression->getSourceRange();
+         diag::err_non_bool_atomic_constraint)
+        << Type << ConstraintExpression->getSourceRange();
     CheckForNonPrimary();
     return false;
   }
 
   if (PossibleNonPrimary)
-      *PossibleNonPrimary = false;
+    *PossibleNonPrimary = false;
   return true;
 }
 
@@ -164,52 +182,290 @@ struct SatisfactionStackRAII {
   SatisfactionStackRAII(Sema &SemaRef, const NamedDecl *ND,
                         const llvm::FoldingSetNodeID &FSNID)
       : SemaRef(SemaRef) {
-      if (ND) {
+    if (ND) {
       SemaRef.PushSatisfactionStackEntry(ND, FSNID);
       Inserted = true;
-      }
+    }
   }
   ~SatisfactionStackRAII() {
-        if (Inserted)
-          SemaRef.PopSatisfactionStackEntry();
+    if (Inserted)
+      SemaRef.PopSatisfactionStackEntry();
   }
 };
 } // namespace
 
-static bool
-DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
-                            const NamedDecl *Templ, const Expr *E,
-                            const MultiLevelTemplateArgumentList &MLTAL) {
+static bool DiagRecursiveConstraintEval(
+    Sema &S, llvm::FoldingSetNodeID &ID, const NamedDecl *Templ, const Expr *E,
+    const MultiLevelTemplateArgumentList *MLTAL = nullptr) {
   E->Profile(ID, S.Context, /*Canonical=*/true);
-  for (const auto &List : MLTAL)
-    for (const auto &TemplateArg : List.Args)
-      TemplateArg.Profile(ID, S.Context);
-
-  // Note that we have to do this with our own collection, because there are
-  // times where a constraint-expression check can cause us to need to evaluate
-  // other constriants that are unrelated, such as when evaluating a recovery
-  // expression, or when trying to determine the constexpr-ness of special
-  // members. Otherwise we could just use the
-  // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function.
+  if (MLTAL) {
+    for (const auto &List : *MLTAL)
+      for (const auto &TemplateArg : List.Args)
+        S.Context.getCanonicalTemplateArgument(TemplateArg)
+            .Profile(ID, S.Context);
+  }
   if (S.SatisfactionStackContains(Templ, ID)) {
     S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
         << const_cast<Expr *>(E) << E->getSourceRange();
     return true;
   }
-
   return false;
 }
 
-static ExprResult EvaluateAtomicConstraint(
-    Sema &S, const Expr *AtomicExpr, const NamedDecl *Template,
-    SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
-    ConstraintSatisfaction &Satisfaction) {
+// Figure out the to-translation-unit depth for this function declaration for
+// the purpose of seeing if they differ by constraints. This isn't the same as
+// getTemplateDepth, because it includes already instantiated parents.
+static unsigned
+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
+                                     bool SkipForSpecialization = false) {
+  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+      ND, ND->getLexicalDeclContext(), /*Final=*/false,
+      /*Innermost=*/std::nullopt,
+      /*RelativeToPrimary=*/true,
+      /*Pattern=*/nullptr,
+      /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+  return MLTAL.getNumLevels();
+}
+
+namespace {
+class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
+  unsigned TemplateDepth = 0;
+
+public:
+  using inherited = TreeTransform<AdjustConstraintDepth>;
+  AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
+      : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
+
+  using inherited::TransformTemplateTypeParmType;
+  QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+                                         TemplateTypeParmTypeLoc TL, bool) {
+    const TemplateTypeParmType *T = TL.getTypePtr();
+
+    TemplateTypeParmDecl *NewTTPDecl = nullptr;
+    if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
+      NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+          TransformDecl(TL.getNameLoc(), OldTTPDecl));
+
+    QualType Result = getSema().Context.getTemplateTypeParmType(
+        T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
+        NewTTPDecl);
+    TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+    NewTL.setNameLoc(TL.getNameLoc());
+    return Result;
+  }
+
+  bool AlreadyTransformed(QualType T) {
+    if (T.isNull())
+      return true;
+
+    if (T->isInstantiationDependentType() || T->isVariablyModifiedType() ||
+        T->containsUnexpandedParameterPack())
+      return false;
+    return true;
+  }
+};
+} // namespace
+
+namespace {
+
+class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
+  using inherited = RecursiveASTVisitor<HashParameterMapping>;
+  friend inherited;
+
+  Sema &SemaRef;
+  const MultiLevelTemplateArgumentList &TemplateArgs;
+  llvm::FoldingSetNodeID &ID;
+  llvm::SmallVector<TemplateArgument, 10> UsedTemplateArgs;
+
+  UnsignedOrNone OuterPackSubstIndex;
+
+  TemplateArgument getPackSubstitutedTemplateArgument(TemplateArgument Arg) {
+    assert(*SemaRef.ArgPackSubstIndex < Arg.pack_size());
+    Arg = Arg.pack_begin()[*SemaRef.ArgPackSubstIndex];
+    if (Arg.isPackExpansion())
+      Arg = Arg.getPackExpansionPattern();
+    return Arg;
+  }
+
+  bool shouldVisitTemplateInstantiations() const { return true; }
+
+public:
+  HashParameterMapping(Sema &SemaRef,
+                       const MultiLevelTemplateArgumentList &TemplateArgs,
+                       llvm::FoldingSetNodeID &ID,
+                       UnsignedOrNone OuterPackSubstIndex)
+      : SemaRef(SemaRef), TemplateArgs(TemplateArgs), ID(ID),
+        OuterPackSubstIndex(OuterPackSubstIndex) {}
+
+  bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
+    // A lambda expression can introduce template parameters that don't have
+    // corresponding template arguments yet.
+    if (T->getDepth() >= TemplateArgs.getNumLevels())
+      return true;
+
+    TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
+
+    if (T->isParameterPack() && SemaRef.ArgPackSubstIndex) {
+      assert(Arg.getKind() == TemplateArgument::Pack &&
+             "Missing argument pack");
+
+      Arg = getPackSubstitutedTemplateArgument(Arg);
+    }
+
+    UsedTemplateArgs.push_back(
+        SemaRef.Context.getCanonicalTemplateArgument(Arg));
+    return true;
+  }
+
+  bool VisitDeclRefExpr(DeclRefExpr *E) {
+    NamedDecl *D = E->getDecl();
+    NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D);
+    if (!NTTP)
+      return TraverseDecl(D);
+
+    TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
+    if (NTTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
+      assert(Arg.getKind() == TemplateArgument::Pack &&
+             "Missing argument pack");
+      Arg = getPackSubstitutedTemplateArgument(Arg);
+    }
+
+    UsedTemplateArgs.push_back(
+        SemaRef.Context.getCanonicalTemplateArgument(Arg));
+    return true;
+  }
+
+  bool VisitTypedefType(TypedefType *TT) {
+    return inherited::TraverseType(TT->desugar());
+  }
+
+  bool TraverseDecl(Decl *D) {
+    if (auto *VD = dyn_cast<ValueDecl>(D))
+      return TraverseType(VD->getType());
+
+    return inherited::TraverseDecl(D);
+  }
+
+  bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
+    // We don't care about TypeLocs. So traverse Types instead.
+    return TraverseType(TL.getType(), TraverseQualifier);
+  }
+
+  bool TraverseTemplateArgument(const TemplateArgument &Arg) {
+    if (!Arg.containsUnexpandedParameterPack() || Arg.isPackExpansion()) {
+      // Act as if we are fully expanding this pack, if it is a PackExpansion.
+      Sema::ArgPackSubstIndexRAII _1(SemaRef, std::nullopt);
+      llvm::SaveAndRestore<UnsignedOrNone> _2(OuterPackSubstIndex,
+                                              std::nullopt);
+      return inherited::TraverseTemplateArgument(Arg);
+    }
+
+    Sema::ArgPackSubstIndexRAII _1(SemaRef, OuterPackSubstIndex);
+    return inherited::TraverseTemplateArgument(Arg);
+  }
+
+  void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) {
+    if (!Constraint.hasParameterMapping()) {
+      for (auto List : TemplateArgs)
+        for (const TemplateArgument &Arg : List.Args)
+          SemaRef.Context.getCanonicalTemplateArgument(Arg).Profile(
+              ID, SemaRef.Context);
+      return;
+    }
+
+    llvm::ArrayRef<TemplateArgumentLoc> Mapping =
+        Constraint.getParameterMapping();
+    for (auto &ArgLoc : Mapping) {
+      TemplateArgument Canonical =
+          SemaRef.Context.getCanonicalTemplateArgument(ArgLoc.getArgument());
+      // We don't want sugars to impede the profile of cache.
+      UsedTemplateArgs.push_back(Canonical);
+      TraverseTemplateArgument(Canonical);
+    }
+
+    // llvm::SmallSet<llvm::FoldingSetNodeID, 10> ArgHash;
+    for (auto &Used : UsedTemplateArgs) {
+      llvm::FoldingSetNodeID R;
+      Used.Profile(R, SemaRef.Context);
+      ID.AddNodeID(R);
+      // ArgHash.insert(R);
+    }
+
+    // for (const llvm::FoldingSetNodeID &V : ArgHash)
+    //   ID.AddNodeID(V);
+  }
+};
+
+class CalculateConstraintSatisfaction {
+  Sema &S;
+  const NamedDecl *Template;
+  SourceLocation TemplateNameLoc;
+  UnsignedOrNone PackSubstitutionIndex;
+
+  ConstraintSatisfaction &Satisfaction;
+
+private:
+  ExprResult
+  EvaluateAtomicConstraint(const Expr *AtomicExpr,
+                           const MultiLevelTemplateArgumentList &MLTAL);
+
+  UnsignedOrNone EvaluateFoldExpandedConstraintSize(
+      const FoldExpandedConstraint &FE,
+      const MultiLevelTemplateArgumentList &MLTAL);
+
+  // XXX: It is SLOW! Use it very carefully.
+  std::optional<MultiLevelTemplateArgumentList> SubstitutionInTemplateArguments(
+      const NormalizedConstraintWithParamMapping &Constraint,
+      MultiLevelTemplateArgumentList MLTAL,
+      llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost);
+
+  ExprResult CalculateSlow(const AtomicConstraint &Constraint,
+                           const MultiLevelTemplateArgumentList &MLTAL);
+
+  ExprResult Calculate(const AtomicConstraint &Constraint,
+                       const MultiLevelTemplateArgumentList &MLTAL);
+
+  ExprResult Calculate(const FoldExpandedConstraint &Constraint,
+                       const MultiLevelTemplateArgumentList &MLTAL);
+
+  ExprResult Calculate(const ConceptIdConstraint &Constraint,
+                       const MultiLevelTemplateArgumentList &MLTAL);
+
+  ExprResult Calculate(const CompoundConstraint &Constraint,
+                       const MultiLevelTemplateArgumentList &MLTAL);
+
+public:
+  CalculateConstraintSatisfaction(Sema &SemaRef, const NamedDecl *Template,
+                                  SourceLocation TemplateNameLoc,
+                                  UnsignedOrNone PackSubstitutionIndex,
+                                  ConstraintSatisfaction &Satisfaction)
+      : S(SemaRef), Template(Template), TemplateNameLoc(TemplateNameLoc),
+        PackSubstitutionIndex(PackSubstitutionIndex),
+        Satisfaction(Satisfaction) {}
+
+  ExprResult Calculate(const NormalizedConstraint &Constraint,
+                       const MultiLevelTemplateArgumentList &MLTAL);
+};
+
+} // namespace
+
+ExprResult CalculateConstraintSatisfaction::EvaluateAtomicConstraint(
+    const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL) {
   EnterExpressionEvaluationContext ConstantEvaluated(
       S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
       Sema::ReuseLambdaContextDecl);
 
+  llvm::FoldingSetNodeID ID;
+  if (Template &&
+      DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, &MLTAL)) {
+    Satisfaction.IsSatisfied = false;
+    Satisfaction.ContainsErrors = true;
+    return ExprEmpty();
+  }
+  SatisfactionStackRAII StackRAII(S, Template, ID);
+
   // Atomic constraint - substitute arguments and check satisfaction.
-  ExprResult SubstitutedExpression;
+  ExprResult SubstitutedExpression = const_cast<Expr *>(AtomicExpr);
   {
     TemplateDeductionInfo Info(TemplateNameLoc);
     Sema::InstantiatingTemplate Inst(
@@ -220,16 +476,6 @@ static ExprResult EvaluateAtomicConstraint(
     if (Inst.isInvalid())
       return ExprError();
 
-    llvm::FoldingSetNodeID ID;
-    if (Template &&
-        DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
-      Satisfaction.IsSatisfied = false;
-      Satisfaction.ContainsErrors = true;
-      return ExprEmpty();
-    }
-
-    SatisfactionStackRAII StackRAII(S, Template, ID);
-
     // We do not want error diagnostics escaping here.
     Sema::SFINAETrap Trap(S);
     SubstitutedExpression =
@@ -289,284 +535,523 @@ static ExprResult EvaluateAtomicConstraint(
   return SubstitutedExpression;
 }
 
-static UnsignedOrNone EvaluateFoldExpandedConstraintSize(
-    Sema &S, const CXXFoldExpr *FE, const NamedDecl *Template,
-    SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
-    ConstraintSatisfaction &Satisfaction) {
+std::optional<MultiLevelTemplateArgumentList>
+CalculateConstraintSatisfaction::SubstitutionInTemplateArguments(
+    const NormalizedConstraintWithParamMapping &Constraint,
+    MultiLevelTemplateArgumentList MLTAL,
+    llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost) {
+
+  if (!Constraint.hasParameterMapping())
+    return std::move(MLTAL);
+
+  TemplateDeductionInfo Info(Constraint.getBeginLoc());
+  Sema::InstantiatingTemplate Inst(
+      S, Constraint.getBeginLoc(),
+      Sema::InstantiatingTemplate::ConstraintSubstitution{},
+      // FIXME: improve const-correctness of InstantiatingTemplate
+      const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
+  if (Inst.isInvalid())
+    return std::nullopt;
+
+  Sema::SFINAETrap Trap(S);
+
+  TemplateArgumentListInfo SubstArgs;
+  Sema::ArgPackSubstIndexRAII SubstIndex(
+      S, Constraint.getPackSubstitutionIndex()
+             ? Constraint.getPackSubstitutionIndex()
+             : PackSubstitutionIndex);
+
+  if (S.SubstTemplateArgumentsInParameterMapping(
+          Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL,
+          SubstArgs, /*BuildPackExpansionTypes=*/true)) {
+    Satisfaction.IsSatisfied = false;
+    return std::nullopt;
+  }
+
+  Sema::CheckTemplateArgumentInfo CTAI;
+  auto *TD = const_cast<TemplateDecl *>(
+      cast<TemplateDecl>(Constraint.getConstraintDecl()));
+  if (S.CheckTemplateArgumentList(TD, Constraint.getUsedTemplateParamList(),
+                                  TD->getLocation(), SubstArgs,
+                                  /*DefaultArguments=*/{},
+                                  /*PartialTemplateArgs=*/false, CTAI))
+    return std::nullopt;
+  NormalizedConstraint::OccurenceList Used = Constraint.mappingOccurenceList();
+  SubstitutedOuterMost =
+      llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost());
+  unsigned Offset = 0;
+  for (unsigned I = 0, MappedIndex = 0; I < Used.size(); I++) {
+    TemplateArgument Arg;
+    if (Used[I])
+      Arg = S.Context.getCanonicalTemplateArgument(
+          CTAI.SugaredConverted[MappedIndex++]);
+    if (I < SubstitutedOuterMost.size()) {
+      SubstitutedOuterMost[I] = Arg;
+      Offset = I + 1;
+    } else {
+      SubstitutedOuterMost.push_back(Arg);
+      Offset = SubstitutedOuterMost.size();
+    }
+  }
+  if (Offset < SubstitutedOuterMost.size())
+    SubstitutedOuterMost.erase(SubstitutedOuterMost.begin() + Offset);
+
+  MLTAL.replaceOutermostTemplateArguments(
+      const_cast<NamedDecl *>(Constraint.getConstraintDecl()),
+      SubstitutedOuterMost);
+  return std::move(MLTAL);
+}
+
+ExprResult CalculateConstraintSatisfaction::CalculateSlow(
+    const AtomicConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
+  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
+      SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
+  if (!SubstitutedArgs) {
+    Satisfaction.IsSatisfied = false;
+    return ExprEmpty();
+  }
+
+  Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
+  ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
+      Constraint.getConstraintExpr(), *SubstitutedArgs);
+
+  if (SubstitutedAtomicExpr.isInvalid())
+    return ExprError();
+
+  if (SubstitutedAtomicExpr.isUnset())
+    // Evaluator has decided satisfaction without yielding an expression.
+    return ExprEmpty();
+
+  // We don't have the ability to evaluate this, since it contains a
+  // RecoveryExpr, so we want to fail overload resolution.  Otherwise,
+  // we'd potentially pick up a different overload, and cause confusing
+  // diagnostics. SO, add a failure detail that will cause us to make this
+  // overload set not viable.
+  if (SubstitutedAtomicExpr.get()->containsErrors()) {
+    Satisfaction.IsSatisfied = false;
+    Satisfaction.ContainsErrors = true;
+
+    PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
+    SmallString<128> DiagString;
+    DiagString = ": ";
+    Msg.EmitToString(S.getDiagnostics(), DiagString);
+    unsigned MessageSize = DiagString.size();
+    char *Mem = new (S.Context) char[MessageSize];
+    memcpy(Mem, DiagString.c_str(), MessageSize);
+    Satisfaction.Details.emplace_back(
+        new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+            SubstitutedAtomicExpr.get()->getBeginLoc(),
+            StringRef(Mem, MessageSize)});
+    return SubstitutedAtomicExpr;
+  }
+
+  if (SubstitutedAtomicExpr.get()->isValueDependent()) {
+    Satisfaction.IsSatisfied = true;
+    Satisfaction.ContainsErrors = false;
+    return SubstitutedAtomicExpr;
+  }
+
+  EnterExpressionEvaluationContext ConstantEvaluated(
+      S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+  SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
+  Expr::EvalResult EvalResult;
+  EvalResult.Diag = &EvaluationDiags;
+  if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult,
+                                                           S.Context) ||
+      !EvaluationDiags.empty()) {
+    // C++2a [temp.constr.atomic]p1
+    //   ...E shall be a constant expression of type bool.
+    S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
+           diag::err_non_constant_constraint_expression)
+        << SubstitutedAtomicExpr.get()->getSourceRange();
+    for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
+      S.Diag(PDiag.first, PDiag.second);
+    return ExprError();
+  }
+
+  assert(EvalResult.Val.isInt() &&
+         "evaluating bool expression didn't produce int");
+  Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+  if (!Satisfaction.IsSatisfied)
+    Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
+
+  return SubstitutedAtomicExpr;
+}
+
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const AtomicConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  unsigned Size = Satisfaction.Details.size();
+  llvm::FoldingSetNodeID ID;
+  UnsignedOrNone OuterPackSubstIndex =
+      Constraint.getPackSubstitutionIndex()
+          ? Constraint.getPackSubstitutionIndex()
+          : PackSubstitutionIndex;
+  // Constraint.getConstraintExpr()->Profile(ID, S.Context, /*Canonical=*/true,
+  //                                         /*ProfileLambdaExpr=*/true);
+  auto *Previous = Constraint.getConstraintExpr();
+  ID.AddPointer(Constraint.getConstraintExpr());
+  ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
+  ID.AddBoolean(Constraint.hasParameterMapping());
+  HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
+      .VisitConstraint(Constraint);
+
+  unsigned CacheKeyHash = ID.computeStableHash();
+
+#define UseCache 1
+  if (auto Iter = S.ConceptIdSatisfactionCache.find(ID);
+      Iter != S.ConceptIdSatisfactionCache.end()) {
+#if UseCache
+    auto &Cached = Iter->second.Satisfaction;
+    Satisfaction.ContainsErrors = Cached.ContainsErrors;
+    Satisfaction.IsSatisfied = Cached.IsSatisfied;
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
+                                Cached.Details.begin(), Cached.Details.end());
+#ifndef NDEBUG
+    if (Iter->second.E != Constraint.getConstraintExpr()) {
+      llvm::errs() << "CacheKey: " << CacheKeyHash << " "
+                   << S.ConceptIdSatisfactionCache.size() << "\n";
+      if (Constraint.hasParameterMapping()) {
+        llvm::errs() << "Mapping: ";
+        for (auto Arg : Constraint.getParameterMapping()) {
+          Arg.getArgument().print(S.getPrintingPolicy(), llvm::errs(),
+                                  /*IncludeType=*/false);
+          llvm::errs() << " ";
+        }
+        llvm::errs() << "\n";
+      }
+      llvm::errs() << "Previous 1: " << Iter->second.E << " ";
+      Iter->second.E->printPretty(llvm::errs(), /*Helper=*/nullptr,
+                                  S.getPrintingPolicy());
+      llvm::errs() << "\n";
+      llvm::errs() << "Current 1: " << Constraint.getConstraintExpr() << " ";
+      Constraint.getConstraintExpr()->printPretty(
+          llvm::errs(), /*Helper=*/nullptr, S.getPrintingPolicy());
+      llvm::errs() << "\n";
+    }
+    assert(Iter->second.E == Constraint.getConstraintExpr());
+#ifndef NDEBUG
+    return Iter->second.SubstExpr;
+#else
+#endif
+  }
+
+  ExprResult E = CalculateSlow(Constraint, MLTAL);
+
+  assert(Constraint.getConstraintExpr() == Previous);
+
+  if (auto Iter = S.ConceptIdSatisfactionCache.find(ID);
+      Iter != S.ConceptIdSatisfactionCache.end()) {
+#if UseCache
+    auto &Cached = Iter->second.Satisfaction;
+    Satisfaction.ContainsErrors = Cached.ContainsErrors;
+    Satisfaction.IsSatisfied = Cached.IsSatisfied;
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
+                                Cached.Details.begin(), Cached.Details.end());
+#ifndef NDEBUG
+    if (Iter->second.E != Constraint.getConstraintExpr()) {
+      llvm::errs() << "CacheKey: " << CacheKeyHash << " ";
+      llvm::errs() << "Previous: ";
+      Iter->second.E->printPretty(llvm::errs(), /*Helper=*/nullptr,
+                                  S.getPrintingPolicy());
+      llvm::errs() << "\n";
+      llvm::errs() << "Current: ";
+      Constraint.getConstraintExpr()->printPretty(
+          llvm::errs(), /*Helper=*/nullptr, S.getPrintingPolicy());
+      llvm::errs() << "\n";
+    }
+    assert(Iter->second.E == Constraint.getConstraintExpr());
+#ifndef NDEBUG
+    return Iter->second.SubstExpr;
+#endif
+  }
+
+  CachedConceptIdConstraint Cache;
+  Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
+  Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
+  std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
+            std::back_inserter(Cache.Satisfaction.Details));
+  Cache.SubstExpr = E;
+  Cache.E = Constraint.getConstraintExpr();
+  S.ConceptIdSatisfactionCache.insert({ID, std::move(Cache)});
+#undef UseCache
+
+  return E;
+}
+
+UnsignedOrNone
+CalculateConstraintSatisfaction::EvaluateFoldExpandedConstraintSize(
+    const FoldExpandedConstraint &FE,
+    const MultiLevelTemplateArgumentList &MLTAL) {
 
   // We should ignore errors in the presence of packs of different size.
   Sema::SFINAETrap Trap(S);
 
-  Expr *Pattern = FE->getPattern();
+  Expr *Pattern = const_cast<Expr *>(FE.getPattern());
 
   SmallVector<UnexpandedParameterPack, 2> Unexpanded;
   S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
   assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
   bool Expand = true;
   bool RetainExpansion = false;
-  UnsignedOrNone NumExpansions = FE->getNumExpansions();
+  UnsignedOrNone NumExpansions(std::nullopt);
   if (S.CheckParameterPacksForExpansion(
-          FE->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
-          /*FailOnPackProducingTemplates=*/true, Expand, RetainExpansion,
+          Pattern->getExprLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
+          /*FailOnPackProducingTemplates=*/false, Expand, RetainExpansion,
           NumExpansions) ||
       !Expand || RetainExpansion)
     return std::nullopt;
 
   if (NumExpansions && S.getLangOpts().BracketDepth < *NumExpansions) {
-    S.Diag(FE->getEllipsisLoc(),
+    S.Diag(Pattern->getExprLoc(),
            clang::diag::err_fold_expression_limit_exceeded)
         << *NumExpansions << S.getLangOpts().BracketDepth
-        << FE->getSourceRange();
-    S.Diag(FE->getEllipsisLoc(), diag::note_bracket_depth);
+        << Pattern->getSourceRange();
+    S.Diag(Pattern->getExprLoc(), diag::note_bracket_depth);
     return std::nullopt;
   }
   return NumExpansions;
 }
 
-static ExprResult calculateConstraintSatisfaction(
-    Sema &S, const Expr *ConstraintExpr, const NamedDecl *Template,
-    SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
-    ConstraintSatisfaction &Satisfaction);
-
-static ExprResult calculateConstraintSatisfaction(
-    Sema &S, const Expr *LHS, OverloadedOperatorKind Op, const Expr *RHS,
-    const NamedDecl *Template, SourceLocation TemplateNameLoc,
-    const MultiLevelTemplateArgumentList &MLTAL,
-    ConstraintSatisfaction &Satisfaction) {
-  size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
-
-  ExprResult LHSRes = calculateConstraintSatisfaction(
-      S, LHS, Template, TemplateNameLoc, MLTAL, Satisfaction);
-
-  if (LHSRes.isInvalid())
-    return ExprError();
-
-  bool IsLHSSatisfied = Satisfaction.IsSatisfied;
-
-  if (Op == clang::OO_PipePipe && IsLHSSatisfied)
-    // [temp.constr.op] p3
-    //    A disjunction is a constraint taking two operands. To determine if
-    //    a disjunction is satisfied, the satisfaction of the first operand
-    //    is checked. If that is satisfied, the disjunction is satisfied.
-    //    Otherwise, the disjunction is satisfied if and only if the second
-    //    operand is satisfied.
-    // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
-    return LHSRes;
-
-  if (Op == clang::OO_AmpAmp && !IsLHSSatisfied)
-    // [temp.constr.op] p2
-    //    A conjunction is a constraint taking two operands. To determine if
-    //    a conjunction is satisfied, the satisfaction of the first operand
-    //    is checked. If that is not satisfied, the conjunction is not
-    //    satisfied. Otherwise, the conjunction is satisfied if and only if
-    //    the second operand is satisfied.
-    // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
-    return LHSRes;
-
-  ExprResult RHSRes = calculateConstraintSatisfaction(
-      S, RHS, Template, TemplateNameLoc, MLTAL, Satisfaction);
-  if (RHSRes.isInvalid())
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const FoldExpandedConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+  bool Conjunction = Constraint.getFoldOperator() ==
+                     FoldExpandedConstraint::FoldOperatorKind::And;
+  unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
+
+  llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
+  // FIXME: Is PackSubstitutionIndex correct?
+  llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex);
+  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
+      SubstitutionInTemplateArguments(
+          static_cast<const NormalizedConstraintWithParamMapping &>(Constraint),
+          MLTAL, SubstitutedOuterMost);
+  if (!SubstitutedArgs) {
+    Satisfaction.IsSatisfied = false;
     return ExprError();
-
-  bool IsRHSSatisfied = Satisfaction.IsSatisfied;
-  // Current implementation adds diagnostic information about the falsity
-  // of each false atomic constraint expression when it evaluates them.
-  // When the evaluation results to `false || true`, the information
-  // generated during the evaluation of left-hand side is meaningless
-  // because the whole expression evaluates to true.
-  // The following code removes the irrelevant diagnostic information.
-  // FIXME: We should probably delay the addition of diagnostic information
-  // until we know the entire expression is false.
-  if (Op == clang::OO_PipePipe && IsRHSSatisfied) {
-    auto EffectiveDetailEnd = Satisfaction.Details.begin();
-    std::advance(EffectiveDetailEnd, EffectiveDetailEndIndex);
-    Satisfaction.Details.erase(EffectiveDetailEnd, Satisfaction.Details.end());
-  }
-
-  if (!LHSRes.isUsable() || !RHSRes.isUsable())
-    return ExprEmpty();
-
-  return BinaryOperator::Create(S.Context, LHSRes.get(), RHSRes.get(),
-                                BinaryOperator::getOverloadedOpcode(Op),
-                                S.Context.BoolTy, VK_PRValue, OK_Ordinary,
-                                LHS->getBeginLoc(), FPOptionsOverride{});
-}
-
-static ExprResult calculateConstraintSatisfaction(
-    Sema &S, const CXXFoldExpr *FE, const NamedDecl *Template,
-    SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
-    ConstraintSatisfaction &Satisfaction) {
-  bool Conjunction = FE->getOperator() == BinaryOperatorKind::BO_LAnd;
-  size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
+  }
 
   ExprResult Out;
-  if (FE->isLeftFold() && FE->getInit()) {
-    Out = calculateConstraintSatisfaction(S, FE->getInit(), Template,
-                                          TemplateNameLoc, MLTAL, Satisfaction);
-    if (Out.isInvalid())
-      return ExprError();
+  UnsignedOrNone NumExpansions =
+      EvaluateFoldExpandedConstraintSize(Constraint, *SubstitutedArgs);
+  if (!NumExpansions)
+    return ExprEmpty();
 
-    // If the first clause of a conjunction is not satisfied,
-    // or if the first clause of a disjection is satisfied,
-    // we have established satisfaction of the whole constraint
-    // and we should not continue further.
-    if (Conjunction != Satisfaction.IsSatisfied)
-      return Out;
+  if (*NumExpansions == 0) {
+    Satisfaction.IsSatisfied = Conjunction;
+    return ExprEmpty();
   }
-  UnsignedOrNone NumExpansions = EvaluateFoldExpandedConstraintSize(
-      S, FE, Template, TemplateNameLoc, MLTAL, Satisfaction);
-  if (!NumExpansions)
-    return ExprError();
+
   for (unsigned I = 0; I < *NumExpansions; I++) {
     Sema::ArgPackSubstIndexRAII SubstIndex(S, I);
-    ExprResult Res = calculateConstraintSatisfaction(
-        S, FE->getPattern(), Template, TemplateNameLoc, MLTAL, Satisfaction);
-    if (Res.isInvalid())
-      return ExprError();
-    bool IsRHSSatisfied = Satisfaction.IsSatisfied;
-    if (!Conjunction && IsRHSSatisfied) {
-      auto EffectiveDetailEnd = Satisfaction.Details.begin();
-      std::advance(EffectiveDetailEnd, EffectiveDetailEndIndex);
-      Satisfaction.Details.erase(EffectiveDetailEnd,
-                                 Satisfaction.Details.end());
+    Satisfaction.IsSatisfied = false;
+    Satisfaction.ContainsErrors = false;
+    ExprResult Expr =
+        CalculateConstraintSatisfaction(S, Template, TemplateNameLoc,
+                                        UnsignedOrNone(I), Satisfaction)
+            .Calculate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
+    if (Expr.isUsable()) {
+      if (Out.isUnset())
+        Out = Expr;
+      else
+        Out = BinaryOperator::Create(S.Context, Out.get(), Expr.get(),
+                                     Conjunction ? BinaryOperatorKind::BO_LAnd
+                                                 : BinaryOperatorKind::BO_LOr,
+                                     S.Context.BoolTy, VK_PRValue, OK_Ordinary,
+                                     Constraint.getBeginLoc(),
+                                     FPOptionsOverride{});
+    } else {
+      assert(!Satisfaction.IsSatisfied);
     }
-    if (Out.isUnset())
-      Out = Res;
-    else if (!Res.isUnset()) {
-      Out = BinaryOperator::Create(
-          S.Context, Out.get(), Res.get(), FE->getOperator(), S.Context.BoolTy,
-          VK_PRValue, OK_Ordinary, FE->getBeginLoc(), FPOptionsOverride{});
+    if (!Conjunction && Satisfaction.IsSatisfied) {
+      Satisfaction.Details.erase(Satisfaction.Details.begin() +
+                                     EffectiveDetailEndIndex,
+                                 Satisfaction.Details.end());
+      break;
     }
-    if (Conjunction != IsRHSSatisfied)
+    if (Satisfaction.IsSatisfied != Conjunction)
       return Out;
   }
 
-  if (FE->isRightFold() && FE->getInit()) {
-    ExprResult Res = calculateConstraintSatisfaction(
-        S, FE->getInit(), Template, TemplateNameLoc, MLTAL, Satisfaction);
-    if (Out.isInvalid())
-      return ExprError();
-
-    if (Out.isUnset())
-      Out = Res;
-    else if (!Res.isUnset()) {
-      Out = BinaryOperator::Create(
-          S.Context, Out.get(), Res.get(), FE->getOperator(), S.Context.BoolTy,
-          VK_PRValue, OK_Ordinary, FE->getBeginLoc(), FPOptionsOverride{});
-    }
-  }
-
-  if (Out.isUnset()) {
-    Satisfaction.IsSatisfied = Conjunction;
-    Out = S.BuildEmptyCXXFoldExpr(FE->getBeginLoc(), FE->getOperator());
-  }
   return Out;
 }
 
-static ExprResult calculateConstraintSatisfaction(
-    Sema &S, const Expr *ConstraintExpr, const NamedDecl *Template,
-    SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
-    ConstraintSatisfaction &Satisfaction) {
-  ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const ConceptIdConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
 
-  if (LogicalBinOp BO = ConstraintExpr)
-    return calculateConstraintSatisfaction(
-        S, BO.getLHS(), BO.getOp(), BO.getRHS(), Template, TemplateNameLoc,
-        MLTAL, Satisfaction);
+  std::optional<Sema::InstantiatingTemplate> InstTemplate;
+  InstTemplate.emplace(S, Constraint.getConceptId()->getBeginLoc(),
+                       Sema::InstantiatingTemplate::ConstraintsCheck{},
+                       Constraint.getConceptId()->getNamedConcept(),
+                       MLTAL.getInnermost(), Constraint.getSourceRange());
 
-  if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
-    // These aren't evaluated, so we don't care about cleanups, so we can just
-    // evaluate these as if the cleanups didn't exist.
-    return calculateConstraintSatisfaction(
-        S, C->getSubExpr(), Template, TemplateNameLoc, MLTAL, Satisfaction);
-  }
+  unsigned Size = Satisfaction.Details.size();
 
-  if (auto *FE = dyn_cast<CXXFoldExpr>(ConstraintExpr);
-      FE && S.getLangOpts().CPlusPlus26 &&
-      (FE->getOperator() == BinaryOperatorKind::BO_LAnd ||
-       FE->getOperator() == BinaryOperatorKind::BO_LOr)) {
-    return calculateConstraintSatisfaction(S, FE, Template, TemplateNameLoc,
-                                           MLTAL, Satisfaction);
+  ExprResult E = Calculate(Constraint.getNormalizedConstraint(), MLTAL);
+
+  if (!E.isUsable()) {
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
+                                Constraint.getConceptId());
+    return E;
   }
 
-  // FIXME: We should not treat ConceptSpecializationExpr as atomic constraints.
+  if (Satisfaction.IsSatisfied)
+    return E;
 
-  // An atomic constraint expression
-  ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
-      S, ConstraintExpr, Template, TemplateNameLoc, MLTAL, Satisfaction);
+  llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
+  std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
+      SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
 
-  if (SubstitutedAtomicExpr.isInvalid())
+  if (!SubstitutedArgs) {
+    Satisfaction.IsSatisfied = false;
+    // FIXME: diagnostics?
     return ExprError();
+  }
 
-  if (!SubstitutedAtomicExpr.isUsable())
-    // Evaluator has decided satisfaction without yielding an expression.
-    return ExprEmpty();
-
-  // We don't have the ability to evaluate this, since it contains a
-  // RecoveryExpr, so we want to fail overload resolution.  Otherwise,
-  // we'd potentially pick up a different overload, and cause confusing
-  // diagnostics. SO, add a failure detail that will cause us to make this
-  // overload set not viable.
-  if (SubstitutedAtomicExpr.get()->containsErrors()) {
+  Sema::SFINAETrap Trap(S);
+  Sema::ArgPackSubstIndexRAII SubstIndex(
+      S, Constraint.getPackSubstitutionIndex()
+             ? Constraint.getPackSubstitutionIndex()
+             : PackSubstitutionIndex);
+
+  const ASTTemplateArgumentListInfo *Ori =
+      Constraint.getConceptId()->getTemplateArgsAsWritten();
+  TemplateDeductionInfo Info(TemplateNameLoc);
+  InstTemplate.emplace(
+      S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{},
+      const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
+
+  TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
+  if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) ||
+      Trap.hasErrorOccurred()) {
     Satisfaction.IsSatisfied = false;
-    Satisfaction.ContainsErrors = true;
+    if (!Trap.hasErrorOccurred())
+      return ExprError();
 
-    PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
+    PartialDiagnosticAt SubstDiag{SourceLocation(),
+                                  PartialDiagnostic::NullDiagnostic()};
+    Info.takeSFINAEDiagnostic(SubstDiag);
+    // FIXME: Concepts: This is an unfortunate consequence of there
+    //  being no serialization code for PartialDiagnostics and the fact
+    //  that serializing them would likely take a lot more storage than
+    //  just storing them as strings. We would still like, in the
+    //  future, to serialize the proper PartialDiagnostic as serializing
+    //  it as a string defeats the purpose of the diagnostic mechanism.
     SmallString<128> DiagString;
     DiagString = ": ";
-    Msg.EmitToString(S.getDiagnostics(), DiagString);
+    SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
     unsigned MessageSize = DiagString.size();
     char *Mem = new (S.Context) char[MessageSize];
     memcpy(Mem, DiagString.c_str(), MessageSize);
-    Satisfaction.Details.emplace_back(
+    Satisfaction.Details.insert(
+        Satisfaction.Details.begin() + Size,
         new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-            SubstitutedAtomicExpr.get()->getBeginLoc(),
-            StringRef(Mem, MessageSize)});
-    return SubstitutedAtomicExpr;
+            SubstDiag.first, StringRef(Mem, MessageSize)});
+    return ExprError();
   }
 
-  EnterExpressionEvaluationContext ConstantEvaluated(
-      S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
-  SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
-  Expr::EvalResult EvalResult;
-  EvalResult.Diag = &EvaluationDiags;
-  if (!SubstitutedAtomicExpr.get()->EvaluateAsConstantExpr(EvalResult,
-                                                           S.Context) ||
-      !EvaluationDiags.empty()) {
-    // C++2a [temp.constr.atomic]p1
-    //   ...E shall be a constant expression of type bool.
-    S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
-           diag::err_non_constant_constraint_expression)
-        << SubstitutedAtomicExpr.get()->getSourceRange();
-    for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
-      S.Diag(PDiag.first, PDiag.second);
-    return ExprError();
+  CXXScopeSpec SS;
+  SS.Adopt(Constraint.getConceptId()->getNestedNameSpecifierLoc());
+
+  ExprResult SubstitutedConceptId = S.CheckConceptTemplateId(
+      SS, Constraint.getConceptId()->getTemplateKWLoc(),
+      Constraint.getConceptId()->getConceptNameInfo(),
+      Constraint.getConceptId()->getFoundDecl(),
+      Constraint.getConceptId()->getNamedConcept(), &OutArgs,
+      /*DoCheckConstraintSatisfaction=*/false);
+
+  if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
+    return E;
+
+  if (Size != Satisfaction.Details.size()) {
+    Satisfaction.Details.insert(
+        Satisfaction.Details.begin() + Size,
+        UnsatisfiedConstraintRecord(
+            SubstitutedConceptId.getAs<ConceptSpecializationExpr>()
+                ->getConceptReference()));
   }
+  return SubstitutedConceptId;
+}
 
-  assert(EvalResult.Val.isInt() &&
-         "evaluating bool expression didn't produce int");
-  Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
-  if (!Satisfaction.IsSatisfied)
-    Satisfaction.Details.emplace_back(SubstitutedAtomicExpr.get());
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const CompoundConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
 
-  return SubstitutedAtomicExpr;
+  unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
+
+  bool Conjunction =
+      Constraint.getCompoundKind() == NormalizedConstraint::CCK_Conjunction;
+
+  ExprResult LHS = Calculate(Constraint.getLHS(), MLTAL);
+
+  if (Conjunction && (!Satisfaction.IsSatisfied || Satisfaction.ContainsErrors))
+    return LHS;
+
+  if (!Conjunction && LHS.isUsable() && Satisfaction.IsSatisfied &&
+      !Satisfaction.ContainsErrors)
+    return LHS;
+
+  Satisfaction.ContainsErrors = false;
+  Satisfaction.IsSatisfied = false;
+
+  ExprResult RHS = Calculate(Constraint.getRHS(), MLTAL);
+
+  if (RHS.isUsable() && Satisfaction.IsSatisfied &&
+      !Satisfaction.ContainsErrors)
+    Satisfaction.Details.erase(Satisfaction.Details.begin() +
+                                   EffectiveDetailEndIndex,
+                               Satisfaction.Details.end());
+
+  if (!LHS.isUsable())
+    return RHS;
+
+  if (!RHS.isUsable())
+    return LHS;
+
+  return BinaryOperator::Create(S.Context, LHS.get(), RHS.get(),
+                                Conjunction ? BinaryOperatorKind::BO_LAnd
+                                            : BinaryOperatorKind::BO_LOr,
+                                S.Context.BoolTy, VK_PRValue, OK_Ordinary,
+                                Constraint.getBeginLoc(), FPOptionsOverride{});
 }
 
-static ExprResult calculateConstraintSatisfaction(
-    Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
-    const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
-    ConstraintSatisfaction &Satisfaction) {
+ExprResult CalculateConstraintSatisfaction::Calculate(
+    const NormalizedConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+  switch (Constraint.getKind()) {
+  case NormalizedConstraint::ConstraintKind::Atomic:
+    return Calculate(static_cast<const AtomicConstraint &>(Constraint), MLTAL);
+
+  case NormalizedConstraint::ConstraintKind::FoldExpanded:
+    return Calculate(static_cast<const FoldExpandedConstraint &>(Constraint),
+                     MLTAL);
+
+  case NormalizedConstraint::ConstraintKind::ConceptId:
+    return Calculate(static_cast<const ConceptIdConstraint &>(Constraint),
+                     MLTAL);
 
-  return calculateConstraintSatisfaction(S, ConstraintExpr, Template,
-                                         TemplateNameLoc, MLTAL, Satisfaction);
+  case NormalizedConstraint::ConstraintKind::Compound:
+    return Calculate(static_cast<const CompoundConstraint &>(Constraint),
+                     MLTAL);
+  }
 }
 
 static bool CheckConstraintSatisfaction(
     Sema &S, const NamedDecl *Template,
     ArrayRef<AssociatedConstraint> AssociatedConstraints,
-    llvm::SmallVectorImpl<Expr *> &Converted,
     const MultiLevelTemplateArgumentList &TemplateArgsLists,
-    SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
+    SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction,
+    Expr **ConvertedExpr, const ConceptReference *TopLevelConceptId = nullptr) {
+
+  if (ConvertedExpr)
+    *ConvertedExpr = nullptr;
+
   if (AssociatedConstraints.empty()) {
     Satisfaction.IsSatisfied = true;
     return false;
@@ -578,57 +1063,60 @@ static bool CheckConstraintSatisfaction(
     return false;
   }
 
-  ArrayRef<TemplateArgument> TemplateArgs =
-      TemplateArgsLists.getNumSubstitutedLevels() > 0
-          ? TemplateArgsLists.getOutermost()
-          : ArrayRef<TemplateArgument>{};
-  Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
-      Sema::InstantiatingTemplate::ConstraintsCheck{},
-      const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
-  if (Inst.isInvalid())
+  llvm::ArrayRef<TemplateArgument> Args;
+  if (TemplateArgsLists.getNumLevels() != 0)
+    Args = TemplateArgsLists.getInnermost();
+
+  std::optional<Sema::InstantiatingTemplate> SynthesisContext;
+  if (!TopLevelConceptId) {
+    SynthesisContext.emplace(S, TemplateIDRange.getBegin(),
+                             Sema::InstantiatingTemplate::ConstraintsCheck{},
+                             const_cast<NamedDecl *>(Template), Args,
+                             TemplateIDRange);
+  }
+
+  const NormalizedConstraint *C =
+      S.getNormalizedAssociatedConstraints(Template, AssociatedConstraints);
+  if (!C) {
+    Satisfaction.IsSatisfied = false;
     return true;
+  }
 
-  for (const AssociatedConstraint &AC : AssociatedConstraints) {
-    if (AC.isNull())
-      return true;
+  if (TopLevelConceptId)
+    C = ConceptIdConstraint::Create(S.getASTContext(), TopLevelConceptId,
+                                    const_cast<NormalizedConstraint *>(C),
+                                    Template, /*CSE=*/nullptr,
+                                    S.ArgPackSubstIndex);
 
-    Sema::ArgPackSubstIndexRAII _(S, AC.ArgPackSubstIndex);
-    ExprResult Res = calculateConstraintSatisfaction(
-        S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
-        AC.ConstraintExpr, Satisfaction);
-    if (Res.isInvalid())
-      return true;
+  ExprResult Res =
+      CalculateConstraintSatisfaction(S, Template, TemplateIDRange.getBegin(),
+                                      S.ArgPackSubstIndex, Satisfaction)
+          .Calculate(*C, TemplateArgsLists);
+
+  if (Res.isInvalid())
+    return true;
+
+  if (Res.isUsable() && ConvertedExpr)
+    *ConvertedExpr = Res.get();
 
-    Converted.push_back(Res.get());
-    if (!Satisfaction.IsSatisfied) {
-      // Backfill the 'converted' list with nulls so we can keep the Converted
-      // and unconverted lists in sync.
-      Converted.append(AssociatedConstraints.size() - Converted.size(),
-                       nullptr);
-      // [temp.constr.op] p2
-      // [...] To determine if a conjunction is satisfied, the satisfaction
-      // of the first operand is checked. If that is not satisfied, the
-      // conjunction is not satisfied. [...]
-      return false;
-    }
-  }
   return false;
 }
 
 bool Sema::CheckConstraintSatisfaction(
-    const NamedDecl *Template,
+    ConstrainedDeclOrNestedRequirement Entity,
     ArrayRef<AssociatedConstraint> AssociatedConstraints,
-    llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
     const MultiLevelTemplateArgumentList &TemplateArgsLists,
-    SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
+    SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction,
+    const ConceptReference *TopLevelConceptId, Expr **ConvertedExpr) {
   if (AssociatedConstraints.empty()) {
     OutSatisfaction.IsSatisfied = true;
     return false;
   }
+  const auto *Template = Entity.dyn_cast<const NamedDecl *>();
   if (!Template) {
     return ::CheckConstraintSatisfaction(
-        *this, nullptr, AssociatedConstraints, ConvertedConstraints,
-        TemplateArgsLists, TemplateIDRange, OutSatisfaction);
+        *this, nullptr, AssociatedConstraints, TemplateArgsLists,
+        TemplateIDRange, OutSatisfaction, ConvertedExpr, TopLevelConceptId);
   }
   // Invalid templates could make their way here. Substituting them could result
   // in dependent expressions.
@@ -643,10 +1131,15 @@ bool Sema::CheckConstraintSatisfaction(
   // here.
   llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
   for (auto List : TemplateArgsLists)
-    llvm::append_range(FlattenedArgs, List.Args);
+    for (const TemplateArgument &Arg : List.Args)
+      FlattenedArgs.emplace_back(Context.getCanonicalTemplateArgument(Arg));
+
+  const NamedDecl *Owner = Template;
+  if (TopLevelConceptId)
+    Owner = TopLevelConceptId->getNamedConcept();
 
   llvm::FoldingSetNodeID ID;
-  ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
+  ConstraintSatisfaction::Profile(ID, Context, Owner, FlattenedArgs);
   void *InsertPos;
   if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
     OutSatisfaction = *Cached;
@@ -654,10 +1147,10 @@ bool Sema::CheckConstraintSatisfaction(
   }
 
   auto Satisfaction =
-      std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
-  if (::CheckConstraintSatisfaction(*this, Template, AssociatedConstraints,
-                                    ConvertedConstraints, TemplateArgsLists,
-                                    TemplateIDRange, *Satisfaction)) {
+      std::make_unique<ConstraintSatisfaction>(Owner, FlattenedArgs);
+  if (::CheckConstraintSatisfaction(
+          *this, Template, AssociatedConstraints, TemplateArgsLists,
+          TemplateIDRange, *Satisfaction, ConvertedExpr, TopLevelConceptId)) {
     OutSatisfaction = *Satisfaction;
     return true;
   }
@@ -688,14 +1181,18 @@ bool Sema::CheckConstraintSatisfaction(
     const ConceptSpecializationExpr *ConstraintExpr,
     ConstraintSatisfaction &Satisfaction) {
 
+  llvm::SmallVector<AssociatedConstraint, 1> Constraints;
+  Constraints.emplace_back(
+      ConstraintExpr->getNamedConcept()->getConstraintExpr());
+
   MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(),
                                        ConstraintExpr->getTemplateArguments(),
                                        true);
 
-  return calculateConstraintSatisfaction(
-             *this, ConstraintExpr, ConstraintExpr->getNamedConcept(),
-             ConstraintExpr->getConceptNameLoc(), MLTAL, Satisfaction)
-      .isInvalid();
+  return CheckConstraintSatisfaction(
+      ConstraintExpr->getNamedConcept(), Constraints, MLTAL,
+      ConstraintExpr->getSourceRange(), Satisfaction,
+      ConstraintExpr->getConceptReference());
 }
 
 bool Sema::SetupConstraintScope(
@@ -854,50 +1351,6 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
       Satisfaction);
 }
 
-
-// Figure out the to-translation-unit depth for this function declaration for
-// the purpose of seeing if they differ by constraints. This isn't the same as
-// getTemplateDepth, because it includes already instantiated parents.
-static unsigned
-CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
-                                     bool SkipForSpecialization = false) {
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      ND, ND->getLexicalDeclContext(), /*Final=*/false,
-      /*Innermost=*/std::nullopt,
-      /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/true, SkipForSpecialization);
-  return MLTAL.getNumLevels();
-}
-
-namespace {
-  class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
-  unsigned TemplateDepth = 0;
-  public:
-  using inherited = TreeTransform<AdjustConstraintDepth>;
-  AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
-      : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
-
-  using inherited::TransformTemplateTypeParmType;
-  QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
-                                         TemplateTypeParmTypeLoc TL, bool) {
-    const TemplateTypeParmType *T = TL.getTypePtr();
-
-    TemplateTypeParmDecl *NewTTPDecl = nullptr;
-    if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
-      NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
-          TransformDecl(TL.getNameLoc(), OldTTPDecl));
-
-    QualType Result = getSema().Context.getTemplateTypeParmType(
-        T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
-        NewTTPDecl);
-    TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
-    NewTL.setNameLoc(TL.getNameLoc());
-    return Result;
-  }
-  };
-} // namespace
-
 static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
     Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
     const Expr *ConstrExpr) {
@@ -1161,73 +1614,61 @@ bool Sema::CheckFunctionTemplateConstraints(
 static void diagnoseUnsatisfiedRequirement(Sema &S,
                                            concepts::ExprRequirement *Req,
                                            bool First) {
-  assert(!Req->isSatisfied()
-         && "Diagnose() can only be used on an unsatisfied requirement");
+  assert(!Req->isSatisfied() &&
+         "Diagnose() can only be used on an unsatisfied requirement");
   switch (Req->getSatisfactionStatus()) {
-    case concepts::ExprRequirement::SS_Dependent:
-      llvm_unreachable("Diagnosing a dependent requirement");
-      break;
-    case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
-      auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
-      if (!SubstDiag->DiagMessage.empty())
-        S.Diag(SubstDiag->DiagLoc,
-               diag::note_expr_requirement_expr_substitution_error)
-               << (int)First << SubstDiag->SubstitutedEntity
-               << SubstDiag->DiagMessage;
-      else
-        S.Diag(SubstDiag->DiagLoc,
-               diag::note_expr_requirement_expr_unknown_substitution_error)
-            << (int)First << SubstDiag->SubstitutedEntity;
-      break;
-    }
-    case concepts::ExprRequirement::SS_NoexceptNotMet:
-      S.Diag(Req->getNoexceptLoc(),
-             diag::note_expr_requirement_noexcept_not_met)
-          << (int)First << Req->getExpr();
-      break;
-    case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
-      auto *SubstDiag =
-          Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
-      if (!SubstDiag->DiagMessage.empty())
-        S.Diag(SubstDiag->DiagLoc,
-               diag::note_expr_requirement_type_requirement_substitution_error)
-            << (int)First << SubstDiag->SubstitutedEntity
-            << SubstDiag->DiagMessage;
-      else
-        S.Diag(SubstDiag->DiagLoc,
-               diag::note_expr_requirement_type_requirement_unknown_substitution_error)
-            << (int)First << SubstDiag->SubstitutedEntity;
-      break;
-    }
-    case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
-      ConceptSpecializationExpr *ConstraintExpr =
-          Req->getReturnTypeRequirementSubstitutedConstraintExpr();
-      if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
-        // A simple case - expr type is the type being constrained and the concept
-        // was not provided arguments.
-        Expr *e = Req->getExpr();
-        S.Diag(e->getBeginLoc(),
-               diag::note_expr_requirement_constraints_not_satisfied_simple)
-            << (int)First << S.Context.getReferenceQualifiedType(e)
-            << ConstraintExpr->getNamedConcept();
-      } else {
-        S.Diag(ConstraintExpr->getBeginLoc(),
-               diag::note_expr_requirement_constraints_not_satisfied)
-            << (int)First << ConstraintExpr;
-      }
-      S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction());
-      break;
-    }
-    case concepts::ExprRequirement::SS_Satisfied:
-      llvm_unreachable("We checked this above");
+  case concepts::ExprRequirement::SS_Dependent:
+    llvm_unreachable("Diagnosing a dependent requirement");
+    break;
+  case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
+    auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
+    if (!SubstDiag->DiagMessage.empty())
+      S.Diag(SubstDiag->DiagLoc,
+             diag::note_expr_requirement_expr_substitution_error)
+          << (int)First << SubstDiag->SubstitutedEntity
+          << SubstDiag->DiagMessage;
+    else
+      S.Diag(SubstDiag->DiagLoc,
+             diag::note_expr_requirement_expr_unknown_substitution_error)
+          << (int)First << SubstDiag->SubstitutedEntity;
+    break;
+  }
+  case concepts::ExprRequirement::SS_NoexceptNotMet:
+    S.Diag(Req->getNoexceptLoc(), diag::note_expr_requirement_noexcept_not_met)
+        << (int)First << Req->getExpr();
+    break;
+  case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
+    auto *SubstDiag =
+        Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
+    if (!SubstDiag->DiagMessage.empty())
+      S.Diag(SubstDiag->DiagLoc,
+             diag::note_expr_requirement_type_requirement_substitution_error)
+          << (int)First << SubstDiag->SubstitutedEntity
+          << SubstDiag->DiagMessage;
+    else
+      S.Diag(
+          SubstDiag->DiagLoc,
+          diag::
+              note_expr_requirement_type_requirement_unknown_substitution_error)
+          << (int)First << SubstDiag->SubstitutedEntity;
+    break;
+  }
+  case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
+    ConceptSpecializationExpr *ConstraintExpr =
+        Req->getReturnTypeRequirementSubstitutedConstraintExpr();
+    S.DiagnoseUnsatisfiedConstraint(ConstraintExpr);
+    break;
+  }
+  case concepts::ExprRequirement::SS_Satisfied:
+    llvm_unreachable("We checked this above");
   }
 }
 
 static void diagnoseUnsatisfiedRequirement(Sema &S,
                                            concepts::TypeRequirement *Req,
                                            bool First) {
-  assert(!Req->isSatisfied()
-         && "Diagnose() can only be used on an unsatisfied requirement");
+  assert(!Req->isSatisfied() &&
+         "Diagnose() can only be used on an unsatisfied requirement");
   switch (Req->getSatisfactionStatus()) {
   case concepts::TypeRequirement::SS_Dependent:
     llvm_unreachable("Diagnosing a dependent requirement");
@@ -1235,9 +1676,9 @@ static void diagnoseUnsatisfiedRequirement(Sema &S,
   case concepts::TypeRequirement::SS_SubstitutionFailure: {
     auto *SubstDiag = Req->getSubstitutionDiagnostic();
     if (!SubstDiag->DiagMessage.empty())
-      S.Diag(SubstDiag->DiagLoc,
-             diag::note_type_requirement_substitution_error) << (int)First
-          << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage;
+      S.Diag(SubstDiag->DiagLoc, diag::note_type_requirement_substitution_error)
+          << (int)First << SubstDiag->SubstitutedEntity
+          << SubstDiag->DiagMessage;
     else
       S.Diag(SubstDiag->DiagLoc,
              diag::note_type_requirement_unknown_substitution_error)
@@ -1249,31 +1690,53 @@ static void diagnoseUnsatisfiedRequirement(Sema &S,
     return;
   }
 }
-static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
-                                                        Expr *SubstExpr,
-                                                        bool First = true);
+
+static void diagnoseUnsatisfiedConceptIdExpr(Sema &S,
+                                             const ConceptReference *Concept,
+                                             SourceLocation Loc, bool First) {
+  if (Concept->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
+    S.Diag(
+        Loc,
+        diag::
+            note_single_arg_concept_specialization_constraint_evaluated_to_false)
+        << (int)First
+        << Concept->getTemplateArgsAsWritten()->arguments()[0].getArgument()
+        << Concept->getNamedConcept();
+  } else {
+    S.Diag(Loc, diag::note_concept_specialization_constraint_evaluated_to_false)
+        << (int)First << Concept;
+  }
+}
+
+static void diagnoseUnsatisfiedConstraintExpr(
+    Sema &S, const UnsatisfiedConstraintRecord &Record, SourceLocation Loc,
+    bool First, concepts::NestedRequirement *Req = nullptr);
+
+static void DiagnoseUnsatisfiedConstraint(
+    Sema &S, ArrayRef<UnsatisfiedConstraintRecord> Records, SourceLocation Loc,
+    bool First = true, concepts::NestedRequirement *Req = nullptr) {
+  for (auto &Record : Records) {
+    diagnoseUnsatisfiedConstraintExpr(S, Record, Loc, First, Req);
+    Loc = {};
+    First = isa<const ConceptReference *>(Record);
+  }
+}
 
 static void diagnoseUnsatisfiedRequirement(Sema &S,
                                            concepts::NestedRequirement *Req,
                                            bool First) {
-  using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
-  for (auto &Record : Req->getConstraintSatisfaction()) {
-    if (auto *SubstDiag = Record.dyn_cast<SubstitutionDiagnostic *>())
-      S.Diag(SubstDiag->first, diag::note_nested_requirement_substitution_error)
-          << (int)First << Req->getInvalidConstraintEntity()
-          << SubstDiag->second;
-    else
-      diagnoseWellFormedUnsatisfiedConstraintExpr(S, Record.dyn_cast<Expr *>(),
-                                                  First);
-    First = false;
-  }
+  DiagnoseUnsatisfiedConstraint(S, Req->getConstraintSatisfaction().records(),
+                                Req->hasInvalidConstraint()
+                                    ? SourceLocation()
+                                    : Req->getConstraintExpr()->getExprLoc(),
+                                First, Req);
 }
 
 static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
-                                                        Expr *SubstExpr,
+                                                        const Expr *SubstExpr,
                                                         bool First) {
   SubstExpr = SubstExpr->IgnoreParenImpCasts();
-  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
+  if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
     switch (BO->getOpcode()) {
     // These two cases will in practice only be reached when using fold
     // expressions with || and &&, since otherwise the || and && will have been
@@ -1319,7 +1782,7 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
         BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context,
                                     Expr::SE_NoSideEffects,
                                     /*InConstantContext=*/true);
-        if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) {
+        if (!SimplifiedLHS.Diag && !SimplifiedRHS.Diag) {
           S.Diag(SubstExpr->getBeginLoc(),
                  diag::note_atomic_constraint_evaluated_to_false_elaborated)
               << (int)First << SubstExpr
@@ -1334,22 +1797,6 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
     default:
       break;
     }
-  } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
-    if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
-      S.Diag(
-          CSE->getSourceRange().getBegin(),
-          diag::
-          note_single_arg_concept_specialization_constraint_evaluated_to_false)
-          << (int)First
-          << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument()
-          << CSE->getNamedConcept();
-    } else {
-      S.Diag(SubstExpr->getSourceRange().getBegin(),
-             diag::note_concept_specialization_constraint_evaluated_to_false)
-          << (int)First << CSE;
-    }
-    S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
-    return;
   } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
     // FIXME: RequiresExpr should store dependent diagnostics.
     for (concepts::Requirement *Req : RE->getRequirements())
@@ -1364,6 +1811,10 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
         break;
       }
     return;
+  } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
+    // Drill down concept ids treated as atomic constraints
+    S.DiagnoseUnsatisfiedConstraint(CSE, First);
+    return;
   } else if (auto *TTE = dyn_cast<TypeTraitExpr>(SubstExpr);
              TTE && TTE->getTrait() == clang::TypeTrait::BTT_IsDeducible) {
     assert(TTE->getNumArgs() == 2);
@@ -1379,216 +1830,327 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
   S.DiagnoseTypeTraitDetails(SubstExpr);
 }
 
-template <typename SubstitutionDiagnostic>
 static void diagnoseUnsatisfiedConstraintExpr(
-    Sema &S, const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
-    bool First = true) {
-  if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()) {
-    S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
-        << Diag->second;
+    Sema &S, const UnsatisfiedConstraintRecord &Record, SourceLocation Loc,
+    bool First, concepts::NestedRequirement *Req) {
+  if (auto *Diag = Record.template dyn_cast<
+                   ConstraintSatisfaction::SubstitutionDiagnostic *>()) {
+    if (Req)
+      S.Diag(Diag->first, diag::note_nested_requirement_substitution_error)
+          << (int)First << Req->getInvalidConstraintEntity() << Diag->second;
+    else
+      S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
+          << Diag->second;
     return;
   }
-
-  diagnoseWellFormedUnsatisfiedConstraintExpr(S, cast<Expr *>(Record), First);
+  if (const auto *Concept = dyn_cast<const ConceptReference *>(Record)) {
+    if (Loc.isInvalid())
+      Loc = Concept->getBeginLoc();
+    diagnoseUnsatisfiedConceptIdExpr(S, Concept, Loc, First);
+    return;
+  }
+  diagnoseWellFormedUnsatisfiedConstraintExpr(
+      S, cast<const class Expr *>(Record), First);
 }
 
-void
-Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction,
-                                    bool First) {
+void Sema::DiagnoseUnsatisfiedConstraint(
+    const ConstraintSatisfaction &Satisfaction, SourceLocation Loc,
+    bool First) {
+
   assert(!Satisfaction.IsSatisfied &&
          "Attempted to diagnose a satisfied constraint");
-  for (auto &Record : Satisfaction.Details) {
-    diagnoseUnsatisfiedConstraintExpr(*this, Record, First);
-    First = false;
-  }
+  ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.Details, Loc, First);
 }
 
 void Sema::DiagnoseUnsatisfiedConstraint(
-    const ASTConstraintSatisfaction &Satisfaction,
-    bool First) {
+    const ConceptSpecializationExpr *ConstraintExpr, bool First) {
+
+  const ASTConstraintSatisfaction &Satisfaction =
+      ConstraintExpr->getSatisfaction();
+
   assert(!Satisfaction.IsSatisfied &&
          "Attempted to diagnose a satisfied constraint");
-  for (auto &Record : Satisfaction) {
-    diagnoseUnsatisfiedConstraintExpr(*this, Record, First);
-    First = false;
-  }
+
+  ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.records(),
+                                  ConstraintExpr->getBeginLoc(), First);
 }
 
-const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
-    const NamedDecl *ConstrainedDecl,
-    ArrayRef<AssociatedConstraint> AssociatedConstraints) {
-  // In case the ConstrainedDecl comes from modules, it is necessary to use
-  // the canonical decl to avoid different atomic constraints with the 'same'
-  // declarations.
-  ConstrainedDecl = cast<NamedDecl>(ConstrainedDecl->getCanonicalDecl());
+namespace {
 
-  auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
-  if (CacheEntry == NormalizationCache.end()) {
-    auto Normalized = NormalizedConstraint::fromAssociatedConstraints(
-        *this, ConstrainedDecl, AssociatedConstraints);
-    CacheEntry =
-        NormalizationCache
-            .try_emplace(ConstrainedDecl,
-                         Normalized
-                             ? new (Context) NormalizedConstraint(
-                                 std::move(*Normalized))
-                             : nullptr)
-            .first;
-  }
-  return CacheEntry->second;
-}
+class SubstituteParameterMappings {
+  Sema &SemaRef;
 
-const NormalizedConstraint *clang::getNormalizedAssociatedConstraints(
-    Sema &S, const NamedDecl *ConstrainedDecl,
-    ArrayRef<AssociatedConstraint> AssociatedConstraints) {
-  return S.getNormalizedAssociatedConstraints(ConstrainedDecl,
-                                              AssociatedConstraints);
-}
+  const MultiLevelTemplateArgumentList *MLTAL;
+  const ASTTemplateArgumentListInfo *ArgsAsWritten;
 
-static bool
-substituteParameterMappings(Sema &S, NormalizedConstraint &N,
-                            ConceptDecl *Concept,
-                            const MultiLevelTemplateArgumentList &MLTAL,
-                            const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+  bool InFoldExpr;
 
-  if (N.isCompound()) {
-    if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
-                                    ArgsAsWritten))
-      return true;
-    return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
-                                       ArgsAsWritten);
-  }
+  SubstituteParameterMappings(Sema &SemaRef,
+                              const MultiLevelTemplateArgumentList *MLTAL,
+                              const ASTTemplateArgumentListInfo *ArgsAsWritten,
+                              bool InFoldExpr)
+      : SemaRef(SemaRef), MLTAL(MLTAL), ArgsAsWritten(ArgsAsWritten),
+        InFoldExpr(InFoldExpr) {}
+
+  void buildParameterMapping(NormalizedConstraintWithParamMapping &N);
 
-  if (N.isFoldExpanded()) {
-    Sema::ArgPackSubstIndexRAII _(S, std::nullopt);
-    return substituteParameterMappings(
-        S, N.getFoldExpandedConstraint()->Constraint, Concept, MLTAL,
-        ArgsAsWritten);
+  bool substitute(NormalizedConstraintWithParamMapping &N);
+
+  bool substitute(ConceptIdConstraint &CC);
+
+public:
+  SubstituteParameterMappings(Sema &SemaRef, bool InFoldExpr = false)
+      : SemaRef(SemaRef), MLTAL(nullptr), ArgsAsWritten(nullptr),
+        InFoldExpr(InFoldExpr) {}
+
+  bool substitute(NormalizedConstraint &N);
+};
+
+void SubstituteParameterMappings::buildParameterMapping(
+    NormalizedConstraintWithParamMapping &N) {
+  TemplateParameterList *TemplateParams =
+      cast<TemplateDecl>(N.getConstraintDecl())->getTemplateParameters();
+
+  llvm::SmallBitVector OccurringIndices(TemplateParams->size());
+
+  if (N.getKind() == NormalizedConstraint::ConstraintKind::Atomic) {
+    SemaRef.MarkUsedTemplateParameters(
+        static_cast<AtomicConstraint &>(N).getConstraintExpr(),
+        /*OnlyDeduced=*/false,
+        /*Depth=*/0, OccurringIndices);
+  } else if (N.getKind() ==
+             NormalizedConstraint::ConstraintKind::FoldExpanded) {
+    SemaRef.MarkUsedTemplateParameters(
+        static_cast<FoldExpandedConstraint &>(N).getPattern(),
+        /*OnlyDeduced=*/false,
+        /*Depth=*/0, OccurringIndices);
+  } else if (N.getKind() == NormalizedConstraint::ConstraintKind::ConceptId) {
+    auto *Args = static_cast<ConceptIdConstraint &>(N)
+                     .getConceptId()
+                     ->getTemplateArgsAsWritten();
+    if (Args)
+      SemaRef.MarkUsedTemplateParameters(Args->arguments(),
+                                         /*Depth=*/0, OccurringIndices);
+  }
+  TemplateArgumentLoc *TempArgs =
+      new (SemaRef.Context) TemplateArgumentLoc[OccurringIndices.count()];
+  llvm::SmallVector<NamedDecl *> UsedParams;
+  for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) {
+    SourceLocation Loc = ArgsAsWritten->NumTemplateArgs > I
+                             ? ArgsAsWritten->arguments()[I].getLocation()
+                             : SourceLocation();
+    // FIXME: Investigate why we couldn't always preserve the SourceLoc. We
+    // can't assert Loc.isValid() now.
+    if (OccurringIndices[I]) {
+      NamedDecl *Param = TemplateParams->begin()[I];
+      new (&(TempArgs)[J]) TemplateArgumentLoc(
+          SemaRef.getIdentityTemplateArgumentLoc(Param, Loc));
+      UsedParams.push_back(Param);
+      J++;
+    }
   }
+  auto *UsedList = TemplateParameterList::Create(
+      SemaRef.Context, TemplateParams->getTemplateLoc(),
+      TemplateParams->getLAngleLoc(), UsedParams,
+      /*RAngleLoc=*/SourceLocation(),
+      /*RequiresClause=*/nullptr);
+  N.updateParameterMapping(
+      OccurringIndices,
+      MutableArrayRef<TemplateArgumentLoc>{TempArgs, OccurringIndices.count()},
+      UsedList);
+}
 
-  TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
+bool SubstituteParameterMappings::substitute(
+    NormalizedConstraintWithParamMapping &N) {
+  if (!N.hasParameterMapping())
+    buildParameterMapping(N);
 
-  AtomicConstraint &Atomic = *N.getAtomicConstraint();
-  TemplateArgumentListInfo SubstArgs;
-  if (!Atomic.ParameterMapping) {
-    llvm::SmallBitVector OccurringIndices(TemplateParams->size());
-    S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
-                                 /*Depth=*/0, OccurringIndices);
-    TemplateArgumentLoc *TempArgs =
-        new (S.Context) TemplateArgumentLoc[OccurringIndices.count()];
-    for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I)
-      if (OccurringIndices[I])
-        new (&(TempArgs)[J++])
-            TemplateArgumentLoc(S.getIdentityTemplateArgumentLoc(
-                TemplateParams->begin()[I],
-                // Here we assume we do not support things like
-                // template<typename A, typename B>
-                // concept C = ...;
-                //
-                // template<typename... Ts> requires C<Ts...>
-                // struct S { };
-                // The above currently yields a diagnostic.
-                // We still might have default arguments for concept parameters.
-                ArgsAsWritten->NumTemplateArgs > I
-                    ? ArgsAsWritten->arguments()[I].getLocation()
-                    : SourceLocation()));
-    Atomic.ParameterMapping.emplace(TempArgs,  OccurringIndices.count());
-  }
-  SourceLocation InstLocBegin =
-      ArgsAsWritten->arguments().empty()
-          ? ArgsAsWritten->getLAngleLoc()
-          : ArgsAsWritten->arguments().front().getSourceRange().getBegin();
-  SourceLocation InstLocEnd =
-      ArgsAsWritten->arguments().empty()
-          ? ArgsAsWritten->getRAngleLoc()
-          : ArgsAsWritten->arguments().front().getSourceRange().getEnd();
+  SourceLocation InstLocBegin, InstLocEnd;
+  llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
+  if (Arguments.empty()) {
+    InstLocBegin = ArgsAsWritten->getLAngleLoc();
+    InstLocEnd = ArgsAsWritten->getRAngleLoc();
+  } else {
+    auto SR = Arguments[0].getSourceRange();
+    InstLocBegin = SR.getBegin();
+    InstLocEnd = SR.getEnd();
+  }
   Sema::InstantiatingTemplate Inst(
-      S, InstLocBegin,
+      SemaRef, InstLocBegin,
       Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
-      const_cast<NamedDecl *>(Atomic.ConstraintDecl),
+      const_cast<NamedDecl *>(N.getConstraintDecl()),
       {InstLocBegin, InstLocEnd});
   if (Inst.isInvalid())
     return true;
-  if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
+
+  // TransformTemplateArguments is unable to preserve the source location of a
+  // pack. The SourceLocation is necessary for the instantiation location.
+  // FIXME: The BaseLoc will be used as the location of the pack expansion,
+  // which is wrong.
+  TemplateArgumentListInfo SubstArgs;
+  if (SemaRef.SubstTemplateArgumentsInParameterMapping(
+          N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs,
+          /*BuildPackExpansionTypes=*/!InFoldExpr))
+    return true;
+  Sema::CheckTemplateArgumentInfo CTAI;
+  auto *TD =
+      const_cast<TemplateDecl *>(cast<TemplateDecl>(N.getConstraintDecl()));
+  if (SemaRef.CheckTemplateArgumentList(TD, N.getUsedTemplateParamList(),
+                                        TD->getLocation(), SubstArgs,
+                                        /*DefaultArguments=*/{},
+                                        /*PartialTemplateArgs=*/false, CTAI))
     return true;
 
   TemplateArgumentLoc *TempArgs =
-      new (S.Context) TemplateArgumentLoc[SubstArgs.size()];
-  std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
-            TempArgs);
-  Atomic.ParameterMapping.emplace(TempArgs, SubstArgs.size());
+      new (SemaRef.Context) TemplateArgumentLoc[CTAI.SugaredConverted.size()];
+
+  for (unsigned I = 0; I < CTAI.SugaredConverted.size(); ++I) {
+    SourceLocation Loc;
+    // If this is an empty pack, we have no corresponding SubstArgs.
+    if (I < SubstArgs.size())
+      Loc = SubstArgs.arguments()[I].getLocation();
+
+    TempArgs[I] = SemaRef.getTrivialTemplateArgumentLoc(
+        CTAI.SugaredConverted[I], QualType(), Loc);
+  }
+
+  MutableArrayRef<TemplateArgumentLoc> Mapping(TempArgs,
+                                               CTAI.SugaredConverted.size());
+  N.updateParameterMapping(N.mappingOccurenceList(), Mapping,
+                           N.getUsedTemplateParamList());
   return false;
 }
 
-static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
-                                        const ConceptSpecializationExpr *CSE) {
-  MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
-      CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
-      /*Final=*/false, CSE->getTemplateArguments(),
-      /*RelativeToPrimary=*/true,
-      /*Pattern=*/nullptr,
-      /*ForConstraintInstantiation=*/true);
+bool SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
+  assert(CC.getConstraintDecl() && MLTAL && ArgsAsWritten);
 
-  return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
-                                     CSE->getTemplateArgsAsWritten());
-}
+  if (substitute(static_cast<NormalizedConstraintWithParamMapping &>(CC)))
+    return true;
+
+  auto *CSE = CC.getConceptSpecializationExpr();
+  assert(CSE);
+  assert(!CC.getBeginLoc().isInvalid());
 
-NormalizedConstraint::NormalizedConstraint(ASTContext &C,
-                                           NormalizedConstraint LHS,
-                                           NormalizedConstraint RHS,
-                                           CompoundConstraintKind Kind)
-    : Constraint{CompoundConstraint{
-          new(C) NormalizedConstraintPair{std::move(LHS), std::move(RHS)},
-          Kind}} {}
-
-NormalizedConstraint::NormalizedConstraint(ASTContext &C,
-                                           const NormalizedConstraint &Other) {
-  if (Other.isAtomic()) {
-    Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint());
-  } else if (Other.isFoldExpanded()) {
-    Constraint = new (C) FoldExpandedConstraint(
-        Other.getFoldExpandedConstraint()->Kind,
-        NormalizedConstraint(C, Other.getFoldExpandedConstraint()->Constraint),
-        Other.getFoldExpandedConstraint()->Pattern);
+  SourceLocation InstLocBegin, InstLocEnd;
+  if (llvm::ArrayRef Arguments = ArgsAsWritten->arguments();
+      Arguments.empty()) {
+    InstLocBegin = ArgsAsWritten->getLAngleLoc();
+    InstLocEnd = ArgsAsWritten->getRAngleLoc();
   } else {
-    Constraint = CompoundConstraint(
-        new (C)
-            NormalizedConstraintPair{NormalizedConstraint(C, Other.getLHS()),
-                                     NormalizedConstraint(C, Other.getRHS())},
-        Other.getCompoundKind());
+    auto SR = Arguments[0].getSourceRange();
+    InstLocBegin = SR.getBegin();
+    InstLocEnd = SR.getEnd();
   }
-}
+  // This is useful for name lookup across modules; see Sema::getLookupModules.
+  Sema::InstantiatingTemplate Inst(
+      SemaRef, InstLocBegin,
+      Sema::InstantiatingTemplate::ParameterMappingSubstitution{},
+      const_cast<NamedDecl *>(CC.getConstraintDecl()),
+      {InstLocBegin, InstLocEnd});
+  if (Inst.isInvalid())
+    return true;
 
-NormalizedConstraint &NormalizedConstraint::getLHS() const {
-  assert(isCompound() && "getLHS called on a non-compound constraint.");
-  return cast<CompoundConstraint>(Constraint).getPointer()->LHS;
+  TemplateArgumentListInfo Out;
+  // TransformTemplateArguments is unable to preserve the source location of a
+  // pack. The SourceLocation is necessary for the instantiation location.
+  // FIXME: The BaseLoc will be used as the location of the pack expansion,
+  // which is wrong.
+  const ASTTemplateArgumentListInfo *ArgsAsWritten =
+      CSE->getTemplateArgsAsWritten();
+  if (SemaRef.SubstTemplateArgumentsInParameterMapping(
+          ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out,
+          /*BuildPackExpansionTypes=*/!InFoldExpr))
+    return true;
+  Sema::CheckTemplateArgumentInfo CTAI;
+  if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(),
+                                        CSE->getConceptNameInfo().getLoc(), Out,
+                                        /*DefaultArgs=*/{},
+                                        /*PartialTemplateArgs=*/false, CTAI,
+                                        /*UpdateArgsWithConversions=*/false))
+    return true;
+  auto TemplateArgs = *MLTAL;
+  TemplateArgs.replaceOutermostTemplateArguments(
+      TemplateArgs.getAssociatedDecl(0).first, CTAI.SugaredConverted);
+  return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten,
+                                     InFoldExpr)
+      .substitute(CC.getNormalizedConstraint());
 }
 
-NormalizedConstraint &NormalizedConstraint::getRHS() const {
-  assert(isCompound() && "getRHS called on a non-compound constraint.");
-  return cast<CompoundConstraint>(Constraint).getPointer()->RHS;
+bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
+  switch (N.getKind()) {
+  case NormalizedConstraint::ConstraintKind::Atomic: {
+    if (!MLTAL) {
+      assert(!ArgsAsWritten);
+      return false;
+    }
+    return substitute(static_cast<NormalizedConstraintWithParamMapping &>(N));
+  }
+  case NormalizedConstraint::ConstraintKind::FoldExpanded: {
+    auto &FE = static_cast<FoldExpandedConstraint &>(N);
+    if (!MLTAL) {
+      llvm::SaveAndRestore _1(InFoldExpr, true);
+      assert(!ArgsAsWritten);
+      return substitute(FE.getNormalizedPattern());
+    }
+    Sema::ArgPackSubstIndexRAII _(SemaRef, std::nullopt);
+    substitute(static_cast<NormalizedConstraintWithParamMapping &>(FE));
+    return SubstituteParameterMappings(SemaRef, /*InFoldExpr=*/true)
+        .substitute(FE.getNormalizedPattern());
+  }
+  case NormalizedConstraint::ConstraintKind::ConceptId: {
+    auto &CC = static_cast<ConceptIdConstraint &>(N);
+    if (MLTAL) {
+      assert(ArgsAsWritten);
+      return substitute(CC);
+    }
+    assert(!ArgsAsWritten);
+    const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+    ConceptDecl *Concept = CSE->getNamedConcept();
+    MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
+        Concept, Concept->getLexicalDeclContext(),
+        /*Final=*/true, CSE->getTemplateArguments(),
+        /*RelativeToPrimary=*/true,
+        /*Pattern=*/nullptr,
+        /*ForConstraintInstantiation=*/true);
+
+    // Don't build Subst* nodes to model lambda expressions.
+    // The transform of Subst* is oblivious to the lambda type.
+    MLTAL.setKind(TemplateSubstitutionKind::Rewrite);
+    return SubstituteParameterMappings(
+               SemaRef, &MLTAL, CSE->getTemplateArgsAsWritten(), InFoldExpr)
+        .substitute(CC.getNormalizedConstraint());
+  }
+  case NormalizedConstraint::ConstraintKind::Compound: {
+    auto &Compound = static_cast<CompoundConstraint &>(N);
+    if (substitute(Compound.getLHS()))
+      return true;
+    return substitute(Compound.getRHS());
+  }
+  }
 }
 
-std::optional<NormalizedConstraint>
-NormalizedConstraint::fromAssociatedConstraints(
+} // namespace
+
+NormalizedConstraint *NormalizedConstraint::fromAssociatedConstraints(
     Sema &S, const NamedDecl *D, ArrayRef<AssociatedConstraint> ACs) {
   assert(ACs.size() != 0);
-  auto Conjunction = fromConstraintExpr(S, D, ACs[0].ConstraintExpr);
+  auto *Conjunction =
+      fromConstraintExpr(S, D, ACs[0].ConstraintExpr, ACs[0].ArgPackSubstIndex);
   if (!Conjunction)
-    return std::nullopt;
+    return nullptr;
   for (unsigned I = 1; I < ACs.size(); ++I) {
-    auto Next = fromConstraintExpr(S, D, ACs[I].ConstraintExpr);
+    auto *Next = fromConstraintExpr(S, D, ACs[I].ConstraintExpr,
+                                    ACs[I].ArgPackSubstIndex);
     if (!Next)
-      return std::nullopt;
-    *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
-                                        std::move(*Next), CCK_Conjunction);
+      return nullptr;
+    Conjunction = CompoundConstraint::CreateConjunction(S.getASTContext(),
+                                                        Conjunction, Next);
   }
   return Conjunction;
 }
 
-std::optional<NormalizedConstraint>
-NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
-                                         const Expr *E) {
+NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
+    Sema &S, const NamedDecl *D, const Expr *E, UnsignedOrNone SubstIndex) {
   assert(E != nullptr);
 
   // C++ [temp.constr.normal]p1.1
@@ -1597,23 +2159,29 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
   // [...]
   E = E->IgnoreParenImpCasts();
 
+  llvm::FoldingSetNodeID ID;
+  if (D && DiagRecursiveConstraintEval(S, ID, D, E)) {
+    return nullptr;
+  }
+  SatisfactionStackRAII StackRAII(S, D, ID);
+
   // C++2a [temp.param]p4:
   //     [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
   // Fold expression is considered atomic constraints per current wording.
   // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
 
   if (LogicalBinOp BO = E) {
-    auto LHS = fromConstraintExpr(S, D, BO.getLHS());
+    auto *LHS = fromConstraintExpr(S, D, BO.getLHS(), SubstIndex);
     if (!LHS)
-      return std::nullopt;
-    auto RHS = fromConstraintExpr(S, D, BO.getRHS());
+      return nullptr;
+    auto *RHS = fromConstraintExpr(S, D, BO.getRHS(), SubstIndex);
     if (!RHS)
-      return std::nullopt;
+      return nullptr;
 
-    return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
-                                BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
+    return CompoundConstraint::Create(
+        S.Context, LHS, BO.isAnd() ? CCK_Conjunction : CCK_Disjunction, RHS);
   } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
-    const NormalizedConstraint *SubNF;
+    NormalizedConstraint *SubNF;
     {
       Sema::InstantiatingTemplate Inst(
           S, CSE->getExprLoc(),
@@ -1621,7 +2189,7 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
           // FIXME: improve const-correctness of InstantiatingTemplate
           const_cast<NamedDecl *>(D), CSE->getSourceRange());
       if (Inst.isInvalid())
-        return std::nullopt;
+        return nullptr;
       // C++ [temp.constr.normal]p1.1
       // [...]
       // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
@@ -1631,20 +2199,23 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
       // constraint. If any such substitution results in an invalid type or
       // expression, the program is ill-formed; no diagnostic is required.
       // [...]
-      ConceptDecl *CD = CSE->getNamedConcept();
-      SubNF = S.getNormalizedAssociatedConstraints(
-          CD, AssociatedConstraint(CD->getConstraintExpr()));
+
+      // Use canonical declarations to merge ConceptDecls across
+      // different modules.
+      ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl();
+      SubNF = NormalizedConstraint::fromAssociatedConstraints(
+          S, CD, AssociatedConstraint(CD->getConstraintExpr(), SubstIndex));
+
       if (!SubNF)
-        return std::nullopt;
+        return nullptr;
     }
+    // if (substituteParameterMappings(S, *SubNF, CSE))
+    //   return nullptr;
 
-    std::optional<NormalizedConstraint> New;
-    New.emplace(S.Context, *SubNF);
-
-    if (substituteParameterMappings(S, *New, CSE))
-      return std::nullopt;
+    return ConceptIdConstraint::Create(S.getASTContext(),
+                                       CSE->getConceptReference(), SubNF, D,
+                                       CSE, SubstIndex);
 
-    return New;
   } else if (auto *FE = dyn_cast<const CXXFoldExpr>(E);
              FE && S.getLangOpts().CPlusPlus26 &&
              (FE->getOperator() == BinaryOperatorKind::BO_LAnd ||
@@ -1658,31 +2229,61 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, const NamedDecl *D,
             : FoldExpandedConstraint::FoldOperatorKind::Or;
 
     if (FE->getInit()) {
-      auto LHS = fromConstraintExpr(S, D, FE->getLHS());
-      auto RHS = fromConstraintExpr(S, D, FE->getRHS());
+      auto *LHS = fromConstraintExpr(S, D, FE->getLHS(), SubstIndex);
+      auto *RHS = fromConstraintExpr(S, D, FE->getRHS(), SubstIndex);
       if (!LHS || !RHS)
-        return std::nullopt;
+        return nullptr;
 
       if (FE->isRightFold())
-        RHS = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
-            Kind, std::move(*RHS), FE->getPattern()}};
+        LHS = FoldExpandedConstraint::Create(S.getASTContext(),
+                                             FE->getPattern(), D, Kind, LHS);
       else
-        LHS = NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
-            Kind, std::move(*LHS), FE->getPattern()}};
-
-      return NormalizedConstraint(
-          S.Context, std::move(*LHS), std::move(*RHS),
-          FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
-                                                           : CCK_Disjunction);
+        RHS = FoldExpandedConstraint::Create(S.getASTContext(),
+                                             FE->getPattern(), D, Kind, RHS);
+
+      return CompoundConstraint::Create(
+          S.getASTContext(), LHS,
+          (FE->getOperator() == BinaryOperatorKind::BO_LAnd ? CCK_Conjunction
+                                                            : CCK_Disjunction),
+          RHS);
     }
-    auto Sub = fromConstraintExpr(S, D, FE->getPattern());
+    auto *Sub = fromConstraintExpr(S, D, FE->getPattern(), SubstIndex);
     if (!Sub)
-      return std::nullopt;
-    return NormalizedConstraint{new (S.Context) FoldExpandedConstraint{
-        Kind, std::move(*Sub), FE->getPattern()}};
+      return nullptr;
+    return FoldExpandedConstraint::Create(S.getASTContext(), FE->getPattern(),
+                                          D, Kind, Sub);
+  }
+  return AtomicConstraint::Create(S.getASTContext(), E, D, SubstIndex);
+}
+
+const NormalizedConstraint *Sema::getNormalizedAssociatedConstraints(
+    ConstrainedDeclOrNestedRequirement ConstrainedDeclOrNestedReq,
+    ArrayRef<AssociatedConstraint> AssociatedConstraints) {
+  if (!ConstrainedDeclOrNestedReq) {
+    auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
+        *this, nullptr, AssociatedConstraints);
+    if (!Normalized ||
+        SubstituteParameterMappings(*this).substitute(*Normalized))
+      return nullptr;
+
+    return Normalized;
   }
 
-  return NormalizedConstraint{new (S.Context) AtomicConstraint(E, D)};
+  // FIXME: ConstrainedDeclOrNestedReq is never a NestedRequirement!
+  const NamedDecl *ND =
+      ConstrainedDeclOrNestedReq.dyn_cast<const NamedDecl *>();
+  auto CacheEntry = NormalizationCache.find(ConstrainedDeclOrNestedReq);
+  if (CacheEntry == NormalizationCache.end()) {
+    auto *Normalized = NormalizedConstraint::fromAssociatedConstraints(
+        *this, ND, AssociatedConstraints);
+    CacheEntry =
+        NormalizationCache.try_emplace(ConstrainedDeclOrNestedReq, Normalized)
+            .first;
+    if (!Normalized ||
+        SubstituteParameterMappings(*this).substitute(*Normalized))
+      return nullptr;
+  }
+  return CacheEntry->second;
 }
 
 bool FoldExpandedConstraint::AreCompatibleForSubsumption(
@@ -1693,8 +2294,10 @@ bool FoldExpandedConstraint::AreCompatibleForSubsumption(
   // if their respective constraints both contain an equivalent unexpanded pack.
 
   llvm::SmallVector<UnexpandedParameterPack> APacks, BPacks;
-  Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(A.Pattern), APacks);
-  Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(B.Pattern), BPacks);
+  Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(A.getPattern()),
+                                        APacks);
+  Sema::collectUnexpandedParameterPacks(const_cast<Expr *>(B.getPattern()),
+                                        BPacks);
 
   for (const UnexpandedParameterPack &APack : APacks) {
     auto ADI = getDepthAndIndex(APack);
@@ -1788,7 +2391,7 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
                                     const AtomicConstraint &B) {
     if (!A.hasMatchingParameterMapping(Context, B))
       return false;
-    const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr;
+    const Expr *EA = A.getConstraintExpr(), *EB = B.getConstraintExpr();
     if (EA == EB)
       return true;
 
@@ -1841,24 +2444,6 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
   return true;
 }
 
-NormalizedConstraint::CompoundConstraintKind
-NormalizedConstraint::getCompoundKind() const {
-  assert(isCompound() && "getCompoundKind on a non-compound constraint..");
-  return cast<CompoundConstraint>(Constraint).getInt();
-}
-
-AtomicConstraint *NormalizedConstraint::getAtomicConstraint() const {
-  assert(isAtomic() && "getAtomicConstraint called on non-atomic constraint.");
-  return cast<AtomicConstraint *>(Constraint);
-}
-
-FoldExpandedConstraint *
-NormalizedConstraint::getFoldExpandedConstraint() const {
-  assert(isFoldExpanded() &&
-         "getFoldExpandedConstraint called on non-fold-expanded constraint.");
-  return cast<FoldExpandedConstraint *>(Constraint);
-}
-
 //
 //
 // ------------------------ Subsumption -----------------------------------
@@ -1874,8 +2459,8 @@ uint16_t SubsumptionChecker::getNewLiteralId() {
   return NextID++;
 }
 
-auto SubsumptionChecker::find(AtomicConstraint *Ori) -> Literal {
-  auto &Elems = AtomicMap[Ori->ConstraintExpr];
+auto SubsumptionChecker::find(const AtomicConstraint *Ori) -> Literal {
+  auto &Elems = AtomicMap[Ori->getConstraintExpr()];
   // C++ [temp.constr.order] p2
   //   - an atomic constraint A subsumes another atomic constraint B
   //     if and only if the A and B are identical [...]
@@ -1891,10 +2476,10 @@ auto SubsumptionChecker::find(AtomicConstraint *Ori) -> Literal {
   // subsumes another, their literal will be the same
 
   llvm::FoldingSetNodeID ID;
-  const auto &Mapping = Ori->ParameterMapping;
-  ID.AddBoolean(Mapping.has_value());
-  if (Mapping) {
-    for (const TemplateArgumentLoc &TAL : *Mapping) {
+  ID.AddBoolean(Ori->hasParameterMapping());
+  if (Ori->hasParameterMapping()) {
+    const auto &Mapping = Ori->getParameterMapping();
+    for (const TemplateArgumentLoc &TAL : Mapping) {
       SemaRef.getASTContext()
           .getCanonicalTemplateArgument(TAL.getArgument())
           .Profile(ID, SemaRef.getASTContext());
@@ -1912,11 +2497,11 @@ auto SubsumptionChecker::find(AtomicConstraint *Ori) -> Literal {
   return It->getSecond().ID;
 }
 
-auto SubsumptionChecker::find(FoldExpandedConstraint *Ori) -> Literal {
-  auto &Elems = FoldMap[Ori->Pattern];
+auto SubsumptionChecker::find(const FoldExpandedConstraint *Ori) -> Literal {
+  auto &Elems = FoldMap[Ori->getPattern()];
 
   FoldExpendedConstraintKey K;
-  K.Kind = Ori->Kind;
+  K.Kind = Ori->getFoldOperator();
 
   auto It = llvm::find_if(Elems, [&K](const FoldExpendedConstraintKey &Other) {
     return K.Kind == Other.Kind;
@@ -1960,38 +2545,47 @@ FormulaType SubsumptionChecker::Normalize(const NormalizedConstraint &NC) {
     AddUniqueClauseToFormula(Res, std::move(C));
   };
 
-  if (NC.isAtomic())
-    return {{find(NC.getAtomicConstraint())}};
+  switch (NC.getKind()) {
 
-  if (NC.isFoldExpanded())
-    return {{find(NC.getFoldExpandedConstraint())}};
+  case NormalizedConstraint::ConstraintKind::Atomic:
+    return {{find(&static_cast<const AtomicConstraint &>(NC))}};
 
-  FormulaType Left, Right;
-  SemaRef.runWithSufficientStackSpace(SourceLocation(), [&] {
-    Left = Normalize<FormulaType>(NC.getLHS());
-    Right = Normalize<FormulaType>(NC.getRHS());
-  });
+  case NormalizedConstraint::ConstraintKind::FoldExpanded:
+    return {{find(&static_cast<const FoldExpandedConstraint &>(NC))}};
 
-  if (NC.getCompoundKind() == FormulaType::Kind) {
-    auto SizeLeft = Left.size();
-    Res = std::move(Left);
-    Res.reserve(SizeLeft + Right.size());
-    std::for_each(std::make_move_iterator(Right.begin()),
-                  std::make_move_iterator(Right.end()), Add);
-    return Res;
-  }
+  case NormalizedConstraint::ConstraintKind::ConceptId:
+    return Normalize<FormulaType>(
+        static_cast<const ConceptIdConstraint &>(NC).getNormalizedConstraint());
+
+  case NormalizedConstraint::ConstraintKind::Compound: {
+    const auto &Compound = static_cast<const CompoundConstraint &>(NC);
+    FormulaType Left, Right;
+    SemaRef.runWithSufficientStackSpace(SourceLocation(), [&] {
+      Left = Normalize<FormulaType>(Compound.getLHS());
+      Right = Normalize<FormulaType>(Compound.getRHS());
+    });
+
+    if (Compound.getCompoundKind() == FormulaType::Kind) {
+      Res = std::move(Left);
+      Res.reserve(Left.size() + Right.size());
+      std::for_each(std::make_move_iterator(Right.begin()),
+                    std::make_move_iterator(Right.end()), Add);
+      return Res;
+    }
 
-  Res.reserve(Left.size() * Right.size());
-  for (const auto &LTransform : Left) {
-    for (const auto &RTransform : Right) {
-      Clause Combined;
-      Combined.reserve(LTransform.size() + RTransform.size());
-      llvm::append_range(Combined, LTransform);
-      llvm::append_range(Combined, RTransform);
-      Add(std::move(Combined));
+    Res.reserve(Left.size() * Right.size());
+    for (const auto &LTransform : Left) {
+      for (const auto &RTransform : Right) {
+        Clause Combined;
+        Combined.reserve(LTransform.size() + RTransform.size());
+        llvm::copy(LTransform, std::back_inserter(Combined));
+        llvm::copy(RTransform, std::back_inserter(Combined));
+        Add(std::move(Combined));
+      }
     }
+    return Res;
+  }
   }
-  return Res;
 }
 
 void SubsumptionChecker::AddUniqueClauseToFormula(Formula &F, Clause C) {
@@ -2006,12 +2600,12 @@ std::optional<bool> SubsumptionChecker::Subsumes(
     const NamedDecl *DP, ArrayRef<AssociatedConstraint> P, const NamedDecl *DQ,
     ArrayRef<AssociatedConstraint> Q) {
   const NormalizedConstraint *PNormalized =
-      getNormalizedAssociatedConstraints(SemaRef, DP, P);
+      SemaRef.getNormalizedAssociatedConstraints(DP, P);
   if (!PNormalized)
     return std::nullopt;
 
   const NormalizedConstraint *QNormalized =
-      getNormalizedAssociatedConstraints(SemaRef, DQ, Q);
+      SemaRef.getNormalizedAssociatedConstraints(DQ, Q);
   if (!QNormalized)
     return std::nullopt;
 
@@ -2061,9 +2655,9 @@ bool SubsumptionChecker::Subsumes(const FoldExpandedConstraint *A,
     // constraint B if they are compatible for subsumption, have the same
     // fold-operator, and the constraint of A subsumes that of B.
     bool DoesSubsume =
-        A->Kind == B->Kind &&
+        A->getFoldOperator() == B->getFoldOperator() &&
         FoldExpandedConstraint::AreCompatibleForSubsumption(*A, *B) &&
-        Subsumes(&A->Constraint, &B->Constraint);
+        Subsumes(&A->getNormalizedPattern(), &B->getNormalizedPattern());
     It = FoldSubsumptionCache.try_emplace(std::move(Key), DoesSubsume).first;
   }
   return It->second;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index fb57b43882911..4c55a452c244a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17877,13 +17877,15 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
         findFailedBooleanCondition(Converted.get());
       if (const auto *ConceptIDExpr =
               dyn_cast_or_null<ConceptSpecializationExpr>(InnerCond)) {
-        // Drill down into concept specialization expressions to see why they
-        // weren't satisfied.
+        const ASTConstraintSatisfaction &Satisfaction =
+            ConceptIDExpr->getSatisfaction();
+        if (!Satisfaction.ContainsErrors || Satisfaction.NumRecords) {
         Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
             << !HasMessage << Msg.str() << AssertExpr->getSourceRange();
-        ConstraintSatisfaction Satisfaction;
-        if (!CheckConstraintSatisfaction(ConceptIDExpr, Satisfaction))
-          DiagnoseUnsatisfiedConstraint(Satisfaction);
+          // Drill down into concept specialization expressions to see why they
+          // weren't satisfied.
+          DiagnoseUnsatisfiedConstraint(ConceptIDExpr);
+        }
       } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) &&
                  !isa<IntegerLiteral>(InnerCond)) {
         Diag(InnerCond->getBeginLoc(),
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1e8bb6e3064a9..c158712fc92c0 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7926,21 +7926,27 @@ Sema::BuildExprRequirement(
     //     be satisfied.
     TemplateParameterList *TPL =
         ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
-    QualType MatchedType =
-        Context.getReferenceQualifiedType(E).getCanonicalType();
+    QualType MatchedType = Context.getReferenceQualifiedType(E);
     llvm::SmallVector<TemplateArgument, 1> Args;
     Args.push_back(TemplateArgument(MatchedType));
 
     auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));
 
-    MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/false);
+    MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/true);
     MLTAL.addOuterRetainedLevels(TPL->getDepth());
     const TypeConstraint *TC = Param->getTypeConstraint();
     assert(TC && "Type Constraint cannot be null here");
     auto *IDC = TC->getImmediatelyDeclaredConstraint();
     assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
     ExprResult Constraint = SubstExpr(IDC, MLTAL);
-    if (Constraint.isInvalid()) {
+    bool HasError = Constraint.isInvalid();
+    if (!HasError) {
+      SubstitutedConstraintExpr =
+          cast<ConceptSpecializationExpr>(Constraint.get());
+      if (SubstitutedConstraintExpr->getSatisfaction().ContainsErrors)
+        HasError = true;
+    }
+    if (HasError) {
       return new (Context) concepts::ExprRequirement(
           createSubstDiagAt(IDC->getExprLoc(),
                             [&](llvm::raw_ostream &OS) {
@@ -7949,8 +7955,6 @@ Sema::BuildExprRequirement(
                             }),
           IsSimple, NoexceptLoc, ReturnTypeRequirement);
     }
-    SubstitutedConstraintExpr =
-        cast<ConceptSpecializationExpr>(Constraint.get());
     if (!SubstitutedConstraintExpr->isSatisfied())
       Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
   }
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index ea5c4265d736d..f741e8283761d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12739,7 +12739,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
         << (unsigned)FnKindPair.first << (unsigned)ocs_non_template
         << FnDesc /* Ignored */;
     ConstraintSatisfaction Satisfaction;
-    if (S.CheckFunctionConstraints(Fn, Satisfaction))
+    if (S.CheckFunctionConstraints(Fn, Satisfaction, SourceLocation(),
+                                   /*ForOverloadResolution=*/true))
       break;
     S.DiagnoseUnsatisfiedConstraint(Satisfaction);
   }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f051a246f954f..7a84a52f7bde3 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -9,6 +9,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "TreeTransform.h"
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
@@ -1188,8 +1189,9 @@ static ExprResult formImmediatelyDeclaredConstraint(
   if (auto *CD = dyn_cast<ConceptDecl>(NamedConcept)) {
     ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
         SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
-        /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD,
-        &ConstraintArgs);
+        /*FoundDecl=*/FoundDecl ? FoundDecl : CD, CD, &ConstraintArgs,
+        /*DoCheckConstraintSatisfaction=*/
+        !S.inParameterMappingSubstitution());
   }
   // We have a template template parameter
   else {
@@ -4816,13 +4818,11 @@ void Sema::diagnoseMissingTemplateArguments(const CXXScopeSpec &SS,
   diagnoseMissingTemplateArguments(Name, Loc);
 }
 
-ExprResult
-Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
-                             SourceLocation TemplateKWLoc,
-                             const DeclarationNameInfo &ConceptNameInfo,
-                             NamedDecl *FoundDecl,
-                             ConceptDecl *NamedConcept,
-                             const TemplateArgumentListInfo *TemplateArgs) {
+ExprResult Sema::CheckConceptTemplateId(
+    const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+    const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl,
+    TemplateDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs,
+    bool DoCheckConstraintSatisfaction) {
   assert(NamedConcept && "A concept template id without a template?");
 
   if (NamedConcept->isInvalidDecl())
@@ -4839,33 +4839,48 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
 
   DiagnoseUseOfDecl(NamedConcept, ConceptNameInfo.getLoc());
 
+  // There's a bug with CTAI.CanonicalConverted.
+  // If the template argument contains a DependentDecltypeType that includes a
+  // TypeAliasType, and the same written type had occurred previously in the
+  // source, then the DependentDecltypeType would be canonicalized to that
+  // previous type which would mess up the substitution.
+  // FIXME: Reland https://github.com/llvm/llvm-project/pull/101782 properly!
   auto *CSD = ImplicitConceptSpecializationDecl::Create(
       Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
-      CTAI.CanonicalConverted);
+      CTAI.SugaredConverted);
   ConstraintSatisfaction Satisfaction;
   bool AreArgsDependent =
       TemplateSpecializationType::anyDependentTemplateArguments(
-          *TemplateArgs, CTAI.CanonicalConverted);
-  MultiLevelTemplateArgumentList MLTAL(NamedConcept, CTAI.CanonicalConverted,
+          *TemplateArgs, CTAI.SugaredConverted);
+  MultiLevelTemplateArgumentList MLTAL(NamedConcept, CTAI.SugaredConverted,
                                        /*Final=*/false);
-  LocalInstantiationScope Scope(*this);
-
-  EnterExpressionEvaluationContext EECtx{
-      *this, ExpressionEvaluationContext::Unevaluated, CSD};
-
-  if (!AreArgsDependent &&
-      CheckConstraintSatisfaction(
-          NamedConcept, AssociatedConstraint(NamedConcept->getConstraintExpr()),
-          MLTAL,
-          SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
-                      TemplateArgs->getRAngleLoc()),
-          Satisfaction))
-    return ExprError();
-  auto *CL = ConceptReference::Create(
+      auto *CL = ConceptReference::Create(
       Context,
       SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
       TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
       ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs));
+
+  bool Error = false;
+  if (const auto *Concept = dyn_cast<ConceptDecl>(NamedConcept);
+      Concept && Concept->getConstraintExpr() && !AreArgsDependent &&
+      DoCheckConstraintSatisfaction) {
+
+    LocalInstantiationScope Scope(*this);
+
+    EnterExpressionEvaluationContext EECtx{
+        *this, ExpressionEvaluationContext::Unevaluated, CSD};
+
+    Error = CheckConstraintSatisfaction(
+        NamedConcept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL,
+        SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
+                    TemplateArgs->getRAngleLoc()),
+        Satisfaction, CL);
+    Satisfaction.ContainsErrors = Error;
+  }
+
+  if (Error)
+    return ExprError();
+
   return ConceptSpecializationExpr::Create(
       Context, CL, CSD, AreArgsDependent ? nullptr : &Satisfaction);
 }
@@ -5183,10 +5198,11 @@ bool Sema::CheckTemplateTypeArgument(
   }
   default: {
     // We allow instantiating a template with template argument packs when
-    // building deduction guides.
+    // building deduction guides or mapping constraint template parameters.
     if (Arg.getKind() == TemplateArgument::Pack &&
-        CodeSynthesisContexts.back().Kind ==
-            Sema::CodeSynthesisContext::BuildingDeductionGuides) {
+        (CodeSynthesisContexts.back().Kind ==
+             Sema::CodeSynthesisContext::BuildingDeductionGuides ||
+         inParameterMappingSubstitution())) {
       SugaredConverted.push_back(Arg);
       CanonicalConverted.push_back(Arg);
       return false;
@@ -5779,6 +5795,20 @@ bool Sema::CheckTemplateArgumentList(
     TemplateArgumentListInfo &TemplateArgs, const DefaultArguments &DefaultArgs,
     bool PartialTemplateArgs, CheckTemplateArgumentInfo &CTAI,
     bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
+  return CheckTemplateArgumentList(
+      Template, GetTemplateParameterList(Template), TemplateLoc, TemplateArgs,
+      DefaultArgs, PartialTemplateArgs, CTAI, UpdateArgsWithConversions,
+      ConstraintsNotSatisfied);
+}
+
+/// Check that the given template argument list is well-formed
+/// for specializing the given template.
+bool Sema::CheckTemplateArgumentList(
+    TemplateDecl *Template, TemplateParameterList *Params,
+    SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs,
+    const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
+    CheckTemplateArgumentInfo &CTAI, bool UpdateArgsWithConversions,
+    bool *ConstraintsNotSatisfied) {
 
   if (ConstraintsNotSatisfied)
     *ConstraintsNotSatisfied = false;
@@ -5788,8 +5818,6 @@ bool Sema::CheckTemplateArgumentList(
   // template.
   TemplateArgumentListInfo NewArgs = TemplateArgs;
 
-  TemplateParameterList *Params = GetTemplateParameterList(Template);
-
   SourceLocation RAngleLoc = NewArgs.getRAngleLoc();
 
   // C++23 [temp.arg.general]p1:
@@ -6004,6 +6032,19 @@ bool Sema::CheckTemplateArgumentList(
         return true;
       }
 
+      // For constraint parameter mapping, we have already built a pack in
+      // TransformTemplateArguments
+      // if (inParameterMappingSubstitution()) {
+      //   llvm::copy(SugaredArgumentPack,
+      //   std::back_inserter(CTAI.SugaredConverted));
+      //   SugaredArgumentPack.clear();
+      //   llvm::copy(CanonicalArgumentPack,
+      //   std::back_inserter(CTAI.CanonicalConverted));
+      //   CanonicalArgumentPack.clear();
+      //   ++Param;
+      //   continue;
+      // }
+
       CTAI.SugaredConverted.push_back(
           TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
       SugaredArgumentPack.clear();
@@ -6129,11 +6170,12 @@ bool Sema::CheckTemplateArgumentList(
     CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
 
     MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
-        Template, NewContext, /*Final=*/false, CTAI.CanonicalConverted,
+        Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
         /*RelativeToPrimary=*/true,
         /*Pattern=*/nullptr,
         /*ForConceptInstantiation=*/true);
-    if (EnsureTemplateArgumentListConstraints(
+    if (!isa<ConceptDecl>(Template) &&
+        EnsureTemplateArgumentListConstraints(
             Template, MLTAL,
             SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
       if (ConstraintsNotSatisfied)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 62e867c44ad14..38a3fb6b84b85 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3223,7 +3223,7 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
   // If we don't need to replace the deduced template arguments,
   // we can add them immediately as the inner-most argument list.
   if (!DeducedArgsNeedReplacement)
-    Innermost = CanonicalDeducedArgs;
+    Innermost = SugaredDeducedArgs;
 
   MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
       Template, Template->getDeclContext(), /*Final=*/false, Innermost,
@@ -3235,7 +3235,7 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
   // not class-scope explicit specialization, so replace with Deduced Args
   // instead of adding to inner-most.
   if (!Innermost)
-    MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
+    MLTAL.replaceInnermostTemplateArguments(Template, SugaredDeducedArgs);
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
@@ -4012,11 +4012,12 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
     if (CheckFunctionTemplateConstraints(
             Info.getLocation(),
             FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
-            CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
+            CTAI.SugaredConverted, Info.AssociatedConstraintsSatisfaction))
       return TemplateDeductionResult::MiscellaneousDeductionFailure;
     if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
-      Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
-                                         Context, CTAI.CanonicalConverted));
+      Info.reset(
+          TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted),
+          Info.takeCanonical());
       return TemplateDeductionResult::ConstraintsNotSatisfied;
     }
   }
@@ -5184,8 +5185,8 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
                                   /*DefaultArgs=*/{},
                                   /*PartialTemplateArgs=*/false, CTAI))
     return true;
-  MultiLevelTemplateArgumentList MLTAL(Concept, CTAI.CanonicalConverted,
-                                       /*Final=*/false);
+  MultiLevelTemplateArgumentList MLTAL(Concept, CTAI.SugaredConverted,
+                                       /*Final=*/true);
   // Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so
   // that the template arguments of the constraint can be preserved. For
   // example:
@@ -5199,7 +5200,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
       S, Sema::ExpressionEvaluationContext::Unevaluated,
       ImplicitConceptSpecializationDecl::Create(
           S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(),
-          CTAI.CanonicalConverted));
+          CTAI.SugaredConverted));
   if (S.CheckConstraintSatisfaction(
           Concept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL,
           TypeLoc.getLocalSourceRange(), Satisfaction))
@@ -6725,6 +6726,7 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
     if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
       if (NTTP->getDepth() == Depth)
         Used[NTTP->getIndex()] = true;
+    DynamicRecursiveASTVisitor::TraverseType(E->getType());
     return true;
   }
 
@@ -7068,10 +7070,13 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
     break;
 
   case Type::UnaryTransform:
-    if (!OnlyDeduced)
-      MarkUsedTemplateParameters(Ctx,
-                                 cast<UnaryTransformType>(T)->getUnderlyingType(),
-                                 OnlyDeduced, Depth, Used);
+    if (!OnlyDeduced) {
+      auto *UTT = cast<UnaryTransformType>(T);
+      auto Next = UTT->getUnderlyingType();
+      if (Next.isNull())
+        Next = UTT->getBaseType();
+      MarkUsedTemplateParameters(Ctx, Next, OnlyDeduced, Depth, Used);
+    }
     break;
 
   case Type::PackExpansion:
@@ -7196,6 +7201,14 @@ void Sema::MarkUsedTemplateParameters(ArrayRef<TemplateArgument> TemplateArgs,
                                  /*OnlyDeduced=*/false, Depth, Used);
 }
 
+void Sema::MarkUsedTemplateParameters(
+    ArrayRef<TemplateArgumentLoc> TemplateArgs, unsigned Depth,
+    llvm::SmallBitVector &Used) {
+  for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+    ::MarkUsedTemplateParameters(Context, TemplateArgs[I].getArgument(),
+                                 /*OnlyDeduced=*/false, Depth, Used);
+}
+
 void Sema::MarkDeducedTemplateParameters(
     ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate,
     llvm::SmallBitVector &Deduced) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a72c95d6d77cf..bfce05135e058 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -629,9 +629,14 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
     Inst.InstantiationRange = InstantiationRange;
     Inst.InConstraintSubstitution =
         Inst.Kind == CodeSynthesisContext::ConstraintSubstitution;
-    if (!SemaRef.CodeSynthesisContexts.empty())
+    Inst.InParameterMappingSubstitution =
+        Inst.Kind == CodeSynthesisContext::ParameterMappingSubstitution;
+    if (!SemaRef.CodeSynthesisContexts.empty()) {
       Inst.InConstraintSubstitution |=
           SemaRef.CodeSynthesisContexts.back().InConstraintSubstitution;
+      Inst.InParameterMappingSubstitution |=
+          SemaRef.CodeSynthesisContexts.back().InParameterMappingSubstitution;
+    }
 
     SemaRef.pushCodeSynthesisContext(Inst);
 
@@ -1387,7 +1392,8 @@ getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) {
 // Template Instantiation for Types
 //===----------------------------------------------------------------------===/
 namespace {
-  class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
+
+class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
     const MultiLevelTemplateArgumentList &TemplateArgs;
     SourceLocation Loc;
     DeclarationName Entity;
@@ -1399,13 +1405,15 @@ namespace {
     // Whether an incomplete substituion should be treated as an error.
     bool BailOutOnIncomplete;
 
-  private:
+    bool PreserveArgumentPacks = false;
+    bool BuildPackExpansionTypes = true;
+
     // CWG2770: Function parameters should be instantiated when they are
     // needed by a satisfaction check of an atomic constraint or
     // (recursively) by another function parameter.
     bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
 
-  public:
+public:
     typedef TreeTransform<TemplateInstantiator> inherited;
 
     TemplateInstantiator(Sema &SemaRef,
@@ -1415,12 +1423,19 @@ namespace {
         : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
           Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
 
-    void setEvaluateConstraints(bool B) {
-      EvaluateConstraints = B;
-    }
-    bool getEvaluateConstraints() {
-      return EvaluateConstraints;
-    }
+  inline static struct ForParameterMappingSubstitution_t {
+  } ForParameterMappingSubstitution;
+
+  TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
+                       SourceLocation Loc,
+                       const MultiLevelTemplateArgumentList &TemplateArgs,
+                       bool BuildPackExpansionTypes)
+      : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+        BailOutOnIncomplete(false), PreserveArgumentPacks(true),
+        BuildPackExpansionTypes(BuildPackExpansionTypes) {}
+
+  void setEvaluateConstraints(bool B) { EvaluateConstraints = B; }
+  bool getEvaluateConstraints() { return EvaluateConstraints; }
 
     /// Determine whether the given type \p T has already been
     /// transformed.
@@ -1463,7 +1478,8 @@ namespace {
                                  bool &ShouldExpand, bool &RetainExpansion,
                                  UnsignedOrNone &NumExpansions) {
       if (SemaRef.CurrentInstantiationScope &&
-          SemaRef.inConstraintSubstitution()) {
+          (SemaRef.inConstraintSubstitution() ||
+           SemaRef.inParameterMappingSubstitution())) {
         for (UnexpandedParameterPack ParmPack : Unexpanded) {
           NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
           if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
@@ -1484,10 +1500,10 @@ namespace {
 
     TemplateArgument ForgetPartiallySubstitutedPack() {
       TemplateArgument Result;
-      if (NamedDecl *PartialPack
-            = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
-        MultiLevelTemplateArgumentList &TemplateArgs
-          = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+    if (NamedDecl *PartialPack =
+            SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+      MultiLevelTemplateArgumentList &TemplateArgs =
+          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
         unsigned Depth, Index;
         std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
         if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
@@ -1507,10 +1523,10 @@ namespace {
       if (Arg.isNull())
         return;
 
-      if (NamedDecl *PartialPack
-            = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
-        MultiLevelTemplateArgumentList &TemplateArgs
-        = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+    if (NamedDecl *PartialPack =
+            SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+      MultiLevelTemplateArgumentList &TemplateArgs =
+          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
         unsigned Depth, Index;
         std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
         TemplateArgs.setArgument(Depth, Index, Arg);
@@ -1527,9 +1543,9 @@ namespace {
           std::move(New);
       return Old;
     }
+
     void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
-      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
-          std::move(Old);
+      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) = Old;
     }
 
     TemplateArgument
@@ -1608,8 +1624,7 @@ namespace {
     /// as an instantiated local.
     VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
                                   TypeSourceInfo *Declarator,
-                                  SourceLocation StartLoc,
-                                  SourceLocation NameLoc,
+                                SourceLocation StartLoc, SourceLocation NameLoc,
                                   IdentifierInfo *Name);
 
     /// Rebuild the Objective-C exception declaration and register the
@@ -1617,8 +1632,15 @@ namespace {
     VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
                                       TypeSourceInfo *TSInfo, QualType T);
 
-    TemplateName
-    TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc,
+  /// Check for tag mismatches when instantiating an
+  /// elaborated type.
+  QualType RebuildElaboratedType(SourceLocation KeywordLoc,
+                                 ElaboratedTypeKeyword Keyword,
+                                 NestedNameSpecifierLoc QualifierLoc,
+                                 QualType T);
+
+  TemplateName
+  TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc,
                           SourceLocation TemplateKWLoc, TemplateName Name,
                           SourceLocation NameLoc,
                           QualType ObjectType = QualType(),
@@ -1645,8 +1667,8 @@ namespace {
                                             NonTypeTemplateParmDecl *D);
     ExprResult TransformSubstNonTypeTemplateParmPackExpr(
                                            SubstNonTypeTemplateParmPackExpr *E);
-    ExprResult TransformSubstNonTypeTemplateParmExpr(
-                                           SubstNonTypeTemplateParmExpr *E);
+  ExprResult
+  TransformSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
 
     /// Rebuild a DeclRefExpr for a VarDecl reference.
     ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
@@ -1714,6 +1736,24 @@ namespace {
       return inherited::TransformTemplateArgument(Input, Output, Uneval);
     }
 
+    // This has to be here to allow its overload.
+    ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
+                                    UnsignedOrNone NumExpansions) {
+      return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
+                                             NumExpansions);
+    }
+
+    TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
+                                             SourceLocation EllipsisLoc,
+                                             UnsignedOrNone NumExpansions) {
+      // We don't rewrite a PackExpansion type when we want to normalize a
+      // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
+      if (!PreserveArgumentPacks || BuildPackExpansionTypes)
+        return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
+                                               NumExpansions);
+      return Pattern;
+    }
+
     using TreeTransform::TransformTemplateSpecializationType;
     QualType
     TransformTemplateSpecializationType(TypeLocBuilder &TLB,
@@ -1751,7 +1791,7 @@ namespace {
       return inherited::ComputeSizeOfPackExprWithoutSubstitution(PackArgs);
     }
 
-    template<typename Fn>
+  template <typename Fn>
     QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
                                         FunctionProtoTypeLoc TL,
                                         CXXRecordDecl *ThisContext,
@@ -1770,10 +1810,12 @@ namespace {
                                            TemplateTypeParmTypeLoc TL,
                                            bool SuppressObjCLifetime);
 
-    QualType BuildSubstTemplateTypeParmType(
-        TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final,
-        Decl *AssociatedDecl, unsigned Index, UnsignedOrNone PackIndex,
-        TemplateArgument Arg, SourceLocation NameLoc);
+  QualType BuildSubstTemplateTypeParmType(TypeLocBuilder &TLB,
+                                          bool SuppressObjCLifetime, bool Final,
+                                          Decl *AssociatedDecl, unsigned Index,
+                                          UnsignedOrNone PackIndex,
+                                          TemplateArgument Arg,
+                                          SourceLocation NameLoc);
 
     /// Transforms an already-substituted template type parameter pack
     /// into either itself (if we aren't substituting into its pack expansion)
@@ -1910,13 +1952,15 @@ namespace {
       return false;
     }
 
-    TemplateParameterList *TransformTemplateParameterList(
-                              TemplateParameterList *OrigTPL)  {
-      if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+    TemplateParameterList *
+    TransformTemplateParameterList(TemplateParameterList *OrigTPL) {
+      if (!OrigTPL || !OrigTPL->size())
+        return OrigTPL;
 
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
-      TemplateDeclInstantiator  DeclInstantiator(getSema(),
-                        /* DeclContext *Owner */ Owner, TemplateArgs);
+      TemplateDeclInstantiator DeclInstantiator(getSema(),
+                                                /* DeclContext *Owner */ Owner,
+                                                TemplateArgs);
       DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
       return DeclInstantiator.SubstTemplateParams(OrigTPL);
     }
@@ -1934,13 +1978,13 @@ namespace {
         SmallVectorImpl<ParmVarDecl *> &TransParams,
         Sema::ExtParameterInfoBuilder &PInfos);
 
-  private:
+private:
     ExprResult
     transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
                                     SourceLocation loc, TemplateArgument arg,
                                     UnsignedOrNone PackIndex, bool Final);
-  };
-}
+};
+} // namespace
 
 bool TemplateInstantiator::AlreadyTransformed(QualType T) {
   if (T.isNull())
@@ -1990,7 +2034,8 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
 
   if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D);
       PVD && SemaRef.CurrentInstantiationScope &&
-      SemaRef.inConstraintSubstitution() &&
+      (SemaRef.inConstraintSubstitution() ||
+       SemaRef.inParameterMappingSubstitution()) &&
       maybeInstantiateFunctionParameterToScope(PVD))
     return nullptr;
 
@@ -2221,6 +2266,15 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
     // We're rewriting the template parameter as a reference to another
     // template parameter.
     Arg = getTemplateArgumentPackPatternForRewrite(Arg);
+    if (Arg.getKind() != TemplateArgument::Expression) {
+      assert(SemaRef.inParameterMappingSubstitution() ||
+             SemaRef.inConstraintSubstitution());
+      ExprResult Expr = SemaRef.BuildExpressionFromNonTypeTemplateArgument(
+          Arg, E->getLocation());
+      if (Expr.isInvalid())
+        return E;
+      Arg = TemplateArgument(Expr.get(), /*IsCanonical=*/false);
+    }
     assert(Arg.getKind() == TemplateArgument::Expression &&
            "unexpected nontype template argument kind in template rewrite");
     // FIXME: This can lead to the same subexpression appearing multiple times
@@ -2926,18 +2980,30 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
 concepts::NestedRequirement *
 TemplateInstantiator::TransformNestedRequirement(
     concepts::NestedRequirement *Req) {
-  if (!Req->isDependent() && !AlwaysRebuild())
-    return Req;
+
+  ASTContext &C = SemaRef.Context;
+
+  Expr *Constraint = Req->getConstraintExpr();
+  ExprResult TransConstraint = Constraint;
+  ConstraintSatisfaction Satisfaction;
+
+  auto NestedReqWithDiag = [&C, this](Expr *E,
+                                      ConstraintSatisfaction Satisfaction) {
+    Satisfaction.IsSatisfied = false;
+    SmallString<128> Entity;
+    llvm::raw_svector_ostream OS(Entity);
+    E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
+    return new (C) concepts::NestedRequirement(
+        SemaRef.Context, C.backupStr(Entity), std::move(Satisfaction));
+  };
+
   if (Req->hasInvalidConstraint()) {
     if (AlwaysRebuild())
       return RebuildNestedRequirement(Req->getInvalidConstraintEntity(),
                                       Req->getConstraintSatisfaction());
     return Req;
   }
-  Sema::InstantiatingTemplate ReqInst(SemaRef,
-      Req->getConstraintExpr()->getBeginLoc(), Req,
-      Sema::InstantiatingTemplate::ConstraintsCheck{},
-      Req->getConstraintExpr()->getSourceRange());
+
   if (!getEvaluateConstraints()) {
     ExprResult TransConstraint = TransformExpr(Req->getConstraintExpr());
     if (TransConstraint.isInvalid() || !TransConstraint.get())
@@ -2950,45 +3016,45 @@ TemplateInstantiator::TransformNestedRequirement(
         SemaRef.Context, TransConstraint.get(), Satisfaction);
   }
 
-  ExprResult TransConstraint;
-  ConstraintSatisfaction Satisfaction;
-  TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc());
+  bool Success;
+  Expr *NewConstraint;
+  TemplateDeductionInfo Info(Constraint->getBeginLoc());
   {
     EnterExpressionEvaluationContext ContextRAII(
         SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
-    Sema::SFINAETrap Trap(SemaRef);
-    Sema::InstantiatingTemplate ConstrInst(SemaRef,
-        Req->getConstraintExpr()->getBeginLoc(), Req, Info,
-        Req->getConstraintExpr()->getSourceRange());
+
+    Sema::InstantiatingTemplate ConstrInst(
+        SemaRef, Constraint->getBeginLoc(), Req,
+        Sema::InstantiatingTemplate::ConstraintsCheck(),
+                                           Constraint->getSourceRange());
+
     if (ConstrInst.isInvalid())
       return nullptr;
-    llvm::SmallVector<Expr *> Result;
-    if (!SemaRef.CheckConstraintSatisfaction(
-            nullptr,
-            AssociatedConstraint(Req->getConstraintExpr(),
-                                 SemaRef.ArgPackSubstIndex),
-            Result, TemplateArgs, Req->getConstraintExpr()->getSourceRange(),
-            Satisfaction) &&
-        !Result.empty())
-      TransConstraint = Result[0];
-    assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
+
+    Sema::SFINAETrap Trap(SemaRef);
+
+    Success = !SemaRef.CheckConstraintSatisfaction(
+        Req, AssociatedConstraint(Constraint, SemaRef.ArgPackSubstIndex),
+        TemplateArgs, Constraint->getSourceRange(), Satisfaction,
+        /*TopLevelConceptId=*/nullptr, &NewConstraint);
+
+    assert(!Success || !Trap.hasErrorOccurred() &&
+                           "Substitution failures must be handled "
                                        "by CheckConstraintSatisfaction.");
   }
-  ASTContext &C = SemaRef.Context;
-  if (TransConstraint.isUsable() &&
-      TransConstraint.get()->isInstantiationDependent())
-    return new (C) concepts::NestedRequirement(TransConstraint.get());
-  if (TransConstraint.isInvalid() || !TransConstraint.get() ||
-      Satisfaction.HasSubstitutionFailure()) {
-    SmallString<128> Entity;
-    llvm::raw_svector_ostream OS(Entity);
-    Req->getConstraintExpr()->printPretty(OS, nullptr,
-                                          SemaRef.getPrintingPolicy());
-    return new (C) concepts::NestedRequirement(
-        SemaRef.Context, C.backupStr(Entity), Satisfaction);
+
+  if (!Success || Satisfaction.HasSubstitutionFailure())
+    return NestedReqWithDiag(Constraint, Satisfaction);
+
+  // FIXME: const correctness
+  // MLTAL might be dependent.
+  if (!NewConstraint) {
+    if (!Satisfaction.IsSatisfied)
+      return NestedReqWithDiag(Constraint, Satisfaction);
+
+    NewConstraint = Constraint;
   }
-  return new (C)
-      concepts::NestedRequirement(C, TransConstraint.get(), Satisfaction);
+  return new (C) concepts::NestedRequirement(C, NewConstraint, Satisfaction);
 }
 
 TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
@@ -3245,7 +3311,7 @@ bool Sema::SubstTypeConstraint(
   const ASTTemplateArgumentListInfo *TemplArgInfo =
       TC->getTemplateArgsAsWritten();
 
-  if (!EvaluateConstraints) {
+  if (!EvaluateConstraints && !inParameterMappingSubstitution()) {
     UnsignedOrNone Index = TC->getArgPackSubstIndex();
     if (!Index)
       Index = SemaRef.ArgPackSubstIndex;
@@ -4545,6 +4611,16 @@ bool Sema::SubstTemplateArguments(
   return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
 }
 
+bool Sema::SubstTemplateArgumentsInParameterMapping(
+    ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
+    const MultiLevelTemplateArgumentList &TemplateArgs,
+    TemplateArgumentListInfo &Out, bool BuildPackExpansionTypes) {
+  TemplateInstantiator Instantiator(
+      TemplateInstantiator::ForParameterMappingSubstitution, *this, BaseLoc,
+      TemplateArgs, BuildPackExpansionTypes);
+  return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
+}
+
 ExprResult
 Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
   if (!E)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 242ffb09af006..129f362fbd263 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -30,6 +30,7 @@
 #include "clang/AST/StmtOpenACC.h"
 #include "clang/AST/StmtOpenMP.h"
 #include "clang/AST/StmtSYCL.h"
+#include "clang/AST/TemplateBase.h"
 #include "clang/Basic/DiagnosticParse.h"
 #include "clang/Basic/OpenMPKinds.h"
 #include "clang/Sema/Designator.h"
@@ -47,8 +48,11 @@
 #include "clang/Sema/SemaSYCL.h"
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <algorithm>
+#include <iterator>
 #include <optional>
 
 using namespace llvm::omp;
@@ -352,6 +356,8 @@ class TreeTransform {
   /// being expanded.
   void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
 
+  bool ShouldPreserveTemplateArgumentsPacks() const { return false; }
+
   /// Transforms the given type into another type.
   ///
   /// By default, this routine transforms a type by creating a
@@ -3714,10 +3720,6 @@ class TreeTransform {
                                         ParentContext);
   }
 
-  /// Build a new Objective-C boxed expression.
-  ///
-  /// By default, performs semantic analysis to build the new expression.
-  /// Subclasses may override this routine to provide different behavior.
   ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
       SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
       NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
@@ -5102,9 +5104,13 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
       typedef TemplateArgumentLocInventIterator<Derived,
                                                 TemplateArgument::pack_iterator>
         PackLocIterator;
+
+      TemplateArgumentListInfo *PackOutput = &Outputs;
+      TemplateArgumentListInfo New;
+
       if (TransformTemplateArguments(
               PackLocIterator(*this, In.getArgument().pack_begin()),
-              PackLocIterator(*this, In.getArgument().pack_end()), Outputs,
+              PackLocIterator(*this, In.getArgument().pack_end()), *PackOutput,
               Uneval))
         return true;
 
@@ -5171,7 +5177,6 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
   }
 
   return false;
-
 }
 
 // FIXME: Find ways to reduce code duplication for pack expansions.
@@ -6239,7 +6244,7 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
                                              /* DefArg */ nullptr);
   newParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
                         OldParm->getFunctionScopeIndex() + indexAdjustment);
-  transformedLocalDecl(OldParm, {newParm});
+  getDerived().transformedLocalDecl(OldParm, {newParm});
   return newParm;
 }
 
@@ -7074,11 +7079,11 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
                                                             TypeLocBuilder &TLB,
                                                      UnaryTransformTypeLoc TL) {
   QualType Result = TL.getType();
+  TypeSourceInfo *NewBaseTSI = TL.getUnderlyingTInfo();
   if (Result->isDependentType()) {
     const UnaryTransformType *T = TL.getTypePtr();
 
-    TypeSourceInfo *NewBaseTSI =
-        getDerived().TransformType(TL.getUnderlyingTInfo());
+    NewBaseTSI = getDerived().TransformType(TL.getUnderlyingTInfo());
     if (!NewBaseTSI)
       return QualType();
     QualType NewBase = NewBaseTSI->getType();
@@ -7093,7 +7098,7 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
   UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result);
   NewTL.setKWLoc(TL.getKWLoc());
   NewTL.setParensRange(TL.getParensRange());
-  NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo());
+  NewTL.setUnderlyingTInfo(NewBaseTSI);
   return Result;
 }
 
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index cf32d4f56b7c2..5456e73956659 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2424,7 +2424,7 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
   VisitDecl(D);
   llvm::SmallVector<TemplateArgument, 4> Args;
   for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
-    Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true));
+    Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/false));
   D->setTemplateArguments(Args);
 }
 
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 213c2c2148f64..aec86e0986b77 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -807,15 +807,20 @@ readConstraintSatisfaction(ASTRecordReader &Record) {
   if (!Satisfaction.IsSatisfied) {
     unsigned NumDetailRecords = Record.readInt();
     for (unsigned i = 0; i != NumDetailRecords; ++i) {
-      if (/* IsDiagnostic */Record.readInt()) {
+      auto Kind = Record.readInt();
+      if (Kind == 0) {
         SourceLocation DiagLocation = Record.readSourceLocation();
         StringRef DiagMessage = C.backupStr(Record.readString());
 
         Satisfaction.Details.emplace_back(
             new (C) ConstraintSatisfaction::SubstitutionDiagnostic(
                 DiagLocation, DiagMessage));
-      } else
+      } else if (Kind == 1) {
         Satisfaction.Details.emplace_back(Record.readExpr());
+      } else {
+        assert(Kind == 2);
+        Satisfaction.Details.emplace_back(Record.readConceptReference());
+      }
     }
   }
   return Satisfaction;
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 21c04ddbc2c7a..9408580fd7a8a 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Serialization/ASTReader.h"
@@ -482,14 +483,20 @@ addConstraintSatisfaction(ASTRecordWriter &Record,
   if (!Satisfaction.IsSatisfied) {
     Record.push_back(Satisfaction.NumRecords);
     for (const auto &DetailRecord : Satisfaction) {
-      auto *E = dyn_cast<Expr *>(DetailRecord);
-      Record.push_back(/* IsDiagnostic */ E == nullptr);
-      if (E)
-        Record.AddStmt(E);
-      else {
-        auto *Diag = cast<std::pair<SourceLocation, StringRef> *>(DetailRecord);
+      if (auto *Diag =
+              dyn_cast<std::pair<SourceLocation, StringRef> *>(DetailRecord)) {
+        Record.push_back(/*Kind=*/0);
         Record.AddSourceLocation(Diag->first);
         Record.AddString(Diag->second);
+        continue;
+      }
+      if (auto *E = dyn_cast<const Expr *>(DetailRecord)) {
+        Record.push_back(/*Kind=*/1);
+        Record.AddStmt(const_cast<Expr *>(E));
+      } else {
+        Record.push_back(/*Kind=*/2);
+        auto *CR = cast<const ConceptReference *>(DetailRecord);
+        Record.AddConceptReference(CR);
       }
     }
   }
diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp
index 84d981d2ab8de..9419dba057a4e 100644
--- a/clang/test/AST/ast-dump-concepts.cpp
+++ b/clang/test/AST/ast-dump-concepts.cpp
@@ -20,8 +20,9 @@ struct Foo {
   // CHECK:      TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept'
   // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13, col:31> 'bool' Concept {{.*}} 'binary_concept'
   // CHECK-NEXT:   |-ImplicitConceptSpecializationDecl {{.*}} <line:13:9> col:9
-  // CHECK-NEXT:   | |-TemplateArgument type 'type-parameter-1-0'  
-  // CHECK-NEXT:   | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
+  // CHECK-NEXT:   | |-TemplateArgument type 'R'
+  // CHECK-NEXT:   | | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
+  // CHECK-NEXT:   | |   `-TemplateTypeParm {{.*}} 'R'
   // CHECK-NEXT:   | `-TemplateArgument type 'int'
   // CHECK-NEXT:   |   `-BuiltinType {{.*}} 'int'
   // CHECK-NEXT:   |-TemplateArgument {{.*}} type 'R'
@@ -35,8 +36,9 @@ struct Foo {
   // CHECK:      TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept'
   // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13> 'bool'
   // CHECK-NEXT:   |-ImplicitConceptSpecializationDecl {{.*}} <line:10:9> col:9
-  // CHECK-NEXT:   | `-TemplateArgument type 'type-parameter-1-0'
-  // CHECK-NEXT:   |   `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
+  // CHECK-NEXT:   | `-TemplateArgument type 'R'
+  // CHECK-NEXT:   |   `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
+  // CHECK-NEXT:   |     `-TemplateTypeParm {{.*}} 'R'
   template <unary_concept R>
   Foo(R);
 
diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp
index 781fb9f28cb8d..9a3adbcb534e8 100644
--- a/clang/test/AST/ast-dump-ctad-alias.cpp
+++ b/clang/test/AST/ast-dump-ctad-alias.cpp
@@ -185,17 +185,18 @@ void foo() {
 // CHECK-NEXT: | |-BinaryOperator {{.*}} 'bool' '&&'
 // CHECK-NEXT: | | |-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'invocable'
 // CHECK-NEXT: | | | |-ImplicitConceptSpecializationDecl {{.*}}
-// CHECK-NEXT: | | | | |-TemplateArgument type 'type-parameter-0-2'
-// CHECK-NEXT: | | | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
-// CHECK-NEXT: | | | | `-TemplateArgument pack '<GH124715::Packs<type-parameter-0-1...>>'
-// CHECK-NEXT: | | | |   `-TemplateArgument type 'GH124715::Packs<type-parameter-0-1...>'
-// CHECK-NEXT: | | | |     `-TemplateSpecializationType {{.*}} 'GH124715::Packs<type-parameter-0-1...>' dependent
-// CHECK-NEXT: | | | |       |-name: 'GH124715::Packs'
+// CHECK-NEXT: | | | | |-TemplateArgument type 'U'
+// CHECK-NEXT: | | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2
+// CHECK-NEXT: | | | | |   `-TemplateTypeParm {{.*}} 'U'
+// CHECK-NEXT: | | | | `-TemplateArgument pack '<Packs<Ts...>>'
+// CHECK-NEXT: | | | |   `-TemplateArgument type 'Packs<Ts...>'
+// CHECK-NEXT: | | | |     `-TemplateSpecializationType {{.*}} 'Packs<Ts...>' dependent
+// CHECK-NEXT: | | | |       |-name: 'Packs':'GH124715::Packs' qualified
 // CHECK-NEXT: | | | |       | `-ClassTemplateDecl {{.*}} Packs
-// CHECK-NEXT: | | | |       `-TemplateArgument pack '<type-parameter-0-1...>'
-// CHECK-NEXT: | | | |         `-TemplateArgument type 'type-parameter-0-1...'
-// CHECK-NEXT: | | | |           `-PackExpansionType {{.*}} 'type-parameter-0-1...' dependent
-// CHECK-NEXT: | | | |             `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: | | | |       `-TemplateArgument type 'Ts...'
+// CHECK-NEXT: | | | |         `-PackExpansionType {{.*}} 'Ts...' dependent
+// CHECK-NEXT: | | | |           `-TemplateTypeParmType {{.*}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: | | | |             `-TemplateTypeParm {{.*}} 'Ts'
 // CHECK-NEXT: | | | |-TemplateArgument {{.*}} type 'U':'type-parameter-0-2'
 // CHECK-NEXT: | | | | `-TemplateTypeParmType {{.*}} 'U' dependent depth 0 index 2
 // CHECK-NEXT: | | | |   `-TemplateTypeParm {{.*}} 'U'
diff --git a/clang/test/CXX/drs/cwg25xx.cpp b/clang/test/CXX/drs/cwg25xx.cpp
index 5c2948f67d0ee..0e0fc735c6843 100644
--- a/clang/test/CXX/drs/cwg25xx.cpp
+++ b/clang/test/CXX/drs/cwg25xx.cpp
@@ -243,19 +243,20 @@ namespace cwg2565 { // cwg2565: 16 open 2023-06-07
   //   since-cxx20-note@#cwg2565-VC {{because 'b' would be invalid: argument may not have 'void' type}}
 
   template<typename T>
-  concept ErrorRequires = requires (ErrorRequires auto x) {
+  concept ErrorRequires = requires (ErrorRequires auto x) { // #cwg2565-expr
   // since-cxx20-error at -1 {{a concept definition cannot refer to itself}}
   //   since-cxx20-note at -2 {{declared here}}
   // since-cxx20-error at -3 {{'auto' not allowed in requires expression parameter}}
     x;
   };
   static_assert(ErrorRequires<int>);
-  // since-cxx20-error at -1 {{static assertion failed}}
-  //   since-cxx20-note at -2 {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // since-cxx20-error at -1 {{static assertion failed}} \
+  //   since-cxx20-note at -1 {{because 'int' does not satisfy 'ErrorRequires'}} \
+  //   since-cxx20-note@#cwg2565-expr {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 
   template<typename T>
   concept NestedErrorInRequires = requires (T x) { // #cwg2565-NEIR
-    requires requires (NestedErrorInRequires auto y) {
+    requires requires (NestedErrorInRequires auto y) { // #cwg2565-NEIR-inner
     // since-cxx20-error at -1 {{a concept definition cannot refer to itself}}
     //   since-cxx20-note@#cwg2565-NEIR {{declared here}}
     // since-cxx20-error at -3 {{'auto' not allowed in requires expression parameter}}
@@ -263,8 +264,9 @@ namespace cwg2565 { // cwg2565: 16 open 2023-06-07
     };
   };
   static_assert(NestedErrorInRequires<int>);
-  // since-cxx20-error at -1 {{static assertion failed}}
-  //   since-cxx20-note at -2 {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // since-cxx20-error at -1 {{static assertion failed}} \
+  //   since-cxx20-note at -1 {{because 'int' does not satisfy 'NestedErrorInRequires'}} \
+  //   since-cxx20-note-re@#cwg2565-NEIR-inner {{because {{.*}} would be invalid: constraint depends on a previously diagnosed expression}}
 
 #endif
 } // namespace cwg2565
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
index 28b5d0adcf054..af2fc938fbea2 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp
@@ -140,7 +140,8 @@ concept C7 = sizeof(T) == 1 || sizeof(
         ::type) == 1;
 
 static_assert(!C6<short>);
-static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}}
+static_assert(!C6<char>);
+// expected-note at -1 {{while checking the satisfaction of concept 'C6<char>' requested here}}
 static_assert(C7<char>);
 static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}}
 
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
index 31587a956b8ab..af2dce81d8a4b 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
@@ -35,14 +35,14 @@ using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class templ
 using r2i3 = r2<D>;
 using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
 
-template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
+template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
 struct r3 {};
 
 using r3i1 = r3<int>;
 using r3i2 = r3<A>;
 using r3i3 = r3<A &>;
 using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
-using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
+using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
 
 // Non-dependent expressions
 
@@ -89,7 +89,7 @@ template<typename T>
 concept Large = sizeof(typename remove_reference<T>::type) >= 4;
 // expected-note at -1{{because 'sizeof(typename remove_reference<short &>::type) >= 4' (2 >= 4) evaluated to false}}
 
-template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'short &' does not satisfy 'Large':}}
+template<typename T> requires requires (T t) { { t } -> Large; } // expected-note{{because 'short &' does not satisfy 'Large'}}
 struct r7 {};
 
 using r7i1 = r7<int>;
@@ -149,7 +149,7 @@ namespace std_example {
   template<typename T> constexpr bool is_same_v<T, T> = true;
 
   template<typename T, typename U> concept same_as = is_same_v<T, U>;
-  // expected-note at -1 {{because 'is_same_v<int, int *>' evaluated to false}}
+  // expected-note at -1 {{because 'is_same_v<int, typename std_example::T2::inner>' evaluated to false}}
 
   static_assert(C1<int>);
   static_assert(C1<int*>);
@@ -160,7 +160,7 @@ namespace std_example {
   template<typename T> concept C2 =
     requires(T x) {
       {*x} -> same_as<typename T::inner>;
-      // expected-note at -1{{because type constraint 'same_as<int, typename std_example::T2::inner>' was not satisfied:}}
+      // expected-note at -1{{because 'same_as<int, typename std_example::T2::inner>' evaluated to false}}
       // expected-note at -2{{because '*x' would be invalid: indirection requires pointer operand ('int' invalid)}}
     };
 
@@ -173,9 +173,9 @@ namespace std_example {
     int operator *() { return 0; }
   };
   static_assert(C2<T1>);
-  template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
+  template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'T2' does not satisfy 'C2'}}
   using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
-  using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
+  using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = T2]}}
 
   template<typename T>
   void g(T t) noexcept(sizeof(T) == 1) {}
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 033ae349a02e5..70a96bed05867 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
@@ -43,11 +43,10 @@ namespace std_example {
       requires sizeof(a) == 4; // OK
       requires a == 0; // expected-error{{substitution into constraint expression resulted in a non-constant expression}}
       // expected-note at -1{{while checking the satisfaction of nested requirement requested here}}
-      // expected-note at -2{{in instantiation of requirement here}}
-      // expected-note at -3{{while checking the satisfaction of nested requirement requested here}}
-      // expected-note at -6{{while substituting template arguments into constraint expression here}}
-      // expected-note at -5{{function parameter 'a' with unknown value cannot be used in a constant expression}}
-      // expected-note at -8{{declared here}}
+      // expected-note at -2{{while checking the satisfaction of nested requirement requested here}}
+      // expected-note at -5{{while substituting template arguments into constraint expression here}}
+      // expected-note at -4{{function parameter 'a' with unknown value cannot be used in a constant expression}}
+      // expected-note at -7{{declared here}}
     };
     static_assert(C2<int>); // expected-error{{static assertion failed}}
     // expected-note at -1{{while checking the satisfaction of concept 'C2<int>' requested here}}
@@ -84,31 +83,26 @@ static_assert(Pipes<S>);
 static_assert(Pipes<double>);
 
 static_assert(Amps1<S>);
-static_assert(!Amps1<double>);
+static_assert(Amps1<double>);
 
 static_assert(Amps2<S>);
-static_assert(!Amps2<double>);
+static_assert(Amps2<double>);
 
 template<class T>
-void foo1() requires requires (T x) { // #foo1
+void foo1() requires requires (T x) {
   requires
-  True<decltype(x.value)> // #foo1Value
+  True<decltype(x.value)>
   && True<T>;
 } {}
 template<class T> void fooPipes() requires Pipes<T> {}
-template<class T> void fooAmps1() requires Amps1<T> {} // #fooAmps1
+template<class T> void fooAmps1() requires Amps1<T> {}
 void foo() {
   foo1<S>();
-  foo1<int>(); // expected-error {{no matching function for call to 'foo1'}}
-  // expected-note@#foo1Value {{because 'True<decltype(x.value)> && True<T>' would be invalid: member reference base type 'int' is not a structure or union}}
-  // expected-note@#foo1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+  foo1<int>();
   fooPipes<S>();
   fooPipes<int>();
   fooAmps1<S>();
-  fooAmps1<int>(); // expected-error {{no matching function for call to 'fooAmps1'}}
-  // expected-note@#fooAmps1 {{candidate template ignored: constraints not satisfied [with T = int]}}
-  // expected-note@#fooAmps1 {{because 'int' does not satisfy 'Amps1'}}
-  // expected-note@#Amps1 {{because 'True<decltype(x.value)> && True<T> && !False<T>' would be invalid: member reference base type 'int' is not a structure or union}}
+  fooAmps1<int>();
 }
 
 template<class T>
@@ -158,15 +152,16 @@ void func() {
   // expected-note@#bar {{while substituting template arguments into constraint expression here}}
   // expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
   // expected-note@#bar {{candidate template ignored: constraints not satisfied [with T = False]}}
-  // expected-note@#bar {{because 'X<SubstitutionFailureNestedRequires::ErrorExpressions_NotSF::False>::value' evaluated to false}}
+  // expected-note@#bar {{because 'X<False>::value' evaluated to false}}
 
   bar<int>();
+  // expected-error at -1 {{no matching function for call to 'bar'}} \
   // expected-note at -1 {{while checking constraint satisfaction for template 'bar<int>' required here}} \
-  // expected-note at -1 {{while substituting deduced template arguments into function template 'bar' [with T = int]}}
+  // 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}}
   // expected-note@#bar {{while substituting template arguments into constraint expression here}}
+  // expected-note@#bar {{candidate template ignored}}
   // expected-error@#X_Value {{type 'int' cannot be used prior to '::' because it has no members}}
 }
 }
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
index 5199708cd8166..5dcb1880ded48 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -39,14 +39,14 @@ using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class
 
 template<typename T> requires requires { sizeof(T); }
 // expected-note at -1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
-// expected-note at -2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
+// expected-note at -2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
 struct r3 {};
 
 using r3i1 = r3<int>;
 using r3i2 = r3<A>;
 using r3i3 = r3<A &>;
 using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
-using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
+using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
 
 template<typename T> requires requires (T t) { 0; "a"; (void)'a'; }
 struct r4 {};
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
index 5433cfb21955d..28dff336d053c 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
@@ -182,14 +182,14 @@ namespace std_example {
   static_assert(C1<has_inner_and_type> && C2<has_inner_and_type> && C3<has_inner_and_type>);
   template<C1 T> struct C1_check {};
   // expected-note at -1 {{because 'int' does not satisfy 'C1'}}
-  // expected-note at -2 {{because 'std_example::has_type' does not satisfy 'C1'}}
+  // expected-note at -2 {{because 'has_type' does not satisfy 'C1'}}
   template<C2 T> struct C2_check {};
-  // expected-note at -1 {{because 'std_example::has_inner' does not satisfy 'C2'}}
+  // expected-note at -1 {{because 'has_inner' does not satisfy 'C2'}}
   template<C3 T> struct C3_check {};
   // expected-note at -1 {{because 'void' does not satisfy 'C3'}}
   using c1 = C1_check<int>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}}
-  using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}}
-  using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}}
+  using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = has_type]}}
+  using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = has_inner]}}
   using c4 = C3_check<void>; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}}
 }
 
@@ -199,10 +199,10 @@ template <typename T> concept C = requires { requires requires { T::a; }; };
 // expected-note at -1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}}
 
 template <C...> struct A {};
-// expected-note at -1 {{because 'PR48656::T1' does not satisfy 'C'}}
+// expected-note at -1 {{because 'T1' does not satisfy 'C'}}
 
 struct T1 {};
-template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <PR48656::T1>]}}
+template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <T1>]}}
 
 struct T2 { static constexpr bool a = false; };
 template struct A<T2>;
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 59e6a48e48878..6dea0c62fe686 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
@@ -28,9 +28,8 @@ template<typename T> requires requires {
   requires S<T>{};
   // expected-error at -1{{atomic constraint must be of type 'bool' (found 'S<int>')}}
   // expected-note at -2{{while checking the satisfaction}}
-  // expected-note at -3{{in instantiation of requirement}}
-  // expected-note at -4{{while checking the satisfaction}}
-  // expected-note at -6{{while substituting template arguments}}
+  // expected-note at -3{{while checking the satisfaction of nested requirement}}
+  // expected-note at -5{{while substituting template arguments}}
   // expected-note@#F3INST{{while checking constraint satisfaction}}
   // expected-note@#F3INST{{while substituting deduced template arguments into function template 'f3' [with T = int]}}
   //
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
index 3992835c44402..35796106da278 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
@@ -1,21 +1,31 @@
 // RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
+// FIXME: RUN: %clang_cc1 -std=c++2c -x c++ -verify %s
 
 template<typename T> concept True = true;
-template<typename T> concept Foo = True<T*>;
-template<typename T> concept Bar = Foo<T&>;
-template<typename T> requires Bar<T> struct S { };
-template<typename T> requires Bar<T> && true struct S<T> { };
+template<typename T> concept Foo = True<T*>; // #Foo
+template<typename T> concept Bar = Foo<T&>;  // #Bar
+template<typename T> requires Bar<T> struct S { }; // #S
+template<typename T> requires Bar<T> && true struct S<T> { }; // #SpecS
+// expected-error at -1 {{class template partial specialization is not more specialized than the primary template}}
+// expected-error@#Foo 2{{'type name' declared as a pointer to a reference of type 'T &'}}
+// expected-note@#SpecS {{while substituting into concept arguments here}}
+// expected-note@#S {{while substituting into concept arguments here}}
+// expected-note@#Bar 2{{while substituting into concept arguments here}}
+// expected-note@#S {{template is declared here}}
+
+
 
 template<typename T> concept True2 = sizeof(T) >= 0;
-template<typename T> concept Foo2 = True2<T*>;
-// expected-error at -1{{'type name' declared as a pointer to a reference of type 'type-parameter-0-0 &'}}
-template<typename T> concept Bar2 = Foo2<T&>;
-// expected-note at -1{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
-template<typename T> requires Bar2<T> struct S2 { };
+template<typename T> concept Foo2 = True2<T*>; // #Foo2
+
+template<typename T> concept Bar2 = Foo2<T&>; // #Bar2
+// expected-note at -1 3{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
+template<typename T> requires Bar2<T> struct S2 { }; // #SpecS2_1
 // expected-note at -1{{template is declared here}}
-template<typename T> requires Bar2<T> && true struct S2<T> { };
+template<typename T> requires Bar2<T> && true struct S2<T> { }; // #SpecS2_2
 // expected-error at -1{{class template partial specialization is not more specialized than the primary template}}
-// expected-note at -2{{while calculating associated constraint of template 'S2<T>' here}}
+// expected-error@#Foo2{{'type name' declared as a pointer to a reference of type 'T &'}}
+
 
 namespace type_pack {
   template<typename... Args>
@@ -71,16 +81,31 @@ namespace non_type_pack {
 namespace PR47174 {
 // This checks that we don't crash with a failed substitution on the first constrained argument when
 // performing normalization.
-template <Bar2 T, True U>
+template <Bar2 T, True U> // #S3_Header
 requires true struct S3; // expected-note {{template is declared here}}
 template <True T, True U>
-requires true struct S3<T, U>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
+requires true struct S3<T, U>;
+// expected-error at -1 {{class template partial specialization is not more specialized than the primary template}}
+// expected-error@#Foo2 2{{'type name' declared as a pointer to a reference of type 'T &'}}
+// expected-note@#SpecS2_1 {{while substituting into concept arguments here}}
+// expected-note@#SpecS2_2 {{while substituting into concept arguments here}}
+// expected-note@#S3_Header {{while substituting into concept arguments here}}
+// expected-note@#Bar2 {{while substituting into concept arguments here}}
+
 
 // Same as above, for the second position (but this was already working).
-template <True T, Bar2 U>
-requires true struct S4; // expected-note {{template is declared here}}
+template <True T, Bar2 U> // #S4_Header
+requires true struct S4; // #S4
 template <True T, True U>
-requires true struct S4<T, U>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
+requires true struct S4<T, U>; // #S4-spec
+// expected-error at -1 {{class template partial specialization is not more specialized than the primary template}}
+// expected-error@#Foo2 {{'type name' declared as a pointer to a reference of type 'U &'}}
+// expected-note@#S4_Header {{while substituting into concept arguments here}}
+// expected-note@#S4 {{template is declared here}}
+// expected-note@#S4 {{similar constraint expressions not considered equivalent}}
+// expected-note@#S4-spec {{similar constraint expression here}}
+
+
 
 struct X {
   template<int> struct Y {
@@ -96,7 +121,7 @@ template<class T> requires C1<T> && C2<T> void t1() = delete; // expected-note {
 template void t1<X>();
 void t1() { t1<X>(); } // expected-error {{call to deleted function 't1'}}
 
-template<class T> requires C1<T> void t2() {}; // expected-note 2 {{candidate function}} 
+template<class T> requires C1<T> void t2() {}; // expected-note 2 {{candidate function}}
 template<class T> requires C2<T> void t2() {}; // expected-note 2 {{candidate function}}
 template void t2<X>(); // expected-error {{partial ordering for explicit instantiation of 't2' is ambiguous}}
 void t2() { t2<X>(); } // expected-error {{call to 't2' is ambiguous}}
diff --git a/clang/test/CXX/temp/temp.param/p10-2a.cpp b/clang/test/CXX/temp/temp.param/p10-2a.cpp
index 4f5fdd3b4809a..c0406f88db5f3 100644
--- a/clang/test/CXX/temp/temp.param/p10-2a.cpp
+++ b/clang/test/CXX/temp/temp.param/p10-2a.cpp
@@ -86,16 +86,18 @@ using f1 = F<int>;
 using f2 = F<long>; // expected-error {{constraints not satisfied for alias template 'F' [with T = long]}}
 
 template<typename T, typename... Ts>
-concept OneOf = (is_same_v<T, Ts> || ...);
-// expected-note at -1 2{{because 'is_same_v<char, char[1]>' evaluated to false}}
-// expected-note at -2 2{{and 'is_same_v<char, char[2]>' evaluated to false}}
-// expected-note at -3 {{because 'is_same_v<short, int>' evaluated to false}}
-// expected-note at -4 {{and 'is_same_v<short, long>' evaluated to false}}
-// expected-note at -5 {{and 'is_same_v<short, char>' evaluated to false}}
-// expected-note at -6 3{{because 'is_same_v<int, char[1]>' evaluated to false}}
-// expected-note at -7 3{{and 'is_same_v<int, char[2]>' evaluated to false}}
-// expected-note at -8 2{{because 'is_same_v<std::nullptr_t, char>' evaluated to false}}
-// expected-note at -9 2{{and 'is_same_v<std::nullptr_t, int>' evaluated to false}}
+concept OneOf = (is_same_v<T, Ts> || ...); // #OneOf
+// expected-note@#OneOf 2{{because 'is_same_v<char, char[1]>' evaluated to false}}
+// expected-note@#OneOf 2{{and 'is_same_v<char, char[2]>' evaluated to false}}
+// expected-note@#OneOf {{because 'is_same_v<short, int>' evaluated to false}}
+// expected-note@#OneOf {{and 'is_same_v<short, long>' evaluated to false}}
+// expected-note@#OneOf {{and 'is_same_v<short, char>' evaluated to false}}
+// expected-note@#OneOf 3{{because 'is_same_v<int, char[1]>' evaluated to false}}
+// expected-note@#OneOf 3{{and 'is_same_v<int, char[2]>' evaluated to false}}
+// expected-note@#OneOf {{because 'is_same_v<decltype(nullptr), char>' evaluated to false}}
+// expected-note@#OneOf {{because 'is_same_v<std::nullptr_t, char>' evaluated to false}}
+// expected-note@#OneOf {{and 'is_same_v<std::nullptr_t, int>' evaluated to false}}
+// expected-note@#OneOf {{and 'is_same_v<decltype(nullptr), int>' evaluated to false}}
 
 template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U>
 // expected-note at -1 2{{because 'OneOf<char, char[1], char[2]>' evaluated to false}}
@@ -124,6 +126,7 @@ using I = int;
 
 using i1 = I<1>;
 using i2 = I<'a'>;
+// FIXME: This crashes with -std=c++2c
 using i3 = I<nullptr>;
 // expected-error at -1 {{constraints not satisfied for alias template 'I' [with x = nullptr]}}
 
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index 99a82d96d321b..ce862666aa48f 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -127,13 +127,12 @@ struct F {
 
 template <typename T>
 constexpr int f5() requires C<T> { return 1; } // expected-note {{while checking the satisfaction}}
-                                               // expected-note at -1 {{while substituting template arguments}}
-                                               // expected-note at -2 {{candidate template ignored}}
+                                               // expected-note at -1 {{candidate template ignored}}
 
 template <typename T>
-constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while checking the satisfaction}}
-                                                  // expected-note at -1 4 {{while substituting template arguments}}
-                                                  // expected-note at -2 {{candidate template ignored}}
+constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while checking the satisfaction}} \
+                                                  // expected-note 4 {{while substituting template arguments}} \
+                                                  // expected-note {{candidate template ignored}}
 
 static_assert(f5<int>() == 1);
 static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 74b3573a0dcaa..6777dc23c44a6 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1257,13 +1257,13 @@ void f() {
     (&A::e)(a, a);
     // expected-error at -1 {{no matching function for call to 'e'}} \
     // expected-note@#tpl-address-e{{candidate template ignored: constraints not satisfied [with T = A, U = A]}} \
-    // expected-note@#tpl-address-e{{because '__is_same(tpl_address::A, int)' evaluated to false}}
+    // expected-note@#tpl-address-e{{because '__is_same(A, int)' evaluated to false}}
 
     (&A::e<A>)(a, 0);
     (&A::e<A>)(a, a);
     // expected-error at -1 {{no matching function for call to 'e'}} \
     // expected-note@#tpl-address-e{{candidate template ignored: constraints not satisfied [with T = A, U = A]}} \
-    // expected-note@#tpl-address-e{{because '__is_same(tpl_address::A, int)' evaluated to false}}
+    // expected-note@#tpl-address-e{{because '__is_same(A, int)' evaluated to false}}
 
     (&A::e<A, int>)(a, 0);
 
@@ -1273,12 +1273,12 @@ void f() {
     (&A::f<A>)(a);
     // expected-error at -1 {{no matching function for call to 'f'}} \
     // expected-note@#tpl-address-f{{candidate template ignored: constraints not satisfied [with T = A]}} \
-    // expected-note@#tpl-address-f{{because '__is_same(tpl_address::A, int)' evaluated to false}}
+    // expected-note@#tpl-address-f{{because '__is_same(A, int)' evaluated to false}}
 
     (&A::f)(a);
     // expected-error at -1 {{no matching function for call to 'f'}} \
     // expected-note@#tpl-address-f{{candidate template ignored: constraints not satisfied [with T = A]}} \
-    // expected-note@#tpl-address-f{{because '__is_same(tpl_address::A, int)' evaluated to false}}
+    // expected-note@#tpl-address-f{{because '__is_same(A, int)' evaluated to false}}
 
     (&A::g)(a);
     (&A::g)(a, 0);
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 4220486d3aed3..137f46ee3dc01 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++2c -verify %s
 
-template <class T> concept A = true;
-template <class T> concept C = A<T> && true;
+template <class T> concept A = (T(), true);
+template <class T> concept C = A<T> && true; // #C
 template <class T> concept D = A<T> && __is_same(T, int);
 
 
@@ -40,13 +40,23 @@ constexpr int i(T...) { return 1; }; // expected-note {{candidate}}
 static_assert(i(0) == 1); // expected-error {{call to 'i' is ambiguous}}
 
 
-template <class... T> requires (A<T> || ... || true)
-constexpr int j(T...) { return 0; };
-template <class... T> requires (C<T> && ... && true)
-constexpr int j(T...) { return 1; };
+template <class... T> requires (A<T> || ... || true) constexpr int j(T...) { return 0; }; // #j1
+template <class... T> requires (C<T> && ... && true) constexpr int j(T...) { return 1; }; // #j2
 
 static_assert(j(0) == 1);
+// expected-error at -1 {{call to 'j' is ambiguous}}
+// expected-note@#j1 {{candidate function [with T = <int>]}}
+// expected-note@#j2 {{candidate function [with T = <int>]}}
+// expected-note@#j2 {{imilar constraint expressions not considered equivalent}}
+// expected-note@#j1 {{similar constraint expression here}}
+
+
 static_assert(j() == 1);
+// expected-error at -1 {{call to 'j' is ambiguous}}
+// expected-note@#j1 {{candidate function [with T = <>]}}
+// expected-note@#j2 {{candidate function [with T = <>]}}
+// expected-note@#j2 {{imilar constraint expressions not considered equivalent}}
+// expected-note@#j1 {{similar constraint expression here}}
 
 
 
@@ -107,7 +117,7 @@ void test() {
 }
 
 namespace substitution {
-    struct S {
+struct S {
     using type = int;
 };
 
@@ -144,51 +154,69 @@ consteval int Or3() requires (C<typename T::type> || ... || C<typename U::type>)
 static_assert(And1<>() == 1);
 static_assert(And1<S>() == 1);
 static_assert(And1<S, S>() == 1);
+// FIXME: The diagnostics are not so great
 static_assert(And1<int>() == 1); // expected-error {{no matching function for call to 'And1'}}
-                                 // expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
-                                 // expected-note@#and1 {{because substituted constraint expression is ill-formed}}
+                                 // expected-note@#and1 {{candidate template ignored: constraints not satisfied [with T = <int>]}}
+                                 // expected-note@#and1 {{because 'typename T::type' does not satisfy 'C'}}
+                                 // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(And1<S, int>() == 1); // expected-error {{no matching function for call to 'And1'}}
-                                   // expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and1 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and1 {{candidate template ignored: constraints not satisfied [with T = <S, int>]}}
+                                   // expected-note@#and1 {{because 'typename T::type' does not satisfy 'C'}}
+                                   // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(And1<int, S>() == 1); // expected-error {{no matching function for call to 'And1'}}
-                                   // expected-note@#and1 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and1 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and1 {{candidate template ignored: constraints not satisfied [with T = <int, S>]}}
+                                   // expected-note@#and1 {{because 'typename T::type' does not satisfy 'C'}}
+                                   // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(And2<S>() == 2);
 static_assert(And2<S, S>() == 2);
-static_assert(And2<int>() == 2);
+static_assert(And2<int>() == 2);  // expected-error {{no matching function for call to 'And2'}}
+                                  // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = int, U = <>]}}
+                                  // expected-note@#and2 {{because 'typename U::type' does not satisfy 'C'}}
+                                  // expected-note@#C {{because 'T' does not satisfy 'A'}}
+
 
 static_assert(And2<int, int>() == 2);  // expected-error {{no matching function for call to 'And2'}}
-                                      // expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
-                                     // expected-note@#and2 {{because substituted constraint expression is ill-formed}}
+                                      // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = S, U = <int>]}} \
+                                      // expected-note@#and2 {{because 'typename U::type' does not satisfy 'C'}}
+                                   // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(And2<S, int>() == 2); // expected-error {{no matching function for call to 'And2'}}
-                                   // expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and2 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = int, U = <S>]}}
+                                   // expected-note@#and2 {{because 'typename T::type' does not satisfy 'C'}}
+                                 // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(And2<int, S>() == 2); // expected-error {{no matching function for call to 'And2'}}
-                                   // expected-note@#and2 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and2 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and2 {{candidate template ignored: constraints not satisfied [with T = int, U = <int>]}}
+                                   // expected-note@#and2 {{because 'typename T::type' does not satisfy 'C'}}
+                                 // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(And3<S>() == 3);
 static_assert(And3<S, S>() == 3);
 static_assert(And3<int>() == 3);   // expected-error {{no matching function for call to 'And3'}}
-                                   // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = int, U = <>]}}
+                                   // expected-note@#and3 {{because 'typename T::type' does not satisfy 'C'}}
+                                   // expected-note@#C {{because 'T' does not satisfy 'A'}}
+
 
 static_assert(And3<int, int>() == 3);  // expected-error {{no matching function for call to 'And3'}}
-                                      // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
-                                     // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
+                                      // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = int, U = <int>]}}
+                                      // expected-note@#and3 {{because 'typename T::type' does not satisfy 'C'}}
+                                     // expected-note@#C {{because 'T' does not satisfy 'A'}}
+
 
 static_assert(And3<S, int>() == 3); // expected-error {{no matching function for call to 'And3'}}
-                                   // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = S, U = <int>]}}
+                                   // expected-note@#and3 {{because 'typename U::type' does not satisfy 'C'}}
+                                   // expected-note@#C {{because 'T' does not satisfy 'A'}}
+
 
 static_assert(And3<int, S>() == 3); // expected-error {{no matching function for call to 'And3'}}
-                                   // expected-note@#and3 {{candidate template ignored: constraints not satisfied}}
-                                   // expected-note@#and3 {{because substituted constraint expression is ill-formed}}
+                                   // expected-note@#and3 {{candidate template ignored: constraints not satisfied [with T = int, U = <S>]}}
+                                   // expected-note@#and3 {{because 'typename T::type' does not satisfy 'C'}}
+                                   // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 
 static_assert(Or1<>() == 1); // expected-error {{no matching function for call to 'Or1'}}
@@ -198,25 +226,26 @@ static_assert(Or1<int, S>() == 1);
 static_assert(Or1<S, int>() == 1);
 static_assert(Or1<S, S>() == 1);
 static_assert(Or1<int>() == 1); // expected-error {{no matching function for call to 'Or1'}}
-                                // expected-note@#or1 {{candidate template ignored: constraints not satisfied}} \
-                                // expected-note@#or1 {{because substituted constraint expression is ill-formed}}
-
+                                // expected-note@#or1 {{candidate template ignored: constraints not satisfied}}
+                                // expected-note@#or1 {{because 'typename T::type' does not satisfy 'C'}}
+                                // expected-note@#C {{because 'T' does not satisfy 'A'}}
 
 static_assert(Or2<S>() == 2);
 static_assert(Or2<int, S>() == 2);
 static_assert(Or2<S, int>() == 2);
 static_assert(Or2<S, S>() == 2);
 static_assert(Or2<int>() == 2); // expected-error {{no matching function for call to 'Or2'}}
-                                // expected-note@#or2 {{candidate template ignored: constraints not satisfied}} \
-                                // expected-note@#or2 {{because substituted constraint expression is ill-formed}}
-
+                                // expected-note@#or2 {{candidate template ignored: constraints not satisfied [with T = int, U = <>]}}
+                                // expected-note@#or2 {{because 'typename T::type' does not satisfy 'C'}}
+                                // expected-note@#C {{because 'T' does not satisfy 'A'}}
 static_assert(Or3<S>() == 3);
 static_assert(Or3<int, S>() == 3);
 static_assert(Or3<S, int>() == 3);
 static_assert(Or3<S, S>() == 3);
 static_assert(Or3<int>() == 3); // expected-error {{no matching function for call to 'Or3'}}
-                                // expected-note@#or3 {{candidate template ignored: constraints not satisfied}} \
-                                // expected-note@#or3 {{because substituted constraint expression is ill-formed}}
+                                // expected-note@#or3 {{candidate template ignored: constraints not satisfied}}
+                                // expected-note@#or3 {{because 'typename T::type' does not satisfy 'C'}}
+                                // expected-note@#C {{because 'T' does not satisfy 'A'}}
 }
 
 namespace bool_conversion_break {
@@ -226,7 +255,7 @@ struct Thingy {
     static constexpr int compare(const Thingy&) {return 1;}
 };
 template <typename ...T, typename ...U>
-void f(A<T ...> *, A<U ...> *) // expected-note {{candidate template ignored: failed template argument deduction}}
+void f(A<T ...> *, A<U ...> *) // expected-note {{candidate template ignored: constraints not satisfied}}
 requires (T::compare(U{}) && ...); // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
 
 void g() {
@@ -269,9 +298,7 @@ struct S {
 
 static_assert(S<int>::f<int>() == 2);
 
-static_assert(S<int>::g<int>() == 2); // expected-error {{call to 'g' is ambiguous}}
-                                      // expected-note@#nested-ambiguous-g1 {{candidate}}
-                                      // expected-note@#nested-ambiguous-g2 {{candidate}}
+static_assert(S<int>::g<int>() == 2);
 
 
 }
@@ -384,3 +411,98 @@ struct LazyLitMatrix<index_by<Indices...>, init> {
 }
 
 }
+
+namespace GH135190 {
+template <typename T>
+concept A = __is_same_as(T, int) || __is_same_as(T, double) ;
+
+template <typename T>
+concept B = A<T> && __is_same_as(T, double);
+
+template <class... Ts>
+requires(A<Ts> && ...)
+constexpr int g() {
+    return 1;
+}
+
+template <class... Ts>
+requires(B<Ts> && ...)
+constexpr int g() {
+    return 2;
+}
+
+static_assert(g<double>() == 2);
+
+
+template <class... Ts>
+concept all_A = (A<Ts> && ...);
+
+template <class... Ts>
+concept all_B = (B<Ts> && ...);
+
+template <class... Ts>
+requires all_A<Ts...>
+constexpr int h() {
+    return 1;
+}
+
+template <class... Ts>
+requires all_B<Ts...>
+constexpr int h() {
+    return 2;
+}
+
+static_assert(h<double>() == 2);
+}
+
+
+namespace parameter_mapping_regressions {
+
+namespace case1 {
+namespace std {
+template <class _Tp, class... _Args>
+constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
+template <class _Tp, class... _Args>
+concept constructible_from = is_constructible_v<_Tp, _Args...>;
+template <class _Tp>
+concept default_initializable = true;
+template <class> using iterator_t = int;
+template <class _Tp>
+concept view = constructible_from<_Tp, _Tp>;
+template <class... _Views>
+  requires(view<_Views> && ...)
+class zip_transform_view;
+} // namespace std
+struct IterDefaultCtrView {};
+template <class... Views>
+using Iter = std::iterator_t<std::zip_transform_view<Views...>>;
+static_assert(
+    std::default_initializable<Iter<IterDefaultCtrView, IterDefaultCtrView>>);
+
+}
+
+namespace case2 {
+
+template <class _Bp>
+constexpr bool False = false;
+
+template <class... _Views>
+concept __zip_all_random_access = (False<_Views> && ...);
+// expected-note at -1 {{evaluated to false}}
+
+template <typename... _Views>
+struct zip_view {
+  void f() requires __zip_all_random_access<_Views...>{};
+  // expected-note at -1 {{because 'int' does not satisfy}}
+};
+
+zip_view<int> test_v;
+static_assert(!__zip_all_random_access<int>);
+
+void test() {
+  test_v.f(); // expected-error {{invalid reference to function 'f'}}
+}
+
+}
+
+}
diff --git a/clang/test/SemaCXX/cxx2c-template-template-param.cpp b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
index ed55a059bb53c..4ad3fd95039cd 100644
--- a/clang/test/SemaCXX/cxx2c-template-template-param.cpp
+++ b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
@@ -106,7 +106,7 @@ concept BinaryDefaultedFalse = false;
 
 template <template <typename...> concept C, typename T>
 struct S {
-    template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+    template <C TT> // expected-note 2{{because 'int' does not satisfy 'UnaryFalse'}}
     void f(TT); // expected-note {{ignored}}
     void g(C auto); // expected-note {{ignored}} \
                     // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
@@ -171,7 +171,7 @@ concept BinaryDefaultedFalse = false;
 
 template <template <typename...> concept C, typename T>
 struct S {
-    template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+    template <C TT> // expected-note 2{{because 'int' does not satisfy 'UnaryFalse'}}
     void f(TT); // expected-note {{ignored}}
     void g(C auto); // expected-note {{ignored}} \
                     // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
diff --git a/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp b/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
index 097ada3caa135..8400340d19f93 100644
--- a/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
+++ b/clang/test/SemaCXX/invalid-requirement-requires-expr.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang -fsyntax-only -std=c++2a -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s
 
-// RequiresExpr contains invalid requirement. (Eg. Highly recurisive template).
+// RequiresExpr contains invalid requirement. (Eg. Highly recursive template).
 template<int x>
 struct A { static constexpr bool far(); };
 class B {
@@ -17,10 +17,9 @@ constexpr bool A<x>::far() {
       b.data_member;
       requires A<x-1>::far(); // #Invalid
       // expected-error@#Invalid {{recursive template instantiation exceeded maximum depth}}
-      // expected-note@#Invalid {{in instantiation}}
-      // expected-note@#Invalid 2 {{while}}
+      // expected-note@#Invalid 3 {{while}}
       // expected-note@#Invalid {{contexts in backtrace}}
-      // expected-note@#Invalid {{increase recursive template instantiation depth}}
+      // expected-note@#Invalid {{use -ftemplate-depth=N to increase}}
     };
 }
 static_assert(A<1>::far());
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index 135865c8450f5..c3bda3988484d 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -102,7 +102,7 @@ static_assert(__is_constructible(Movable, int));
 // expected-error at -1 {{no matching constructor for initialization of 'Movable'}} \
 // expected-note at -1 2{{}}
 // expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}}
-// expected-note@#err-self-constraint-1 4{{}}
+// expected-note@#err-self-constraint-1 3{{}}
 // expected-note@#Movable  {{'Movable' defined here}}
 
 template <typename T>
@@ -200,7 +200,6 @@ void h(short n) { f(n); }
 // expected-note at -1{{while checking constraint satisfaction for template}}
 // expected-note@#GH62096-note1{{in instantiation}}
 // expected-note@#GH62096-note1{{while substituting template arguments into constraint expression here}}
-// expected-note@#GH62096-note2{{while substituting template arguments into constraint expression here}}
 // expected-note@#GH62096-note2{{while checking the satisfaction of concept}}
 // expected-note@#GH62096-err {{expression evaluates}}
 }
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 3f0124755c674..25900cca6b79a 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -5086,12 +5086,12 @@ namespace GH121278 {
 #if __cplusplus >= 202002L
 template <typename B, typename D>
 concept C = __is_base_of(B, D);
-// expected-error at -1 {{incomplete type 'GH121278::S' used in type trait expression}}
+// expected-error at -1 {{incomplete type 'S' used in type trait expression}}
 // expected-note at -2 {{while substituting template arguments into constraint expression here}}
 
 struct T;
 struct S;
 bool b = C<T, S>;
-// expected-note at -1 {{while checking the satisfaction of concept 'C<GH121278::T, GH121278::S>' requested here}}
+// expected-note at -1 {{while checking the satisfaction of concept 'C<T, S>' requested here}}
 #endif
 }
diff --git a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
index d7c6876d3b9e3..999372c95554e 100644
--- a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl
@@ -19,7 +19,7 @@ Buffer<double2> r4;
 
 // expected-error at +4 {{constraints not satisfied for class template 'Buffer'}}
 // expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class Buffer}}
-// expected-note@*:* {{because 'hlsl::Buffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'Buffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(hlsl::Buffer<int>)' evaluated to false}}
 Buffer<Buffer<int> > r5;
 
@@ -65,7 +65,7 @@ Buffer<half[4]> r10;
 
 typedef vector<int, 8> int8;
 // expected-error at +3 {{constraints not satisfied for class template 'Buffer'}}
-// expected-note@*:* {{because 'vector<int, 8>' (vector of 8 'int' values) does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'int8' (aka 'vector<int, 8>') does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<int, 8>)' evaluated to false}}
 Buffer<int8> r11;
 
@@ -90,7 +90,7 @@ enum numbers { one, two, three };
 Buffer<numbers> r15;
 
 // expected-error at +3 {{constraints not satisfied for class template 'Buffer'}}
-// expected-note@*:* {{because 'vector<double, 3>' (vector of 3 'double' values) does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'double3' (aka 'vector<double, 3>') does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<double, 3>)' evaluated to false}}
 Buffer<double3> r16;
 
diff --git a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
index 361f4303b4961..b33f2af8a1117 100644
--- a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
@@ -19,7 +19,7 @@ RWBuffer<double2> r4;
 
 // expected-error at +4 {{constraints not satisfied for class template 'RWBuffer'}}
 // expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class RWBuffer}}
-// expected-note@*:* {{because 'hlsl::RWBuffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'RWBuffer<int>' does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(hlsl::RWBuffer<int>)' evaluated to false}}
 RWBuffer<RWBuffer<int> > r5;
 
@@ -65,7 +65,7 @@ RWBuffer<half[4]> r10;
 
 typedef vector<int, 8> int8;
 // expected-error at +3 {{constraints not satisfied for class template 'RWBuffer'}}
-// expected-note@*:* {{because 'vector<int, 8>' (vector of 8 'int' values) does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'int8' (aka 'vector<int, 8>') does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<int, 8>)' evaluated to false}}
 RWBuffer<int8> r11;
 
@@ -90,7 +90,7 @@ enum numbers { one, two, three };
 RWBuffer<numbers> r15;
 
 // expected-error at +3 {{constraints not satisfied for class template 'RWBuffer'}}
-// expected-note@*:* {{because 'vector<double, 3>' (vector of 3 'double' values) does not satisfy '__is_typed_resource_element_compatible'}}
+// expected-note@*:* {{because 'double3' (aka 'vector<double, 3>') does not satisfy '__is_typed_resource_element_compatible'}}
 // expected-note@*:* {{because '__builtin_hlsl_is_typed_resource_element_compatible(vector<double, 3>)' evaluated to false}}
 RWBuffer<double3> r16;
 
diff --git a/clang/test/SemaTemplate/concepts-recovery-expr.cpp b/clang/test/SemaTemplate/concepts-recovery-expr.cpp
index 6bed1790051f3..aa4ed53ec4ed3 100644
--- a/clang/test/SemaTemplate/concepts-recovery-expr.cpp
+++ b/clang/test/SemaTemplate/concepts-recovery-expr.cpp
@@ -4,7 +4,7 @@
 constexpr bool CausesRecoveryExpr = "test" + 1.0f;
 
 template<typename T>
-concept ReferencesCRE = CausesRecoveryExpr;
+concept ReferencesCRE = CausesRecoveryExpr; // #subst1
 
 template<typename T> requires CausesRecoveryExpr // #NVC1REQ
 void NoViableCands1(){} // #NVC1
@@ -19,16 +19,18 @@ void NVCUse() {
   NoViableCands1<int>();
   // expected-error at -1 {{no matching function for call to 'NoViableCands1'}}
   // expected-note@#NVC1{{candidate template ignored: constraints not satisfied}}
+  // expected-note@#NVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
   // expected-note@#NVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 
   NoViableCands2<int>();
   // expected-error at -1 {{no matching function for call to 'NoViableCands2'}}
   // expected-note@#NVC2{{candidate template ignored: constraints not satisfied}}
-  // expected-note@#NVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
   NoViableCands3<int>();
   // expected-error at -1 {{no matching function for call to 'NoViableCands3'}}
   // expected-note@#NVC3{{candidate template ignored: constraints not satisfied}}
-  // expected-note@#NVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#NVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 }
 
 template<typename T> requires CausesRecoveryExpr // #OVC1REQ
@@ -58,12 +60,14 @@ void OVCUse() {
   // expected-error at -1 {{no matching function for call to 'OtherViableCands2'}}
   // expected-note@#OVC2_ALT {{candidate function}}
   // expected-note@#OVC2 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#OVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#OVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
   OtherViableCands3<int>();
   // expected-error at -1 {{no matching function for call to 'OtherViableCands3'}}
   // expected-note@#OVC3_ALT {{candidate function}}
   // expected-note@#OVC3 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#OVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#OVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 }
 
 template<typename T> requires CausesRecoveryExpr // #OBNVC1REQ
@@ -95,13 +99,15 @@ void OBNVCUse() {
   // expected-note@#OBNVC2_ALT {{candidate template ignored: constraints not satisfied}}
   // expected-note@#OBNVC2REQ_ALT {{because 'false' evaluated to false}}
   // expected-note@#OBNVC2 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#OBNVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#OBNVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
   OtherBadNoViableCands3<int>();
   // expected-error at -1 {{no matching function for call to 'OtherBadNoViableCands3'}}
   // expected-note@#OBNVC3_ALT {{candidate template ignored: constraints not satisfied}}
   // expected-note@#OBNVC3REQ_ALT {{because 'false' evaluated to false}}
   // expected-note@#OBNVC3 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#OBNVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#OBNVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 }
 
 
@@ -136,12 +142,14 @@ void MemOVCUse() {
   // expected-error at -1 {{no matching member function for call to 'OtherViableCands2'}}
   // expected-note@#MEMOVC2_ALT {{candidate function}}
   // expected-note@#MEMOVC2 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#MEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#MEMOVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
   S.OtherViableCands3<int>();
   // expected-error at -1 {{no matching member function for call to 'OtherViableCands3'}}
   // expected-note@#MEMOVC3_ALT {{candidate function}}
   // expected-note@#MEMOVC3 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#MEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#MEMOVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 }
 
 struct StaticOVC {
@@ -173,12 +181,14 @@ void StaticMemOVCUse() {
   // expected-error at -1 {{no matching function for call to 'OtherViableCands2'}}
   // expected-note@#SMEMOVC2_ALT {{candidate function}}
   // expected-note@#SMEMOVC2 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#SMEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#SMEMOVC2REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
   StaticOVC::OtherViableCands3<int>();
   // expected-error at -1 {{no matching function for call to 'OtherViableCands3'}}
   // expected-note@#SMEMOVC3_ALT {{candidate function}}
   // expected-note@#SMEMOVC3 {{candidate template ignored: constraints not satisfied}}
-  // expected-note@#SMEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#SMEMOVC3REQ{{because 'int' does not satisfy 'ReferencesCRE'}}
+  // expected-note@#subst1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 }
 
 namespace GH58548 {
diff --git a/clang/test/SemaTemplate/concepts-recursive-inst.cpp b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
index 097cad1a64179..73dce9317f383 100644
--- a/clang/test/SemaTemplate/concepts-recursive-inst.cpp
+++ b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
@@ -12,7 +12,7 @@ void g() {
   // expected-note@#FDEF{{because 'int' does not satisfy 'c'}}
   // expected-note@#CDEF{{because 'f(t)' would be invalid: no matching function for call to 'f'}}
 }
-} // namespace GH53213 
+} // namespace GH53213
 
 namespace GH45736 {
 struct constrained;
@@ -67,15 +67,14 @@ struct my_range{
 
 void baz() {
 auto it = begin(rng); // #BEGIN_CALL
-// expected-error@#INF_BEGIN {{satisfaction of constraint 'Inf<Inf auto>' depends on itself}}
-// expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
+// expected-error-re@#INF_REQ {{satisfaction of constraint {{.*}} depends on itself}}
+// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
 // expected-note@#INF_BEGIN_EXPR {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
 // expected-note@#INF_BEGIN_EXPR {{while substituting deduced template arguments into function template 'begin'}}
 // expected-note@#INF_BEGIN_EXPR {{in instantiation of requirement here}}
 // expected-note@#INF_REQ {{while substituting template arguments into constraint expression here}}
-// 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@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<struct my_range>' requested here}}
+// expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<struct my_range>' required here}}
 // 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
@@ -83,6 +82,7 @@ auto it = begin(rng); // #BEGIN_CALL
 // expected-error@#BEGIN_CALL {{no matching function for call to 'begin'}}
 // expected-note@#NOTINF_BEGIN {{candidate function}}
 // expected-note@#INF_BEGIN{{candidate template ignored: constraints not satisfied}}
+// expected-note@#INF_BEGIN{{because 'Inf auto' does not satisfy 'Inf}}
 }
 } // namespace DirectRecursiveCheck
 
@@ -100,16 +100,17 @@ namespace GH50891 {
   static_assert(Numeric<Deferred>); // #STATIC_ASSERT
   // expected-error@#NUMERIC{{satisfaction of constraint 'requires (T a) { foo(a); }' depends on itself}}
   // expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
-  // 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 {{while substituting deduced template arguments into function template}}
-  // expected-note@#FOO_CALL {{in instantiation of requirement here}}
+  // expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
+  // expected-note@#OP_TO {{skipping 1 context}}
+  // expected-note@#FOO_CALL 2{{while checking constraint satisfaction for template}}
+  // expected-note@#FOO_CALL 2{{while substituting deduced template arguments into function template}}
+  // expected-note@#FOO_CALL 2{{in instantiation of requirement here}}
   // expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
 
   // expected-error@#STATIC_ASSERT {{static assertion failed}}
-  // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
-  // expected-note@#STATIC_ASSERT{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+  // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
+  // expected-note@#STATIC_ASSERT{{because 'Deferred' does not satisfy 'Numeric'}}
+  // expected-note@#FOO_CALL{{because 'foo(a)' would be invalid}}
 
 } // namespace GH50891
 
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 209e7dc69797d..cbb8b752a90bc 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1002,7 +1002,7 @@ template<class>
 concept Irrelevant = false;
 
 template <typename T>
-concept ErrorRequires = requires(ErrorRequires auto x) { x; };
+concept ErrorRequires = requires(ErrorRequires auto x) { x; }; //#GH54678-ill-formed-concept
 // expected-error at -1 {{a concept definition cannot refer to itself}} \
 // expected-error at -1 {{'auto' not allowed in requires expression parameter}} \
 // expected-note at -1 {{declared here}}
@@ -1023,8 +1023,7 @@ template<class T> void eee(T t) // expected-note {{candidate template ignored: c
 requires (Irrelevant<T> || Irrelevant<T> || True<T>) && False<T> {} // expected-note {{'long' does not satisfy 'False'}}
 
 template<class T> void fff(T t) // expected-note {{candidate template ignored: constraints not satisfied}}
-requires((ErrorRequires<T> || False<T> || True<T>) && False<T>) {} // expected-note {{'unsigned long' does not satisfy 'False'}}
-
+requires((ErrorRequires<T> || False<T> || True<T>) && False<T>) {} // expected-note {{because 'unsigned long' does not satisfy 'False'}}
 void test() {
     aaa(42); // expected-error {{no matching function}}
     bbb(42L); // expected-error{{no matching function}}
@@ -1278,4 +1277,13 @@ template <typename T> concept PerfectSquare = [](){} // expected-note 2{{here}}
 ([](auto) { return true; }) < PerfectSquare <class T>;
 // expected-error at -1 {{declaration of 'T' shadows template parameter}} \
 // expected-error at -1 {{a concept definition cannot refer to itself}}
+
+}
+namespace GH61811{
+template <class T> struct A { static const int x = 42; };
+template <class Ta> concept A42 = A<Ta>::x == 42;
+template <class Tv> concept Void = __is_same_as(Tv, void);
+template <class Tb, class Ub> concept A42b = Void<Tb> || A42<Ub>;
+template <class Tc> concept R42c = A42b<Tc, Tc&>;
+static_assert (R42c<void>);
 }
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index e41ba7b3eeb2e..7ba92c3b66d98 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -574,8 +574,9 @@ static_assert(x.size == 4);
 // CHECK-NEXT: | |-ParmVarDecl 0x{{.+}} <col:18, col:24> col:21 'U (&)[3]'
 // CHECK-NEXT: | `-ConceptSpecializationExpr 0x{{.+}} <col:36, col:42> 'bool' Concept 0x{{.+}} 'True'
 // CHECK-NEXT: |   |-ImplicitConceptSpecializationDecl 0x{{.+}} <{{.+}}> col:28
-// CHECK-NEXT: |   | `-TemplateArgument type 'type-parameter-0-0'
-// CHECK-NEXT: |   |   `-TemplateTypeParmType 0x{{.+}} 'type-parameter-0-0' dependent depth 0 index 0
+// CHECK-NEXT: |   | `-TemplateArgument type 'T'
+// CHECK-NEXT: |   |   `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
+// CHECK-NEXT: |   |     `-TemplateTypeParm 0x{{.+}} 'T'
 // CHECK-NEXT: |   `-TemplateArgument <{{.+}}> type 'T':'type-parameter-0-0'
 // CHECK-NEXT: |     `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
 // CHECK-NEXT: |       `-TemplateTypeParm 0x{{.+}} 'T'
@@ -588,8 +589,9 @@ static_assert(x.size == 4);
 // CHECK-NEXT:   |-ParmVarDecl 0x{{.+}} <col:18, col:24> col:21 'double (&)[3]'
 // CHECK-NEXT:   `-ConceptSpecializationExpr 0x{{.+}} <col:36, col:42> 'bool' Concept 0x{{.+}} 'True'
 // CHECK-NEXT:     |-ImplicitConceptSpecializationDecl 0x{{.+}} <{{.+}}> col:28
-// CHECK-NEXT:     | `-TemplateArgument type 'type-parameter-0-0'
-// CHECK-NEXT:     |   `-TemplateTypeParmType 0x{{.+}} 'type-parameter-0-0' dependent depth 0 index 0
+// CHECK-NEXT:     | `-TemplateArgument type 'T'
+// CHECK-NEXT:     |   `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
+// CHECK-NEXT:     |     `-TemplateTypeParm 0x{{.+}} 'T'
 // CHECK-NEXT:     `-TemplateArgument <{{.+}}> type 'T':'type-parameter-0-0'
 // CHECK-NEXT:       `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
 // CHECK-NEXT:         `-TemplateTypeParm 0x{{.+}} 'T'
@@ -660,8 +662,9 @@ Test test(42);
 // CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'Constraint' depth 0 index 1 auto:1
 // CHECK-NEXT: | `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'Constraint'
 // CHECK-NEXT: |   |-ImplicitConceptSpecializationDecl {{.*}}
-// CHECK-NEXT: |   | |-TemplateArgument type 'type-parameter-0-1'
-// CHECK-NEXT: |   | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
+// CHECK-NEXT: |   | |-TemplateArgument type 'auto:1'
+// CHECK-NEXT: |   | | `-TemplateTypeParmType {{.*}} 'auto:1' dependent depth 0 index 1
+// CHECK-NEXT: |   | |   `-TemplateTypeParm {{.*}} 'auto:1'
 // CHECK-NEXT: |   | `-TemplateArgument type 'int'
 // CHECK-NEXT: |   |   `-BuiltinType {{.*}} 'int'
 // CHECK-NEXT: |   |-TemplateArgument {{.*}} type 'auto:1':'type-parameter-0-1'
diff --git a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
index 1f2171a25ebb0..e03756ea3e3a8 100644
--- a/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
+++ b/clang/test/SemaTemplate/instantiate-abbreviated-template.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
 
+
 template<typename...>
 concept C = false; // expected-note 9{{because}}
 
diff --git a/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp b/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
index 3edf243982958..de4a4847d0996 100644
--- a/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
+++ b/clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp
@@ -7,8 +7,7 @@ template<typename T>
 constexpr bool is_same_v<T, T> = true;
 
 template<typename T, typename U>
-concept same_as = is_same_v<T, U>;
-// expected-note at -1{{because 'is_same_v<int, bool>' evaluated to false}}
+concept same_as = is_same_v<T, U>; //#is_same_v
 
 template<typename T, typename... Us>
 concept either = (is_same_v<T, Us> || ...);
@@ -17,6 +16,7 @@ template<typename... Ts>
 struct T {
     template<same_as<Ts>... Us>
     // expected-note at -1{{because 'same_as<int, bool>' evaluated to false}}
+    // expected-note@#is_same_v{{because 'is_same_v<int, bool>' evaluated to false}}
     static void foo(Us... u, int x) { };
     // expected-note at -1{{candidate template ignored: deduced too few arguments}}
     // expected-note at -2{{candidate template ignored: constraints not satisfied}}
diff --git a/clang/test/SemaTemplate/instantiate-requires-expr.cpp b/clang/test/SemaTemplate/instantiate-requires-expr.cpp
index e60f79230aa00..32ad5374f46a7 100644
--- a/clang/test/SemaTemplate/instantiate-requires-expr.cpp
+++ b/clang/test/SemaTemplate/instantiate-requires-expr.cpp
@@ -72,12 +72,12 @@ namespace type_requirement {
 
   template<typename T> requires
   false_v<requires { typename T::template temp<T>; }>
-  // expected-note at -1 {{because 'false_v<requires { typename type_requirement::contains_template<int>::template temp<type_requirement::contains_template<int>>; }>' evaluated to false}}
-  // expected-note at -2 {{because 'false_v<requires { typename type_requirement::contains_template<short>::template temp<type_requirement::contains_template<short>>; }>' evaluated to false}}
+  // expected-note at -1 {{because 'false_v<requires { typename contains_template<int>::template temp<contains_template<int>>; }>' evaluated to false}}
+  // expected-note at -2 {{because 'false_v<requires { typename contains_template<short>::template temp<contains_template<short>>; }>' evaluated to false}}
   struct r2 {};
 
-  using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<int>]}}
-  using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<short>]}}
+  using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<int>]}}
+  using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<short>]}}
 
   // substitution error occurs, then requires expr is instantiated again
 
@@ -108,7 +108,7 @@ namespace type_requirement {
   // expected-note at -1 {{because 'false_v<requires { <<error-type>>; } && requires { <<error-type>>; }>' evaluated to false}}
   struct r7 {};
 
-  using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, type_requirement::A>]}}
+  using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, A>]}}
 }
 
 namespace expr_requirement {
@@ -268,3 +268,13 @@ struct Foo {
 };
 
 } // namespace GH110785
+
+namespace sugared_instantiation {
+  template <class C1> concept C = requires { C1{}; };
+  template <class D1> concept D = requires { new D1; };
+
+  // Test that 'deduced auto' doesn't get confused with 'undeduced auto'.
+  auto f() { return 0; }
+  static_assert(requires { { f() } -> C; });
+  static_assert(requires { { f() } -> D; });
+} // namespace sugared_instantiation
diff --git a/clang/test/SemaTemplate/instantiate-template-argument.cpp b/clang/test/SemaTemplate/instantiate-template-argument.cpp
index 43d5d00c8cb20..74050acdf4f35 100644
--- a/clang/test/SemaTemplate/instantiate-template-argument.cpp
+++ b/clang/test/SemaTemplate/instantiate-template-argument.cpp
@@ -9,20 +9,24 @@ concept C2 = C1<Y{}, V>;
 // sizeof(U) >= 4 [U = V (decltype(Y{}))]
 
 template<char W>
-constexpr int foo() requires C2<int, W> { return 1; }
+constexpr int foo() requires C2<int, W> { return 1; } // #cand1
 // sizeof(U) >= 4 [U = W (decltype(int{}))]
 
 template<char X>
 // expected-note at +1{{candidate function}}
-constexpr int foo() requires C1<1, X> && true { return 2; }
+constexpr int foo() requires C1<1, X> && true { return 2; } // #cand2
 // sizeof(U) >= 4 [U = X (decltype(1))]
 
 static_assert(foo<'a'>() == 2);
+// expected-error at -1 {{call to 'foo' is ambiguous}}
+// expected-note@#cand1 {{candidate function}}
+// expected-note@#cand2 {{candidate function}}
 
 template<char Z>
-// expected-note at +1{{candidate function}}
-constexpr int foo() requires C2<long long, Z> && true { return 3; }
+constexpr int foo() requires C2<long long, Z> && true { return 3; } // #cand3
 // sizeof(U) >= 4 [U = Z (decltype(long long{}))]
 
 static_assert(foo<'a'>() == 3);
-// expected-error at -1{{call to 'foo' is ambiguous}}
\ No newline at end of file
+// expected-error at -1{{call to 'foo' is ambiguous}}
+// expected-note@#cand1 {{candidate function}}
+// expected-note@#cand3 {{candidate function}}
diff --git a/clang/test/SemaTemplate/pr52970.cpp b/clang/test/SemaTemplate/pr52970.cpp
index 7aac5ee856593..6aabc419bd2b8 100644
--- a/clang/test/SemaTemplate/pr52970.cpp
+++ b/clang/test/SemaTemplate/pr52970.cpp
@@ -53,7 +53,7 @@ static_assert(!DotFollowingPointer::f(Bad{}), "");
 #if __cplusplus >= 202002L
 template <class T>
 concept C = requires(T t) { t.begin(); };
-  // cxx20-note at -1 {{because 't.begin()' would be invalid: member reference type 'Holder<Incomplete> *' is a pointer}}
+  // cxx20-note at -1 {{because 't.begin()' would be invalid: member reference type 'Bad' (aka 'Holder<Incomplete> *') is a pointer}}
 
 static_assert(C<Good>);
 static_assert(!C<Bad>);

>From bfcad787e98f97efda7f39d65b69400e4af999da Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Sep 2025 16:31:41 +0200
Subject: [PATCH 02/29] more build failures

---
 clang/lib/Sema/SemaConcept.cpp | 59 +---------------------------------
 1 file changed, 1 insertion(+), 58 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 22b131f4d48c2..5a46f315c9456 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -700,76 +700,20 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
       .VisitConstraint(Constraint);
 
-  unsigned CacheKeyHash = ID.computeStableHash();
-
-#define UseCache 1
   if (auto Iter = S.ConceptIdSatisfactionCache.find(ID);
       Iter != S.ConceptIdSatisfactionCache.end()) {
-#if UseCache
+
     auto &Cached = Iter->second.Satisfaction;
     Satisfaction.ContainsErrors = Cached.ContainsErrors;
     Satisfaction.IsSatisfied = Cached.IsSatisfied;
     Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
                                 Cached.Details.begin(), Cached.Details.end());
-#ifndef NDEBUG
-    if (Iter->second.E != Constraint.getConstraintExpr()) {
-      llvm::errs() << "CacheKey: " << CacheKeyHash << " "
-                   << S.ConceptIdSatisfactionCache.size() << "\n";
-      if (Constraint.hasParameterMapping()) {
-        llvm::errs() << "Mapping: ";
-        for (auto Arg : Constraint.getParameterMapping()) {
-          Arg.getArgument().print(S.getPrintingPolicy(), llvm::errs(),
-                                  /*IncludeType=*/false);
-          llvm::errs() << " ";
-        }
-        llvm::errs() << "\n";
-      }
-      llvm::errs() << "Previous 1: " << Iter->second.E << " ";
-      Iter->second.E->printPretty(llvm::errs(), /*Helper=*/nullptr,
-                                  S.getPrintingPolicy());
-      llvm::errs() << "\n";
-      llvm::errs() << "Current 1: " << Constraint.getConstraintExpr() << " ";
-      Constraint.getConstraintExpr()->printPretty(
-          llvm::errs(), /*Helper=*/nullptr, S.getPrintingPolicy());
-      llvm::errs() << "\n";
-    }
-    assert(Iter->second.E == Constraint.getConstraintExpr());
-#ifndef NDEBUG
-    return Iter->second.SubstExpr;
-#else
-#endif
   }
 
   ExprResult E = CalculateSlow(Constraint, MLTAL);
 
   assert(Constraint.getConstraintExpr() == Previous);
 
-  if (auto Iter = S.ConceptIdSatisfactionCache.find(ID);
-      Iter != S.ConceptIdSatisfactionCache.end()) {
-#if UseCache
-    auto &Cached = Iter->second.Satisfaction;
-    Satisfaction.ContainsErrors = Cached.ContainsErrors;
-    Satisfaction.IsSatisfied = Cached.IsSatisfied;
-    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
-                                Cached.Details.begin(), Cached.Details.end());
-#ifndef NDEBUG
-    if (Iter->second.E != Constraint.getConstraintExpr()) {
-      llvm::errs() << "CacheKey: " << CacheKeyHash << " ";
-      llvm::errs() << "Previous: ";
-      Iter->second.E->printPretty(llvm::errs(), /*Helper=*/nullptr,
-                                  S.getPrintingPolicy());
-      llvm::errs() << "\n";
-      llvm::errs() << "Current: ";
-      Constraint.getConstraintExpr()->printPretty(
-          llvm::errs(), /*Helper=*/nullptr, S.getPrintingPolicy());
-      llvm::errs() << "\n";
-    }
-    assert(Iter->second.E == Constraint.getConstraintExpr());
-#ifndef NDEBUG
-    return Iter->second.SubstExpr;
-#endif
-  }
-
   CachedConceptIdConstraint Cache;
   Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
   Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
@@ -778,7 +722,6 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   Cache.SubstExpr = E;
   Cache.E = Constraint.getConstraintExpr();
   S.ConceptIdSatisfactionCache.insert({ID, std::move(Cache)});
-#undef UseCache
 
   return E;
 }

>From 7d66cd802433275877e1ddb284df03cd8fa5fca0 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Sep 2025 16:47:31 +0200
Subject: [PATCH 03/29] I accidentally disabled caching

---
 clang/lib/Sema/SemaConcept.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 5a46f315c9456..f45da77621d55 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -708,6 +708,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
     Satisfaction.IsSatisfied = Cached.IsSatisfied;
     Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
                                 Cached.Details.begin(), Cached.Details.end());
+    return Iter->second.SubstExpr;
   }
 
   ExprResult E = CalculateSlow(Constraint, MLTAL);

>From ccb3eb0899d59df9bb42cb2890f3798347de3a92 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Sep 2025 16:50:04 +0200
Subject: [PATCH 04/29] fix libcxx test

---
 .../test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
index 629a887c0f7ed..93415f916190e 100644
--- a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
@@ -143,7 +143,7 @@ void check_forward_iterator_requirements() {
   // expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}}
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(postincrement_not_ref, ""); // expected-error {{static assertion failed}}
 #ifndef _AIX
-  // expected-note-re@*:* {{because type constraint 'convertible_to<{{(valid_iterator<postincrement_not_ref>::)?}}Proxy, const postincrement_not_ref &>' was not satisfied}}
+  // expected-note-re@*:* {{because 'convertible_to<{{(valid_iterator<postincrement_not_ref>::)?}}Proxy, const postincrement_not_ref &>' evaluated to false}}
 #endif
 }
 
@@ -173,7 +173,7 @@ void check_bidirectional_iterator_requirements() {
   _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(missing_postdecrement, ""); // expected-error {{static assertion failed}}
   // expected-note@*:* {{cannot decrement value of type 'missing_postdecrement'}}
   _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(not_returning_iter_reference, ""); // expected-error {{static assertion failed}}
-  // expected-note-re@*:* {{because type constraint 'same_as<int, __iter_reference<not_returning_iter_reference>{{ ?}}>' was not satisfied}}
+  // expected-note-re@*:* {{because 'same_as<int, __iter_reference<not_returning_iter_reference>{{ ?}}>' evaluated to false}}
   // clang-format on
 }
 

>From 7ff50beb0a38b98b7832a74a61dfa295e7d51155 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Sep 2025 18:11:05 +0200
Subject: [PATCH 05/29] fix windows build

---
 clang/include/clang/Sema/SemaConcept.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index 3ba48b75c1286..c70c83d1727be 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -157,7 +157,7 @@ struct NormalizedConstraint {
 
   NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK,
                        NormalizedConstraint *RHS)
-      : Compound{llvm::to_underlying(ConstraintKind::Compound), CCK, LHS, RHS} {
+      : Compound{llvm::to_underlying(ConstraintKind::Compound), llvm::to_underlying(CCK), LHS, RHS} {
   }
 
   bool hasParameterMapping() const {

>From badb3f20a89e2ab8c695c4fa7d98d2707a36a3f1 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 9 Sep 2025 18:12:14 +0200
Subject: [PATCH 06/29] format

---
 clang/include/clang/AST/ASTContext.h       |   1 -
 clang/include/clang/Sema/SemaConcept.h     |  17 +-
 clang/lib/Sema/SemaDeclCXX.cpp             |   4 +-
 clang/lib/Sema/SemaTemplate.cpp            |   2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 958 ++++++++++-----------
 5 files changed, 488 insertions(+), 494 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 655c8522b67c4..c67efe8795a27 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -3863,7 +3863,6 @@ typename clang::LazyGenerationalUpdatePtr<Owner, T, Update>::ValueType
     return new (Ctx) LazyData(Source, Value);
   return Value;
 }
-
 template <> struct llvm::DenseMapInfo<llvm::FoldingSetNodeID> {
   static FoldingSetNodeID getEmptyKey() { return FoldingSetNodeID{}; }
 
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index c70c83d1727be..df0007d1eedb3 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -157,12 +157,11 @@ struct NormalizedConstraint {
 
   NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK,
                        NormalizedConstraint *RHS)
-      : Compound{llvm::to_underlying(ConstraintKind::Compound), llvm::to_underlying(CCK), LHS, RHS} {
-  }
+      : Compound{llvm::to_underlying(ConstraintKind::Compound),
+                 llvm::to_underlying(CCK), LHS, RHS} {}
 
   bool hasParameterMapping() const {
-    return getKind() != ConstraintKind::Compound
-                            && Atomic.Args != nullptr;
+    return getKind() != ConstraintKind::Compound && Atomic.Args != nullptr;
   }
 
   const OccurenceList &mappingOccurenceList() const {
@@ -365,12 +364,10 @@ class ConceptIdConstraint : public NormalizedConstraintWithParamMapping {
       NormalizedConstraintWithParamMapping;
 
 public:
-  static ConceptIdConstraint *Create(ASTContext &Ctx,
-                                     const ConceptReference *ConceptId,
-                                     NormalizedConstraint *SubConstraint,
-                                     const NamedDecl *ConstraintDecl,
-                                     const ConceptSpecializationExpr *CSE,
-                                     UnsignedOrNone PackIndex) {
+  static ConceptIdConstraint *
+  Create(ASTContext &Ctx, const ConceptReference *ConceptId,
+         NormalizedConstraint *SubConstraint, const NamedDecl *ConstraintDecl,
+         const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex) {
     return new (Ctx) ConceptIdConstraint(ConceptId, ConstraintDecl,
                                          SubConstraint, CSE, PackIndex);
   }
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 4c55a452c244a..233869419442e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17880,8 +17880,8 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
         const ASTConstraintSatisfaction &Satisfaction =
             ConceptIDExpr->getSatisfaction();
         if (!Satisfaction.ContainsErrors || Satisfaction.NumRecords) {
-        Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
-            << !HasMessage << Msg.str() << AssertExpr->getSourceRange();
+          Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
+              << !HasMessage << Msg.str() << AssertExpr->getSourceRange();
           // Drill down into concept specialization expressions to see why they
           // weren't satisfied.
           DiagnoseUnsatisfiedConstraint(ConceptIDExpr);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7a84a52f7bde3..e780435548bed 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4854,7 +4854,7 @@ ExprResult Sema::CheckConceptTemplateId(
           *TemplateArgs, CTAI.SugaredConverted);
   MultiLevelTemplateArgumentList MLTAL(NamedConcept, CTAI.SugaredConverted,
                                        /*Final=*/false);
-      auto *CL = ConceptReference::Create(
+  auto *CL = ConceptReference::Create(
       Context,
       SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
       TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index bfce05135e058..12fe1f61405c0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1394,34 +1394,34 @@ getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) {
 namespace {
 
 class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
-    const MultiLevelTemplateArgumentList &TemplateArgs;
-    SourceLocation Loc;
-    DeclarationName Entity;
-    // Whether to evaluate the C++20 constraints or simply substitute into them.
-    bool EvaluateConstraints = true;
-    // Whether Substitution was Incomplete, that is, we tried to substitute in
-    // any user provided template arguments which were null.
-    bool IsIncomplete = false;
-    // Whether an incomplete substituion should be treated as an error.
-    bool BailOutOnIncomplete;
-
-    bool PreserveArgumentPacks = false;
-    bool BuildPackExpansionTypes = true;
-
-    // CWG2770: Function parameters should be instantiated when they are
-    // needed by a satisfaction check of an atomic constraint or
-    // (recursively) by another function parameter.
-    bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
+  const MultiLevelTemplateArgumentList &TemplateArgs;
+  SourceLocation Loc;
+  DeclarationName Entity;
+  // Whether to evaluate the C++20 constraints or simply substitute into them.
+  bool EvaluateConstraints = true;
+  // Whether Substitution was Incomplete, that is, we tried to substitute in
+  // any user provided template arguments which were null.
+  bool IsIncomplete = false;
+  // Whether an incomplete substituion should be treated as an error.
+  bool BailOutOnIncomplete;
+
+  bool PreserveArgumentPacks = false;
+  bool BuildPackExpansionTypes = true;
+
+  // CWG2770: Function parameters should be instantiated when they are
+  // needed by a satisfaction check of an atomic constraint or
+  // (recursively) by another function parameter.
+  bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
 
 public:
-    typedef TreeTransform<TemplateInstantiator> inherited;
+  typedef TreeTransform<TemplateInstantiator> inherited;
 
-    TemplateInstantiator(Sema &SemaRef,
-                         const MultiLevelTemplateArgumentList &TemplateArgs,
-                         SourceLocation Loc, DeclarationName Entity,
-                         bool BailOutOnIncomplete = false)
-        : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
-          Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
+  TemplateInstantiator(Sema &SemaRef,
+                       const MultiLevelTemplateArgumentList &TemplateArgs,
+                       SourceLocation Loc, DeclarationName Entity,
+                       bool BailOutOnIncomplete = false)
+      : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+        Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
 
   inline static struct ForParameterMappingSubstitution_t {
   } ForParameterMappingSubstitution;
@@ -1437,200 +1437,200 @@ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
   void setEvaluateConstraints(bool B) { EvaluateConstraints = B; }
   bool getEvaluateConstraints() { return EvaluateConstraints; }
 
-    /// Determine whether the given type \p T has already been
-    /// transformed.
-    ///
-    /// For the purposes of template instantiation, a type has already been
-    /// transformed if it is NULL or if it is not dependent.
-    bool AlreadyTransformed(QualType T);
+  /// Determine whether the given type \p T has already been
+  /// transformed.
+  ///
+  /// For the purposes of template instantiation, a type has already been
+  /// transformed if it is NULL or if it is not dependent.
+  bool AlreadyTransformed(QualType T);
 
-    /// Returns the location of the entity being instantiated, if known.
-    SourceLocation getBaseLocation() { return Loc; }
+  /// Returns the location of the entity being instantiated, if known.
+  SourceLocation getBaseLocation() { return Loc; }
 
-    /// Returns the name of the entity being instantiated, if any.
-    DeclarationName getBaseEntity() { return Entity; }
+  /// Returns the name of the entity being instantiated, if any.
+  DeclarationName getBaseEntity() { return Entity; }
 
-    /// Returns whether any substitution so far was incomplete.
-    bool getIsIncomplete() const { return IsIncomplete; }
+  /// Returns whether any substitution so far was incomplete.
+  bool getIsIncomplete() const { return IsIncomplete; }
 
-    /// Sets the "base" location and entity when that
-    /// information is known based on another transformation.
-    void setBase(SourceLocation Loc, DeclarationName Entity) {
-      this->Loc = Loc;
-      this->Entity = Entity;
-    }
+  /// Sets the "base" location and entity when that
+  /// information is known based on another transformation.
+  void setBase(SourceLocation Loc, DeclarationName Entity) {
+    this->Loc = Loc;
+    this->Entity = Entity;
+  }
 
-    unsigned TransformTemplateDepth(unsigned Depth) {
-      return TemplateArgs.getNewDepth(Depth);
-    }
+  unsigned TransformTemplateDepth(unsigned Depth) {
+    return TemplateArgs.getNewDepth(Depth);
+  }
 
-    UnsignedOrNone getPackIndex(TemplateArgument Pack) {
-      UnsignedOrNone Index = getSema().ArgPackSubstIndex;
-      if (!Index)
-        return std::nullopt;
-      return Pack.pack_size() - 1 - *Index;
-    }
+  UnsignedOrNone getPackIndex(TemplateArgument Pack) {
+    UnsignedOrNone Index = getSema().ArgPackSubstIndex;
+    if (!Index)
+      return std::nullopt;
+    return Pack.pack_size() - 1 - *Index;
+  }
 
-    bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
-                                 SourceRange PatternRange,
-                                 ArrayRef<UnexpandedParameterPack> Unexpanded,
-                                 bool FailOnPackProducingTemplates,
-                                 bool &ShouldExpand, bool &RetainExpansion,
-                                 UnsignedOrNone &NumExpansions) {
-      if (SemaRef.CurrentInstantiationScope &&
-          (SemaRef.inConstraintSubstitution() ||
-           SemaRef.inParameterMappingSubstitution())) {
-        for (UnexpandedParameterPack ParmPack : Unexpanded) {
-          NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
-          if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
-              PVD && maybeInstantiateFunctionParameterToScope(PVD))
-            return true;
-        }
+  bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
+                               SourceRange PatternRange,
+                               ArrayRef<UnexpandedParameterPack> Unexpanded,
+                               bool FailOnPackProducingTemplates,
+                               bool &ShouldExpand, bool &RetainExpansion,
+                               UnsignedOrNone &NumExpansions) {
+    if (SemaRef.CurrentInstantiationScope &&
+        (SemaRef.inConstraintSubstitution() ||
+         SemaRef.inParameterMappingSubstitution())) {
+      for (UnexpandedParameterPack ParmPack : Unexpanded) {
+        NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
+        if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
+            PVD && maybeInstantiateFunctionParameterToScope(PVD))
+          return true;
       }
-
-      return getSema().CheckParameterPacksForExpansion(
-          EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
-          FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
-          NumExpansions);
     }
 
-    void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
-      SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
-    }
+    return getSema().CheckParameterPacksForExpansion(
+        EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
+        FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
+        NumExpansions);
+  }
+
+  void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
+    SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
+  }
 
-    TemplateArgument ForgetPartiallySubstitutedPack() {
-      TemplateArgument Result;
+  TemplateArgument ForgetPartiallySubstitutedPack() {
+    TemplateArgument Result;
     if (NamedDecl *PartialPack =
             SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
       MultiLevelTemplateArgumentList &TemplateArgs =
           const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-        unsigned Depth, Index;
-        std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
-        if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
-          Result = TemplateArgs(Depth, Index);
-          TemplateArgs.setArgument(Depth, Index, TemplateArgument());
-        } else {
-          IsIncomplete = true;
-          if (BailOutOnIncomplete)
-            return TemplateArgument();
-        }
+      unsigned Depth, Index;
+      std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+      if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
+        Result = TemplateArgs(Depth, Index);
+        TemplateArgs.setArgument(Depth, Index, TemplateArgument());
+      } else {
+        IsIncomplete = true;
+        if (BailOutOnIncomplete)
+          return TemplateArgument();
       }
-
-      return Result;
     }
 
-    void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
-      if (Arg.isNull())
-        return;
+    return Result;
+  }
+
+  void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
+    if (Arg.isNull())
+      return;
 
     if (NamedDecl *PartialPack =
             SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
       MultiLevelTemplateArgumentList &TemplateArgs =
           const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-        unsigned Depth, Index;
-        std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
-        TemplateArgs.setArgument(Depth, Index, Arg);
-      }
+      unsigned Depth, Index;
+      std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+      TemplateArgs.setArgument(Depth, Index, Arg);
     }
+  }
 
-    MultiLevelTemplateArgumentList ForgetSubstitution() {
-      MultiLevelTemplateArgumentList New;
-      New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
+  MultiLevelTemplateArgumentList ForgetSubstitution() {
+    MultiLevelTemplateArgumentList New;
+    New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
 
-      MultiLevelTemplateArgumentList Old =
-          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
-          std::move(New);
-      return Old;
-    }
+    MultiLevelTemplateArgumentList Old =
+        const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+    const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
+        std::move(New);
+    return Old;
+  }
 
-    void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
-      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) = Old;
-    }
+  void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
+    const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) = Old;
+  }
 
-    TemplateArgument
-    getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
-      if (TA.getKind() != TemplateArgument::Pack)
-        return TA;
-      if (SemaRef.ArgPackSubstIndex)
-        return getPackSubstitutedTemplateArgument(SemaRef, TA);
-      assert(TA.pack_size() == 1 && TA.pack_begin()->isPackExpansion() &&
-             "unexpected pack arguments in template rewrite");
-      TemplateArgument Arg = *TA.pack_begin();
-      if (Arg.isPackExpansion())
-        Arg = Arg.getPackExpansionPattern();
-      return Arg;
-    }
+  TemplateArgument
+  getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
+    if (TA.getKind() != TemplateArgument::Pack)
+      return TA;
+    if (SemaRef.ArgPackSubstIndex)
+      return getPackSubstitutedTemplateArgument(SemaRef, TA);
+    assert(TA.pack_size() == 1 && TA.pack_begin()->isPackExpansion() &&
+           "unexpected pack arguments in template rewrite");
+    TemplateArgument Arg = *TA.pack_begin();
+    if (Arg.isPackExpansion())
+      Arg = Arg.getPackExpansionPattern();
+    return Arg;
+  }
 
-    /// Transform the given declaration by instantiating a reference to
-    /// this declaration.
-    Decl *TransformDecl(SourceLocation Loc, Decl *D);
+  /// Transform the given declaration by instantiating a reference to
+  /// this declaration.
+  Decl *TransformDecl(SourceLocation Loc, Decl *D);
 
-    void transformAttrs(Decl *Old, Decl *New) {
-      SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
-    }
+  void transformAttrs(Decl *Old, Decl *New) {
+    SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
+  }
 
-    void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) {
-      if (Old->isParameterPack() &&
-          (NewDecls.size() != 1 || !NewDecls.front()->isParameterPack())) {
-        SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old);
-        for (auto *New : NewDecls)
-          SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(
-              Old, cast<VarDecl>(New));
-        return;
-      }
+  void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) {
+    if (Old->isParameterPack() &&
+        (NewDecls.size() != 1 || !NewDecls.front()->isParameterPack())) {
+      SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old);
+      for (auto *New : NewDecls)
+        SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(
+            Old, cast<VarDecl>(New));
+      return;
+    }
 
-      assert(NewDecls.size() == 1 &&
-             "should only have multiple expansions for a pack");
-      Decl *New = NewDecls.front();
-
-      // If we've instantiated the call operator of a lambda or the call
-      // operator template of a generic lambda, update the "instantiation of"
-      // information.
-      auto *NewMD = dyn_cast<CXXMethodDecl>(New);
-      if (NewMD && isLambdaCallOperator(NewMD)) {
-        auto *OldMD = dyn_cast<CXXMethodDecl>(Old);
-        if (auto *NewTD = NewMD->getDescribedFunctionTemplate())
-          NewTD->setInstantiatedFromMemberTemplate(
-              OldMD->getDescribedFunctionTemplate());
-        else
-          NewMD->setInstantiationOfMemberFunction(OldMD,
-                                                  TSK_ImplicitInstantiation);
-      }
+    assert(NewDecls.size() == 1 &&
+           "should only have multiple expansions for a pack");
+    Decl *New = NewDecls.front();
+
+    // If we've instantiated the call operator of a lambda or the call
+    // operator template of a generic lambda, update the "instantiation of"
+    // information.
+    auto *NewMD = dyn_cast<CXXMethodDecl>(New);
+    if (NewMD && isLambdaCallOperator(NewMD)) {
+      auto *OldMD = dyn_cast<CXXMethodDecl>(Old);
+      if (auto *NewTD = NewMD->getDescribedFunctionTemplate())
+        NewTD->setInstantiatedFromMemberTemplate(
+            OldMD->getDescribedFunctionTemplate());
+      else
+        NewMD->setInstantiationOfMemberFunction(OldMD,
+                                                TSK_ImplicitInstantiation);
+    }
 
-      SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
+    SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
 
-      // We recreated a local declaration, but not by instantiating it. There
-      // may be pending dependent diagnostics to produce.
-      if (auto *DC = dyn_cast<DeclContext>(Old);
-          DC && DC->isDependentContext() && DC->isFunctionOrMethod())
-        SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
-    }
+    // We recreated a local declaration, but not by instantiating it. There
+    // may be pending dependent diagnostics to produce.
+    if (auto *DC = dyn_cast<DeclContext>(Old);
+        DC && DC->isDependentContext() && DC->isFunctionOrMethod())
+      SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
+  }
 
-    /// Transform the definition of the given declaration by
-    /// instantiating it.
-    Decl *TransformDefinition(SourceLocation Loc, Decl *D);
+  /// Transform the definition of the given declaration by
+  /// instantiating it.
+  Decl *TransformDefinition(SourceLocation Loc, Decl *D);
 
-    /// Transform the first qualifier within a scope by instantiating the
-    /// declaration.
-    NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
+  /// Transform the first qualifier within a scope by instantiating the
+  /// declaration.
+  NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
 
-    bool TransformExceptionSpec(SourceLocation Loc,
-                                FunctionProtoType::ExceptionSpecInfo &ESI,
-                                SmallVectorImpl<QualType> &Exceptions,
-                                bool &Changed);
+  bool TransformExceptionSpec(SourceLocation Loc,
+                              FunctionProtoType::ExceptionSpecInfo &ESI,
+                              SmallVectorImpl<QualType> &Exceptions,
+                              bool &Changed);
 
-    /// Rebuild the exception declaration and register the declaration
-    /// as an instantiated local.
-    VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
-                                  TypeSourceInfo *Declarator,
+  /// Rebuild the exception declaration and register the declaration
+  /// as an instantiated local.
+  VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
+                                TypeSourceInfo *Declarator,
                                 SourceLocation StartLoc, SourceLocation NameLoc,
-                                  IdentifierInfo *Name);
+                                IdentifierInfo *Name);
 
-    /// Rebuild the Objective-C exception declaration and register the
-    /// declaration as an instantiated local.
-    VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
-                                      TypeSourceInfo *TSInfo, QualType T);
+  /// Rebuild the Objective-C exception declaration and register the
+  /// declaration as an instantiated local.
+  VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+                                    TypeSourceInfo *TSInfo, QualType T);
 
   /// Check for tag mismatches when instantiating an
   /// elaborated type.
@@ -1639,176 +1639,174 @@ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
                                  NestedNameSpecifierLoc QualifierLoc,
                                  QualType T);
 
-  TemplateName
-  TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc,
-                          SourceLocation TemplateKWLoc, TemplateName Name,
-                          SourceLocation NameLoc,
-                          QualType ObjectType = QualType(),
-                          NamedDecl *FirstQualifierInScope = nullptr,
-                          bool AllowInjectedClassName = false);
-
-    const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
-    const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
-    const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
-    const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
-                                                  const Stmt *InstS,
-                                                  const NoInlineAttr *A);
-    const AlwaysInlineAttr *
-    TransformStmtAlwaysInlineAttr(const Stmt *OrigS, const Stmt *InstS,
-                                  const AlwaysInlineAttr *A);
-    const CodeAlignAttr *TransformCodeAlignAttr(const CodeAlignAttr *CA);
-    const OpenACCRoutineDeclAttr *
-    TransformOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
-    ExprResult TransformPredefinedExpr(PredefinedExpr *E);
-    ExprResult TransformDeclRefExpr(DeclRefExpr *E);
-    ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
-
-    ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
-                                            NonTypeTemplateParmDecl *D);
-    ExprResult TransformSubstNonTypeTemplateParmPackExpr(
-                                           SubstNonTypeTemplateParmPackExpr *E);
+  TemplateName TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc,
+                                     SourceLocation TemplateKWLoc,
+                                     TemplateName Name, SourceLocation NameLoc,
+                                     QualType ObjectType = QualType(),
+                                     NamedDecl *FirstQualifierInScope = nullptr,
+                                     bool AllowInjectedClassName = false);
+
+  const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
+  const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
+  const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
+  const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
+                                                const Stmt *InstS,
+                                                const NoInlineAttr *A);
+  const AlwaysInlineAttr *
+  TransformStmtAlwaysInlineAttr(const Stmt *OrigS, const Stmt *InstS,
+                                const AlwaysInlineAttr *A);
+  const CodeAlignAttr *TransformCodeAlignAttr(const CodeAlignAttr *CA);
+  const OpenACCRoutineDeclAttr *
+  TransformOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
+  ExprResult TransformPredefinedExpr(PredefinedExpr *E);
+  ExprResult TransformDeclRefExpr(DeclRefExpr *E);
+  ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+
+  ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
+                                          NonTypeTemplateParmDecl *D);
+  ExprResult TransformSubstNonTypeTemplateParmPackExpr(
+      SubstNonTypeTemplateParmPackExpr *E);
   ExprResult
   TransformSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
 
-    /// Rebuild a DeclRefExpr for a VarDecl reference.
-    ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
+  /// Rebuild a DeclRefExpr for a VarDecl reference.
+  ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
 
-    /// Transform a reference to a function or init-capture parameter pack.
-    ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, ValueDecl *PD);
+  /// Transform a reference to a function or init-capture parameter pack.
+  ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, ValueDecl *PD);
 
-    /// Transform a FunctionParmPackExpr which was built when we couldn't
-    /// expand a function parameter pack reference which refers to an expanded
-    /// pack.
-    ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
+  /// Transform a FunctionParmPackExpr which was built when we couldn't
+  /// expand a function parameter pack reference which refers to an expanded
+  /// pack.
+  ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
 
-    QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
-                                        FunctionProtoTypeLoc TL) {
-      // Call the base version; it will forward to our overridden version below.
-      return inherited::TransformFunctionProtoType(TLB, TL);
-    }
+  QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                      FunctionProtoTypeLoc TL) {
+    // Call the base version; it will forward to our overridden version below.
+    return inherited::TransformFunctionProtoType(TLB, TL);
+  }
 
-    QualType TransformTagType(TypeLocBuilder &TLB, TagTypeLoc TL) {
-      auto Type = inherited::TransformTagType(TLB, TL);
-      if (!Type.isNull())
-        return Type;
-      // Special case for transforming a deduction guide, we return a
-      // transformed TemplateSpecializationType.
-      // FIXME: Why is this hack necessary?
-      if (const auto *ICNT = dyn_cast<InjectedClassNameType>(TL.getTypePtr());
-          ICNT && SemaRef.CodeSynthesisContexts.back().Kind ==
-                      Sema::CodeSynthesisContext::BuildingDeductionGuides) {
-        Type = inherited::TransformType(
-            ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType(
-                SemaRef.Context));
-        TLB.pushTrivial(SemaRef.Context, Type, TL.getNameLoc());
-      }
+  QualType TransformTagType(TypeLocBuilder &TLB, TagTypeLoc TL) {
+    auto Type = inherited::TransformTagType(TLB, TL);
+    if (!Type.isNull())
       return Type;
+    // Special case for transforming a deduction guide, we return a
+    // transformed TemplateSpecializationType.
+    // FIXME: Why is this hack necessary?
+    if (const auto *ICNT = dyn_cast<InjectedClassNameType>(TL.getTypePtr());
+        ICNT && SemaRef.CodeSynthesisContexts.back().Kind ==
+                    Sema::CodeSynthesisContext::BuildingDeductionGuides) {
+      Type = inherited::TransformType(
+          ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType(
+              SemaRef.Context));
+      TLB.pushTrivial(SemaRef.Context, Type, TL.getNameLoc());
     }
-    // Override the default version to handle a rewrite-template-arg-pack case
-    // for building a deduction guide.
-    bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
-                                   TemplateArgumentLoc &Output,
-                                   bool Uneval = false) {
-      const TemplateArgument &Arg = Input.getArgument();
-      std::vector<TemplateArgument> TArgs;
-      switch (Arg.getKind()) {
-      case TemplateArgument::Pack:
-        assert(SemaRef.CodeSynthesisContexts.empty() ||
-               SemaRef.CodeSynthesisContexts.back().Kind ==
-                   Sema::CodeSynthesisContext::BuildingDeductionGuides);
-        // Literally rewrite the template argument pack, instead of unpacking
-        // it.
-        for (auto &pack : Arg.getPackAsArray()) {
-          TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
-              pack, QualType(), SourceLocation{});
-          TemplateArgumentLoc Output;
-          if (TransformTemplateArgument(Input, Output, Uneval))
-            return true; // fails
-          TArgs.push_back(Output.getArgument());
-        }
-        Output = SemaRef.getTrivialTemplateArgumentLoc(
-            TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)),
-            QualType(), SourceLocation{});
-        return false;
-      default:
-        break;
+    return Type;
+  }
+  // Override the default version to handle a rewrite-template-arg-pack case
+  // for building a deduction guide.
+  bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
+                                 TemplateArgumentLoc &Output,
+                                 bool Uneval = false) {
+    const TemplateArgument &Arg = Input.getArgument();
+    std::vector<TemplateArgument> TArgs;
+    switch (Arg.getKind()) {
+    case TemplateArgument::Pack:
+      assert(SemaRef.CodeSynthesisContexts.empty() ||
+             SemaRef.CodeSynthesisContexts.back().Kind ==
+                 Sema::CodeSynthesisContext::BuildingDeductionGuides);
+      // Literally rewrite the template argument pack, instead of unpacking
+      // it.
+      for (auto &pack : Arg.getPackAsArray()) {
+        TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
+            pack, QualType(), SourceLocation{});
+        TemplateArgumentLoc Output;
+        if (TransformTemplateArgument(Input, Output, Uneval))
+          return true; // fails
+        TArgs.push_back(Output.getArgument());
       }
-      return inherited::TransformTemplateArgument(Input, Output, Uneval);
+      Output = SemaRef.getTrivialTemplateArgumentLoc(
+          TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)),
+          QualType(), SourceLocation{});
+      return false;
+    default:
+      break;
     }
+    return inherited::TransformTemplateArgument(Input, Output, Uneval);
+  }
+
+  // This has to be here to allow its overload.
+  ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
+                                  UnsignedOrNone NumExpansions) {
+    return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, NumExpansions);
+  }
 
-    // This has to be here to allow its overload.
-    ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
-                                    UnsignedOrNone NumExpansions) {
+  TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
+                                           SourceLocation EllipsisLoc,
+                                           UnsignedOrNone NumExpansions) {
+    // We don't rewrite a PackExpansion type when we want to normalize a
+    // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
+    if (!PreserveArgumentPacks || BuildPackExpansionTypes)
       return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
                                              NumExpansions);
-    }
+    return Pattern;
+  }
 
-    TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
-                                             SourceLocation EllipsisLoc,
-                                             UnsignedOrNone NumExpansions) {
-      // We don't rewrite a PackExpansion type when we want to normalize a
-      // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
-      if (!PreserveArgumentPacks || BuildPackExpansionTypes)
-        return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
-                                               NumExpansions);
-      return Pattern;
-    }
+  using TreeTransform::TransformTemplateSpecializationType;
+  QualType
+  TransformTemplateSpecializationType(TypeLocBuilder &TLB,
+                                      TemplateSpecializationTypeLoc TL) {
+    auto *T = TL.getTypePtr();
+    if (!getSema().ArgPackSubstIndex || !T->isSugared() ||
+        !isPackProducingBuiltinTemplateName(T->getTemplateName()))
+      return TreeTransform::TransformTemplateSpecializationType(TLB, TL);
+    // Look through sugar to get to the SubstBuiltinTemplatePackType that we
+    // need to substitute into.
+
+    // `TransformType` code below will handle picking the element from a pack
+    // with the index `ArgPackSubstIndex`.
+    // FIXME: add ability to represent sugarred type for N-th element of a
+    // builtin pack and produce the sugar here.
+    QualType R = TransformType(T->desugar());
+    TLB.pushTrivial(getSema().getASTContext(), R, TL.getBeginLoc());
+    return R;
+  }
 
-    using TreeTransform::TransformTemplateSpecializationType;
-    QualType
-    TransformTemplateSpecializationType(TypeLocBuilder &TLB,
-                                        TemplateSpecializationTypeLoc TL) {
-      auto *T = TL.getTypePtr();
-      if (!getSema().ArgPackSubstIndex || !T->isSugared() ||
-          !isPackProducingBuiltinTemplateName(T->getTemplateName()))
-        return TreeTransform::TransformTemplateSpecializationType(TLB, TL);
-      // Look through sugar to get to the SubstBuiltinTemplatePackType that we
-      // need to substitute into.
-
-      // `TransformType` code below will handle picking the element from a pack
-      // with the index `ArgPackSubstIndex`.
-      // FIXME: add ability to represent sugarred type for N-th element of a
-      // builtin pack and produce the sugar here.
-      QualType R = TransformType(T->desugar());
-      TLB.pushTrivial(getSema().getASTContext(), R, TL.getBeginLoc());
-      return R;
-    }
+  UnsignedOrNone ComputeSizeOfPackExprWithoutSubstitution(
+      ArrayRef<TemplateArgument> PackArgs) {
+    // Don't do this when rewriting template parameters for CTAD:
+    //   1) The heuristic needs the unpacked Subst* nodes to figure out the
+    //   expanded size, but this never applies since Subst* nodes are not
+    //   created in rewrite scenarios.
+    //
+    //   2) The heuristic substitutes into the pattern with pack expansion
+    //   suppressed, which does not meet the requirements for argument
+    //   rewriting when template arguments include a non-pack matching against
+    //   a pack, particularly when rewriting an alias CTAD.
+    if (TemplateArgs.isRewrite())
+      return std::nullopt;
 
-    UnsignedOrNone ComputeSizeOfPackExprWithoutSubstitution(
-        ArrayRef<TemplateArgument> PackArgs) {
-      // Don't do this when rewriting template parameters for CTAD:
-      //   1) The heuristic needs the unpacked Subst* nodes to figure out the
-      //   expanded size, but this never applies since Subst* nodes are not
-      //   created in rewrite scenarios.
-      //
-      //   2) The heuristic substitutes into the pattern with pack expansion
-      //   suppressed, which does not meet the requirements for argument
-      //   rewriting when template arguments include a non-pack matching against
-      //   a pack, particularly when rewriting an alias CTAD.
-      if (TemplateArgs.isRewrite())
-        return std::nullopt;
-
-      return inherited::ComputeSizeOfPackExprWithoutSubstitution(PackArgs);
-    }
+    return inherited::ComputeSizeOfPackExprWithoutSubstitution(PackArgs);
+  }
 
   template <typename Fn>
-    QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
-                                        FunctionProtoTypeLoc TL,
-                                        CXXRecordDecl *ThisContext,
-                                        Qualifiers ThisTypeQuals,
-                                        Fn TransformExceptionSpec);
-
-    ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
-                                            int indexAdjustment,
-                                            UnsignedOrNone NumExpansions,
-                                            bool ExpectParameterPack);
-
-    using inherited::TransformTemplateTypeParmType;
-    /// Transforms a template type parameter type by performing
-    /// substitution of the corresponding template type argument.
-    QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
-                                           TemplateTypeParmTypeLoc TL,
-                                           bool SuppressObjCLifetime);
+  QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                      FunctionProtoTypeLoc TL,
+                                      CXXRecordDecl *ThisContext,
+                                      Qualifiers ThisTypeQuals,
+                                      Fn TransformExceptionSpec);
+
+  ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
+                                          int indexAdjustment,
+                                          UnsignedOrNone NumExpansions,
+                                          bool ExpectParameterPack);
+
+  using inherited::TransformTemplateTypeParmType;
+  /// Transforms a template type parameter type by performing
+  /// substitution of the corresponding template type argument.
+  QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+                                         TemplateTypeParmTypeLoc TL,
+                                         bool SuppressObjCLifetime);
 
   QualType BuildSubstTemplateTypeParmType(TypeLocBuilder &TLB,
                                           bool SuppressObjCLifetime, bool Final,
@@ -1817,172 +1815,172 @@ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
                                           TemplateArgument Arg,
                                           SourceLocation NameLoc);
 
-    /// Transforms an already-substituted template type parameter pack
-    /// into either itself (if we aren't substituting into its pack expansion)
-    /// or the appropriate substituted argument.
-    using inherited::TransformSubstTemplateTypeParmPackType;
-    QualType
-    TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
-                                           SubstTemplateTypeParmPackTypeLoc TL,
-                                           bool SuppressObjCLifetime);
-    QualType
-    TransformSubstBuiltinTemplatePackType(TypeLocBuilder &TLB,
-                                          SubstBuiltinTemplatePackTypeLoc TL);
-
-    CXXRecordDecl::LambdaDependencyKind
-    ComputeLambdaDependency(LambdaScopeInfo *LSI) {
-      if (auto TypeAlias =
-              TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
-                  getSema());
-          TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
-                           LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
-        unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
-        if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
+  /// Transforms an already-substituted template type parameter pack
+  /// into either itself (if we aren't substituting into its pack expansion)
+  /// or the appropriate substituted argument.
+  using inherited::TransformSubstTemplateTypeParmPackType;
+  QualType
+  TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
+                                         SubstTemplateTypeParmPackTypeLoc TL,
+                                         bool SuppressObjCLifetime);
+  QualType
+  TransformSubstBuiltinTemplatePackType(TypeLocBuilder &TLB,
+                                        SubstBuiltinTemplatePackTypeLoc TL);
+
+  CXXRecordDecl::LambdaDependencyKind
+  ComputeLambdaDependency(LambdaScopeInfo *LSI) {
+    if (auto TypeAlias =
+            TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
+                getSema());
+        TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+                         LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
+      unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
+      if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
+        return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+      for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
+        if (TA.isDependent())
           return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
-        for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
-          if (TA.isDependent())
-            return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
-      }
-      return inherited::ComputeLambdaDependency(LSI);
     }
+    return inherited::ComputeLambdaDependency(LSI);
+  }
 
-    ExprResult TransformLambdaExpr(LambdaExpr *E) {
-      // Do not rebuild lambdas to avoid creating a new type.
-      // Lambdas have already been processed inside their eval contexts.
-      if (SemaRef.RebuildingImmediateInvocation)
-        return E;
-      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
-                                    /*InstantiatingLambdaOrBlock=*/true);
-      Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+  ExprResult TransformLambdaExpr(LambdaExpr *E) {
+    // Do not rebuild lambdas to avoid creating a new type.
+    // Lambdas have already been processed inside their eval contexts.
+    if (SemaRef.RebuildingImmediateInvocation)
+      return E;
+    LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
+                                  /*InstantiatingLambdaOrBlock=*/true);
+    Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
 
-      return inherited::TransformLambdaExpr(E);
-    }
+    return inherited::TransformLambdaExpr(E);
+  }
 
-    ExprResult TransformBlockExpr(BlockExpr *E) {
-      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
-                                    /*InstantiatingLambdaOrBlock=*/true);
-      return inherited::TransformBlockExpr(E);
-    }
+  ExprResult TransformBlockExpr(BlockExpr *E) {
+    LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
+                                  /*InstantiatingLambdaOrBlock=*/true);
+    return inherited::TransformBlockExpr(E);
+  }
 
-    ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
-                                 LambdaScopeInfo *LSI) {
-      CXXMethodDecl *MD = LSI->CallOperator;
-      for (ParmVarDecl *PVD : MD->parameters()) {
-        assert(PVD && "null in a parameter list");
-        if (!PVD->hasDefaultArg())
-          continue;
-        Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
-        // FIXME: Obtain the source location for the '=' token.
-        SourceLocation EqualLoc = UninstExpr->getBeginLoc();
-        if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
-          // If substitution fails, the default argument is set to a
-          // RecoveryExpr that wraps the uninstantiated default argument so
-          // that downstream diagnostics are omitted.
-          ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
-              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
-              UninstExpr->getType());
-          if (ErrorResult.isUsable())
-            PVD->setDefaultArg(ErrorResult.get());
-        }
+  ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
+                               LambdaScopeInfo *LSI) {
+    CXXMethodDecl *MD = LSI->CallOperator;
+    for (ParmVarDecl *PVD : MD->parameters()) {
+      assert(PVD && "null in a parameter list");
+      if (!PVD->hasDefaultArg())
+        continue;
+      Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+      // FIXME: Obtain the source location for the '=' token.
+      SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+      if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+        // If substitution fails, the default argument is set to a
+        // RecoveryExpr that wraps the uninstantiated default argument so
+        // that downstream diagnostics are omitted.
+        ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+            UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
+            UninstExpr->getType());
+        if (ErrorResult.isUsable())
+          PVD->setDefaultArg(ErrorResult.get());
       }
-      return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
     }
+    return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
+  }
 
-    StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) {
-      // Currently, we instantiate the body when instantiating the lambda
-      // expression. However, `EvaluateConstraints` is disabled during the
-      // instantiation of the lambda expression, causing the instantiation
-      // failure of the return type requirement in the body. If p0588r1 is fully
-      // implemented, the body will be lazily instantiated, and this problem
-      // will not occur. Here, `EvaluateConstraints` is temporarily set to
-      // `true` to temporarily fix this issue.
-      // FIXME: This temporary fix can be removed after fully implementing
-      // p0588r1.
-      llvm::SaveAndRestore _(EvaluateConstraints, true);
-      return inherited::TransformLambdaBody(E, Body);
-    }
+  StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) {
+    // Currently, we instantiate the body when instantiating the lambda
+    // expression. However, `EvaluateConstraints` is disabled during the
+    // instantiation of the lambda expression, causing the instantiation
+    // failure of the return type requirement in the body. If p0588r1 is fully
+    // implemented, the body will be lazily instantiated, and this problem
+    // will not occur. Here, `EvaluateConstraints` is temporarily set to
+    // `true` to temporarily fix this issue.
+    // FIXME: This temporary fix can be removed after fully implementing
+    // p0588r1.
+    llvm::SaveAndRestore _(EvaluateConstraints, true);
+    return inherited::TransformLambdaBody(E, Body);
+  }
 
-    ExprResult TransformRequiresExpr(RequiresExpr *E) {
-      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-      ExprResult TransReq = inherited::TransformRequiresExpr(E);
-      if (TransReq.isInvalid())
-        return TransReq;
-      assert(TransReq.get() != E &&
-             "Do not change value of isSatisfied for the existing expression. "
-             "Create a new expression instead.");
-      if (E->getBody()->isDependentContext()) {
-        Sema::SFINAETrap Trap(SemaRef);
-        // We recreate the RequiresExpr body, but not by instantiating it.
-        // Produce pending diagnostics for dependent access check.
-        SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
-        // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis.
-        if (Trap.hasErrorOccurred())
-          TransReq.getAs<RequiresExpr>()->setSatisfied(false);
-      }
+  ExprResult TransformRequiresExpr(RequiresExpr *E) {
+    LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+    ExprResult TransReq = inherited::TransformRequiresExpr(E);
+    if (TransReq.isInvalid())
       return TransReq;
+    assert(TransReq.get() != E &&
+           "Do not change value of isSatisfied for the existing expression. "
+           "Create a new expression instead.");
+    if (E->getBody()->isDependentContext()) {
+      Sema::SFINAETrap Trap(SemaRef);
+      // We recreate the RequiresExpr body, but not by instantiating it.
+      // Produce pending diagnostics for dependent access check.
+      SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+      // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis.
+      if (Trap.hasErrorOccurred())
+        TransReq.getAs<RequiresExpr>()->setSatisfied(false);
     }
+    return TransReq;
+  }
 
-    bool TransformRequiresExprRequirements(
-        ArrayRef<concepts::Requirement *> Reqs,
-        SmallVectorImpl<concepts::Requirement *> &Transformed) {
-      bool SatisfactionDetermined = false;
-      for (concepts::Requirement *Req : Reqs) {
-        concepts::Requirement *TransReq = nullptr;
-        if (!SatisfactionDetermined) {
-          if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
-            TransReq = TransformTypeRequirement(TypeReq);
-          else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
-            TransReq = TransformExprRequirement(ExprReq);
-          else
-            TransReq = TransformNestedRequirement(
-                cast<concepts::NestedRequirement>(Req));
-          if (!TransReq)
-            return true;
-          if (!TransReq->isDependent() && !TransReq->isSatisfied())
-            // [expr.prim.req]p6
-            //   [...]  The substitution and semantic constraint checking
-            //   proceeds in lexical order and stops when a condition that
-            //   determines the result of the requires-expression is
-            //   encountered. [..]
-            SatisfactionDetermined = true;
-        } else
-          TransReq = Req;
-        Transformed.push_back(TransReq);
-      }
-      return false;
+  bool TransformRequiresExprRequirements(
+      ArrayRef<concepts::Requirement *> Reqs,
+      SmallVectorImpl<concepts::Requirement *> &Transformed) {
+    bool SatisfactionDetermined = false;
+    for (concepts::Requirement *Req : Reqs) {
+      concepts::Requirement *TransReq = nullptr;
+      if (!SatisfactionDetermined) {
+        if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
+          TransReq = TransformTypeRequirement(TypeReq);
+        else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
+          TransReq = TransformExprRequirement(ExprReq);
+        else
+          TransReq = TransformNestedRequirement(
+              cast<concepts::NestedRequirement>(Req));
+        if (!TransReq)
+          return true;
+        if (!TransReq->isDependent() && !TransReq->isSatisfied())
+          // [expr.prim.req]p6
+          //   [...]  The substitution and semantic constraint checking
+          //   proceeds in lexical order and stops when a condition that
+          //   determines the result of the requires-expression is
+          //   encountered. [..]
+          SatisfactionDetermined = true;
+      } else
+        TransReq = Req;
+      Transformed.push_back(TransReq);
     }
+    return false;
+  }
 
-    TemplateParameterList *
-    TransformTemplateParameterList(TemplateParameterList *OrigTPL) {
-      if (!OrigTPL || !OrigTPL->size())
-        return OrigTPL;
-
-      DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
-      TemplateDeclInstantiator DeclInstantiator(getSema(),
-                                                /* DeclContext *Owner */ Owner,
-                                                TemplateArgs);
-      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
-      return DeclInstantiator.SubstTemplateParams(OrigTPL);
-    }
+  TemplateParameterList *
+  TransformTemplateParameterList(TemplateParameterList *OrigTPL) {
+    if (!OrigTPL || !OrigTPL->size())
+      return OrigTPL;
+
+    DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
+    TemplateDeclInstantiator DeclInstantiator(getSema(),
+                                              /* DeclContext *Owner */ Owner,
+                                              TemplateArgs);
+    DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
+    return DeclInstantiator.SubstTemplateParams(OrigTPL);
+  }
 
-    concepts::TypeRequirement *
-    TransformTypeRequirement(concepts::TypeRequirement *Req);
-    concepts::ExprRequirement *
-    TransformExprRequirement(concepts::ExprRequirement *Req);
-    concepts::NestedRequirement *
-    TransformNestedRequirement(concepts::NestedRequirement *Req);
-    ExprResult TransformRequiresTypeParams(
-        SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
-        RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
-        SmallVectorImpl<QualType> &PTypes,
-        SmallVectorImpl<ParmVarDecl *> &TransParams,
-        Sema::ExtParameterInfoBuilder &PInfos);
+  concepts::TypeRequirement *
+  TransformTypeRequirement(concepts::TypeRequirement *Req);
+  concepts::ExprRequirement *
+  TransformExprRequirement(concepts::ExprRequirement *Req);
+  concepts::NestedRequirement *
+  TransformNestedRequirement(concepts::NestedRequirement *Req);
+  ExprResult TransformRequiresTypeParams(
+      SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+      RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+      SmallVectorImpl<QualType> &PTypes,
+      SmallVectorImpl<ParmVarDecl *> &TransParams,
+      Sema::ExtParameterInfoBuilder &PInfos);
 
 private:
-    ExprResult
-    transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
-                                    SourceLocation loc, TemplateArgument arg,
-                                    UnsignedOrNone PackIndex, bool Final);
+  ExprResult
+  transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
+                                  SourceLocation loc, TemplateArgument arg,
+                                  UnsignedOrNone PackIndex, bool Final);
 };
 } // namespace
 
@@ -3026,7 +3024,7 @@ TemplateInstantiator::TransformNestedRequirement(
     Sema::InstantiatingTemplate ConstrInst(
         SemaRef, Constraint->getBeginLoc(), Req,
         Sema::InstantiatingTemplate::ConstraintsCheck(),
-                                           Constraint->getSourceRange());
+        Constraint->getSourceRange());
 
     if (ConstrInst.isInvalid())
       return nullptr;
@@ -3040,7 +3038,7 @@ TemplateInstantiator::TransformNestedRequirement(
 
     assert(!Success || !Trap.hasErrorOccurred() &&
                            "Substitution failures must be handled "
-                                       "by CheckConstraintSatisfaction.");
+                           "by CheckConstraintSatisfaction.");
   }
 
   if (!Success || Satisfaction.HasSubstitutionFailure())

>From 3e37bd433fb6603f8ecaccc7cd786fd81cce92ba Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 14:03:34 +0200
Subject: [PATCH 07/29] fix libc++ test

---
 .../test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
index 93415f916190e..70341eee79a96 100644
--- a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
@@ -143,7 +143,7 @@ void check_forward_iterator_requirements() {
   // expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}}
   _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(postincrement_not_ref, ""); // expected-error {{static assertion failed}}
 #ifndef _AIX
-  // expected-note-re@*:* {{because 'convertible_to<{{(valid_iterator<postincrement_not_ref>::)?}}Proxy, const postincrement_not_ref &>' evaluated to false}}
+  // expected-note-re@*:* {{'convertible_to<{{(valid_iterator<postincrement_not_ref>::)?}}Proxy, const postincrement_not_ref &>'}}
 #endif
 }
 
@@ -173,7 +173,7 @@ void check_bidirectional_iterator_requirements() {
   _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(missing_postdecrement, ""); // expected-error {{static assertion failed}}
   // expected-note@*:* {{cannot decrement value of type 'missing_postdecrement'}}
   _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(not_returning_iter_reference, ""); // expected-error {{static assertion failed}}
-  // expected-note-re@*:* {{because 'same_as<int, __iter_reference<not_returning_iter_reference>{{ ?}}>' evaluated to false}}
+  // expected-note-re@*:* {{'same_as<int, __iter_reference<not_returning_iter_reference>{{ ?}}>'}}
   // clang-format on
 }
 

>From e412201113d8bbb454e3a688db0371bb0b95f9f3 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 14:39:51 +0200
Subject: [PATCH 08/29] cleanups

---
 clang/include/clang/Sema/SemaConcept.h        | 23 +++++++++++--------
 clang/include/clang/Sema/Template.h           | 20 ++++------------
 clang/lib/AST/ASTContext.cpp                  |  1 -
 clang/lib/Sema/SemaConcept.cpp                | 20 +---------------
 clang/lib/Sema/SemaTemplate.cpp               | 13 -----------
 clang/lib/Sema/TreeTransform.h                |  2 --
 .../temp.constr/temp.constr.normal/p1.cpp     |  2 +-
 7 files changed, 19 insertions(+), 62 deletions(-)

diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index df0007d1eedb3..581cc9ca84317 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -63,11 +63,15 @@ struct NormalizedConstraint {
   using ExprOrConcept =
       llvm::PointerUnion<const Expr *, const ConceptReference *>;
 
-  struct AtomicBits {
+  struct AtomicConstraintBits {
     LLVM_PREFERRED_TYPE(ConstraintKind)
+    // Kind is the first member of all union members,
+    // as we rely on their initial common sequence.
     unsigned Kind : 5;
     unsigned Placeholder : 1;
     unsigned PackSubstitutionIndex : 26;
+    // Indexes and Args are part of the common initial sequences
+    // of constraints that do have a mapping.
     OccurenceList Indexes;
     TemplateArgumentLoc *Args;
     TemplateParameterList *ParamList;
@@ -75,7 +79,7 @@ struct NormalizedConstraint {
     const NamedDecl *ConstraintDecl;
   };
 
-  struct FoldExpandedBits {
+  struct FoldExpandedConstraintBits {
     LLVM_PREFERRED_TYPE(ConstraintKind)
     unsigned Kind : 5;
     LLVM_PREFERRED_TYPE(FoldOperatorKind)
@@ -89,14 +93,14 @@ struct NormalizedConstraint {
     NormalizedConstraint *Constraint;
   };
 
-  struct ConceptIdBits : AtomicBits {
+  struct ConceptIdBits : AtomicConstraintBits {
     NormalizedConstraint *Sub;
 
     // Only used for parameter mapping.
     const ConceptSpecializationExpr *CSE;
   };
 
-  struct CompoundBits {
+  struct CompoundConstraintBits {
     LLVM_PREFERRED_TYPE(ConstraintKind)
     unsigned Kind : 5;
     LLVM_PREFERRED_TYPE(CompoundConstraintKind)
@@ -106,10 +110,10 @@ struct NormalizedConstraint {
   };
 
   union {
-    AtomicBits Atomic;
-    FoldExpandedBits FoldExpanded;
+    AtomicConstraintBits Atomic;
+    FoldExpandedConstraintBits FoldExpanded;
     ConceptIdBits ConceptId;
-    CompoundBits Compound;
+    CompoundConstraintBits Compound;
   };
 
   ~NormalizedConstraint() {
@@ -161,6 +165,8 @@ struct NormalizedConstraint {
                  llvm::to_underlying(CCK), LHS, RHS} {}
 
   bool hasParameterMapping() const {
+    // compound constraints do not have a mapping
+    // and Args is not part of their common initial sequence.
     return getKind() != ConstraintKind::Compound && Atomic.Args != nullptr;
   }
 
@@ -388,9 +394,6 @@ class ConceptIdConstraint : public NormalizedConstraintWithParamMapping {
 };
 
 struct CachedConceptIdConstraint {
-#ifndef NDEBUG
-  const Expr *E;
-#endif
   ExprResult SubstExpr;
   ConstraintSatisfaction Satisfaction;
 };
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 5176e4ad5a362..60c7d275f1aaf 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -240,28 +240,16 @@ enum class TemplateSubstitutionKind : char {
              "Replacing in an empty list?");
 
       if (!TemplateArgumentLists.empty()) {
-        // assert((!TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer()
-        // ||
-        //         TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer()
-        //         ==
-        //             AssociatedDecl) &&
-        //         "Trying to change incorrect declaration?");
         TemplateArgumentLists[0].Args = Args;
-      } else {
-        --NumRetainedOuterLevels;
-        TemplateArgumentLists.push_back(
-            {{AssociatedDecl, /*Final=*/Final}, Args});
+        return;
       }
+      --NumRetainedOuterLevels;
+      TemplateArgumentLists.push_back(
+          {{AssociatedDecl, /*Final=*/Final}, Args});
     }
 
     void replaceOutermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
       assert((!TemplateArgumentLists.empty()) && "Replacing in an empty list?");
-      // assert((!TemplateArgumentLists.back().AssociatedDeclAndFinal.getPointer()
-      // ||
-      //         TemplateArgumentLists.back().AssociatedDeclAndFinal.getPointer()
-      //         ==
-      //             AssociatedDecl) &&
-      //        "Trying to change incorrect declaration?");
       TemplateArgumentLists.back().AssociatedDeclAndFinal.setPointer(
           AssociatedDecl);
       TemplateArgumentLists.back().Args = Args;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2a5e151e33a85..e49ff9080571e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5793,7 +5793,6 @@ QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
   llvm::FoldingSetNodeID ID;
   SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
                                      PackIndex, Final);
-
   void *InsertPos = nullptr;
   SubstTemplateTypeParmType *SubstParm =
       SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f45da77621d55..06673a5bcd17d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -17,7 +17,6 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
-#include "clang/AST/DependenceFlags.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -32,20 +31,10 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Casting.h"
 #include "llvm/Support/SaveAndRestore.h"
-#include "llvm/Support/raw_ostream.h"
-#include <chrono>
-#include <cstddef>
-#include <iterator>
-#include <optional>
 
 using namespace clang;
 using namespace sema;
@@ -691,9 +680,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
       Constraint.getPackSubstitutionIndex()
           ? Constraint.getPackSubstitutionIndex()
           : PackSubstitutionIndex;
-  // Constraint.getConstraintExpr()->Profile(ID, S.Context, /*Canonical=*/true,
-  //                                         /*ProfileLambdaExpr=*/true);
-  auto *Previous = Constraint.getConstraintExpr();
+
   ID.AddPointer(Constraint.getConstraintExpr());
   ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
   ID.AddBoolean(Constraint.hasParameterMapping());
@@ -713,15 +700,12 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
 
   ExprResult E = CalculateSlow(Constraint, MLTAL);
 
-  assert(Constraint.getConstraintExpr() == Previous);
-
   CachedConceptIdConstraint Cache;
   Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
   Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
   std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
             std::back_inserter(Cache.Satisfaction.Details));
   Cache.SubstExpr = E;
-  Cache.E = Constraint.getConstraintExpr();
   S.ConceptIdSatisfactionCache.insert({ID, std::move(Cache)});
 
   return E;
@@ -2153,8 +2137,6 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
       if (!SubNF)
         return nullptr;
     }
-    // if (substituteParameterMappings(S, *SubNF, CSE))
-    //   return nullptr;
 
     return ConceptIdConstraint::Create(S.getASTContext(),
                                        CSE->getConceptReference(), SubNF, D,
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index e780435548bed..e2725359c659d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6032,19 +6032,6 @@ bool Sema::CheckTemplateArgumentList(
         return true;
       }
 
-      // For constraint parameter mapping, we have already built a pack in
-      // TransformTemplateArguments
-      // if (inParameterMappingSubstitution()) {
-      //   llvm::copy(SugaredArgumentPack,
-      //   std::back_inserter(CTAI.SugaredConverted));
-      //   SugaredArgumentPack.clear();
-      //   llvm::copy(CanonicalArgumentPack,
-      //   std::back_inserter(CTAI.CanonicalConverted));
-      //   CanonicalArgumentPack.clear();
-      //   ++Param;
-      //   continue;
-      // }
-
       CTAI.SugaredConverted.push_back(
           TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
       SugaredArgumentPack.clear();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 129f362fbd263..ad84f73b84a97 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -356,8 +356,6 @@ class TreeTransform {
   /// being expanded.
   void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
 
-  bool ShouldPreserveTemplateArgumentsPacks() const { return false; }
-
   /// Transforms the given type into another type.
   ///
   /// By default, this routine transforms a type by creating a
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
index 35796106da278..34c5c5d338bfe 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
-// FIXME: RUN: %clang_cc1 -std=c++2c -x c++ -verify %s
+// RUN: %clang_cc1 -std=c++2c -x c++ -verify %s
 
 template<typename T> concept True = true;
 template<typename T> concept Foo = True<T*>; // #Foo

>From fc0e1164d68315c53880482c5bbc513e3d047bfc Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 14:49:26 +0200
Subject: [PATCH 09/29] add fixmes

---
 clang/lib/Sema/SemaConcept.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 06673a5bcd17d..52930d9eb8fe2 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -754,6 +754,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
 
   llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
   // FIXME: Is PackSubstitutionIndex correct?
+  // TODO: We might want to cache the substitution of fold expanded constraints.
   llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex);
   std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
       SubstitutionInTemplateArguments(
@@ -832,6 +833,8 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   if (Satisfaction.IsSatisfied)
     return E;
 
+  // TODO: We might want to cache the substitution of concept id constraints
+  // as it can be slow in the SFINAE case.
   llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
   std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
       SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);

>From e8d251b46cea74b4c0a76f2311ac6e32e886a8d2 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 15:41:01 +0200
Subject: [PATCH 10/29] fix windows build

---
 clang/include/clang/Sema/SemaConcept.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index 581cc9ca84317..f5e067b57fbc5 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -40,15 +40,15 @@ class MultiLevelTemplateArgumentList;
 
 struct NormalizedConstraint {
 
-  enum class ConstraintKind {
+  enum class ConstraintKind : unsigned char{
     Atomic = 0,
     ConceptId,
     FoldExpanded,
     Compound,
   };
 
-  enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
-  enum class FoldOperatorKind : unsigned int { And, Or };
+  enum CompoundConstraintKind : unsigned char { CCK_Conjunction, CCK_Disjunction };
+  enum class FoldOperatorKind : unsigned char { And, Or };
 
   using OccurenceList = llvm::SmallBitVector;
 

>From da2022ae06fb6bbf0e49dcc7faa038d1f203ce9f Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 18:33:23 +0200
Subject: [PATCH 11/29] more cleanups

---
 clang/include/clang/AST/TemplateBase.h     |   1 +
 clang/include/clang/Sema/Sema.h            |  15 +-
 clang/include/clang/Sema/SemaConcept.h     |  14 +-
 clang/lib/Sema/SemaConcept.cpp             | 162 +++++++++++++--------
 clang/lib/Sema/SemaTemplateInstantiate.cpp |   7 +-
 clang/lib/Sema/TreeTransform.h             |   4 -
 clang/lib/Serialization/ASTWriterStmt.cpp  |   1 -
 7 files changed, 128 insertions(+), 76 deletions(-)

diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index 0359f4beb6309..de248ac3cf703 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -475,6 +475,7 @@ class TemplateArgument {
   /// Used to insert TemplateArguments into FoldingSets.
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
 };
+
 /// Location information for a TemplateArgument.
 struct TemplateArgumentLocInfo {
   struct TemplateTemplateArgLocInfo {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4c4b07be1b31e..c83000900444b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13092,6 +13092,7 @@ class Sema final : public SemaBase {
     /// Whether we're substituting into constraints.
     bool InConstraintSubstitution;
 
+    /// Whether we're substituting into the parameter mapping of a constraint.
     bool InParameterMappingSubstitution;
 
     /// The point of instantiation or synthesis within the source code.
@@ -14849,10 +14850,18 @@ class Sema final : public SemaBase {
       const NamedDecl *D1, ArrayRef<AssociatedConstraint> AC1,
       const NamedDecl *D2, ArrayRef<AssociatedConstraint> AC2);
 
-  llvm::DenseMap<llvm::FoldingSetNodeID, CachedConceptIdConstraint>
-      ConceptIdSatisfactionCache;
+  /// Cache the satisfaction of an atomic constraint.
+  /// The key is based on the unsubstituted expression and the parameter
+  /// mapping. This lets us not substituting the mapping more than once,
+  /// which is (very!) expensive.
+  /// FIXME: this should be private.
+  llvm::DenseMap<llvm::FoldingSetNodeID,
+                 UnsubstitutedConstraintSatisfactionCacheResult>
+      UnsubstitutedConstraintSatisfactionCache;
 
 private:
+  friend class CalculateConstraintSatisfaction;
+
   /// Caches pairs of template-like decls whose associated constraints were
   /// checked for subsumption and whether or not the first's constraints did in
   /// fact subsume the second's.
@@ -14865,6 +14874,8 @@ class Sema final : public SemaBase {
   llvm::DenseMap<ConstrainedDeclOrNestedRequirement, NormalizedConstraint *>
       NormalizationCache;
 
+  /// Cache whether the associated constraint of a declaration
+  /// is satisfied.
   llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
       SatisfactionCache;
 
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index f5e067b57fbc5..b47814aefa2c0 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -18,15 +18,11 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/UnsignedOrNone.h"
 #include "clang/Sema/Ownership.h"
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Compiler.h"
 #include <optional>
 #include <utility>
 
@@ -37,17 +33,19 @@ class MultiLevelTemplateArgumentList;
 /// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
 /// either an atomic constraint, a conjunction of normalized constraints or a
 /// disjunction of normalized constraints.
-
 struct NormalizedConstraint {
 
-  enum class ConstraintKind : unsigned char{
+  enum class ConstraintKind : unsigned char {
     Atomic = 0,
     ConceptId,
     FoldExpanded,
     Compound,
   };
 
-  enum CompoundConstraintKind : unsigned char { CCK_Conjunction, CCK_Disjunction };
+  enum CompoundConstraintKind : unsigned char {
+    CCK_Conjunction,
+    CCK_Disjunction
+  };
   enum class FoldOperatorKind : unsigned char { And, Or };
 
   using OccurenceList = llvm::SmallBitVector;
@@ -393,7 +391,7 @@ class ConceptIdConstraint : public NormalizedConstraintWithParamMapping {
   NormalizedConstraint &getNormalizedConstraint() { return *ConceptId.Sub; }
 };
 
-struct CachedConceptIdConstraint {
+struct UnsubstitutedConstraintSatisfactionCacheResult {
   ExprResult SubstExpr;
   ConstraintSatisfaction Satisfaction;
 };
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 52930d9eb8fe2..403bd82e0215d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -10,19 +10,68 @@
 //
 //===----------------------------------------------------------------------===//
 
+/*
+ * A note on implementation:
+ *
+ * As per the C++ standard, constraints are normalized [temp.constr.normal]
+ * and the normal form is used both for subsumption, and constraint checking.
+ * Both depend on a parameter mapping that substitutes lazily. In particular,
+ * we should not substitute in unused arguments.
+ *
+ * Clang follows the order of operations prescribed by the standard.
+ *
+ * Normalization happens prior to satisfaction and subsumption
+ * and is handled by `NormalizedConstraint`.
+ *
+ * Clang preserves in the normalized form intermediate concept-ids
+ * (ConceptIdConstraint) This is used for diagnostics only and no substitution
+ * happens in a ConceptIdConstraint if its expression is satisfied.
+ *
+ * The normal form of the associated constraints of a declaration is cached in
+ * Sema::NormalizationCache such that it is only computed once.
+ *
+ * a `NormalizedConstraint` is a recursive data structure, where each node
+ * contains a parameter maping, represented by the indexes of all parameter
+ * being used.
+ *
+ * Checking satisfaction is done by ConstraintSatisfactionChecker, recursively
+ * walking NormalizedConstraint. At each level, we substitute the outermost
+ * level of the template arguments referenced in the parameter mapping of a
+ * normalized expression (MultiLevelTemplateArgumentList).
+ *
+ * template <typename T>
+ * concept A = __is_same(T, int);
+ *
+ * template <typename U>
+ * concept B = A<U> && __is_same(U, int);
+ *
+ * The  normal form is `__is_same(T, int) /T->U, inner most level/
+ *                   && __is_same(U, int) {U->U} /T->U, outermost most level/
+ *                   `
+ *
+ * After substitution in the mapping, we substitute in the constraint expression
+ * using that copy of the MultiLevelTemplateArgumentList, and then evaluate it.
+ *
+ * Because this is excruciatingly slow, it is cached in
+ * `UnsubstitutedConstraintSatisfactionCache`.
+ *
+ * Any error during satisfaction is recorded in ConstraintSatisfaction.
+ * for nested requirements, ConstraintSatisfaction is stored (including
+ * diagnostics) in the AST, which is something we might want to improve.
+ *
+ * When an atomic constraint is not satified, we try to substitute into any
+ * enclosing concept-id using the same mechanism described above, for
+ * diagnostics purpose, and inject that in the ConstraintSatisfaction.
+ */
+
 #include "clang/Sema/SemaConcept.h"
 #include "TreeTransform.h"
 #include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTLambda.h"
-#include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/TemplateBase.h"
 #include "clang/Basic/OperatorPrecedence.h"
-#include "clang/Basic/UnsignedOrNone.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Overload.h"
@@ -372,20 +421,15 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
       TraverseTemplateArgument(Canonical);
     }
 
-    // llvm::SmallSet<llvm::FoldingSetNodeID, 10> ArgHash;
     for (auto &Used : UsedTemplateArgs) {
       llvm::FoldingSetNodeID R;
       Used.Profile(R, SemaRef.Context);
       ID.AddNodeID(R);
-      // ArgHash.insert(R);
     }
-
-    // for (const llvm::FoldingSetNodeID &V : ArgHash)
-    //   ID.AddNodeID(V);
   }
 };
 
-class CalculateConstraintSatisfaction {
+class ConstraintSatisfactionChecker {
   Sema &S;
   const NamedDecl *Template;
   SourceLocation TemplateNameLoc;
@@ -408,37 +452,37 @@ class CalculateConstraintSatisfaction {
       MultiLevelTemplateArgumentList MLTAL,
       llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost);
 
-  ExprResult CalculateSlow(const AtomicConstraint &Constraint,
-                           const MultiLevelTemplateArgumentList &MLTAL);
+  ExprResult EvaluateSlow(const AtomicConstraint &Constraint,
+                          const MultiLevelTemplateArgumentList &MLTAL);
 
-  ExprResult Calculate(const AtomicConstraint &Constraint,
-                       const MultiLevelTemplateArgumentList &MLTAL);
+  ExprResult Evaluate(const AtomicConstraint &Constraint,
+                      const MultiLevelTemplateArgumentList &MLTAL);
 
-  ExprResult Calculate(const FoldExpandedConstraint &Constraint,
-                       const MultiLevelTemplateArgumentList &MLTAL);
+  ExprResult Evaluate(const FoldExpandedConstraint &Constraint,
+                      const MultiLevelTemplateArgumentList &MLTAL);
 
-  ExprResult Calculate(const ConceptIdConstraint &Constraint,
-                       const MultiLevelTemplateArgumentList &MLTAL);
+  ExprResult Evaluate(const ConceptIdConstraint &Constraint,
+                      const MultiLevelTemplateArgumentList &MLTAL);
 
-  ExprResult Calculate(const CompoundConstraint &Constraint,
-                       const MultiLevelTemplateArgumentList &MLTAL);
+  ExprResult Evaluate(const CompoundConstraint &Constraint,
+                      const MultiLevelTemplateArgumentList &MLTAL);
 
 public:
-  CalculateConstraintSatisfaction(Sema &SemaRef, const NamedDecl *Template,
-                                  SourceLocation TemplateNameLoc,
-                                  UnsignedOrNone PackSubstitutionIndex,
-                                  ConstraintSatisfaction &Satisfaction)
+  ConstraintSatisfactionChecker(Sema &SemaRef, const NamedDecl *Template,
+                                SourceLocation TemplateNameLoc,
+                                UnsignedOrNone PackSubstitutionIndex,
+                                ConstraintSatisfaction &Satisfaction)
       : S(SemaRef), Template(Template), TemplateNameLoc(TemplateNameLoc),
         PackSubstitutionIndex(PackSubstitutionIndex),
         Satisfaction(Satisfaction) {}
 
-  ExprResult Calculate(const NormalizedConstraint &Constraint,
-                       const MultiLevelTemplateArgumentList &MLTAL);
+  ExprResult Evaluate(const NormalizedConstraint &Constraint,
+                      const MultiLevelTemplateArgumentList &MLTAL);
 };
 
 } // namespace
 
-ExprResult CalculateConstraintSatisfaction::EvaluateAtomicConstraint(
+ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
     const Expr *AtomicExpr, const MultiLevelTemplateArgumentList &MLTAL) {
   EnterExpressionEvaluationContext ConstantEvaluated(
       S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
@@ -482,7 +526,7 @@ ExprResult CalculateConstraintSatisfaction::EvaluateAtomicConstraint(
       PartialDiagnosticAt SubstDiag{SourceLocation(),
                                     PartialDiagnostic::NullDiagnostic()};
       Info.takeSFINAEDiagnostic(SubstDiag);
-      // FIXME: Concepts: This is an unfortunate consequence of there
+      // FIXME: This is an unfortunate consequence of there
       //  being no serialization code for PartialDiagnostics and the fact
       //  that serializing them would likely take a lot more storage than
       //  just storing them as strings. We would still like, in the
@@ -525,7 +569,7 @@ ExprResult CalculateConstraintSatisfaction::EvaluateAtomicConstraint(
 }
 
 std::optional<MultiLevelTemplateArgumentList>
-CalculateConstraintSatisfaction::SubstitutionInTemplateArguments(
+ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
     const NormalizedConstraintWithParamMapping &Constraint,
     MultiLevelTemplateArgumentList MLTAL,
     llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost) {
@@ -591,7 +635,7 @@ CalculateConstraintSatisfaction::SubstitutionInTemplateArguments(
   return std::move(MLTAL);
 }
 
-ExprResult CalculateConstraintSatisfaction::CalculateSlow(
+ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     const AtomicConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
 
@@ -670,7 +714,7 @@ ExprResult CalculateConstraintSatisfaction::CalculateSlow(
   return SubstitutedAtomicExpr;
 }
 
-ExprResult CalculateConstraintSatisfaction::Calculate(
+ExprResult ConstraintSatisfactionChecker::Evaluate(
     const AtomicConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
 
@@ -687,8 +731,8 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
       .VisitConstraint(Constraint);
 
-  if (auto Iter = S.ConceptIdSatisfactionCache.find(ID);
-      Iter != S.ConceptIdSatisfactionCache.end()) {
+  if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
+      Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
 
     auto &Cached = Iter->second.Satisfaction;
     Satisfaction.ContainsErrors = Cached.ContainsErrors;
@@ -698,21 +742,21 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
     return Iter->second.SubstExpr;
   }
 
-  ExprResult E = CalculateSlow(Constraint, MLTAL);
+  ExprResult E = EvaluateSlow(Constraint, MLTAL);
 
-  CachedConceptIdConstraint Cache;
+  UnsubstitutedConstraintSatisfactionCacheResult Cache;
   Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
   Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
   std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
             std::back_inserter(Cache.Satisfaction.Details));
   Cache.SubstExpr = E;
-  S.ConceptIdSatisfactionCache.insert({ID, std::move(Cache)});
+  S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
 
   return E;
 }
 
 UnsignedOrNone
-CalculateConstraintSatisfaction::EvaluateFoldExpandedConstraintSize(
+ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize(
     const FoldExpandedConstraint &FE,
     const MultiLevelTemplateArgumentList &MLTAL) {
 
@@ -745,7 +789,7 @@ CalculateConstraintSatisfaction::EvaluateFoldExpandedConstraintSize(
   return NumExpansions;
 }
 
-ExprResult CalculateConstraintSatisfaction::Calculate(
+ExprResult ConstraintSatisfactionChecker::Evaluate(
     const FoldExpandedConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
   bool Conjunction = Constraint.getFoldOperator() ==
@@ -781,9 +825,9 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
     Satisfaction.IsSatisfied = false;
     Satisfaction.ContainsErrors = false;
     ExprResult Expr =
-        CalculateConstraintSatisfaction(S, Template, TemplateNameLoc,
-                                        UnsignedOrNone(I), Satisfaction)
-            .Calculate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
+        ConstraintSatisfactionChecker(S, Template, TemplateNameLoc,
+                                      UnsignedOrNone(I), Satisfaction)
+            .Evaluate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
     if (Expr.isUsable()) {
       if (Out.isUnset())
         Out = Expr;
@@ -810,7 +854,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   return Out;
 }
 
-ExprResult CalculateConstraintSatisfaction::Calculate(
+ExprResult ConstraintSatisfactionChecker::Evaluate(
     const ConceptIdConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
 
@@ -822,7 +866,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
 
   unsigned Size = Satisfaction.Details.size();
 
-  ExprResult E = Calculate(Constraint.getNormalizedConstraint(), MLTAL);
+  ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
 
   if (!E.isUsable()) {
     Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
@@ -830,6 +874,9 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
     return E;
   }
 
+  // ConceptIdConstraint is only relevant for diagnostics,
+  // so if the normalized constraint is satisfied, we should not
+  // substiture into the constraint.
   if (Satisfaction.IsSatisfied)
     return E;
 
@@ -910,7 +957,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   return SubstitutedConceptId;
 }
 
-ExprResult CalculateConstraintSatisfaction::Calculate(
+ExprResult ConstraintSatisfactionChecker::Evaluate(
     const CompoundConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
 
@@ -919,7 +966,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   bool Conjunction =
       Constraint.getCompoundKind() == NormalizedConstraint::CCK_Conjunction;
 
-  ExprResult LHS = Calculate(Constraint.getLHS(), MLTAL);
+  ExprResult LHS = Evaluate(Constraint.getLHS(), MLTAL);
 
   if (Conjunction && (!Satisfaction.IsSatisfied || Satisfaction.ContainsErrors))
     return LHS;
@@ -931,7 +978,7 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
   Satisfaction.ContainsErrors = false;
   Satisfaction.IsSatisfied = false;
 
-  ExprResult RHS = Calculate(Constraint.getRHS(), MLTAL);
+  ExprResult RHS = Evaluate(Constraint.getRHS(), MLTAL);
 
   if (RHS.isUsable() && Satisfaction.IsSatisfied &&
       !Satisfaction.ContainsErrors)
@@ -952,24 +999,23 @@ ExprResult CalculateConstraintSatisfaction::Calculate(
                                 Constraint.getBeginLoc(), FPOptionsOverride{});
 }
 
-ExprResult CalculateConstraintSatisfaction::Calculate(
+ExprResult ConstraintSatisfactionChecker::Evaluate(
     const NormalizedConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
   switch (Constraint.getKind()) {
   case NormalizedConstraint::ConstraintKind::Atomic:
-    return Calculate(static_cast<const AtomicConstraint &>(Constraint), MLTAL);
+    return Evaluate(static_cast<const AtomicConstraint &>(Constraint), MLTAL);
 
   case NormalizedConstraint::ConstraintKind::FoldExpanded:
-    return Calculate(static_cast<const FoldExpandedConstraint &>(Constraint),
-                     MLTAL);
+    return Evaluate(static_cast<const FoldExpandedConstraint &>(Constraint),
+                    MLTAL);
 
   case NormalizedConstraint::ConstraintKind::ConceptId:
-    return Calculate(static_cast<const ConceptIdConstraint &>(Constraint),
-                     MLTAL);
+    return Evaluate(static_cast<const ConceptIdConstraint &>(Constraint),
+                    MLTAL);
 
   case NormalizedConstraint::ConstraintKind::Compound:
-    return Calculate(static_cast<const CompoundConstraint &>(Constraint),
-                     MLTAL);
+    return Evaluate(static_cast<const CompoundConstraint &>(Constraint), MLTAL);
   }
 }
 
@@ -1020,9 +1066,9 @@ static bool CheckConstraintSatisfaction(
                                     S.ArgPackSubstIndex);
 
   ExprResult Res =
-      CalculateConstraintSatisfaction(S, Template, TemplateIDRange.getBegin(),
-                                      S.ArgPackSubstIndex, Satisfaction)
-          .Calculate(*C, TemplateArgsLists);
+      ConstraintSatisfactionChecker(S, Template, TemplateIDRange.getBegin(),
+                                    S.ArgPackSubstIndex, Satisfaction)
+          .Evaluate(*C, TemplateArgsLists);
 
   if (Res.isInvalid())
     return true;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 12fe1f61405c0..2657d0f9d2eb9 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1405,7 +1405,8 @@ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
   // Whether an incomplete substituion should be treated as an error.
   bool BailOutOnIncomplete;
 
-  bool PreserveArgumentPacks = false;
+  // Whether to rebuild pack expansion types; We don't do that when
+  // rebuilding a fold expression appearing in a constraint expression.
   bool BuildPackExpansionTypes = true;
 
   // CWG2770: Function parameters should be instantiated when they are
@@ -1431,7 +1432,7 @@ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
                        const MultiLevelTemplateArgumentList &TemplateArgs,
                        bool BuildPackExpansionTypes)
       : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
-        BailOutOnIncomplete(false), PreserveArgumentPacks(true),
+        BailOutOnIncomplete(false),
         BuildPackExpansionTypes(BuildPackExpansionTypes) {}
 
   void setEvaluateConstraints(bool B) { EvaluateConstraints = B; }
@@ -1746,7 +1747,7 @@ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
                                            UnsignedOrNone NumExpansions) {
     // We don't rewrite a PackExpansion type when we want to normalize a
     // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
-    if (!PreserveArgumentPacks || BuildPackExpansionTypes)
+    if (BuildPackExpansionTypes)
       return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
                                              NumExpansions);
     return Pattern;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index ad84f73b84a97..e0ebfe36289a8 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -30,7 +30,6 @@
 #include "clang/AST/StmtOpenACC.h"
 #include "clang/AST/StmtOpenMP.h"
 #include "clang/AST/StmtSYCL.h"
-#include "clang/AST/TemplateBase.h"
 #include "clang/Basic/DiagnosticParse.h"
 #include "clang/Basic/OpenMPKinds.h"
 #include "clang/Sema/Designator.h"
@@ -48,11 +47,8 @@
 #include "clang/Sema/SemaSYCL.h"
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <algorithm>
-#include <iterator>
 #include <optional>
 
 using namespace llvm::omp;
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 9408580fd7a8a..76f328fe76904 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -16,7 +16,6 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Serialization/ASTReader.h"

>From eb3922e0b1bfbd4fecd94511d60e96461d4ed261 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 18:59:10 +0200
Subject: [PATCH 12/29] remove some whitespace changes

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 1080 ++++++++++----------
 1 file changed, 541 insertions(+), 539 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 2657d0f9d2eb9..54075d81b0c6b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1393,597 +1393,599 @@ getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) {
 //===----------------------------------------------------------------------===/
 namespace {
 
-class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
-  const MultiLevelTemplateArgumentList &TemplateArgs;
-  SourceLocation Loc;
-  DeclarationName Entity;
-  // Whether to evaluate the C++20 constraints or simply substitute into them.
-  bool EvaluateConstraints = true;
-  // Whether Substitution was Incomplete, that is, we tried to substitute in
-  // any user provided template arguments which were null.
-  bool IsIncomplete = false;
-  // Whether an incomplete substituion should be treated as an error.
-  bool BailOutOnIncomplete;
-
-  // Whether to rebuild pack expansion types; We don't do that when
-  // rebuilding a fold expression appearing in a constraint expression.
-  bool BuildPackExpansionTypes = true;
-
-  // CWG2770: Function parameters should be instantiated when they are
-  // needed by a satisfaction check of an atomic constraint or
-  // (recursively) by another function parameter.
-  bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
-
-public:
-  typedef TreeTransform<TemplateInstantiator> inherited;
-
-  TemplateInstantiator(Sema &SemaRef,
-                       const MultiLevelTemplateArgumentList &TemplateArgs,
-                       SourceLocation Loc, DeclarationName Entity,
-                       bool BailOutOnIncomplete = false)
-      : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
-        Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
-
-  inline static struct ForParameterMappingSubstitution_t {
-  } ForParameterMappingSubstitution;
-
-  TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
-                       SourceLocation Loc,
-                       const MultiLevelTemplateArgumentList &TemplateArgs,
-                       bool BuildPackExpansionTypes)
-      : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
-        BailOutOnIncomplete(false),
-        BuildPackExpansionTypes(BuildPackExpansionTypes) {}
-
-  void setEvaluateConstraints(bool B) { EvaluateConstraints = B; }
-  bool getEvaluateConstraints() { return EvaluateConstraints; }
-
-  /// Determine whether the given type \p T has already been
-  /// transformed.
-  ///
-  /// For the purposes of template instantiation, a type has already been
-  /// transformed if it is NULL or if it is not dependent.
-  bool AlreadyTransformed(QualType T);
-
-  /// Returns the location of the entity being instantiated, if known.
-  SourceLocation getBaseLocation() { return Loc; }
-
-  /// Returns the name of the entity being instantiated, if any.
-  DeclarationName getBaseEntity() { return Entity; }
-
-  /// Returns whether any substitution so far was incomplete.
-  bool getIsIncomplete() const { return IsIncomplete; }
-
-  /// Sets the "base" location and entity when that
-  /// information is known based on another transformation.
-  void setBase(SourceLocation Loc, DeclarationName Entity) {
-    this->Loc = Loc;
-    this->Entity = Entity;
-  }
+  class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
+    const MultiLevelTemplateArgumentList &TemplateArgs;
+    SourceLocation Loc;
+    DeclarationName Entity;
+    // Whether to evaluate the C++20 constraints or simply substitute into them.
+    bool EvaluateConstraints = true;
+    // Whether Substitution was Incomplete, that is, we tried to substitute in
+    // any user provided template arguments which were null.
+    bool IsIncomplete = false;
+    // Whether an incomplete substituion should be treated as an error.
+    bool BailOutOnIncomplete;
+
+    // Whether to rebuild pack expansion types; We don't do that when
+    // rebuilding a fold expression appearing in a constraint expression.
+    bool BuildPackExpansionTypes = true;
+
+    // CWG2770: Function parameters should be instantiated when they are
+    // needed by a satisfaction check of an atomic constraint or
+    // (recursively) by another function parameter.
+    bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
+
+  public:
+    typedef TreeTransform<TemplateInstantiator> inherited;
+
+    TemplateInstantiator(Sema &SemaRef,
+                         const MultiLevelTemplateArgumentList &TemplateArgs,
+                         SourceLocation Loc, DeclarationName Entity,
+                         bool BailOutOnIncomplete = false)
+        : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+          Entity(Entity), BailOutOnIncomplete(BailOutOnIncomplete) {}
 
-  unsigned TransformTemplateDepth(unsigned Depth) {
-    return TemplateArgs.getNewDepth(Depth);
-  }
+    void setEvaluateConstraints(bool B) {
+      EvaluateConstraints = B;
+    }
+    bool getEvaluateConstraints() {
+      return EvaluateConstraints;
+    }
 
-  UnsignedOrNone getPackIndex(TemplateArgument Pack) {
-    UnsignedOrNone Index = getSema().ArgPackSubstIndex;
-    if (!Index)
-      return std::nullopt;
-    return Pack.pack_size() - 1 - *Index;
-  }
+    inline static struct ForParameterMappingSubstitution_t {
+    } ForParameterMappingSubstitution;
 
-  bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
-                               SourceRange PatternRange,
-                               ArrayRef<UnexpandedParameterPack> Unexpanded,
-                               bool FailOnPackProducingTemplates,
-                               bool &ShouldExpand, bool &RetainExpansion,
-                               UnsignedOrNone &NumExpansions) {
-    if (SemaRef.CurrentInstantiationScope &&
-        (SemaRef.inConstraintSubstitution() ||
-         SemaRef.inParameterMappingSubstitution())) {
-      for (UnexpandedParameterPack ParmPack : Unexpanded) {
-        NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
-        if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
-            PVD && maybeInstantiateFunctionParameterToScope(PVD))
-          return true;
-      }
+    TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
+                         SourceLocation Loc,
+                         const MultiLevelTemplateArgumentList &TemplateArgs,
+                         bool BuildPackExpansionTypes)
+        : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+          BailOutOnIncomplete(false),
+          BuildPackExpansionTypes(BuildPackExpansionTypes) {}
+
+    /// Determine whether the given type \p T has already been
+    /// transformed.
+    ///
+    /// For the purposes of template instantiation, a type has already been
+    /// transformed if it is NULL or if it is not dependent.
+    bool AlreadyTransformed(QualType T);
+
+    /// Returns the location of the entity being instantiated, if known.
+    SourceLocation getBaseLocation() { return Loc; }
+
+    /// Returns the name of the entity being instantiated, if any.
+    DeclarationName getBaseEntity() { return Entity; }
+
+    /// Returns whether any substitution so far was incomplete.
+    bool getIsIncomplete() const { return IsIncomplete; }
+
+    /// Sets the "base" location and entity when that
+    /// information is known based on another transformation.
+    void setBase(SourceLocation Loc, DeclarationName Entity) {
+      this->Loc = Loc;
+      this->Entity = Entity;
     }
 
-    return getSema().CheckParameterPacksForExpansion(
-        EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
-        FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
-        NumExpansions);
-  }
-
-  void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
-    SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
-  }
+    unsigned TransformTemplateDepth(unsigned Depth) {
+      return TemplateArgs.getNewDepth(Depth);
+    }
 
-  TemplateArgument ForgetPartiallySubstitutedPack() {
-    TemplateArgument Result;
-    if (NamedDecl *PartialPack =
-            SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
-      MultiLevelTemplateArgumentList &TemplateArgs =
-          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-      unsigned Depth, Index;
-      std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
-      if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
-        Result = TemplateArgs(Depth, Index);
-        TemplateArgs.setArgument(Depth, Index, TemplateArgument());
-      } else {
-        IsIncomplete = true;
-        if (BailOutOnIncomplete)
-          return TemplateArgument();
-      }
+    UnsignedOrNone getPackIndex(TemplateArgument Pack) {
+      UnsignedOrNone Index = getSema().ArgPackSubstIndex;
+      if (!Index)
+        return std::nullopt;
+      return Pack.pack_size() - 1 - *Index;
     }
 
-    return Result;
-  }
+    bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
+                                 SourceRange PatternRange,
+                                 ArrayRef<UnexpandedParameterPack> Unexpanded,
+                                 bool FailOnPackProducingTemplates,
+                                 bool &ShouldExpand, bool &RetainExpansion,
+                                 UnsignedOrNone &NumExpansions) {
+      if (SemaRef.CurrentInstantiationScope &&
+          (SemaRef.inConstraintSubstitution() ||
+           SemaRef.inParameterMappingSubstitution())) {
+        for (UnexpandedParameterPack ParmPack : Unexpanded) {
+          NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
+          if (auto *PVD = dyn_cast_if_present<ParmVarDecl>(VD);
+              PVD && maybeInstantiateFunctionParameterToScope(PVD))
+            return true;
+        }
+      }
 
-  void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
-    if (Arg.isNull())
-      return;
+      return getSema().CheckParameterPacksForExpansion(
+          EllipsisLoc, PatternRange, Unexpanded, TemplateArgs,
+          FailOnPackProducingTemplates, ShouldExpand, RetainExpansion,
+          NumExpansions);
+    }
 
-    if (NamedDecl *PartialPack =
-            SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
-      MultiLevelTemplateArgumentList &TemplateArgs =
-          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-      unsigned Depth, Index;
-      std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
-      TemplateArgs.setArgument(Depth, Index, Arg);
+    void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
+      SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
     }
-  }
 
-  MultiLevelTemplateArgumentList ForgetSubstitution() {
-    MultiLevelTemplateArgumentList New;
-    New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
+    TemplateArgument ForgetPartiallySubstitutedPack() {
+      TemplateArgument Result;
+      if (NamedDecl *PartialPack =
+              SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+        MultiLevelTemplateArgumentList &TemplateArgs =
+            const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+        unsigned Depth, Index;
+        std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+        if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
+          Result = TemplateArgs(Depth, Index);
+          TemplateArgs.setArgument(Depth, Index, TemplateArgument());
+        } else {
+          IsIncomplete = true;
+          if (BailOutOnIncomplete)
+            return TemplateArgument();
+        }
+      }
 
-    MultiLevelTemplateArgumentList Old =
-        const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
-    const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
-        std::move(New);
-    return Old;
-  }
+      return Result;
+    }
 
-  void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
-    const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) = Old;
-  }
+    void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
+      if (Arg.isNull())
+        return;
+
+      if (NamedDecl *PartialPack =
+              SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+        MultiLevelTemplateArgumentList &TemplateArgs =
+            const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+        unsigned Depth, Index;
+        std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+        TemplateArgs.setArgument(Depth, Index, Arg);
+      }
+    }
 
-  TemplateArgument
-  getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
-    if (TA.getKind() != TemplateArgument::Pack)
-      return TA;
-    if (SemaRef.ArgPackSubstIndex)
-      return getPackSubstitutedTemplateArgument(SemaRef, TA);
-    assert(TA.pack_size() == 1 && TA.pack_begin()->isPackExpansion() &&
-           "unexpected pack arguments in template rewrite");
-    TemplateArgument Arg = *TA.pack_begin();
-    if (Arg.isPackExpansion())
-      Arg = Arg.getPackExpansionPattern();
-    return Arg;
-  }
+    MultiLevelTemplateArgumentList ForgetSubstitution() {
+      MultiLevelTemplateArgumentList New;
+      New.addOuterRetainedLevels(this->TemplateArgs.getNumLevels());
 
-  /// Transform the given declaration by instantiating a reference to
-  /// this declaration.
-  Decl *TransformDecl(SourceLocation Loc, Decl *D);
+      MultiLevelTemplateArgumentList Old =
+          const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) =
+          std::move(New);
+      return Old;
+    }
 
-  void transformAttrs(Decl *Old, Decl *New) {
-    SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
-  }
+    void RememberSubstitution(MultiLevelTemplateArgumentList Old) {
+      const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs) = Old;
+    }
 
-  void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) {
-    if (Old->isParameterPack() &&
-        (NewDecls.size() != 1 || !NewDecls.front()->isParameterPack())) {
-      SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old);
-      for (auto *New : NewDecls)
-        SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(
-            Old, cast<VarDecl>(New));
-      return;
+    TemplateArgument
+    getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) {
+      if (TA.getKind() != TemplateArgument::Pack)
+        return TA;
+      if (SemaRef.ArgPackSubstIndex)
+        return getPackSubstitutedTemplateArgument(SemaRef, TA);
+      assert(TA.pack_size() == 1 && TA.pack_begin()->isPackExpansion() &&
+             "unexpected pack arguments in template rewrite");
+      TemplateArgument Arg = *TA.pack_begin();
+      if (Arg.isPackExpansion())
+        Arg = Arg.getPackExpansionPattern();
+      return Arg;
     }
 
-    assert(NewDecls.size() == 1 &&
-           "should only have multiple expansions for a pack");
-    Decl *New = NewDecls.front();
-
-    // If we've instantiated the call operator of a lambda or the call
-    // operator template of a generic lambda, update the "instantiation of"
-    // information.
-    auto *NewMD = dyn_cast<CXXMethodDecl>(New);
-    if (NewMD && isLambdaCallOperator(NewMD)) {
-      auto *OldMD = dyn_cast<CXXMethodDecl>(Old);
-      if (auto *NewTD = NewMD->getDescribedFunctionTemplate())
-        NewTD->setInstantiatedFromMemberTemplate(
-            OldMD->getDescribedFunctionTemplate());
-      else
-        NewMD->setInstantiationOfMemberFunction(OldMD,
-                                                TSK_ImplicitInstantiation);
+    /// Transform the given declaration by instantiating a reference to
+    /// this declaration.
+    Decl *TransformDecl(SourceLocation Loc, Decl *D);
+
+    void transformAttrs(Decl *Old, Decl *New) {
+      SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
     }
 
-    SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
+    void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) {
+      if (Old->isParameterPack() &&
+          (NewDecls.size() != 1 || !NewDecls.front()->isParameterPack())) {
+        SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old);
+        for (auto *New : NewDecls)
+          SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(
+              Old, cast<VarDecl>(New));
+        return;
+      }
 
-    // We recreated a local declaration, but not by instantiating it. There
-    // may be pending dependent diagnostics to produce.
-    if (auto *DC = dyn_cast<DeclContext>(Old);
-        DC && DC->isDependentContext() && DC->isFunctionOrMethod())
-      SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
-  }
+      assert(NewDecls.size() == 1 &&
+             "should only have multiple expansions for a pack");
+      Decl *New = NewDecls.front();
+
+      // If we've instantiated the call operator of a lambda or the call
+      // operator template of a generic lambda, update the "instantiation of"
+      // information.
+      auto *NewMD = dyn_cast<CXXMethodDecl>(New);
+      if (NewMD && isLambdaCallOperator(NewMD)) {
+        auto *OldMD = dyn_cast<CXXMethodDecl>(Old);
+        if (auto *NewTD = NewMD->getDescribedFunctionTemplate())
+          NewTD->setInstantiatedFromMemberTemplate(
+              OldMD->getDescribedFunctionTemplate());
+        else
+          NewMD->setInstantiationOfMemberFunction(OldMD,
+                                                  TSK_ImplicitInstantiation);
+      }
 
-  /// Transform the definition of the given declaration by
-  /// instantiating it.
-  Decl *TransformDefinition(SourceLocation Loc, Decl *D);
+      SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
 
-  /// Transform the first qualifier within a scope by instantiating the
-  /// declaration.
-  NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
+      // We recreated a local declaration, but not by instantiating it. There
+      // may be pending dependent diagnostics to produce.
+      if (auto *DC = dyn_cast<DeclContext>(Old);
+          DC && DC->isDependentContext() && DC->isFunctionOrMethod())
+        SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
+    }
 
-  bool TransformExceptionSpec(SourceLocation Loc,
-                              FunctionProtoType::ExceptionSpecInfo &ESI,
-                              SmallVectorImpl<QualType> &Exceptions,
-                              bool &Changed);
-
-  /// Rebuild the exception declaration and register the declaration
-  /// as an instantiated local.
-  VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
-                                TypeSourceInfo *Declarator,
-                                SourceLocation StartLoc, SourceLocation NameLoc,
-                                IdentifierInfo *Name);
-
-  /// Rebuild the Objective-C exception declaration and register the
-  /// declaration as an instantiated local.
-  VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
-                                    TypeSourceInfo *TSInfo, QualType T);
-
-  /// Check for tag mismatches when instantiating an
-  /// elaborated type.
-  QualType RebuildElaboratedType(SourceLocation KeywordLoc,
-                                 ElaboratedTypeKeyword Keyword,
-                                 NestedNameSpecifierLoc QualifierLoc,
-                                 QualType T);
-
-  TemplateName TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc,
-                                     SourceLocation TemplateKWLoc,
-                                     TemplateName Name, SourceLocation NameLoc,
-                                     QualType ObjectType = QualType(),
-                                     NamedDecl *FirstQualifierInScope = nullptr,
-                                     bool AllowInjectedClassName = false);
-
-  const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
-  const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
-  const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
-  const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
-                                                const Stmt *InstS,
-                                                const NoInlineAttr *A);
-  const AlwaysInlineAttr *
-  TransformStmtAlwaysInlineAttr(const Stmt *OrigS, const Stmt *InstS,
-                                const AlwaysInlineAttr *A);
-  const CodeAlignAttr *TransformCodeAlignAttr(const CodeAlignAttr *CA);
-  const OpenACCRoutineDeclAttr *
-  TransformOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
-  ExprResult TransformPredefinedExpr(PredefinedExpr *E);
-  ExprResult TransformDeclRefExpr(DeclRefExpr *E);
-  ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
-
-  ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
-                                          NonTypeTemplateParmDecl *D);
-  ExprResult TransformSubstNonTypeTemplateParmPackExpr(
-      SubstNonTypeTemplateParmPackExpr *E);
-  ExprResult
-  TransformSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
-
-  /// Rebuild a DeclRefExpr for a VarDecl reference.
-  ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
-
-  /// Transform a reference to a function or init-capture parameter pack.
-  ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, ValueDecl *PD);
-
-  /// Transform a FunctionParmPackExpr which was built when we couldn't
-  /// expand a function parameter pack reference which refers to an expanded
-  /// pack.
-  ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
-
-  QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
-                                      FunctionProtoTypeLoc TL) {
-    // Call the base version; it will forward to our overridden version below.
-    return inherited::TransformFunctionProtoType(TLB, TL);
-  }
+    /// Transform the definition of the given declaration by
+    /// instantiating it.
+    Decl *TransformDefinition(SourceLocation Loc, Decl *D);
+
+    /// Transform the first qualifier within a scope by instantiating the
+    /// declaration.
+    NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
+
+    bool TransformExceptionSpec(SourceLocation Loc,
+                                FunctionProtoType::ExceptionSpecInfo &ESI,
+                                SmallVectorImpl<QualType> &Exceptions,
+                                bool &Changed);
+
+    /// Rebuild the exception declaration and register the declaration
+    /// as an instantiated local.
+    VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl,
+                                  TypeSourceInfo *Declarator,
+                                  SourceLocation StartLoc,
+                                  SourceLocation NameLoc,
+                                  IdentifierInfo *Name);
+
+    /// Rebuild the Objective-C exception declaration and register the
+    /// declaration as an instantiated local.
+    VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+                                      TypeSourceInfo *TSInfo, QualType T);
+
+    TemplateName
+    TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc,
+                          SourceLocation TemplateKWLoc, TemplateName Name,
+                          SourceLocation NameLoc,
+                          QualType ObjectType = QualType(),
+                          NamedDecl *FirstQualifierInScope = nullptr,
+                          bool AllowInjectedClassName = false);
+
+    /// Check for tag mismatches when instantiating an
+    /// elaborated type.
+    QualType RebuildElaboratedType(SourceLocation KeywordLoc,
+                                   ElaboratedTypeKeyword Keyword,
+                                   NestedNameSpecifierLoc QualifierLoc,
+                                   QualType T);
+
+    const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
+    const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
+    const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
+    const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
+                                                  const Stmt *InstS,
+                                                  const NoInlineAttr *A);
+    const AlwaysInlineAttr *
+    TransformStmtAlwaysInlineAttr(const Stmt *OrigS, const Stmt *InstS,
+                                  const AlwaysInlineAttr *A);
+    const CodeAlignAttr *TransformCodeAlignAttr(const CodeAlignAttr *CA);
+    const OpenACCRoutineDeclAttr *
+    TransformOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
+    ExprResult TransformPredefinedExpr(PredefinedExpr *E);
+    ExprResult TransformDeclRefExpr(DeclRefExpr *E);
+    ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E);
+
+    ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
+                                            NonTypeTemplateParmDecl *D);
+    ExprResult TransformSubstNonTypeTemplateParmPackExpr(
+                                           SubstNonTypeTemplateParmPackExpr *E);
+    ExprResult TransformSubstNonTypeTemplateParmExpr(
+                                           SubstNonTypeTemplateParmExpr *E);
+
+    /// Rebuild a DeclRefExpr for a VarDecl reference.
+    ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
+
+    /// Transform a reference to a function or init-capture parameter pack.
+    ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, ValueDecl *PD);
+
+    /// Transform a FunctionParmPackExpr which was built when we couldn't
+    /// expand a function parameter pack reference which refers to an expanded
+    /// pack.
+    ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
+
+    QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                        FunctionProtoTypeLoc TL) {
+      // Call the base version; it will forward to our overridden version below.
+      return inherited::TransformFunctionProtoType(TLB, TL);
+    }
 
-  QualType TransformTagType(TypeLocBuilder &TLB, TagTypeLoc TL) {
-    auto Type = inherited::TransformTagType(TLB, TL);
-    if (!Type.isNull())
+    QualType TransformTagType(TypeLocBuilder &TLB, TagTypeLoc TL) {
+      auto Type = inherited::TransformTagType(TLB, TL);
+      if (!Type.isNull())
+        return Type;
+      // Special case for transforming a deduction guide, we return a
+      // transformed TemplateSpecializationType.
+      // FIXME: Why is this hack necessary?
+      if (const auto *ICNT = dyn_cast<InjectedClassNameType>(TL.getTypePtr());
+          ICNT && SemaRef.CodeSynthesisContexts.back().Kind ==
+                      Sema::CodeSynthesisContext::BuildingDeductionGuides) {
+        Type = inherited::TransformType(
+            ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType(
+                SemaRef.Context));
+        TLB.pushTrivial(SemaRef.Context, Type, TL.getNameLoc());
+      }
       return Type;
-    // Special case for transforming a deduction guide, we return a
-    // transformed TemplateSpecializationType.
-    // FIXME: Why is this hack necessary?
-    if (const auto *ICNT = dyn_cast<InjectedClassNameType>(TL.getTypePtr());
-        ICNT && SemaRef.CodeSynthesisContexts.back().Kind ==
-                    Sema::CodeSynthesisContext::BuildingDeductionGuides) {
-      Type = inherited::TransformType(
-          ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType(
-              SemaRef.Context));
-      TLB.pushTrivial(SemaRef.Context, Type, TL.getNameLoc());
     }
-    return Type;
-  }
-  // Override the default version to handle a rewrite-template-arg-pack case
-  // for building a deduction guide.
-  bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
-                                 TemplateArgumentLoc &Output,
-                                 bool Uneval = false) {
-    const TemplateArgument &Arg = Input.getArgument();
-    std::vector<TemplateArgument> TArgs;
-    switch (Arg.getKind()) {
-    case TemplateArgument::Pack:
-      assert(SemaRef.CodeSynthesisContexts.empty() ||
-             SemaRef.CodeSynthesisContexts.back().Kind ==
-                 Sema::CodeSynthesisContext::BuildingDeductionGuides);
-      // Literally rewrite the template argument pack, instead of unpacking
-      // it.
-      for (auto &pack : Arg.getPackAsArray()) {
-        TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
-            pack, QualType(), SourceLocation{});
-        TemplateArgumentLoc Output;
-        if (TransformTemplateArgument(Input, Output, Uneval))
-          return true; // fails
-        TArgs.push_back(Output.getArgument());
+    // Override the default version to handle a rewrite-template-arg-pack case
+    // for building a deduction guide.
+    bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
+                                   TemplateArgumentLoc &Output,
+                                   bool Uneval = false) {
+      const TemplateArgument &Arg = Input.getArgument();
+      std::vector<TemplateArgument> TArgs;
+      switch (Arg.getKind()) {
+      case TemplateArgument::Pack:
+        assert(SemaRef.CodeSynthesisContexts.empty() ||
+               SemaRef.CodeSynthesisContexts.back().Kind ==
+                   Sema::CodeSynthesisContext::BuildingDeductionGuides);
+        // Literally rewrite the template argument pack, instead of unpacking
+        // it.
+        for (auto &pack : Arg.getPackAsArray()) {
+          TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
+              pack, QualType(), SourceLocation{});
+          TemplateArgumentLoc Output;
+          if (TransformTemplateArgument(Input, Output, Uneval))
+            return true; // fails
+          TArgs.push_back(Output.getArgument());
+        }
+        Output = SemaRef.getTrivialTemplateArgumentLoc(
+            TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)),
+            QualType(), SourceLocation{});
+        return false;
+      default:
+        break;
       }
-      Output = SemaRef.getTrivialTemplateArgumentLoc(
-          TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)),
-          QualType(), SourceLocation{});
-      return false;
-    default:
-      break;
+      return inherited::TransformTemplateArgument(Input, Output, Uneval);
     }
-    return inherited::TransformTemplateArgument(Input, Output, Uneval);
-  }
-
-  // This has to be here to allow its overload.
-  ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
-                                  UnsignedOrNone NumExpansions) {
-    return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, NumExpansions);
-  }
 
-  TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
-                                           SourceLocation EllipsisLoc,
-                                           UnsignedOrNone NumExpansions) {
-    // We don't rewrite a PackExpansion type when we want to normalize a
-    // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
-    if (BuildPackExpansionTypes)
-      return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
-                                             NumExpansions);
-    return Pattern;
-  }
+    // This has to be here to allow its overload.
+    ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
+                                    UnsignedOrNone NumExpansions) {
+      return inherited::RebuildPackExpansion(Pattern, EllipsisLoc, NumExpansions);
+    }
 
-  using TreeTransform::TransformTemplateSpecializationType;
-  QualType
-  TransformTemplateSpecializationType(TypeLocBuilder &TLB,
-                                      TemplateSpecializationTypeLoc TL) {
-    auto *T = TL.getTypePtr();
-    if (!getSema().ArgPackSubstIndex || !T->isSugared() ||
-        !isPackProducingBuiltinTemplateName(T->getTemplateName()))
-      return TreeTransform::TransformTemplateSpecializationType(TLB, TL);
-    // Look through sugar to get to the SubstBuiltinTemplatePackType that we
-    // need to substitute into.
-
-    // `TransformType` code below will handle picking the element from a pack
-    // with the index `ArgPackSubstIndex`.
-    // FIXME: add ability to represent sugarred type for N-th element of a
-    // builtin pack and produce the sugar here.
-    QualType R = TransformType(T->desugar());
-    TLB.pushTrivial(getSema().getASTContext(), R, TL.getBeginLoc());
-    return R;
-  }
+    TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
+                                             SourceLocation EllipsisLoc,
+                                             UnsignedOrNone NumExpansions) {
+      // We don't rewrite a PackExpansion type when we want to normalize a
+      // CXXFoldExpr constraint. We'll expand it when evaluating the constraint.
+      if (BuildPackExpansionTypes)
+        return inherited::RebuildPackExpansion(Pattern, EllipsisLoc,
+                                               NumExpansions);
+      return Pattern;
+    }
 
-  UnsignedOrNone ComputeSizeOfPackExprWithoutSubstitution(
-      ArrayRef<TemplateArgument> PackArgs) {
-    // Don't do this when rewriting template parameters for CTAD:
-    //   1) The heuristic needs the unpacked Subst* nodes to figure out the
-    //   expanded size, but this never applies since Subst* nodes are not
-    //   created in rewrite scenarios.
-    //
-    //   2) The heuristic substitutes into the pattern with pack expansion
-    //   suppressed, which does not meet the requirements for argument
-    //   rewriting when template arguments include a non-pack matching against
-    //   a pack, particularly when rewriting an alias CTAD.
-    if (TemplateArgs.isRewrite())
-      return std::nullopt;
+    using TreeTransform::TransformTemplateSpecializationType;
+    QualType
+    TransformTemplateSpecializationType(TypeLocBuilder &TLB,
+                                        TemplateSpecializationTypeLoc TL) {
+      auto *T = TL.getTypePtr();
+      if (!getSema().ArgPackSubstIndex || !T->isSugared() ||
+          !isPackProducingBuiltinTemplateName(T->getTemplateName()))
+        return TreeTransform::TransformTemplateSpecializationType(TLB, TL);
+      // Look through sugar to get to the SubstBuiltinTemplatePackType that we
+      // need to substitute into.
+
+      // `TransformType` code below will handle picking the element from a pack
+      // with the index `ArgPackSubstIndex`.
+      // FIXME: add ability to represent sugarred type for N-th element of a
+      // builtin pack and produce the sugar here.
+      QualType R = TransformType(T->desugar());
+      TLB.pushTrivial(getSema().getASTContext(), R, TL.getBeginLoc());
+      return R;
+    }
 
-    return inherited::ComputeSizeOfPackExprWithoutSubstitution(PackArgs);
-  }
+    UnsignedOrNone ComputeSizeOfPackExprWithoutSubstitution(
+        ArrayRef<TemplateArgument> PackArgs) {
+      // Don't do this when rewriting template parameters for CTAD:
+      //   1) The heuristic needs the unpacked Subst* nodes to figure out the
+      //   expanded size, but this never applies since Subst* nodes are not
+      //   created in rewrite scenarios.
+      //
+      //   2) The heuristic substitutes into the pattern with pack expansion
+      //   suppressed, which does not meet the requirements for argument
+      //   rewriting when template arguments include a non-pack matching against
+      //   a pack, particularly when rewriting an alias CTAD.
+      if (TemplateArgs.isRewrite())
+        return std::nullopt;
+
+      return inherited::ComputeSizeOfPackExprWithoutSubstitution(PackArgs);
+    }
 
-  template <typename Fn>
-  QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
-                                      FunctionProtoTypeLoc TL,
-                                      CXXRecordDecl *ThisContext,
-                                      Qualifiers ThisTypeQuals,
-                                      Fn TransformExceptionSpec);
-
-  ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
-                                          int indexAdjustment,
-                                          UnsignedOrNone NumExpansions,
-                                          bool ExpectParameterPack);
-
-  using inherited::TransformTemplateTypeParmType;
-  /// Transforms a template type parameter type by performing
-  /// substitution of the corresponding template type argument.
-  QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
-                                         TemplateTypeParmTypeLoc TL,
-                                         bool SuppressObjCLifetime);
-
-  QualType BuildSubstTemplateTypeParmType(TypeLocBuilder &TLB,
-                                          bool SuppressObjCLifetime, bool Final,
-                                          Decl *AssociatedDecl, unsigned Index,
-                                          UnsignedOrNone PackIndex,
-                                          TemplateArgument Arg,
-                                          SourceLocation NameLoc);
-
-  /// Transforms an already-substituted template type parameter pack
-  /// into either itself (if we aren't substituting into its pack expansion)
-  /// or the appropriate substituted argument.
-  using inherited::TransformSubstTemplateTypeParmPackType;
-  QualType
-  TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
-                                         SubstTemplateTypeParmPackTypeLoc TL,
-                                         bool SuppressObjCLifetime);
-  QualType
-  TransformSubstBuiltinTemplatePackType(TypeLocBuilder &TLB,
-                                        SubstBuiltinTemplatePackTypeLoc TL);
-
-  CXXRecordDecl::LambdaDependencyKind
-  ComputeLambdaDependency(LambdaScopeInfo *LSI) {
-    if (auto TypeAlias =
-            TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
-                getSema());
-        TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
-                         LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
-      unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
-      if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
-        return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
-      for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
-        if (TA.isDependent())
+    template<typename Fn>
+    QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+                                        FunctionProtoTypeLoc TL,
+                                        CXXRecordDecl *ThisContext,
+                                        Qualifiers ThisTypeQuals,
+                                        Fn TransformExceptionSpec);
+
+    ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
+                                            int indexAdjustment,
+                                            UnsignedOrNone NumExpansions,
+                                            bool ExpectParameterPack);
+
+    using inherited::TransformTemplateTypeParmType;
+    /// Transforms a template type parameter type by performing
+    /// substitution of the corresponding template type argument.
+    QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+                                           TemplateTypeParmTypeLoc TL,
+                                           bool SuppressObjCLifetime);
+
+    QualType BuildSubstTemplateTypeParmType(
+        TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final,
+        Decl *AssociatedDecl, unsigned Index, UnsignedOrNone PackIndex,
+        TemplateArgument Arg, SourceLocation NameLoc);
+
+    /// Transforms an already-substituted template type parameter pack
+    /// into either itself (if we aren't substituting into its pack expansion)
+    /// or the appropriate substituted argument.
+    using inherited::TransformSubstTemplateTypeParmPackType;
+    QualType
+    TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
+                                           SubstTemplateTypeParmPackTypeLoc TL,
+                                           bool SuppressObjCLifetime);
+    QualType
+    TransformSubstBuiltinTemplatePackType(TypeLocBuilder &TLB,
+                                          SubstBuiltinTemplatePackTypeLoc TL);
+
+    CXXRecordDecl::LambdaDependencyKind
+    ComputeLambdaDependency(LambdaScopeInfo *LSI) {
+      if (auto TypeAlias =
+              TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
+                  getSema());
+          TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+                           LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
+        unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
+        if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
           return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+        for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
+          if (TA.isDependent())
+            return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+      }
+      return inherited::ComputeLambdaDependency(LSI);
     }
-    return inherited::ComputeLambdaDependency(LSI);
-  }
 
-  ExprResult TransformLambdaExpr(LambdaExpr *E) {
-    // Do not rebuild lambdas to avoid creating a new type.
-    // Lambdas have already been processed inside their eval contexts.
-    if (SemaRef.RebuildingImmediateInvocation)
-      return E;
-    LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
-                                  /*InstantiatingLambdaOrBlock=*/true);
-    Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+    ExprResult TransformLambdaExpr(LambdaExpr *E) {
+      // Do not rebuild lambdas to avoid creating a new type.
+      // Lambdas have already been processed inside their eval contexts.
+      if (SemaRef.RebuildingImmediateInvocation)
+        return E;
+      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
+                                    /*InstantiatingLambdaOrBlock=*/true);
+      Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
 
-    return inherited::TransformLambdaExpr(E);
-  }
+      return inherited::TransformLambdaExpr(E);
+    }
 
-  ExprResult TransformBlockExpr(BlockExpr *E) {
-    LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
-                                  /*InstantiatingLambdaOrBlock=*/true);
-    return inherited::TransformBlockExpr(E);
-  }
+    ExprResult TransformBlockExpr(BlockExpr *E) {
+      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
+                                    /*InstantiatingLambdaOrBlock=*/true);
+      return inherited::TransformBlockExpr(E);
+    }
 
-  ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
-                               LambdaScopeInfo *LSI) {
-    CXXMethodDecl *MD = LSI->CallOperator;
-    for (ParmVarDecl *PVD : MD->parameters()) {
-      assert(PVD && "null in a parameter list");
-      if (!PVD->hasDefaultArg())
-        continue;
-      Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
-      // FIXME: Obtain the source location for the '=' token.
-      SourceLocation EqualLoc = UninstExpr->getBeginLoc();
-      if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
-        // If substitution fails, the default argument is set to a
-        // RecoveryExpr that wraps the uninstantiated default argument so
-        // that downstream diagnostics are omitted.
-        ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
-            UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
-            UninstExpr->getType());
-        if (ErrorResult.isUsable())
-          PVD->setDefaultArg(ErrorResult.get());
+    ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
+                                 LambdaScopeInfo *LSI) {
+      CXXMethodDecl *MD = LSI->CallOperator;
+      for (ParmVarDecl *PVD : MD->parameters()) {
+        assert(PVD && "null in a parameter list");
+        if (!PVD->hasDefaultArg())
+          continue;
+        Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+        // FIXME: Obtain the source location for the '=' token.
+        SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+        if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+          // If substitution fails, the default argument is set to a
+          // RecoveryExpr that wraps the uninstantiated default argument so
+          // that downstream diagnostics are omitted.
+          ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+              UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
+              UninstExpr->getType());
+          if (ErrorResult.isUsable())
+            PVD->setDefaultArg(ErrorResult.get());
+        }
       }
+      return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
     }
-    return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI);
-  }
 
-  StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) {
-    // Currently, we instantiate the body when instantiating the lambda
-    // expression. However, `EvaluateConstraints` is disabled during the
-    // instantiation of the lambda expression, causing the instantiation
-    // failure of the return type requirement in the body. If p0588r1 is fully
-    // implemented, the body will be lazily instantiated, and this problem
-    // will not occur. Here, `EvaluateConstraints` is temporarily set to
-    // `true` to temporarily fix this issue.
-    // FIXME: This temporary fix can be removed after fully implementing
-    // p0588r1.
-    llvm::SaveAndRestore _(EvaluateConstraints, true);
-    return inherited::TransformLambdaBody(E, Body);
-  }
+    StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) {
+      // Currently, we instantiate the body when instantiating the lambda
+      // expression. However, `EvaluateConstraints` is disabled during the
+      // instantiation of the lambda expression, causing the instantiation
+      // failure of the return type requirement in the body. If p0588r1 is fully
+      // implemented, the body will be lazily instantiated, and this problem
+      // will not occur. Here, `EvaluateConstraints` is temporarily set to
+      // `true` to temporarily fix this issue.
+      // FIXME: This temporary fix can be removed after fully implementing
+      // p0588r1.
+      llvm::SaveAndRestore _(EvaluateConstraints, true);
+      return inherited::TransformLambdaBody(E, Body);
+    }
 
-  ExprResult TransformRequiresExpr(RequiresExpr *E) {
-    LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
-    ExprResult TransReq = inherited::TransformRequiresExpr(E);
-    if (TransReq.isInvalid())
+    ExprResult TransformRequiresExpr(RequiresExpr *E) {
+      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+      ExprResult TransReq = inherited::TransformRequiresExpr(E);
+      if (TransReq.isInvalid())
+        return TransReq;
+      assert(TransReq.get() != E &&
+             "Do not change value of isSatisfied for the existing expression. "
+             "Create a new expression instead.");
+      if (E->getBody()->isDependentContext()) {
+        Sema::SFINAETrap Trap(SemaRef);
+        // We recreate the RequiresExpr body, but not by instantiating it.
+        // Produce pending diagnostics for dependent access check.
+        SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+        // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis.
+        if (Trap.hasErrorOccurred())
+          TransReq.getAs<RequiresExpr>()->setSatisfied(false);
+      }
       return TransReq;
-    assert(TransReq.get() != E &&
-           "Do not change value of isSatisfied for the existing expression. "
-           "Create a new expression instead.");
-    if (E->getBody()->isDependentContext()) {
-      Sema::SFINAETrap Trap(SemaRef);
-      // We recreate the RequiresExpr body, but not by instantiating it.
-      // Produce pending diagnostics for dependent access check.
-      SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
-      // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis.
-      if (Trap.hasErrorOccurred())
-        TransReq.getAs<RequiresExpr>()->setSatisfied(false);
     }
-    return TransReq;
-  }
 
-  bool TransformRequiresExprRequirements(
-      ArrayRef<concepts::Requirement *> Reqs,
-      SmallVectorImpl<concepts::Requirement *> &Transformed) {
-    bool SatisfactionDetermined = false;
-    for (concepts::Requirement *Req : Reqs) {
-      concepts::Requirement *TransReq = nullptr;
-      if (!SatisfactionDetermined) {
-        if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
-          TransReq = TransformTypeRequirement(TypeReq);
-        else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
-          TransReq = TransformExprRequirement(ExprReq);
-        else
-          TransReq = TransformNestedRequirement(
-              cast<concepts::NestedRequirement>(Req));
-        if (!TransReq)
-          return true;
-        if (!TransReq->isDependent() && !TransReq->isSatisfied())
-          // [expr.prim.req]p6
-          //   [...]  The substitution and semantic constraint checking
-          //   proceeds in lexical order and stops when a condition that
-          //   determines the result of the requires-expression is
-          //   encountered. [..]
-          SatisfactionDetermined = true;
-      } else
-        TransReq = Req;
-      Transformed.push_back(TransReq);
+    bool TransformRequiresExprRequirements(
+        ArrayRef<concepts::Requirement *> Reqs,
+        SmallVectorImpl<concepts::Requirement *> &Transformed) {
+      bool SatisfactionDetermined = false;
+      for (concepts::Requirement *Req : Reqs) {
+        concepts::Requirement *TransReq = nullptr;
+        if (!SatisfactionDetermined) {
+          if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
+            TransReq = TransformTypeRequirement(TypeReq);
+          else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
+            TransReq = TransformExprRequirement(ExprReq);
+          else
+            TransReq = TransformNestedRequirement(
+                cast<concepts::NestedRequirement>(Req));
+          if (!TransReq)
+            return true;
+          if (!TransReq->isDependent() && !TransReq->isSatisfied())
+            // [expr.prim.req]p6
+            //   [...]  The substitution and semantic constraint checking
+            //   proceeds in lexical order and stops when a condition that
+            //   determines the result of the requires-expression is
+            //   encountered. [..]
+            SatisfactionDetermined = true;
+        } else
+          TransReq = Req;
+        Transformed.push_back(TransReq);
+      }
+      return false;
     }
-    return false;
-  }
 
-  TemplateParameterList *
-  TransformTemplateParameterList(TemplateParameterList *OrigTPL) {
-    if (!OrigTPL || !OrigTPL->size())
-      return OrigTPL;
-
-    DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
-    TemplateDeclInstantiator DeclInstantiator(getSema(),
-                                              /* DeclContext *Owner */ Owner,
-                                              TemplateArgs);
-    DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
-    return DeclInstantiator.SubstTemplateParams(OrigTPL);
-  }
+    TemplateParameterList *TransformTemplateParameterList(
+                              TemplateParameterList *OrigTPL)  {
+      if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
 
-  concepts::TypeRequirement *
-  TransformTypeRequirement(concepts::TypeRequirement *Req);
-  concepts::ExprRequirement *
-  TransformExprRequirement(concepts::ExprRequirement *Req);
-  concepts::NestedRequirement *
-  TransformNestedRequirement(concepts::NestedRequirement *Req);
-  ExprResult TransformRequiresTypeParams(
-      SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
-      RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
-      SmallVectorImpl<QualType> &PTypes,
-      SmallVectorImpl<ParmVarDecl *> &TransParams,
-      Sema::ExtParameterInfoBuilder &PInfos);
-
-private:
-  ExprResult
-  transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
-                                  SourceLocation loc, TemplateArgument arg,
-                                  UnsignedOrNone PackIndex, bool Final);
-};
-} // namespace
+      DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
+      TemplateDeclInstantiator  DeclInstantiator(getSema(),
+                        /* DeclContext *Owner */ Owner, TemplateArgs);
+      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
+      return DeclInstantiator.SubstTemplateParams(OrigTPL);
+    }
+
+    concepts::TypeRequirement *
+    TransformTypeRequirement(concepts::TypeRequirement *Req);
+    concepts::ExprRequirement *
+    TransformExprRequirement(concepts::ExprRequirement *Req);
+    concepts::NestedRequirement *
+    TransformNestedRequirement(concepts::NestedRequirement *Req);
+    ExprResult TransformRequiresTypeParams(
+        SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+        RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+        SmallVectorImpl<QualType> &PTypes,
+        SmallVectorImpl<ParmVarDecl *> &TransParams,
+        Sema::ExtParameterInfoBuilder &PInfos);
+
+  private:
+    ExprResult
+    transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
+                                    SourceLocation loc, TemplateArgument arg,
+                                    UnsignedOrNone PackIndex, bool Final);
+  };
+}
 
 bool TemplateInstantiator::AlreadyTransformed(QualType T) {
   if (T.isNull())

>From 90b7a283773bc72f32fda7398dc61e1257baf11b Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 10 Sep 2025 19:02:27 +0200
Subject: [PATCH 13/29] fix doc

---
 clang/lib/Sema/SemaConcept.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 403bd82e0215d..ed86fcc0da9f2 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -45,9 +45,9 @@
  * template <typename U>
  * concept B = A<U> && __is_same(U, int);
  *
- * The  normal form is `__is_same(T, int) /T->U, inner most level/
- *                   && __is_same(U, int) {U->U} /T->U, outermost most level/
- *                   `
+ * The normal form of b is is `__is_same(T, int) /T->U, inner most level/
+ *                          && __is_same(U, int) {U->U} /T->U, outermost most level/
+ *                            `
  *
  * After substitution in the mapping, we substitute in the constraint expression
  * using that copy of the MultiLevelTemplateArgumentList, and then evaluate it.

>From d2e310e038ec2c4722082f92d13f20bc04c56169 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 11 Sep 2025 14:25:55 +0200
Subject: [PATCH 14/29] more cleanups

---
 clang/lib/Sema/SemaConcept.cpp             | 26 +++++++++++-----------
 clang/lib/Sema/SemaTemplateInstantiate.cpp |  3 ++-
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ed86fcc0da9f2..46f7bca633f8b 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -46,7 +46,8 @@
  * concept B = A<U> && __is_same(U, int);
  *
  * The normal form of b is is `__is_same(T, int) /T->U, inner most level/
- *                          && __is_same(U, int) {U->U} /T->U, outermost most level/
+ *                          && __is_same(U, int) {U->U} /T->U, outermost most
+ * level/
  *                            `
  *
  * After substitution in the mapping, we substitute in the constraint expression
@@ -858,25 +859,26 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
     const ConceptIdConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
 
+  const ConceptReference *ConceptId = Constraint.getConceptId();
+
   std::optional<Sema::InstantiatingTemplate> InstTemplate;
-  InstTemplate.emplace(S, Constraint.getConceptId()->getBeginLoc(),
+  InstTemplate.emplace(S, ConceptId->getBeginLoc(),
                        Sema::InstantiatingTemplate::ConstraintsCheck{},
-                       Constraint.getConceptId()->getNamedConcept(),
-                       MLTAL.getInnermost(), Constraint.getSourceRange());
+                       ConceptId->getNamedConcept(), MLTAL.getInnermost(),
+                       Constraint.getSourceRange());
 
   unsigned Size = Satisfaction.Details.size();
 
   ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
 
   if (!E.isUsable()) {
-    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
-                                Constraint.getConceptId());
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
     return E;
   }
 
   // ConceptIdConstraint is only relevant for diagnostics,
   // so if the normalized constraint is satisfied, we should not
-  // substiture into the constraint.
+  // substitute into the constraint.
   if (Satisfaction.IsSatisfied)
     return E;
 
@@ -899,7 +901,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
              : PackSubstitutionIndex);
 
   const ASTTemplateArgumentListInfo *Ori =
-      Constraint.getConceptId()->getTemplateArgsAsWritten();
+      ConceptId->getTemplateArgsAsWritten();
   TemplateDeductionInfo Info(TemplateNameLoc);
   InstTemplate.emplace(
       S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{},
@@ -935,13 +937,11 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   }
 
   CXXScopeSpec SS;
-  SS.Adopt(Constraint.getConceptId()->getNestedNameSpecifierLoc());
+  SS.Adopt(ConceptId->getNestedNameSpecifierLoc());
 
   ExprResult SubstitutedConceptId = S.CheckConceptTemplateId(
-      SS, Constraint.getConceptId()->getTemplateKWLoc(),
-      Constraint.getConceptId()->getConceptNameInfo(),
-      Constraint.getConceptId()->getFoundDecl(),
-      Constraint.getConceptId()->getNamedConcept(), &OutArgs,
+      SS, ConceptId->getTemplateKWLoc(), ConceptId->getConceptNameInfo(),
+      ConceptId->getFoundDecl(), ConceptId->getNamedConcept(), &OutArgs,
       /*DoCheckConstraintSatisfaction=*/false);
 
   if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 54075d81b0c6b..ed3dddf8c6367 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1406,7 +1406,8 @@ namespace {
     bool BailOutOnIncomplete;
 
     // Whether to rebuild pack expansion types; We don't do that when
-    // rebuilding a fold expression appearing in a constraint expression.
+    // rebuilding the parameter mapping of a fold expression appearing
+    // in a constraint expression.
     bool BuildPackExpansionTypes = true;
 
     // CWG2770: Function parameters should be instantiated when they are

>From 5f239d4b4abff9ce6c1b4c5f12f95a63a10d28e0 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 11 Sep 2025 15:41:22 +0200
Subject: [PATCH 15/29] remove some duplication

---
 clang/lib/Sema/SemaConcept.cpp | 39 +++++++++++++++-------------------
 1 file changed, 17 insertions(+), 22 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 46f7bca633f8b..1ba92e24cd722 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -481,6 +481,17 @@ class ConstraintSatisfactionChecker {
                       const MultiLevelTemplateArgumentList &MLTAL);
 };
 
+StringRef allocateStringFromConceptDiagnostic(const Sema &S,
+                                              const PartialDiagnostic Diag) {
+  SmallString<128> DiagString;
+  DiagString = ": ";
+  Diag.EmitToString(S.getDiagnostics(), DiagString);
+  unsigned MessageSize = DiagString.size();
+  char *Mem = new (S.Context) char[MessageSize];
+  memcpy(Mem, DiagString.c_str(), MessageSize);
+  return StringRef(Mem, MessageSize);
+}
+
 } // namespace
 
 ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
@@ -533,15 +544,10 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
       //  just storing them as strings. We would still like, in the
       //  future, to serialize the proper PartialDiagnostic as serializing
       //  it as a string defeats the purpose of the diagnostic mechanism.
-      SmallString<128> DiagString;
-      DiagString = ": ";
-      SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
-      unsigned MessageSize = DiagString.size();
-      char *Mem = new (S.Context) char[MessageSize];
-      memcpy(Mem, DiagString.c_str(), MessageSize);
       Satisfaction.Details.emplace_back(
           new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-              SubstDiag.first, StringRef(Mem, MessageSize)});
+              SubstDiag.first,
+              allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
       Satisfaction.IsSatisfied = false;
       return ExprEmpty();
     }
@@ -669,16 +675,10 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     Satisfaction.ContainsErrors = true;
 
     PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
-    SmallString<128> DiagString;
-    DiagString = ": ";
-    Msg.EmitToString(S.getDiagnostics(), DiagString);
-    unsigned MessageSize = DiagString.size();
-    char *Mem = new (S.Context) char[MessageSize];
-    memcpy(Mem, DiagString.c_str(), MessageSize);
     Satisfaction.Details.emplace_back(
         new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
             SubstitutedAtomicExpr.get()->getBeginLoc(),
-            StringRef(Mem, MessageSize)});
+            allocateStringFromConceptDiagnostic(S, Msg)});
     return SubstitutedAtomicExpr;
   }
 
@@ -917,22 +917,17 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
     PartialDiagnosticAt SubstDiag{SourceLocation(),
                                   PartialDiagnostic::NullDiagnostic()};
     Info.takeSFINAEDiagnostic(SubstDiag);
-    // FIXME: Concepts: This is an unfortunate consequence of there
+    // FIXME: This is an unfortunate consequence of there
     //  being no serialization code for PartialDiagnostics and the fact
     //  that serializing them would likely take a lot more storage than
     //  just storing them as strings. We would still like, in the
     //  future, to serialize the proper PartialDiagnostic as serializing
     //  it as a string defeats the purpose of the diagnostic mechanism.
-    SmallString<128> DiagString;
-    DiagString = ": ";
-    SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
-    unsigned MessageSize = DiagString.size();
-    char *Mem = new (S.Context) char[MessageSize];
-    memcpy(Mem, DiagString.c_str(), MessageSize);
     Satisfaction.Details.insert(
         Satisfaction.Details.begin() + Size,
         new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-            SubstDiag.first, StringRef(Mem, MessageSize)});
+            SubstDiag.first,
+            allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
     return ExprError();
   }
 

>From c5a8c316f5ee3802edd3b57cf1a91946b47edb81 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 11 Sep 2025 16:48:37 +0200
Subject: [PATCH 16/29] Cache satisfaction of ConceptIdConstraint.

We substitute into concept ids for diagnostics purposes.
However, most of the time this happen in SFINEA context
and impact performance noticeably.
---
 clang/lib/Sema/SemaConcept.cpp | 104 +++++++++++++++++++++++----------
 1 file changed, 74 insertions(+), 30 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 1ba92e24cd722..ed8895713e7a5 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -462,6 +462,10 @@ class ConstraintSatisfactionChecker {
   ExprResult Evaluate(const FoldExpandedConstraint &Constraint,
                       const MultiLevelTemplateArgumentList &MLTAL);
 
+  ExprResult EvaluateSlow(const ConceptIdConstraint &Constraint,
+                          const MultiLevelTemplateArgumentList &MLTAL,
+                          unsigned int Size);
+
   ExprResult Evaluate(const ConceptIdConstraint &Constraint,
                       const MultiLevelTemplateArgumentList &MLTAL);
 
@@ -855,35 +859,12 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   return Out;
 }
 
-ExprResult ConstraintSatisfactionChecker::Evaluate(
+ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     const ConceptIdConstraint &Constraint,
-    const MultiLevelTemplateArgumentList &MLTAL) {
-
+    const MultiLevelTemplateArgumentList &MLTAL,
+    unsigned Size) {
   const ConceptReference *ConceptId = Constraint.getConceptId();
 
-  std::optional<Sema::InstantiatingTemplate> InstTemplate;
-  InstTemplate.emplace(S, ConceptId->getBeginLoc(),
-                       Sema::InstantiatingTemplate::ConstraintsCheck{},
-                       ConceptId->getNamedConcept(), MLTAL.getInnermost(),
-                       Constraint.getSourceRange());
-
-  unsigned Size = Satisfaction.Details.size();
-
-  ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
-
-  if (!E.isUsable()) {
-    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
-    return E;
-  }
-
-  // ConceptIdConstraint is only relevant for diagnostics,
-  // so if the normalized constraint is satisfied, we should not
-  // substitute into the constraint.
-  if (Satisfaction.IsSatisfied)
-    return E;
-
-  // TODO: We might want to cache the substitution of concept id constraints
-  // as it can be slow in the SFINAE case.
   llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
   std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
       SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost);
@@ -903,7 +884,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   const ASTTemplateArgumentListInfo *Ori =
       ConceptId->getTemplateArgsAsWritten();
   TemplateDeductionInfo Info(TemplateNameLoc);
-  InstTemplate.emplace(
+  Sema::InstantiatingTemplate _(
       S, TemplateNameLoc, Sema::InstantiatingTemplate::ConstraintSubstitution{},
       const_cast<NamedDecl *>(Template), Info, Constraint.getSourceRange());
 
@@ -926,8 +907,8 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
     Satisfaction.Details.insert(
         Satisfaction.Details.begin() + Size,
         new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-            SubstDiag.first,
-            allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
+                                                                       SubstDiag.first,
+                                                                       allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
     return ExprError();
   }
 
@@ -940,7 +921,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
       /*DoCheckConstraintSatisfaction=*/false);
 
   if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
-    return E;
+    return ExprError();
 
   if (Size != Satisfaction.Details.size()) {
     Satisfaction.Details.insert(
@@ -952,6 +933,69 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   return SubstitutedConceptId;
 }
 
+ExprResult ConstraintSatisfactionChecker::Evaluate(
+    const ConceptIdConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  const ConceptReference *ConceptId = Constraint.getConceptId();
+
+  UnsignedOrNone OuterPackSubstIndex =
+      Constraint.getPackSubstitutionIndex()
+          ? Constraint.getPackSubstitutionIndex()
+          : PackSubstitutionIndex;
+
+  Sema::InstantiatingTemplate _ (S, ConceptId->getBeginLoc(),
+                       Sema::InstantiatingTemplate::ConstraintsCheck{},
+                       ConceptId->getNamedConcept(), MLTAL.getInnermost(),
+                       Constraint.getSourceRange());
+
+  unsigned Size = Satisfaction.Details.size();
+
+  ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
+
+  if (!E.isUsable()) {
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size, ConceptId);
+    return E;
+  }
+
+  // ConceptIdConstraint is only relevant for diagnostics,
+  // so if the normalized constraint is satisfied, we should not
+  // substitute into the constraint.
+  if (Satisfaction.IsSatisfied)
+    return E;
+
+  llvm::FoldingSetNodeID ID;
+  ID.AddPointer(Constraint.getConceptId());
+  ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
+  ID.AddBoolean(Constraint.hasParameterMapping());
+  HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
+      .VisitConstraint(Constraint);
+
+
+  if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
+      Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
+
+    auto &Cached = Iter->second.Satisfaction;
+    Satisfaction.ContainsErrors = Cached.ContainsErrors;
+    Satisfaction.IsSatisfied = Cached.IsSatisfied;
+    Satisfaction.Details.insert(Satisfaction.Details.begin() + Size,
+                                Cached.Details.begin(), Cached.Details.end());
+    return Iter->second.SubstExpr;
+  }
+
+  ExprResult CE = EvaluateSlow(Constraint, MLTAL, Size);
+  if(CE.isInvalid())
+    return E;
+  UnsubstitutedConstraintSatisfactionCacheResult Cache;
+  Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
+  Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
+  std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
+            std::back_inserter(Cache.Satisfaction.Details));
+  Cache.SubstExpr = CE;
+  S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
+  return CE;
+}
+
 ExprResult ConstraintSatisfactionChecker::Evaluate(
     const CompoundConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {

>From 9361310205bb8c4f1ca9a341d3ececbc7ddf16c1 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 11 Sep 2025 17:38:44 +0200
Subject: [PATCH 17/29] more caching

---
 clang/lib/Sema/SemaConcept.cpp | 62 ++++++++++++++++++++++++++--------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ed8895713e7a5..476790238384d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -405,7 +405,7 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
 
   void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) {
     if (!Constraint.hasParameterMapping()) {
-      for (auto List : TemplateArgs)
+      for (const auto &List : TemplateArgs)
         for (const TemplateArgument &Arg : List.Args)
           SemaRef.Context.getCanonicalTemplateArgument(Arg).Profile(
               ID, SemaRef.Context);
@@ -459,6 +459,9 @@ class ConstraintSatisfactionChecker {
   ExprResult Evaluate(const AtomicConstraint &Constraint,
                       const MultiLevelTemplateArgumentList &MLTAL);
 
+  ExprResult EvaluateSlow(const FoldExpandedConstraint &Constraint,
+                          const MultiLevelTemplateArgumentList &MLTAL);
+
   ExprResult Evaluate(const FoldExpandedConstraint &Constraint,
                       const MultiLevelTemplateArgumentList &MLTAL);
 
@@ -732,7 +735,6 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
 
   ID.AddPointer(Constraint.getConstraintExpr());
   ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
-  ID.AddBoolean(Constraint.hasParameterMapping());
   HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
       .VisitConstraint(Constraint);
 
@@ -794,16 +796,16 @@ ConstraintSatisfactionChecker::EvaluateFoldExpandedConstraintSize(
   return NumExpansions;
 }
 
-ExprResult ConstraintSatisfactionChecker::Evaluate(
+ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     const FoldExpandedConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
+
   bool Conjunction = Constraint.getFoldOperator() ==
                      FoldExpandedConstraint::FoldOperatorKind::And;
   unsigned EffectiveDetailEndIndex = Satisfaction.Details.size();
 
   llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
   // FIXME: Is PackSubstitutionIndex correct?
-  // TODO: We might want to cache the substitution of fold expanded constraints.
   llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex);
   std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
       SubstitutionInTemplateArguments(
@@ -859,10 +861,41 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   return Out;
 }
 
+ExprResult ConstraintSatisfactionChecker::Evaluate(
+    const FoldExpandedConstraint &Constraint,
+    const MultiLevelTemplateArgumentList &MLTAL) {
+
+  llvm::FoldingSetNodeID ID;
+  ID.AddPointer(Constraint.getPattern());
+  HashParameterMapping(S, MLTAL, ID, std::nullopt).VisitConstraint(Constraint);
+
+  if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
+      Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
+
+    auto &Cached = Iter->second.Satisfaction;
+    Satisfaction.ContainsErrors = Cached.ContainsErrors;
+    Satisfaction.IsSatisfied = Cached.IsSatisfied;
+    Satisfaction.Details.insert(Satisfaction.Details.end(),
+                                Cached.Details.begin(), Cached.Details.end());
+    return Iter->second.SubstExpr;
+  }
+
+  unsigned Size = Satisfaction.Details.size();
+
+  ExprResult E = EvaluateSlow(Constraint, MLTAL);
+  UnsubstitutedConstraintSatisfactionCacheResult Cache;
+  Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;
+  Cache.Satisfaction.IsSatisfied = Satisfaction.IsSatisfied;
+  std::copy(Satisfaction.Details.begin() + Size, Satisfaction.Details.end(),
+            std::back_inserter(Cache.Satisfaction.Details));
+  Cache.SubstExpr = E;
+  S.UnsubstitutedConstraintSatisfactionCache.insert({ID, std::move(Cache)});
+  return E;
+}
+
 ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     const ConceptIdConstraint &Constraint,
-    const MultiLevelTemplateArgumentList &MLTAL,
-    unsigned Size) {
+    const MultiLevelTemplateArgumentList &MLTAL, unsigned Size) {
   const ConceptReference *ConceptId = Constraint.getConceptId();
 
   llvm::SmallVector<TemplateArgument> SubstitutedOuterMost;
@@ -907,8 +940,8 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     Satisfaction.Details.insert(
         Satisfaction.Details.begin() + Size,
         new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-                                                                       SubstDiag.first,
-                                                                       allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
+            SubstDiag.first,
+            allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
     return ExprError();
   }
 
@@ -944,10 +977,11 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
           ? Constraint.getPackSubstitutionIndex()
           : PackSubstitutionIndex;
 
-  Sema::InstantiatingTemplate _ (S, ConceptId->getBeginLoc(),
-                       Sema::InstantiatingTemplate::ConstraintsCheck{},
-                       ConceptId->getNamedConcept(), MLTAL.getInnermost(),
-                       Constraint.getSourceRange());
+  Sema::InstantiatingTemplate _(S, ConceptId->getBeginLoc(),
+                                Sema::InstantiatingTemplate::ConstraintsCheck{},
+                                ConceptId->getNamedConcept(),
+                                MLTAL.getInnermost(),
+                                Constraint.getSourceRange());
 
   unsigned Size = Satisfaction.Details.size();
 
@@ -967,11 +1001,9 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   llvm::FoldingSetNodeID ID;
   ID.AddPointer(Constraint.getConceptId());
   ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
-  ID.AddBoolean(Constraint.hasParameterMapping());
   HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
       .VisitConstraint(Constraint);
 
-
   if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
       Iter != S.UnsubstitutedConstraintSatisfactionCache.end()) {
 
@@ -984,7 +1016,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
   }
 
   ExprResult CE = EvaluateSlow(Constraint, MLTAL, Size);
-  if(CE.isInvalid())
+  if (CE.isInvalid())
     return E;
   UnsubstitutedConstraintSatisfactionCacheResult Cache;
   Cache.Satisfaction.ContainsErrors = Satisfaction.ContainsErrors;

>From 3aec41a25df37b0462d7609753ba35bc745dfbc1 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 12 Sep 2025 14:03:53 +0800
Subject: [PATCH 18/29] Fix stdexec regressions (#59)

We may substitute _Fn::template __f (a dependent template name) into
a template-template parameter name, when building a parameter mapping.

They can't have the same NNSLoc, so the assertion doesn't hold.

Also we missed a case when profiling the concept, as in
InjectedClassNameType.
---
 clang/lib/AST/TemplateBase.cpp       |  7 +++++--
 clang/lib/Sema/SemaConcept.cpp       | 15 +++++++++++++++
 clang/test/SemaTemplate/concepts.cpp | 22 ++++++++++++++++++++++
 3 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 76f96fb8c5dcc..d8d6a4f3b08fe 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -606,8 +606,11 @@ TemplateArgumentLoc::TemplateArgumentLoc(ASTContext &Ctx,
       LocInfo(Ctx, TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc) {
   assert(Argument.getKind() == TemplateArgument::Template ||
          Argument.getKind() == TemplateArgument::TemplateExpansion);
-  assert(QualifierLoc.getNestedNameSpecifier() ==
-         Argument.getAsTemplateOrTemplatePattern().getQualifier());
+  // We can't assume QualifierLoc.getNestedNameSpecifier() ==
+  // Argument.getAsTemplateOrTemplatePattern().getQualifier() at this point,
+  // because in template rewriting, we may substitute a DependentTemplateName
+  // (which has a NNSLoc) into a template template parameter (which
+  // doesn't have a NNSLoc).
 }
 
 NestedNameSpecifierLoc TemplateArgumentLoc::getTemplateQualifierLoc() const {
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 476790238384d..970f4798052a6 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -307,6 +307,7 @@ class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
 
 namespace {
 
+// FIXME: Convert it to DynamicRecursiveASTVisitor
 class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
   using inherited = RecursiveASTVisitor<HashParameterMapping>;
   friend inherited;
@@ -390,6 +391,20 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
     return TraverseType(TL.getType(), TraverseQualifier);
   }
 
+  bool TraverseTagType(const TagType *T, bool TraverseQualifier) {
+    // T's parent can be dependent while T doesn't have any template arguments.
+    // We should have already traversed its qualifier.
+    // FIXME: Add an assert to catch cases where we failed to profile the
+    // concept. assert(!T->isDependentType() && "We missed a case in profiling
+    // concepts!");
+    return true;
+  }
+
+  bool TraverseInjectedClassNameType(InjectedClassNameType *T,
+                                     bool TraverseQualifier) {
+    return TraverseTemplateArguments(T->getTemplateArgs(SemaRef.Context));
+  }
+
   bool TraverseTemplateArgument(const TemplateArgument &Arg) {
     if (!Arg.containsUnexpandedParameterPack() || Arg.isPackExpansion()) {
       // Act as if we are fully expanding this pack, if it is a PackExpansion.
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index cbb8b752a90bc..ff453131d8df1 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1287,3 +1287,25 @@ template <class Tb, class Ub> concept A42b = Void<Tb> || A42<Ub>;
 template <class Tc> concept R42c = A42b<Tc, Tc&>;
 static_assert (R42c<void>);
 }
+
+namespace parameter_mapping_regressions {
+
+namespace case1 {
+
+template <template <class> class> using __meval = struct __q;
+template <template <class> class _Tp>
+concept __mvalid = requires { typename __meval<_Tp>; };
+template <class _Fn>
+concept __minvocable = __mvalid<_Fn::template __f>;
+template <class...> struct __mdefer_;
+template <class _Fn, class... _Args>
+  requires __minvocable<_Fn>
+struct __mdefer_<_Fn, _Args...> {};
+template <class = __q> struct __mtransform {
+  template <class> using __f = int;
+};
+struct __completion_domain_or_none_ : __mdefer_<__mtransform<>> {};
+
+}
+
+}

>From aa797121dbed5ebcfb86ac8f20ed0f71c7f46d53 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 12 Sep 2025 08:45:30 +0200
Subject: [PATCH 19/29] more cleanups

---
 clang/include/clang/AST/ASTConcept.h | 1 -
 clang/lib/Sema/SemaConcept.cpp       | 5 +----
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index 9babfd39dd668..9411c4501d621 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -44,7 +44,6 @@ using UnsatisfiedConstraintRecord =
 /// The result of a constraint satisfaction check, containing the necessary
 /// information to diagnose an unsatisfied constraint.
 class ConstraintSatisfaction : public llvm::FoldingSetNode {
-private:
   // The template-like entity that 'owns' the constraint checked here (can be a
   // constrained entity or a concept).
   const NamedDecl *ConstraintOwner = nullptr;
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 970f4798052a6..7c7af193120ba 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -508,10 +508,7 @@ StringRef allocateStringFromConceptDiagnostic(const Sema &S,
   SmallString<128> DiagString;
   DiagString = ": ";
   Diag.EmitToString(S.getDiagnostics(), DiagString);
-  unsigned MessageSize = DiagString.size();
-  char *Mem = new (S.Context) char[MessageSize];
-  memcpy(Mem, DiagString.c_str(), MessageSize);
-  return StringRef(Mem, MessageSize);
+  return S.getASTContext().backupStr(DiagString);
 }
 
 } // namespace

>From 905de976cdff5036c8a468894a757b7dea01492a Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 12 Sep 2025 09:13:51 +0200
Subject: [PATCH 20/29] Release note

---
 clang/docs/ReleaseNotes.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c898784b3f93e..d5459a6087110 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -147,6 +147,10 @@ C++23 Feature Support
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
+- Clang now normalizes constraints before checking their satisfaction, as mandated by the standard.
+  As a result, Clang no longer incorrectly diagnose subsdtitution failures in template arguments only
+  used in concept-ids, and produce better diagnostics for satisfaction failure. (#G61811) (#GH135190)
+
 C++17 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 

>From 7237aaa7610c9968f73ce953a2b6f4c7fc4902c9 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 15 Sep 2025 14:26:20 +0800
Subject: [PATCH 21/29] Use ordinary substitution for parameter mapping (#60)

---
 clang/lib/AST/TemplateBase.cpp             |  7 ++-----
 clang/lib/Sema/SemaConcept.cpp             |  3 ---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 21 +++++++++++----------
 clang/test/SemaTemplate/concepts.cpp       |  8 ++++++++
 4 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index d8d6a4f3b08fe..76f96fb8c5dcc 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -606,11 +606,8 @@ TemplateArgumentLoc::TemplateArgumentLoc(ASTContext &Ctx,
       LocInfo(Ctx, TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc) {
   assert(Argument.getKind() == TemplateArgument::Template ||
          Argument.getKind() == TemplateArgument::TemplateExpansion);
-  // We can't assume QualifierLoc.getNestedNameSpecifier() ==
-  // Argument.getAsTemplateOrTemplatePattern().getQualifier() at this point,
-  // because in template rewriting, we may substitute a DependentTemplateName
-  // (which has a NNSLoc) into a template template parameter (which
-  // doesn't have a NNSLoc).
+  assert(QualifierLoc.getNestedNameSpecifier() ==
+         Argument.getAsTemplateOrTemplatePattern().getQualifier());
 }
 
 NestedNameSpecifierLoc TemplateArgumentLoc::getTemplateQualifierLoc() const {
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 7c7af193120ba..4430cdd06e380 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -2173,9 +2173,6 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
         /*Pattern=*/nullptr,
         /*ForConstraintInstantiation=*/true);
 
-    // Don't build Subst* nodes to model lambda expressions.
-    // The transform of Subst* is oblivious to the lambda type.
-    MLTAL.setKind(TemplateSubstitutionKind::Rewrite);
     return SubstituteParameterMappings(
                SemaRef, &MLTAL, CSE->getTemplateArgsAsWritten(), InFoldExpr)
         .substitute(CC.getNormalizedConstraint());
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index ed3dddf8c6367..35ce977582f5e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2268,15 +2268,6 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
     // We're rewriting the template parameter as a reference to another
     // template parameter.
     Arg = getTemplateArgumentPackPatternForRewrite(Arg);
-    if (Arg.getKind() != TemplateArgument::Expression) {
-      assert(SemaRef.inParameterMappingSubstitution() ||
-             SemaRef.inConstraintSubstitution());
-      ExprResult Expr = SemaRef.BuildExpressionFromNonTypeTemplateArgument(
-          Arg, E->getLocation());
-      if (Expr.isInvalid())
-        return E;
-      Arg = TemplateArgument(Expr.get(), /*IsCanonical=*/false);
-    }
     assert(Arg.getKind() == TemplateArgument::Expression &&
            "unexpected nontype template argument kind in template rewrite");
     // FIXME: This can lead to the same subexpression appearing multiple times
@@ -2498,11 +2489,21 @@ ExprResult
 TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
                                           SubstNonTypeTemplateParmExpr *E) {
   ExprResult SubstReplacement = E->getReplacement();
+  QualType ParamType = E->getParameterType(getSema().Context);
+  bool WasDependentLambda = false;
+  if (auto *RT = dyn_cast<RecordType>(ParamType);
+      RT && RT->getAsCXXRecordDecl())
+    WasDependentLambda = RT->getAsCXXRecordDecl()->isDependentLambda();
   if (!isa<ConstantExpr>(SubstReplacement.get()))
     SubstReplacement = TransformExpr(E->getReplacement());
   if (SubstReplacement.isInvalid())
     return true;
-  QualType SubstType = TransformType(E->getParameterType(getSema().Context));
+  // FIXME: This transform cannot find the instantiated lambda declaration
+  // because lambdas are instantiated in a unique scope.
+  QualType SubstType =
+      WasDependentLambda
+          ? SubstReplacement.get()->getType().getUnqualifiedType()
+          : TransformType(ParamType);
   if (SubstType.isNull())
     return true;
   // The type may have been previously dependent and not now, which means we
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index ff453131d8df1..e543623bac824 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1308,4 +1308,12 @@ struct __completion_domain_or_none_ : __mdefer_<__mtransform<>> {};
 
 }
 
+namespace case2 {
+
+template<auto& Q, class P> concept C = Q.template operator()<P>();
+template<class P> concept E = C<[]<class Ty>{ return false; }, P>;
+static_assert(!E<int>);
+
+}
+
 }

>From e11c377104892d794cd51eeeae9f41631a5e55bf Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 15 Sep 2025 17:22:49 +0200
Subject: [PATCH 22/29] fix typos

---
 clang/docs/ReleaseNotes.rst            | 6 +++---
 clang/include/clang/AST/ASTConcept.h   | 2 +-
 clang/include/clang/Sema/SemaConcept.h | 2 +-
 clang/lib/Sema/SemaConcept.cpp         | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d5459a6087110..c172e58fcb4a2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -147,9 +147,9 @@ C++23 Feature Support
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
-- Clang now normalizes constraints before checking their satisfaction, as mandated by the standard.
-  As a result, Clang no longer incorrectly diagnose subsdtitution failures in template arguments only
-  used in concept-ids, and produce better diagnostics for satisfaction failure. (#G61811) (#GH135190)
+- Clang now normalizes constraints before checking whether they are satisfied, as mandated by the standard.
+  As a result, Clang no longer incorrectly diagnoses substitution failures in template arguments only
+  used in concept-ids, and produces better diagnostics for satisfaction failure. (#GH61811) (#GH135190)
 
 C++17 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index 9411c4501d621..a13fa4bb587c9 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -287,7 +287,7 @@ class TypeConstraint {
   }
 };
 
-/// Insertion operator for diagnostics.  This allows sending TemplateName's
+/// Insertion operator for diagnostics.  This allows sending ConceptReferences's
 /// into a diagnostic with <<.
 const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
                                       const ConceptReference *C);
diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h
index b47814aefa2c0..75647f0fd2e64 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -62,9 +62,9 @@ struct NormalizedConstraint {
       llvm::PointerUnion<const Expr *, const ConceptReference *>;
 
   struct AtomicConstraintBits {
-    LLVM_PREFERRED_TYPE(ConstraintKind)
     // Kind is the first member of all union members,
     // as we rely on their initial common sequence.
+    LLVM_PREFERRED_TYPE(ConstraintKind)
     unsigned Kind : 5;
     unsigned Placeholder : 1;
     unsigned PackSubstitutionIndex : 26;
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 4430cdd06e380..8eb421639896c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -45,7 +45,7 @@
  * template <typename U>
  * concept B = A<U> && __is_same(U, int);
  *
- * The normal form of b is is `__is_same(T, int) /T->U, inner most level/
+ * The normal form of b is is `__is_same(T, int) /T->U, innermost level/
  *                          && __is_same(U, int) {U->U} /T->U, outermost most
  * level/
  *                            `

>From 0eec94be34e048762d502a27b93d73caa61f5f6b Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 16 Sep 2025 18:32:10 +0200
Subject: [PATCH 23/29] fix tests after rebase

---
 clang/test/SemaTemplate/concepts.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index e543623bac824..dc1a84f530d59 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1263,12 +1263,7 @@ C auto x = 0;
 // expected-error@#T_Type {{type 'int' cannot be used prior to '::'}} \
 // expected-note at -1 {{in instantiation of default argument}}
 
-// This will be fixed when we merge https://github.com/llvm/llvm-project/pull/141776
-// Which makes us behave like GCC.
 static_assert(f(0));
-// expected-error at -1 {{no matching function for call}} \
-// expected-note@#GH61824_f {{constraints not satisfied}} \
-// expected-note@#T_Type {{type 'int' cannot be used prior to '::'}}
 
 }
 

>From 8dc536c00aab69e583fe3319c1afaffef8df9acd Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 19 Sep 2025 11:00:50 +0200
Subject: [PATCH 24/29] address some of Erich's feedback

---
 clang/docs/InternalsManual.rst | 59 ++++++++++++++++++++++++++++++++++
 clang/lib/Sema/SemaConcept.cpp |  7 ++--
 2 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index bd742273f4ed5..2a184c4fb77eb 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -2859,6 +2859,65 @@ This library is called by the :ref:`Parser library <Parser>` during parsing to
 do semantic analysis of the input.  For valid programs, Sema builds an AST for
 parsed constructs.
 
+
+Concept Satisfaction Checking and Subsumption
+---------------------------------------------
+
+As per the C++ standard, constraints are
+ `normalized <https://eel.is/c++draft/temp.constr.normal>`_
+and the normal form is used both for subsumption, and constraint checking.
+Both depend on a parameter mapping that substitutes lazily. In particular,
+we should not substitute in unused arguments.
+
+Clang follows the order of operations prescribed by the standard.
+
+Normalization happens prior to satisfaction and subsumption
+and is handled by ``NormalizedConstraint``.
+
+Clang preserves in the normalized form intermediate concept-ids
+(``ConceptIdConstraint``) This is used for diagnostics only and no substitution
+happens in a ConceptIdConstraint if its expression is satisfied.
+
+The normal form of the associated constraints of a declaration is cached in
+Sema::NormalizationCache such that it is only computed once.
+
+a ``NormalizedConstraint`` is a recursive data structure, where each node
+contains a parameter mapping, represented by the indexes of all parameter
+being used.
+
+Checking satisfaction is done by ConstraintSatisfactionChecker, recursively
+walking NormalizedConstraint. At each level, we substitute the outermost
+level of the template arguments referenced in the parameter mapping of a
+normalized expression (``MultiLevelTemplateArgumentList``).
+
+.. code-block:: c++
+
+  template <typename T>
+  concept A = __is_same(T, int);
+
+  template <typename U>
+  concept B = A<U> && __is_same(U, int);
+
+The normal form of B is
+
+.. code-block:: c++
+    __is_same(T, int) /*T->U, innermost level*/
+ && __is_same(U, int) {U->U} /*T->U, outermost most level*/
+
+After substitution in the mapping, we substitute in the constraint expression
+using that copy of the MultiLevelTemplateArgumentList, and then evaluate it.
+
+Because this is expensive, it is cached in
+``UnsubstitutedConstraintSatisfactionCache``.
+
+Any error during satisfaction is recorded in ``ConstraintSatisfaction``.
+for nested requirements, ``ConstraintSatisfaction`` is stored (including
+diagnostics) in the AST, which is something we might want to improve.
+
+When an atomic constraint is not satified, we try to substitute into any
+enclosing concept-id using the same mechanism described above, for
+diagnostics purpose, and inject that in the ``ConstraintSatisfaction``.
+
 .. _CodeGen:
 
 The CodeGen Library
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 8eb421639896c..0a281c8811449 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -31,7 +31,7 @@
  * Sema::NormalizationCache such that it is only computed once.
  *
  * a `NormalizedConstraint` is a recursive data structure, where each node
- * contains a parameter maping, represented by the indexes of all parameter
+ * contains a parameter mapping, represented by the indexes of all parameter
  * being used.
  *
  * Checking satisfaction is done by ConstraintSatisfactionChecker, recursively
@@ -45,7 +45,7 @@
  * template <typename U>
  * concept B = A<U> && __is_same(U, int);
  *
- * The normal form of b is is `__is_same(T, int) /T->U, innermost level/
+ * The normal form of B is is `__is_same(T, int) /T->U, innermost level/
  *                          && __is_same(U, int) {U->U} /T->U, outermost most
  * level/
  *                            `
@@ -635,7 +635,8 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
                                   /*DefaultArguments=*/{},
                                   /*PartialTemplateArgs=*/false, CTAI))
     return std::nullopt;
-  NormalizedConstraint::OccurenceList Used = Constraint.mappingOccurenceList();
+  const NormalizedConstraint::OccurenceList &Used =
+      Constraint.mappingOccurenceList();
   SubstitutedOuterMost =
       llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost());
   unsigned Offset = 0;

>From b01c7f523573622e34f8d0f681ad5eed66066b9e Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 19 Sep 2025 11:08:45 +0200
Subject: [PATCH 25/29] fix rebase

---
 clang/include/clang/AST/ASTContext.h | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index c67efe8795a27..3d086547cf35a 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -51,27 +51,6 @@ class FixedPointSemantics;
 struct fltSemantics;
 template <typename T, unsigned N> class SmallPtrSet;
 
-template <> struct DenseMapInfo<llvm::FoldingSetNodeID> {
-  static FoldingSetNodeID getEmptyKey() { return FoldingSetNodeID{}; }
-
-  static FoldingSetNodeID getTombstoneKey() {
-    FoldingSetNodeID id;
-    for (size_t i = 0; i < sizeof(id) / sizeof(unsigned); ++i) {
-      id.AddInteger(std::numeric_limits<unsigned>::max());
-    }
-    return id;
-  }
-
-  static unsigned getHashValue(const FoldingSetNodeID &Val) {
-    return Val.ComputeHash();
-  }
-
-  static bool isEqual(const FoldingSetNodeID &LHS,
-                      const FoldingSetNodeID &RHS) {
-    return LHS == RHS;
-  }
-};
-
 } // namespace llvm
 
 namespace clang {

>From 56aaa21194c7d8edc65a4f93f0996997cc54c08d Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 19 Sep 2025 11:17:46 +0200
Subject: [PATCH 26/29] remove comment (moved to doc)

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

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 0a281c8811449..5ee417e32e59e 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -10,61 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-/*
- * A note on implementation:
- *
- * As per the C++ standard, constraints are normalized [temp.constr.normal]
- * and the normal form is used both for subsumption, and constraint checking.
- * Both depend on a parameter mapping that substitutes lazily. In particular,
- * we should not substitute in unused arguments.
- *
- * Clang follows the order of operations prescribed by the standard.
- *
- * Normalization happens prior to satisfaction and subsumption
- * and is handled by `NormalizedConstraint`.
- *
- * Clang preserves in the normalized form intermediate concept-ids
- * (ConceptIdConstraint) This is used for diagnostics only and no substitution
- * happens in a ConceptIdConstraint if its expression is satisfied.
- *
- * The normal form of the associated constraints of a declaration is cached in
- * Sema::NormalizationCache such that it is only computed once.
- *
- * a `NormalizedConstraint` is a recursive data structure, where each node
- * contains a parameter mapping, represented by the indexes of all parameter
- * being used.
- *
- * Checking satisfaction is done by ConstraintSatisfactionChecker, recursively
- * walking NormalizedConstraint. At each level, we substitute the outermost
- * level of the template arguments referenced in the parameter mapping of a
- * normalized expression (MultiLevelTemplateArgumentList).
- *
- * template <typename T>
- * concept A = __is_same(T, int);
- *
- * template <typename U>
- * concept B = A<U> && __is_same(U, int);
- *
- * The normal form of B is is `__is_same(T, int) /T->U, innermost level/
- *                          && __is_same(U, int) {U->U} /T->U, outermost most
- * level/
- *                            `
- *
- * After substitution in the mapping, we substitute in the constraint expression
- * using that copy of the MultiLevelTemplateArgumentList, and then evaluate it.
- *
- * Because this is excruciatingly slow, it is cached in
- * `UnsubstitutedConstraintSatisfactionCache`.
- *
- * Any error during satisfaction is recorded in ConstraintSatisfaction.
- * for nested requirements, ConstraintSatisfaction is stored (including
- * diagnostics) in the AST, which is something we might want to improve.
- *
- * When an atomic constraint is not satified, we try to substitute into any
- * enclosing concept-id using the same mechanism described above, for
- * diagnostics purpose, and inject that in the ConstraintSatisfaction.
- */
-
 #include "clang/Sema/SemaConcept.h"
 #include "TreeTransform.h"
 #include "clang/AST/ASTConcept.h"

>From 5454d0082fcea2bcdb94e7e07e2f3321683cb0ae Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 19 Sep 2025 11:45:41 +0200
Subject: [PATCH 27/29] Make sure the SubstitutionDiagnostic alias is used
 consistently

---
 clang/include/clang/AST/ASTConcept.h      | 11 +++++------
 clang/lib/AST/ASTConcept.cpp              |  4 ++--
 clang/lib/AST/ASTImporter.cpp             | 10 +++++-----
 clang/lib/Sema/SemaConcept.cpp            | 11 ++++++-----
 clang/lib/Serialization/ASTReaderStmt.cpp |  5 ++---
 clang/lib/Serialization/ASTWriterStmt.cpp |  4 ++--
 6 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index a13fa4bb587c9..f362f24ebc72a 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -33,13 +33,14 @@ class Expr;
 class NamedDecl;
 struct PrintingPolicy;
 
-/// Pairs of unsatisfied atomic constraint expressions along with the
-/// substituted constraint expr, if the template arguments could be
+/// Unsatisfied constraint expressions if the template arguments could be
 /// substituted into them, or a diagnostic if substitution resulted in
 /// an invalid expression.
+///
+using ConstraintSubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
 using UnsatisfiedConstraintRecord =
     llvm::PointerUnion<const Expr *, const ConceptReference *,
-                       std::pair<SourceLocation, StringRef> *>;
+                       const ConstraintSubstitutionDiagnostic *>;
 
 /// The result of a constraint satisfaction check, containing the necessary
 /// information to diagnose an unsatisfied constraint.
@@ -57,8 +58,6 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
                          ArrayRef<TemplateArgument> TemplateArgs)
       : ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}
 
-  using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
-
   bool IsSatisfied = false;
   bool ContainsErrors = false;
 
@@ -77,7 +76,7 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
 
   bool HasSubstitutionFailure() {
     for (const auto &Detail : Details)
-      if (Detail.dyn_cast<SubstitutionDiagnostic *>())
+      if (Detail.dyn_cast<const ConstraintSubstitutionDiagnostic *>())
         return true;
     return false;
   }
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index d533aac707cbc..fd12bc4e83827 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -33,9 +33,9 @@ CreateUnsatisfiedConstraintRecord(const ASTContext &C,
     new (TrailingObject) UnsatisfiedConstraintRecord(Concept);
   else {
     auto &SubstitutionDiagnostic =
-        *cast<std::pair<SourceLocation, StringRef> *>(Detail);
+        *cast<const clang::ConstraintSubstitutionDiagnostic *>(Detail);
     StringRef Message = C.backupStr(SubstitutionDiagnostic.second);
-    auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
+    auto *NewSubstDiag = new (C) clang::ConstraintSubstitutionDiagnostic(
         SubstitutionDiagnostic.first, Message);
     new (TrailingObject) UnsatisfiedConstraintRecord(NewSubstDiag);
   }
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 7eaae4488d657..f43fa8c90ad3b 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1075,16 +1075,16 @@ Error ASTNodeImporter::ImportConstraintSatisfaction(
           return ToSecondExpr.takeError();
         ToSat.Details.emplace_back(ToSecondExpr.get());
       } else {
-        auto Pair = Record->dyn_cast<std::pair<SourceLocation, StringRef> *>();
+        auto Pair =
+            Record->dyn_cast<const ConstraintSubstitutionDiagnostic *>();
 
         ExpectedSLoc ToPairFirst = import(Pair->first);
         if (!ToPairFirst)
           return ToPairFirst.takeError();
         StringRef ToPairSecond = ImportASTStringRef(Pair->second);
-        ToSat.Details.emplace_back(
-            new (Importer.getToContext())
-                ConstraintSatisfaction::SubstitutionDiagnostic{
-                    ToPairFirst.get(), ToPairSecond});
+        ToSat.Details.emplace_back(new (Importer.getToContext())
+                                       ConstraintSubstitutionDiagnostic{
+                                           ToPairFirst.get(), ToPairSecond});
       }
     }
   }
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 5ee417e32e59e..9af3adbdfc68e 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -509,7 +509,7 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint(
       //  future, to serialize the proper PartialDiagnostic as serializing
       //  it as a string defeats the purpose of the diagnostic mechanism.
       Satisfaction.Details.emplace_back(
-          new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+          new (S.Context) ConstraintSubstitutionDiagnostic{
               SubstDiag.first,
               allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
       Satisfaction.IsSatisfied = false;
@@ -641,7 +641,7 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
 
     PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
     Satisfaction.Details.emplace_back(
-        new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+        new (S.Context) ConstraintSubstitutionDiagnostic{
             SubstitutedAtomicExpr.get()->getBeginLoc(),
             allocateStringFromConceptDiagnostic(S, Msg)});
     return SubstitutedAtomicExpr;
@@ -897,7 +897,7 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     //  it as a string defeats the purpose of the diagnostic mechanism.
     Satisfaction.Details.insert(
         Satisfaction.Details.begin() + Size,
-        new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+        new (S.Context) ConstraintSubstitutionDiagnostic{
             SubstDiag.first,
             allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
     return ExprError();
@@ -1839,8 +1839,9 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
 static void diagnoseUnsatisfiedConstraintExpr(
     Sema &S, const UnsatisfiedConstraintRecord &Record, SourceLocation Loc,
     bool First, concepts::NestedRequirement *Req) {
-  if (auto *Diag = Record.template dyn_cast<
-                   ConstraintSatisfaction::SubstitutionDiagnostic *>()) {
+  if (auto *Diag =
+          Record
+              .template dyn_cast<const ConstraintSubstitutionDiagnostic *>()) {
     if (Req)
       S.Diag(Diag->first, diag::note_nested_requirement_substitution_error)
           << (int)First << Req->getInvalidConstraintEntity() << Diag->second;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index aec86e0986b77..53c144d291a96 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -812,9 +812,8 @@ readConstraintSatisfaction(ASTRecordReader &Record) {
         SourceLocation DiagLocation = Record.readSourceLocation();
         StringRef DiagMessage = C.backupStr(Record.readString());
 
-        Satisfaction.Details.emplace_back(
-            new (C) ConstraintSatisfaction::SubstitutionDiagnostic(
-                DiagLocation, DiagMessage));
+        Satisfaction.Details.emplace_back(new (
+            C) ConstraintSubstitutionDiagnostic(DiagLocation, DiagMessage));
       } else if (Kind == 1) {
         Satisfaction.Details.emplace_back(Record.readExpr());
       } else {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 76f328fe76904..4e2a78108ed82 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -482,8 +482,8 @@ addConstraintSatisfaction(ASTRecordWriter &Record,
   if (!Satisfaction.IsSatisfied) {
     Record.push_back(Satisfaction.NumRecords);
     for (const auto &DetailRecord : Satisfaction) {
-      if (auto *Diag =
-              dyn_cast<std::pair<SourceLocation, StringRef> *>(DetailRecord)) {
+      if (auto *Diag = dyn_cast<const ConstraintSubstitutionDiagnostic *>(
+              DetailRecord)) {
         Record.push_back(/*Kind=*/0);
         Record.AddSourceLocation(Diag->first);
         Record.AddString(Diag->second);

>From f2bf57c8f64a0cc93afdb47aa275ad1cb74c729c Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 19 Sep 2025 11:55:14 +0200
Subject: [PATCH 28/29] fix typos, fix merge

---
 clang/docs/InternalsManual.rst             | 12 +++++++-----
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 21 ++++++++++-----------
 2 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index 2a184c4fb77eb..4c4b8df5e4c99 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -2881,15 +2881,17 @@ happens in a ConceptIdConstraint if its expression is satisfied.
 The normal form of the associated constraints of a declaration is cached in
 Sema::NormalizationCache such that it is only computed once.
 
-a ``NormalizedConstraint`` is a recursive data structure, where each node
+A ``NormalizedConstraint`` is a recursive data structure, where each node
 contains a parameter mapping, represented by the indexes of all parameter
 being used.
 
-Checking satisfaction is done by ConstraintSatisfactionChecker, recursively
-walking NormalizedConstraint. At each level, we substitute the outermost
+Checking satisfaction is done by ``ConstraintSatisfactionChecker``, recursively
+walking ``NormalizedConstraint``. At each level, we substitute the outermost
 level of the template arguments referenced in the parameter mapping of a
 normalized expression (``MultiLevelTemplateArgumentList``).
 
+For the following example,
+
 .. code-block:: c++
 
   template <typename T>
@@ -2902,10 +2904,10 @@ The normal form of B is
 
 .. code-block:: c++
     __is_same(T, int) /*T->U, innermost level*/
- && __is_same(U, int) {U->U} /*T->U, outermost most level*/
+ && __is_same(U, int) {U->U} /*T->U, outermost level*/
 
 After substitution in the mapping, we substitute in the constraint expression
-using that copy of the MultiLevelTemplateArgumentList, and then evaluate it.
+using that copy of the ``MultiLevelTemplateArgumentList``, and then evaluate it.
 
 Because this is expensive, it is cached in
 ``UnsubstitutedConstraintSatisfactionCache``.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 35ce977582f5e..8a723d0cc4d6b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2489,23 +2489,22 @@ ExprResult
 TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
                                           SubstNonTypeTemplateParmExpr *E) {
   ExprResult SubstReplacement = E->getReplacement();
-  QualType ParamType = E->getParameterType(getSema().Context);
-  bool WasDependentLambda = false;
-  if (auto *RT = dyn_cast<RecordType>(ParamType);
-      RT && RT->getAsCXXRecordDecl())
-    WasDependentLambda = RT->getAsCXXRecordDecl()->isDependentLambda();
   if (!isa<ConstantExpr>(SubstReplacement.get()))
     SubstReplacement = TransformExpr(E->getReplacement());
   if (SubstReplacement.isInvalid())
     return true;
-  // FIXME: This transform cannot find the instantiated lambda declaration
-  // because lambdas are instantiated in a unique scope.
-  QualType SubstType =
-      WasDependentLambda
-          ? SubstReplacement.get()->getType().getUnqualifiedType()
-          : TransformType(ParamType);
+  QualType SubstType = TransformType(E->getParameterType(getSema().Context));
   if (SubstType.isNull())
     return true;
+  // FIXME: The type transform cannot find the instantiated lambda declaration
+  // because lambdas are instantiated in a unique scope. So use the Type of
+  // SubstReplacement to avoid creating incorrect dependent expressions.
+  if (QualType Type = SubstReplacement.get()->getType();
+      SubstType->isDependentType() && !Type->isDependentType() &&
+      // This ensures that ImpCastExpr is unnecessary, which is built by
+      // CheckTemplateArgument.
+      SubstType == E->getReplacement()->getType())
+    SubstType = Type;
   // The type may have been previously dependent and not now, which means we
   // might have to implicit cast the argument to the new type, for example:
   // template<auto T, decltype(T) U>

>From 99b62f00de4c0f35351a301f22ddef4a7fb70331 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Fri, 19 Sep 2025 12:06:43 +0200
Subject: [PATCH 29/29] fix docs

---
 clang/docs/InternalsManual.rst | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index 4c4b8df5e4c99..ab73f19d1ecc8 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -2863,8 +2863,7 @@ parsed constructs.
 Concept Satisfaction Checking and Subsumption
 ---------------------------------------------
 
-As per the C++ standard, constraints are
- `normalized <https://eel.is/c++draft/temp.constr.normal>`_
+As per the C++ standard, constraints are `normalized <https://eel.is/c++draft/temp.constr.normal>`_
 and the normal form is used both for subsumption, and constraint checking.
 Both depend on a parameter mapping that substitutes lazily. In particular,
 we should not substitute in unused arguments.



More information about the libcxx-commits mailing list