https://github.com/qiongsiwu updated 
https://github.com/llvm/llvm-project/pull/200961

>From b2ffa916c4b4f43183fb90a47548f08e2986882b Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Mon, 1 Jun 2026 14:54:21 -0700
Subject: [PATCH 1/2] Fixing attributed type deduplication.

---
 clang/include/clang/AST/Attr.h                 | 12 ++++++++++++
 clang/include/clang/AST/TypeBase.h             |  8 +-------
 clang/include/clang/Basic/Attr.td              |  5 +++++
 clang/lib/AST/Type.cpp                         | 11 +++++++++++
 .../AST/attributed-type-dedup-nullability.m    | 18 ++++++++++++++++++
 .../AST/attributed-type-dedup-swift-attr.m     | 15 +++++++++++++++
 6 files changed, 62 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/AST/attributed-type-dedup-nullability.m
 create mode 100644 clang/test/AST/attributed-type-dedup-swift-attr.m

diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 0f9fc01391c30..df2da85cf6402 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -81,6 +81,8 @@ class Attr : public AttributeCommonInfo {
     return ::operator delete(Ptr, C, Alignment);
   }
 
+  virtual ~Attr() = default;
+
 protected:
   Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
        attr::Kind AK, bool IsLateParsed)
@@ -120,6 +122,16 @@ class Attr : public AttributeCommonInfo {
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
   static StringRef getDocumentation(attr::Kind);
+
+  // Contribute Attr-specific content to a FoldingSetNodeID for callers like
+  // AttributedType::Profile that dedupe nodes by Attr identity. The default
+  // is empty: AttributedType::Profile already hashes attrKind (and
+  // asserts attr->getKind() == attrKind), so a no-op default makes stateless
+  // Attrs (nullability, ARC ownership, calling conventions, ...) dedupe by
+  // (kind, modified, equivalent) — pointer identity of the Attr is ignored.
+  // Override this in subclasses whose arguments meaningfully distinguish
+  // the wrapped type (e.g. SwiftAttrAttr hashes its string payload).
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const {}
 };
 
 class TypeAttr : public Attr {
diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index c64eee11fd91e..cce7af88181cd 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6746,13 +6746,7 @@ class AttributedType : public Type, public 
llvm::FoldingSetNode {
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
-                      QualType modified, QualType equivalent,
-                      const Attr *attr) {
-    ID.AddInteger(attrKind);
-    ID.AddPointer(modified.getAsOpaquePtr());
-    ID.AddPointer(equivalent.getAsOpaquePtr());
-    ID.AddPointer(attr);
-  }
+                      QualType modified, QualType equivalent, const Attr 
*attr);
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == Attributed;
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 32f72e8da960e..533f13d2ca879 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3196,6 +3196,11 @@ def SwiftAttr : DeclOrTypeAttr {
   let Args = [StringArgument<"Attribute">];
   let Documentation = [SwiftAttrDocs];
   let PragmaAttributeSupport = 1;
+  let AdditionalMembers = [{
+    void Profile(llvm::FoldingSetNodeID &ID) const override {
+      ID.AddString(getAttribute());
+    }
+  }];
 }
 
 def SwiftBridge : InheritableAttr {
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 96a398aa21dad..711b216d81de7 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5338,6 +5338,17 @@ NullabilityKindOrNone 
AttributedType::stripOuterNullability(QualType &T) {
   return std::nullopt;
 }
 
+void AttributedType::Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
+                             QualType modified, QualType equivalent,
+                             const Attr *attr) {
+
+  ID.AddInteger(attrKind);
+  ID.AddPointer(modified.getAsOpaquePtr());
+  ID.AddPointer(equivalent.getAsOpaquePtr());
+  if (attr)
+    attr->Profile(ID);
+}
+
 bool Type::isSignableIntegerType(const ASTContext &Ctx) const {
   if (!isIntegralType(Ctx) || isEnumeralType())
     return false;
diff --git a/clang/test/AST/attributed-type-dedup-nullability.m 
b/clang/test/AST/attributed-type-dedup-nullability.m
new file mode 100644
index 0000000000000..9904ec00913d0
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-nullability.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fobjc-arc -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// All three non-null types below should share a single AttributedType node and
+// serialize as exactly one TYPE_ATTRIBUTED record.
+
+@class NSString;
+
+#pragma clang assume_nonnull begin
+@interface T
+- (NSString *)a;
+- (NSString *)b;
+- (NSString *)c;
+@end
+#pragma clang assume_nonnull end
+
+// CHECK-COUNT-1: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED
diff --git a/clang/test/AST/attributed-type-dedup-swift-attr.m 
b/clang/test/AST/attributed-type-dedup-swift-attr.m
new file mode 100644
index 0000000000000..d39778572eda5
--- /dev/null
+++ b/clang/test/AST/attributed-type-dedup-swift-attr.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-arc -emit-pch -o %t.pch %s
+// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s
+
+// Checks that swift_attr deduplication works correctly.
+// The following test should generate two attributed types, not three.
+
+#define ATTR_A __attribute__((swift_attr("@A")))
+#define ATTR_B __attribute__((swift_attr("@B")))
+
+void f1(int * ATTR_A p);
+void f2(int * ATTR_A p);
+void f3(int * ATTR_B p);
+
+// CHECK-COUNT-2: <TYPE_ATTRIBUTED
+// CHECK-NOT:     <TYPE_ATTRIBUTED

>From 90f72abfe49e55b1c93eaa93640e9ba05ebd00f6 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Tue, 2 Jun 2026 10:52:23 -0700
Subject: [PATCH 2/2] Revise to make the fix more focused. Removed the virtual
 method Profile from the base Attr class.

---
 clang/include/clang/AST/Attr.h    | 12 ------------
 clang/include/clang/Basic/Attr.td |  2 +-
 clang/lib/AST/Type.cpp            |  6 +++---
 3 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index df2da85cf6402..0f9fc01391c30 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -81,8 +81,6 @@ class Attr : public AttributeCommonInfo {
     return ::operator delete(Ptr, C, Alignment);
   }
 
-  virtual ~Attr() = default;
-
 protected:
   Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
        attr::Kind AK, bool IsLateParsed)
