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

>From 4c24d35b9592a815d31ed590deadaa36d0414396 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Fri, 9 Oct 2026 12:32:41 +0800
Subject: [PATCH 1/2] [Clang] Improve ConstraintSatisfaction

---
 clang/include/clang/AST/ASTConcept.h          | 49 +++++++++----------
 clang/include/clang/AST/ExprConcepts.h        |  4 +-
 clang/include/clang/Sema/Sema.h               |  7 +--
 clang/lib/AST/ASTConcept.cpp                  | 12 ++---
 clang/lib/AST/ASTImporter.cpp                 |  4 +-
 clang/lib/AST/ComputeDependence.cpp           |  2 +-
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp |  2 +-
 clang/lib/Sema/Sema.cpp                       |  8 +--
 clang/lib/Sema/SemaConcept.cpp                | 12 ++---
 clang/lib/Sema/SemaDeclCXX.cpp                |  2 +-
 clang/lib/Sema/SemaExprCXX.cpp                | 10 +---
 clang/lib/Sema/TreeTransform.h                |  4 +-
 clang/lib/Serialization/ASTWriterStmt.cpp     |  8 +--
 13 files changed, 52 insertions(+), 72 deletions(-)

diff --git a/clang/include/clang/AST/ASTConcept.h 
b/clang/include/clang/AST/ASTConcept.h
index 62fe2c0f653d57..71a16931d6b3d0 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -44,31 +44,15 @@ using UnsatisfiedConstraintRecord =
 
 /// The result of a constraint satisfaction check, containing the necessary
 /// information to diagnose an unsatisfied constraint.
-class ConstraintSatisfaction : public llvm::FoldingSetNode {
-  // The template-like entity that 'owns' the constraint checked here (can be a
-  // constrained entity or a concept).
-  const NamedDecl *ConstraintOwner = nullptr;
-  llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
-
+class ConstraintSatisfaction {
 public:
-
-  ConstraintSatisfaction() = default;
-
-  ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
-                         ArrayRef<TemplateArgument> TemplateArgs)
-      : ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}
-
   bool IsSatisfied = false;
   bool ContainsErrors = false;
 
   /// \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<UnsatisfiedConstraintRecord, 4> Details;
-
-  void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
-    Profile(ID, C, ConstraintOwner, TemplateArgs);
-  }
+  llvm::SmallVector<UnsatisfiedConstraintRecord, 1> Details;
 
   static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
                       const NamedDecl *ConstraintOwner,
@@ -86,13 +70,24 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
 /// necessary information to diagnose an unsatisfied constraint.
 ///
 /// This is safe to store in an AST node, as opposed to ConstraintSatisfaction.
-struct ASTConstraintSatisfaction final :
-    llvm::TrailingObjects<ASTConstraintSatisfaction,
-                          UnsatisfiedConstraintRecord> {
-  std::size_t NumRecords;
+class ASTConstraintSatisfaction final
+    : llvm::TrailingObjects<ASTConstraintSatisfaction,
+                            UnsatisfiedConstraintRecord> {
+  friend TrailingObjects;
+  friend class ASTStmtWriter;
+  friend class ASTStmtReader;
+
+  unsigned NumRecords : 30;
   bool IsSatisfied : 1;
   bool ContainsErrors : 1;
 
+  ASTConstraintSatisfaction(const ASTContext &C,
+                            const ConstraintSatisfaction &Satisfaction);
+
+  ASTConstraintSatisfaction(const ASTContext &C,
+                            const ASTConstraintSatisfaction &Satisfaction);
+
+public:
   const UnsatisfiedConstraintRecord *begin() const {
     return getTrailingObjects();
   }
@@ -105,13 +100,15 @@ struct ASTConstraintSatisfaction final :
     return {begin(), end()};
   }
 
-  ASTConstraintSatisfaction(const ASTContext &C,
-                            const ConstraintSatisfaction &Satisfaction);
-  ASTConstraintSatisfaction(const ASTContext &C,
-                            const ASTConstraintSatisfaction &Satisfaction);
+  bool isSatisfied() const { return IsSatisfied; }
+
+  bool containsErrors() const { return ContainsErrors; }
+
+  unsigned record_size() const { return NumRecords; }
 
   static ASTConstraintSatisfaction *
   Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
+
   static ASTConstraintSatisfaction *
   Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction);
 };
