https://github.com/MaskRay updated 
https://github.com/llvm/llvm-project/pull/220168

>From 1f777e49c3e3423f158cf5f9a876fb9f9762c43e Mon Sep 17 00:00:00 2001
From: Fangrui Song <[email protected]>
Date: Mon, 31 Aug 2026 23:42:33 -0700
Subject: [PATCH 1/2] [clang] Fix FoldingSet lookups that disagree with the
 node's Profile

Some clang code calls FoldingSetImpl::insert with a node whose profile
doesn't match its insert token, leading to missing hash-consing.

* getObjCTypeParamType keys on Decl->getUnderlyingType() where Profile()
  reports getCanonicalTypeInternal().  Canonicalize before the lookup: the
  decl's underlying type can be updated later.
* getUnaryTransformType drops UnderlyingType for a dependent base after
  building the ID.
* getFunctionTypeInternal keys canonically where Profile() passes
  isCanonicalUnqualified(), which differs for a computed noexcept.
* getConstantArrayType keys on the full index qualifiers; only the three CVR
  bits are stored.
* LoanManager keys a PlaceholderBase on the bare decl pointer where Profile()
  reports the PointerUnion's opaque value.

These issues would be caught by #220166

Aided by Opus 5
---
 .../Analysis/Analyses/LifetimeSafety/Loans.h  |  6 +++-
 clang/lib/AST/ASTContext.cpp                  | 31 ++++++++++++-------
 clang/lib/AST/Type.cpp                        |  4 ++-
 clang/lib/Analysis/LifetimeSafety/Loans.cpp   |  4 +--
 4 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h
index 8137a207290d7..784968789d40a 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Loans.h
@@ -89,9 +89,13 @@ class PlaceholderBase : public llvm::FoldingSetNode {
     return ParamOrMethod.dyn_cast<const CXXMethodDecl *>();
   }
 
-  void Profile(llvm::FoldingSetNodeID &ID) const {
+  using KeyTy = llvm::PointerUnion<const ParmVarDecl *, const CXXMethodDecl *>;
+
+  static void Profile(llvm::FoldingSetNodeID &ID, KeyTy ParamOrMethod) {
     ID.AddPointer(ParamOrMethod.getOpaqueValue());
   }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, ParamOrMethod); 
}
 };
 
 /// Represents the storage location being borrowed, e.g., a specific stack
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b7e771595e86e..819e2527a26d5 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4287,6 +4287,10 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
   llvm::APInt ArySize(ArySizeIn);
   ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());
 
+  // The type stores only the CVR bits of the index qualifiers, so key on
+  // those.
+  IndexTypeQuals &= Qualifiers::CVRMask;
+
   llvm::FoldingSetNodeID ID;
   ConstantArrayType::Profile(ID, *this, EltTy, ArySize.getZExtValue(), 
SizeExpr,
                              ASM, IndexTypeQuals);