@@ -122,16 +120,6 @@ class Attr : public AttributeCommonInfo {
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
   static StringRef getDocumentation(attr::Kind);
-
-  // Contribute Attr-specific content to a FoldingSetNodeID for callers like
-  // AttributedType::Profile that dedupe nodes by Attr identity. The default
-  // is empty: AttributedType::Profile already hashes attrKind (and
-  // asserts attr->getKind() == attrKind), so a no-op default makes stateless
-  // Attrs (nullability, ARC ownership, calling conventions, ...) dedupe by
-  // (kind, modified, equivalent) — pointer identity of the Attr is ignored.
-  // Override this in subclasses whose arguments meaningfully distinguish
-  // the wrapped type (e.g. SwiftAttrAttr hashes its string payload).
-  virtual void Profile(llvm::FoldingSetNodeID &ID) const {}
 };
 
 class TypeAttr : public Attr {
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 533f13d2ca879..44f8ea6d16532 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3197,7 +3197,7 @@ def SwiftAttr : DeclOrTypeAttr {
   let Documentation = [SwiftAttrDocs];
   let PragmaAttributeSupport = 1;
   let AdditionalMembers = [{
-    void Profile(llvm::FoldingSetNodeID &ID) const override {
+    void Profile(llvm::FoldingSetNodeID &ID) const {
       ID.AddString(getAttribute());
     }
   }];
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 711b216d81de7..c9d038ec308ef 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -14,6 +14,7 @@
 #include "Linkage.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/Attrs.inc"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
@@ -5341,12 +5342,11 @@ NullabilityKindOrNone 
AttributedType::stripOuterNullability(QualType &T) {
 void AttributedType::Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
                              QualType modified, QualType equivalent,
                              const Attr *attr) {
-
   ID.AddInteger(attrKind);
   ID.AddPointer(modified.getAsOpaquePtr());
   ID.AddPointer(equivalent.getAsOpaquePtr());
-  if (attr)
-    attr->Profile(ID);
+  if (const auto *A = dyn_cast_or_null<SwiftAttrAttr>(attr))
+    A->Profile(ID);
 }
 
 bool Type::isSignableIntegerType(const ASTContext &Ctx) const {

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

Reply via email to