diff --git a/clang/include/clang/AST/ExprConcepts.h 
b/clang/include/clang/AST/ExprConcepts.h
index 18ce5a94ebef3c..7d977069e80964 100644
--- a/clang/include/clang/AST/ExprConcepts.h
+++ b/clang/include/clang/AST/ExprConcepts.h
@@ -128,7 +128,7 @@ class ConceptSpecializationExpr final : public Expr {
   bool isSatisfied() const {
     assert(!isValueDependent() &&
            "isSatisfied called on a dependent ConceptSpecializationExpr");
-    return Satisfaction->IsSatisfied;
+    return Satisfaction->isSatisfied();
   }
 
   /// \brief Get elaborated satisfaction info about the template arguments'
@@ -463,7 +463,7 @@ class NestedRequirement : public Requirement {
       : Requirement(RK_Nested,
                     /*IsDependent=*/false,
                     /*ContainsUnexpandedParameterPack*/ false,
-                    Satisfaction->IsSatisfied),
+                    Satisfaction->isSatisfied()),
         Satisfaction(Satisfaction), HasInvalidConstraint(true),
         InvalidConstraintEntity(InvalidConstraintEntity) {}
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0864337a9374c6..e33d15c11cd757 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -115,7 +115,7 @@ struct InlineAsmIdentifierInfo;
 namespace clang {
 class ADLResult;
 class APValue;
-struct ASTConstraintSatisfaction;
+class ASTConstraintSatisfaction;
 class ASTConsumer;
 class ASTContext;
 class ASTDeclReader;
@@ -8883,9 +8883,6 @@ class Sema final : public SemaBase {
   concepts::TypeRequirement *BuildTypeRequirement(
       concepts::Requirement::SubstitutionDiagnostic *SubstDiag);
   concepts::NestedRequirement *BuildNestedRequirement(Expr *E);
-  concepts::NestedRequirement *
-  BuildNestedRequirement(StringRef InvalidConstraintEntity,
-                         const ASTConstraintSatisfaction &Satisfaction);
   ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc,
                                RequiresExprBodyDecl *Body,
                                SourceLocation LParenLoc,
@@ -15165,7 +15162,7 @@ class Sema final : public SemaBase {
 
   /// Cache whether the associated constraint of a declaration
   /// is satisfied.
-  llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
+  llvm::DenseMap<llvm::FoldingSetNodeID, ConstraintSatisfaction *>
       SatisfactionCache;
 
   // The current stack of constraint satisfactions, so we can exit-early.
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 2b04821a157da4..ee8ef848cebe09 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -43,9 +43,9 @@ CreateUnsatisfiedConstraintRecord(const ASTContext &C,
 
 ASTConstraintSatisfaction::ASTConstraintSatisfaction(
     const ASTContext &C, const ConstraintSatisfaction &Satisfaction)
-    : NumRecords{Satisfaction.Details.size()},
-      IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{
-                                                 Satisfaction.ContainsErrors} {
+    : NumRecords(Satisfaction.Details.size()),
+      IsSatisfied(Satisfaction.IsSatisfied),
+      ContainsErrors(Satisfaction.ContainsErrors) {
   for (unsigned I = 0; I < NumRecords; ++I)
     CreateUnsatisfiedConstraintRecord(C, Satisfaction.Details[I],
                                       getTrailingObjects() + I);
@@ -53,9 +53,9 @@ ASTConstraintSatisfaction::ASTConstraintSatisfaction(
 
 ASTConstraintSatisfaction::ASTConstraintSatisfaction(
     const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction)
-    : NumRecords{Satisfaction.NumRecords},
-      IsSatisfied{Satisfaction.IsSatisfied},
-      ContainsErrors{Satisfaction.ContainsErrors} {
+    : NumRecords(Satisfaction.NumRecords),
+      IsSatisfied(Satisfaction.IsSatisfied),
+      ContainsErrors(Satisfaction.ContainsErrors) {
   for (unsigned I = 0; I < NumRecords; ++I)
     CreateUnsatisfiedConstraintRecord(C, *(Satisfaction.begin() + I),
                                       getTrailingObjects() + I);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 22c3af47f451f6..10ee9b75afec0f 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1075,8 +1075,8 @@ StringRef ASTNodeImporter::ImportASTStringRef(StringRef 
FromStr) {
 
 Error ASTNodeImporter::ImportConstraintSatisfaction(
     const ASTConstraintSatisfaction &FromSat, ConstraintSatisfaction &ToSat) {
-  ToSat.IsSatisfied = FromSat.IsSatisfied;
-  ToSat.ContainsErrors = FromSat.ContainsErrors;
+  ToSat.IsSatisfied = FromSat.isSatisfied();
+  ToSat.ContainsErrors = FromSat.containsErrors();
   if (!ToSat.IsSatisfied) {
     for (auto Record = FromSat.begin(); Record != FromSat.end(); ++Record) {
       if (const Expr *E = Record->dyn_cast<const Expr *>()) {
diff --git a/clang/lib/AST/ComputeDependence.cpp 
b/clang/lib/AST/ComputeDependence.cpp
index 7ea1c67ff77389..c4bf3681a79122 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -955,7 +955,7 @@ ExprDependence 
clang::computeDependence(ConceptSpecializationExpr *E,
   ExprDependence D =
       ValueDependent ? ExprDependence::Value : ExprDependence::None;
   auto Res = D | toExprDependence(TA);
-  if(!ValueDependent && E->getSatisfaction().ContainsErrors)
+  if (!ValueDependent && E->getSatisfaction().containsErrors())
     Res |= ExprDependence::Error;
   return Res;
 }
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index e49b1cba7b1dde..54d5e3eba66af8 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -433,7 +433,7 @@ 
TemplateParameterListBuilder::constructConceptSpecializationExpr(
   // Constraint satisfaction is used to construct the
   // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
   // located at the bottom of the sample AST above.
-  const ConstraintSatisfaction CS(CD, {ConceptTA});
+  ConstraintSatisfaction CS;
   TemplateArgumentLoc TAL =
       S.getTrivialTemplateArgumentLoc(ConceptTA, QualType(), SourceLocation());
 
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 21f71d7f8b40e2..25ead1308c537a 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -328,7 +328,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer 
&consumer,
       GlobalNewDeleteDeclared(false), DisableTypoCorrection(false),
       TyposCorrected(0), IsBuildingRecoveryCallExpr(false),
       CurrentInstantiationScope(nullptr), NonInstantiationEntries(0),
-      ArgPackSubstIndex(std::nullopt), SatisfactionCache(Context) {
+      ArgPackSubstIndex(std::nullopt) {
   assert(pp.TUKind == TUKind);
   TUScope = nullptr;
 
@@ -626,11 +626,7 @@ Sema::~Sema() {
     ExternalSema->ForgetSema();
 
   // Delete cached satisfactions.
-  std::vector<ConstraintSatisfaction *> Satisfactions;
-  Satisfactions.reserve(SatisfactionCache.size());
-  for (auto &Node : SatisfactionCache)
-    Satisfactions.push_back(&Node);
-  for (auto *Node : Satisfactions)
+  for (auto [_, Node] : SatisfactionCache)
     delete Node;
 
   threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index fb66bdd6d2bd04..15b6b9c0c8b396 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1323,14 +1323,12 @@ bool Sema::CheckConstraintSatisfaction(
 
   llvm::FoldingSetNodeID ID;
   ConstraintSatisfaction::Profile(ID, Context, Owner, FlattenedArgs);
-  llvm::FoldingSetInsertToken Token;
-  if (auto *Cached = SatisfactionCache.lookup(ID, Token)) {
+  if (auto *Cached = SatisfactionCache.lookup(ID)) {
     OutSatisfaction = *Cached;
     return false;
   }
 
-  auto Satisfaction =
-      std::make_unique<ConstraintSatisfaction>(Owner, FlattenedArgs);
+  auto Satisfaction = std::make_unique<ConstraintSatisfaction>();
   if (::CheckConstraintSatisfaction(
           *this, Template, AssociatedConstraints, TemplateArgsLists,
           TemplateIDRange, *Satisfaction, ConvertedExpr, TopLevelConceptId)) {
@@ -1338,7 +1336,7 @@ bool Sema::CheckConstraintSatisfaction(
     return true;
   }
 
-  if (auto *Cached = SatisfactionCache.lookup(ID, Token)) {
+  if (auto *Cached = SatisfactionCache.lookup(ID)) {
     // The evaluation of this constraint resulted in us trying to re-evaluate 
it
     // recursively. This isn't really possible, except we try to form a
     // RecoveryExpr as a part of the evaluation.  If this is the case, just
@@ -1354,7 +1352,7 @@ bool Sema::CheckConstraintSatisfaction(
   // Else we can simply add this satisfaction to the list.
   OutSatisfaction = *Satisfaction;
   // Note that entries of SatisfactionCache are deleted in Sema's destructor.
-  SatisfactionCache.insert(Satisfaction.release());
+  SatisfactionCache.insert({ID, Satisfaction.release()});
   return false;
 }
 
@@ -2060,7 +2058,7 @@ void Sema::DiagnoseUnsatisfiedConstraint(
   const ASTConstraintSatisfaction &Satisfaction =
       ConstraintExpr->getSatisfaction();
 
-  assert(!Satisfaction.IsSatisfied &&
+  assert(!Satisfaction.isSatisfied() &&
          "Attempted to diagnose a satisfied constraint");
 
   ::DiagnoseUnsatisfiedConstraint(*this, Satisfaction.records(),
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ea628f29d8a005..af8e53d4aea2ed 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18092,7 +18092,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation 
StaticAssertLoc,
               dyn_cast_or_null<ConceptSpecializationExpr>(InnerCond)) {
         const ASTConstraintSatisfaction &Satisfaction =
             ConceptIDExpr->getSatisfaction();
-        if (!Satisfaction.ContainsErrors || Satisfaction.NumRecords) {
+        if (!Satisfaction.containsErrors() || Satisfaction.record_size()) {
           Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
               << !HasMessage << Msg.str() << AssertExpr->getSourceRange();
           // Drill down into concept specialization expressions to see why they
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index deb7bdd09fdc7d..e65b8240255c96 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8121,7 +8121,7 @@ Sema::BuildExprRequirement(
     if (!HasError) {
       SubstitutedConstraintExpr =
           cast<ConceptSpecializationExpr>(Constraint.get());
-      if (SubstitutedConstraintExpr->getSatisfaction().ContainsErrors)
+      if (SubstitutedConstraintExpr->getSatisfaction().containsErrors())
         HasError = true;
     }
     if (HasError) {
@@ -8191,14 +8191,6 @@ Sema::BuildNestedRequirement(Expr *Constraint) {
                                                    Satisfaction);
 }
 
-concepts::NestedRequirement *
-Sema::BuildNestedRequirement(StringRef InvalidConstraintEntity,
-                       const ASTConstraintSatisfaction &Satisfaction) {
-  return new (Context) concepts::NestedRequirement(
-      InvalidConstraintEntity,
-      ASTConstraintSatisfaction::Rebuild(Context, Satisfaction));
-}
-
 RequiresExprBodyDecl *
 Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
                              ArrayRef<ParmVarDecl *> LocalParameters,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c8458fda58a88e..841228d9272050 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3872,8 +3872,8 @@ class TreeTransform {
   concepts::NestedRequirement *
   RebuildNestedRequirement(StringRef InvalidConstraintEntity,
                            const ASTConstraintSatisfaction &Satisfaction) {
-    return SemaRef.BuildNestedRequirement(InvalidConstraintEntity,
-                                          Satisfaction);
+    return new (getSema().Context)
+        concepts::NestedRequirement(InvalidConstraintEntity, &Satisfaction);
   }
 
   concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index 513c832c38ffd9..dea4d34fb73f80 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -490,10 +490,10 @@ void 
ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
 static void
 addConstraintSatisfaction(ASTRecordWriter &Record,
                           const ASTConstraintSatisfaction &Satisfaction) {
-  Record.push_back(Satisfaction.IsSatisfied);
-  Record.push_back(Satisfaction.ContainsErrors);
-  if (!Satisfaction.IsSatisfied) {
-    Record.push_back(Satisfaction.NumRecords);
+  Record.push_back(Satisfaction.isSatisfied());
+  Record.push_back(Satisfaction.containsErrors());
+  if (!Satisfaction.isSatisfied()) {
+    Record.push_back(Satisfaction.record_size());
     for (const auto &DetailRecord : Satisfaction) {
       if (auto *Diag = dyn_cast<const ConstraintSubstitutionDiagnostic *>(
               DetailRecord)) {

>From 2e21c48624922a0d57d1f56e6f16119f4a7150a9 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Fri, 9 Oct 2026 19:09:26 +0800
Subject: [PATCH 2/2] Remove duplicate cache lookup

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

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 15b6b9c0c8b396..b02faa5f8ff957 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -597,9 +597,11 @@ class ConstraintSatisfactionChecker {
       auto &Cached = Iter->second.Satisfaction;
       Satisfaction.ContainsErrors = Cached.ContainsErrors;
       Satisfaction.IsSatisfied = Cached.IsSatisfied;
-      Satisfaction.Details.insert(Satisfaction.Details.begin() +
-                                      PreviousDetailsSize,
-                                  Cached.Details.begin(), 
Cached.Details.end());
+      SmallVector<UnsatisfiedConstraintRecord, 1> Details(
+          Satisfaction.Details.begin(),
+          Satisfaction.Details.begin() + PreviousDetailsSize);
+      Details.append(Cached.Details.begin(), Cached.Details.end());
+      std::swap(Details, Satisfaction.Details);
       return &Iter->second;
     }
 
@@ -1336,23 +1338,12 @@ bool Sema::CheckConstraintSatisfaction(
     return true;
   }
 
-  if (auto *Cached = SatisfactionCache.lookup(ID)) {
-    // The evaluation of this constraint resulted in us trying to re-evaluate 
it
-    // recursively. This isn't really possible, except we try to form a
-    // RecoveryExpr as a part of the evaluation.  If this is the case, just
-    // return the 'cached' version (which will have the same result), and save
-    // ourselves the extra-insert. If it ever becomes possible to legitimately
-    // recursively check a constraint, we should skip checking the 'inner' one
-    // above, and replace the cached version with this one, as it would be more
-    // specific.
-    OutSatisfaction = *Cached;
-    return false;
-  }
-
   // Else we can simply add this satisfaction to the list.
   OutSatisfaction = *Satisfaction;
   // Note that entries of SatisfactionCache are deleted in Sema's destructor.
-  SatisfactionCache.insert({ID, Satisfaction.release()});
+  auto [Iter, Inserted] = SatisfactionCache.insert({ID, nullptr});
+  if (Inserted)
+    Iter->second = Satisfaction.release();
   return false;
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to