@@ -5701,8 +5705,8 @@ UnresolvedUsingType 
*ASTContext::getUnresolvedUsingTypeInternal(
   auto *T = new (Mem) UnresolvedUsingType(Keyword, Qualifier, D, 
CanonicalType);
   if (Token) {
     auto *Placeholder = new (T->getFoldingSetPlaceholder())
-        FoldingSetPlaceholder<TypedefType>();
-    TypedefTypes.insert(Placeholder, Token);
+        FoldingSetPlaceholder<UnresolvedUsingType>();
+    UnresolvedUsingTypes.insert(Placeholder, Token);
   }
   Types.push_back(T);
   return T;
@@ -6534,13 +6538,6 @@ ASTContext::applyObjCProtocolQualifiers(QualType type,
 QualType
 ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
                                  ArrayRef<ObjCProtocolDecl *> protocols) const 
{
-  // Look in the folding set for an existing type.
-  llvm::FoldingSetNodeID ID;
-  ObjCTypeParamType::Profile(ID, Decl, Decl->getUnderlyingType(), protocols);
-  llvm::FoldingSetInsertToken Token;
-  if (ObjCTypeParamType *TypeParam = ObjCTypeParamTypes.lookup(ID, Token))
-    return QualType(TypeParam, 0);
-
   // We canonicalize to the underlying type.
   QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
   if (!protocols.empty()) {
@@ -6551,6 +6548,14 @@ ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl 
*Decl,
     assert(!hasError && "Error when apply protocol qualifier to bound type");
   }
 
+  // Key on the canonical type the node is constructed with, which is what
+  // Profile() reports; the decl's underlying type can be updated later.
+  llvm::FoldingSetNodeID ID;
+  ObjCTypeParamType::Profile(ID, Decl, Canonical, protocols);
+  llvm::FoldingSetInsertToken Token;
+  if (ObjCTypeParamType *TypeParam = ObjCTypeParamTypes.lookup(ID, Token))
+    return QualType(TypeParam, 0);
+
   unsigned size = sizeof(ObjCTypeParamType);
   size += protocols.size() * sizeof(ObjCProtocolDecl *);
   void *mem = Allocate(size, alignof(ObjCTypeParamType));
@@ -6837,6 +6842,12 @@ QualType ASTContext::getPackIndexingType(QualType 
Pattern, Expr *IndexExpr,
 QualType
 ASTContext::getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
                                   UnaryTransformType::UTTKind Kind) const {
+  // Clear UnderlyingType for a dependent base before building the ID: that is
+  // what the node is constructed with, and what Profile() reports.
+  if (BaseType->isDependentType()) {
+    assert(UnderlyingType.isNull() || BaseType == UnderlyingType);
+    UnderlyingType = QualType();
+  }
 
   llvm::FoldingSetNodeID ID;
   UnaryTransformType::Profile(ID, BaseType, UnderlyingType, Kind);
@@ -6849,8 +6860,6 @@ ASTContext::getUnaryTransformType(QualType BaseType, 
QualType UnderlyingType,
   if (!BaseType->isDependentType()) {
     CanonType = UnderlyingType.getCanonicalType();
   } else {
-    assert(UnderlyingType.isNull() || BaseType == UnderlyingType);
-    UnderlyingType = QualType();
     if (QualType CanonBase = BaseType.getCanonicalType();
         BaseType != CanonBase) {
       CanonType = getUnaryTransformType(CanonBase, QualType(), Kind);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index df296eb4e28e5..f1f8d79fba957 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4115,8 +4115,10 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID 
&ID, QualType Result,
 
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
                                 const ASTContext &Ctx) {
+  // getFunctionTypeInternal keys every node canonically and compares noexcept
+  // expressions after the lookup, so report that same key.
   Profile(ID, getReturnType(), param_type_begin(), getNumParams(),
-          getExtProtoInfo(), Ctx, isCanonicalUnqualified());
+          getExtProtoInfo(), Ctx, /*Canonical=*/true);
 }
 
 TypeCoupledDeclRefInfo::TypeCoupledDeclRefInfo(ValueDecl *D, bool Deref)
diff --git a/clang/lib/Analysis/LifetimeSafety/Loans.cpp 
b/clang/lib/Analysis/LifetimeSafety/Loans.cpp
index 3a850ca8a9b74..e6cbd922d20c7 100644
--- a/clang/lib/Analysis/LifetimeSafety/Loans.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Loans.cpp
@@ -38,7 +38,7 @@ void Loan::dump(llvm::raw_ostream &OS) const {
 const PlaceholderBase *
 LoanManager::getOrCreatePlaceholderBase(const ParmVarDecl *PVD) {
   llvm::FoldingSetNodeID ID;
-  ID.AddPointer(PVD);
+  PlaceholderBase::Profile(ID, PVD);
   llvm::FoldingSetInsertToken InsertToken;
   if (PlaceholderBase *Existing = PlaceholderBases.lookup(ID, InsertToken))
     return Existing;
@@ -52,7 +52,7 @@ LoanManager::getOrCreatePlaceholderBase(const ParmVarDecl 
*PVD) {
 const PlaceholderBase *
 LoanManager::getOrCreatePlaceholderBase(const CXXMethodDecl *MD) {
   llvm::FoldingSetNodeID ID;
-  ID.AddPointer(MD);
+  PlaceholderBase::Profile(ID, MD);
   llvm::FoldingSetInsertToken InsertToken;
   if (PlaceholderBase *Existing = PlaceholderBases.lookup(ID, InsertToken))
     return Existing;

>From 6c01976709f0d063f91053362b99fd6bd2eaf1e8 Mon Sep 17 00:00:00 2001
From: Fangrui Song <[email protected]>
Date: Wed, 2 Sep 2026 22:57:25 -0700
Subject: [PATCH 2/2] simplify FunctionProtoType::Profile; remove `bool
 Canonical`

---
 clang/include/clang/AST/TypeBase.h |  3 +--
 clang/lib/AST/ASTContext.cpp       |  2 +-
 clang/lib/AST/Type.cpp             | 10 +++++-----
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index e69173a1fdd6c..cdbd20b62bac5 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6011,8 +6011,7 @@ class FunctionProtoType final
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
   static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
                       param_type_iterator ArgTys, unsigned NumArgs,
-                      const ExtProtoInfo &EPI, const ASTContext &Context,
-                      bool Canonical);
+                      const ExtProtoInfo &EPI, const ASTContext &Context);
 };
 
 /// The elaboration keyword that precedes a qualified type name or
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 819e2527a26d5..f1f51a7976321 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5070,7 +5070,7 @@ QualType ASTContext::getFunctionTypeInternal(
   // structure.
   llvm::FoldingSetNodeID ID;
   FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI,
-                             *this, true);
+                             *this);
 
   QualType Canonical;
   bool Unique = false;
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index f1f8d79fba957..4b539b7c2b1f6 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4047,7 +4047,7 @@ bool FunctionProtoType::isTemplateVariadic() const {
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
                                 const QualType *ArgTys, unsigned NumParams,
                                 const ExtProtoInfo &epi,
-                                const ASTContext &Context, bool Canonical) {
+                                const ASTContext &Context) {
   // We have to be careful not to get ambiguous profile encodings.
   // Note that valid type pointers are never ambiguous with anything else.
   //
@@ -4086,7 +4086,9 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID 
&ID, QualType Result,
     for (QualType Ex : epi.ExceptionSpec.Exceptions)
       ID.AddPointer(Ex.getAsOpaquePtr());
   } else if (isComputedNoexcept(epi.ExceptionSpec.Type)) {
-    epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical);
+    // getFunctionTypeInternal compares noexcept expressions after the lookup,
+    // so the key only needs their canonical form.
+    epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, /*Canonical=*/true);
   } else if (epi.ExceptionSpec.Type == EST_Uninstantiated ||
              epi.ExceptionSpec.Type == EST_Unevaluated) {
     ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl());
@@ -4115,10 +4117,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID 
&ID, QualType Result,
 
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
                                 const ASTContext &Ctx) {
-  // getFunctionTypeInternal keys every node canonically and compares noexcept
-  // expressions after the lookup, so report that same key.
   Profile(ID, getReturnType(), param_type_begin(), getNumParams(),
-          getExtProtoInfo(), Ctx, /*Canonical=*/true);
+          getExtProtoInfo(), Ctx);
 }
 
 TypeCoupledDeclRefInfo::TypeCoupledDeclRefInfo(ValueDecl *D, bool Deref)

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

Reply via email to