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/3] 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/3] 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 { >From 215556f0fc002cc2750f5915e100c9a8010d05d1 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu <[email protected]> Date: Wed, 3 Jun 2026 14:23:57 -0700 Subject: [PATCH 3/3] More general fix - an attribute's argument is taken into account automatically when computing the profile. --- clang/include/clang/AST/ASTContext.h | 3 +- clang/include/clang/AST/Attr.h | 2 + clang/include/clang/AST/TypeBase.h | 9 +- clang/include/clang/Basic/Attr.td | 11 ++- clang/lib/AST/ASTContext.cpp | 10 ++- clang/lib/AST/AttrImpl.cpp | 84 +++++++++++++++++++ clang/lib/AST/Type.cpp | 10 +-- .../AST/attributed-type-dedup-address-space.c | 9 ++ ...attributed-type-dedup-annotate-type-args.c | 14 ++++ .../AST/attributed-type-dedup-annotate-type.m | 12 +++ .../attributed-type-dedup-objc-ownership.m | 11 +++ clang/test/AST/attributed-type-dedup-pcs.c | 15 ++++ clang/utils/TableGen/ClangAttrEmitter.cpp | 43 ++++++++++ 13 files changed, 213 insertions(+), 20 deletions(-) create mode 100644 clang/test/AST/attributed-type-dedup-address-space.c create mode 100644 clang/test/AST/attributed-type-dedup-annotate-type-args.c create mode 100644 clang/test/AST/attributed-type-dedup-annotate-type.m create mode 100644 clang/test/AST/attributed-type-dedup-objc-ownership.m create mode 100644 clang/test/AST/attributed-type-dedup-pcs.c diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index c952b8d46974c..e58e123cf95af 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -294,7 +294,8 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable llvm::FoldingSet<DeducedTemplateSpecializationType> DeducedTemplateSpecializationTypes; mutable llvm::FoldingSet<AtomicType> AtomicTypes; - mutable llvm::FoldingSet<AttributedType> AttributedTypes; + mutable llvm::ContextualFoldingSet<AttributedType, ASTContext &> + AttributedTypes; mutable llvm::FoldingSet<PipeType> PipeTypes; mutable llvm::FoldingSet<BitIntType> BitIntTypes; mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &> diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 0f9fc01391c30..f204bb4faa9b7 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -116,6 +116,8 @@ class Attr : public AttributeCommonInfo { bool isEquivalent(const Attr &Other, StructuralEquivalenceContext &Context) const; + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) const; + // Pretty print this attribute. void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h index cce7af88181cd..e3141a82b54d2 100644 --- a/clang/include/clang/AST/TypeBase.h +++ b/clang/include/clang/AST/TypeBase.h @@ -6741,12 +6741,13 @@ class AttributedType : public Type, public llvm::FoldingSetNode { /// \returns the top-level nullability, if present. static NullabilityKindOrNone stripOuterNullability(QualType &T); - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute); + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { + Profile(ID, Ctx, getAttrKind(), ModifiedType, EquivalentType, Attribute); } - static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, - QualType modified, QualType equivalent, const Attr *attr); + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, + Kind attrKind, 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 44f8ea6d16532..b01fe640d842e 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -768,10 +768,13 @@ class Attr { // Note: Any additional data members will leak and should be constructed // externally on the ASTContext. code AdditionalMembers = [{}]; + + string comparisonFn = ""; + string profileFn = ""; + // Any documentation that should be associated with the attribute. Since an // attribute may be documented under multiple categories, more than one // Documentation entry may be listed. - string comparisonFn = ""; list<Documentation> Documentation; } @@ -897,6 +900,7 @@ def Aligned : InheritableAttr { CustomKeyword<"_Alignas">]>, Accessor<"isDeclspec",[Declspec<"align">]>]; let comparisonFn = "areAlignedAttrsEqual"; + let profileFn = "profileAlignedAttr"; let Documentation = [Undocumented]; } @@ -3196,11 +3200,6 @@ def SwiftAttr : DeclOrTypeAttr { let Args = [StringArgument<"Attribute">]; let Documentation = [SwiftAttrDocs]; let PragmaAttributeSupport = 1; - let AdditionalMembers = [{ - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddString(getAttribute()); - } - }]; } def SwiftBridge : InheritableAttr { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a401a7471e6fc..f46672b086c12 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -937,9 +937,10 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize), DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()), DependentPackIndexingTypes(this_()), TemplateSpecializationTypes(this_()), - DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), - DeducedTemplates(this_()), ArrayParameterTypes(this_()), - CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), + AttributedTypes(this_()), DependentBitIntTypes(this_()), + SubstTemplateTemplateParmPacks(this_()), DeducedTemplates(this_()), + ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), + SourceMgr(SM), LangOpts(LOpts), NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, @@ -5741,7 +5742,8 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind, QualType equivalentType, const Attr *attr) const { llvm::FoldingSetNodeID id; - AttributedType::Profile(id, attrKind, modifiedType, equivalentType, attr); + AttributedType::Profile(id, *this, attrKind, modifiedType, equivalentType, + attr); void *insertPos = nullptr; AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos); diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index 3a379891016f8..00a09dae766f0 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -376,4 +376,88 @@ bool areAlignedAttrsEqual(const AlignedAttr &A1, const AlignedAttr &A2, } } // namespace +namespace { +// Machinery to unique attributes based on the arguments. +// The construction mirrors the equivalent testing code above. +// The content of the arguments are added to the FoldingSetNodeID instance, +// which allows the AttributedTypes to unique the attributes based on +// the value of the arguments. + +#define USE_DEFAULT_PROFILE \ + (std::is_same_v<T, StringRef> || std::is_same_v<T, VersionTuple> || \ + std::is_same_v<T, IdentifierInfo *> || \ + std::is_same_v<T, const IdentifierInfo *> || std::is_enum_v<T> || \ + std::is_integral_v<T>) + +template <class T> +typename std::enable_if_t<!USE_DEFAULT_PROFILE> +profileAttrArg(llvm::FoldingSetNodeID &, const ASTContext &, T) {} + +template <class T> +typename std::enable_if_t<USE_DEFAULT_PROFILE> +profileAttrArg(llvm::FoldingSetNodeID &ID, const ASTContext &, T V) { + if constexpr (std::is_same_v<T, StringRef>) + ID.AddString(V); + else if constexpr (std::is_same_v<T, VersionTuple>) { + ID.AddInteger(V.getMajor()); + ID.AddInteger(V.getMinor().value_or(0)); + ID.AddInteger(V.getSubminor().value_or(0)); + ID.AddInteger(V.getBuild().value_or(0)); + } else if constexpr (std::is_same_v<T, IdentifierInfo *> || + std::is_same_v<T, const IdentifierInfo *>) + ID.AddPointer(V); + else + ID.AddInteger(static_cast<long long>(V)); +} + +template <> +inline void profileAttrArg<ParamIdx>(llvm::FoldingSetNodeID &ID, + const ASTContext &, ParamIdx P) { + ID.AddBoolean(P.isValid()); + if (P.isValid()) + ID.AddInteger(P.getASTIndex()); +} + +template <class T> +inline void profileAttrArg(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, + T *Begin, T *End) { + ID.AddInteger(End - Begin); + for (; Begin != End; ++Begin) + profileAttrArg(ID, Ctx, *Begin); +} + +template <> +inline void profileAttrArg<Attr *>(llvm::FoldingSetNodeID &ID, + const ASTContext &Ctx, Attr *A) { + if (!A) { + ID.AddPointer(nullptr); + return; + } + ID.AddInteger(A->getKind()); + A->Profile(ID, Ctx); +} + +template <> +inline void profileAttrArg<Expr *>(llvm::FoldingSetNodeID &ID, + const ASTContext &Ctx, Expr *E) { + E->Profile(ID, Ctx, /*Canonical=*/true); +} + +template <> +inline void profileAttrArg<QualType>(llvm::FoldingSetNodeID &ID, + const ASTContext &, QualType T) { + ID.AddPointer(T.getCanonicalType().getAsOpaquePtr()); +} + +void profileAlignedAttr(const AlignedAttr &A, llvm::FoldingSetNodeID &ID, + const ASTContext &Ctx) { + ID.AddInteger(A.getSpellingListIndex()); + ID.AddBoolean(A.isAlignmentExpr()); + if (A.isAlignmentExpr()) + profileAttrArg(ID, Ctx, A.getAlignmentExpr()); + else + profileAttrArg(ID, Ctx, A.getAlignmentType()->getType()); +} +} // namespace + #include "clang/AST/AttrImpl.inc" diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index c9d038ec308ef..55c3e5c3ead17 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5339,14 +5339,14 @@ NullabilityKindOrNone AttributedType::stripOuterNullability(QualType &T) { return std::nullopt; } -void AttributedType::Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, - QualType modified, QualType equivalent, - const Attr *attr) { +void AttributedType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, + Kind attrKind, QualType modified, + QualType equivalent, const Attr *attr) { ID.AddInteger(attrKind); ID.AddPointer(modified.getAsOpaquePtr()); ID.AddPointer(equivalent.getAsOpaquePtr()); - if (const auto *A = dyn_cast_or_null<SwiftAttrAttr>(attr)) - A->Profile(ID); + if (attr) + attr->Profile(ID, Ctx); } bool Type::isSignableIntegerType(const ASTContext &Ctx) const { diff --git a/clang/test/AST/attributed-type-dedup-address-space.c b/clang/test/AST/attributed-type-dedup-address-space.c new file mode 100644 index 0000000000000..8372a21c4eb5a --- /dev/null +++ b/clang/test/AST/attributed-type-dedup-address-space.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-pch -o %t.pch %s +// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s + +__attribute__((address_space(1))) int *a; +__attribute__((address_space(1))) int *b; +__attribute__((address_space(2))) int *c; + +// CHECK-COUNT-2: <TYPE_ATTRIBUTED +// CHECK-NOT: <TYPE_ATTRIBUTED diff --git a/clang/test/AST/attributed-type-dedup-annotate-type-args.c b/clang/test/AST/attributed-type-dedup-annotate-type-args.c new file mode 100644 index 0000000000000..060dbfc9bf37e --- /dev/null +++ b/clang/test/AST/attributed-type-dedup-annotate-type-args.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-pch -o %t.pch %s +// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s + +// annotate_type with VariadicExprArgument. The attribued types should +// dedupe not only based on the string argument, but all of the variadic +// arguments. + +int *[[clang::annotate_type("foo", 1)]] a; +int *[[clang::annotate_type("foo", 1)]] b; +int *[[clang::annotate_type("foo", 2)]] c; +int *[[clang::annotate_type("foo")]] d; + +// CHECK-COUNT-3: <TYPE_ATTRIBUTED +// CHECK-NOT: <TYPE_ATTRIBUTED diff --git a/clang/test/AST/attributed-type-dedup-annotate-type.m b/clang/test/AST/attributed-type-dedup-annotate-type.m new file mode 100644 index 0000000000000..2c4bfff0aefbe --- /dev/null +++ b/clang/test/AST/attributed-type-dedup-annotate-type.m @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-pch -o %t.pch %s +// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s + +// Only two unique string arguments are present. Correspondingly, +// we should have two TYPE_ATTRIBUTED records. + +int *[[clang::annotate_type("foo")]] a; +int *[[clang::annotate_type("foo")]] b; +int *[[clang::annotate_type("bar")]] c; + +// CHECK-COUNT-2: <TYPE_ATTRIBUTED +// CHECK-NOT: <TYPE_ATTRIBUTED diff --git a/clang/test/AST/attributed-type-dedup-objc-ownership.m b/clang/test/AST/attributed-type-dedup-objc-ownership.m new file mode 100644 index 0000000000000..4d3d69373a1d5 --- /dev/null +++ b/clang/test/AST/attributed-type-dedup-objc-ownership.m @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fobjc-arc -emit-pch -o %t.pch %s +// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s + +@class NSString; + +__attribute__((objc_ownership(strong))) NSString *a; +__attribute__((objc_ownership(strong))) NSString *b; +__attribute__((objc_ownership(none))) NSString *c; + +// CHECK-COUNT-2: <TYPE_ATTRIBUTED +// CHECK-NOT: <TYPE_ATTRIBUTED diff --git a/clang/test/AST/attributed-type-dedup-pcs.c b/clang/test/AST/attributed-type-dedup-pcs.c new file mode 100644 index 0000000000000..cfd7b7d9f4658 --- /dev/null +++ b/clang/test/AST/attributed-type-dedup-pcs.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple arm-none-eabi -emit-pch -o %t.pch %s +// RUN: llvm-bcanalyzer --dump --disable-histogram %t.pch | FileCheck %s + +// Pcs uses an EnumArgument and is encoded in the FunctionProtoType's +// calling convention bits on ARM targets, so the equivalent type +// discriminates aapcs vs aapcs-vfp. Two same-PCS uses must dedup; a +// different-PCS use must be distinct. Requires an ARM triple — on x86 / +// arm64-apple-darwin, pcs is silently ignored and no records are emitted. + +void __attribute__((pcs("aapcs"))) f1(void); +void __attribute__((pcs("aapcs"))) f2(void); +void __attribute__((pcs("aapcs-vfp"))) f3(void); + +// CHECK-COUNT-2: <TYPE_ATTRIBUTED +// CHECK-NOT: <TYPE_ATTRIBUTED diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 7df99d3beb11a..1eaec5f07c75e 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -287,6 +287,10 @@ namespace { std::string S = std::string("get") + std::string(getUpperName()) + "()"; return getArgEqualityFn().str() + "(" + S + ", Other." + S + ", Context)"; } + + virtual std::string emitAttrArgProfileCall() const { + return "profileAttrArg(ID, Ctx, get" + getUpperName().str() + "())"; + } }; class SimpleArgument : public Argument { @@ -867,6 +871,11 @@ namespace { GenIter(false, "end") + ", " + GenIter(true, "begin") + ", " + GenIter(true, "end") + ", Context)"; } + + std::string emitAttrArgProfileCall() const override { + std::string LN = getLowerName().str(); + return "profileAttrArg(ID, Ctx, " + LN + "_begin(), " + LN + "_end())"; + } }; class VariadicOMPInteropInfoArgument : public VariadicArgument { @@ -3266,6 +3275,22 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS, OS << "}\n\n"; } + std::string ProfileSig = "Profile(llvm::FoldingSetNodeID &ID, " + "const ASTContext &Ctx) const"; + if (Header) { + OS << " void " << ProfileSig << ";\n"; + } else { + OS << "void " << R.getName() << "Attr::" << ProfileSig << " {\n"; + std::string CustomFn = R.getValueAsString("profileFn").str(); + if (CustomFn.empty()) { + for (const auto &ai : Args) + OS << " " << ai->emitAttrArgProfileCall() << ";\n"; + } else { + OS << " " << CustomFn << "(*this, ID, Ctx);\n"; + } + OS << "}\n\n"; + } + if (Header) { if (DelayedArgs) { DelayedArgs->writeAccessors(OS); @@ -3338,6 +3363,23 @@ static void emitEquivalenceFunction(const RecordKeeper &Records, OS << "}\n\n"; } +static void emitProfileFunction(const RecordKeeper &Records, raw_ostream &OS) { + OS << "void Attr::Profile(llvm::FoldingSetNodeID &ID, " + "const ASTContext &Ctx) const {\n"; + OS << " switch (getKind()) {\n"; + for (const auto *Attr : Records.getAllDerivedDefinitions("Attr")) { + const Record &R = *Attr; + if (!R.getValueAsBit("ASTNode")) + continue; + OS << " case attr::" << R.getName() << ":\n"; + OS << " return cast<" << R.getName() + << "Attr>(this)->Profile(ID, Ctx);\n"; + } + OS << " }\n"; + OS << " llvm_unreachable(\"Unexpected attribute kind!\");\n"; + OS << "}\n\n"; +} + // Emits the class method definitions for attributes. void clang::EmitClangAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader("Attribute classes' member function definitions", OS, @@ -3374,6 +3416,7 @@ void clang::EmitClangAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { EmitFunc("printPretty(OS, Policy)"); emitEquivalenceFunction(Records, OS); + emitProfileFunction(Records, OS); } static void emitAttrList(raw_ostream &OS, StringRef Class, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
