[clang] [APINotes] Support adding arbitrary Swift attributes (PR #180382)
Hunter Baker via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 08:17:04 PST 2026
https://github.com/literally-anything updated https://github.com/llvm/llvm-project/pull/180382
>From 30c34295d4726f44a84f131d6ee8e61ea1d485c3 Mon Sep 17 00:00:00 2001
From: Hunter Baker <62899372+literally-anything at users.noreply.github.com>
Date: Sat, 7 Feb 2026 20:35:31 -0500
Subject: [PATCH 1/3] [APINotes] Support adding arbitrary Swift attributes
---
clang/include/clang/APINotes/Types.h | 10 +++++-
clang/lib/APINotes/APINotesFormat.h | 2 +-
clang/lib/APINotes/APINotesReader.cpp | 19 ++++++++++
clang/lib/APINotes/APINotesTypes.cpp | 7 ++++
clang/lib/APINotes/APINotesWriter.cpp | 23 +++++++++++-
clang/lib/APINotes/APINotesYAMLCompiler.cpp | 34 ++++++++++++++++++
clang/lib/Sema/SemaAPINotes.cpp | 5 +++
.../Inputs/Headers/SwiftAttributes.apinotes | 24 +++++++++++++
.../APINotes/Inputs/Headers/SwiftAttributes.h | 11 ++++++
.../APINotes/Inputs/Headers/module.modulemap | 4 +++
clang/test/APINotes/swift-attributes.cpp | 35 +++++++++++++++++++
11 files changed, 171 insertions(+), 3 deletions(-)
create mode 100644 clang/test/APINotes/Inputs/Headers/SwiftAttributes.apinotes
create mode 100644 clang/test/APINotes/Inputs/Headers/SwiftAttributes.h
create mode 100644 clang/test/APINotes/swift-attributes.cpp
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index fb2b91a3e1750..ca5b35954d027 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -83,6 +83,9 @@ class CommonEntityInfo {
/// Swift name of this entity.
std::string SwiftName;
+ /// Swift attributes to apply to this entity.
+ std::vector<std::string> SwiftAttributes;
+
CommonEntityInfo()
: Unavailable(0), UnavailableInSwift(0), SwiftPrivateSpecified(0),
SwiftPrivate(0), SwiftSafetyAudited(0), SwiftSafety(0) {}
@@ -133,6 +136,9 @@ class CommonEntityInfo {
if (SwiftName.empty())
SwiftName = RHS.SwiftName;
+ // Merge SwiftAttributes
+ SwiftAttributes.insert(SwiftAttributes.end(), RHS.SwiftAttributes.begin(), RHS.SwiftAttributes.end());
+
return *this;
}
@@ -147,7 +153,9 @@ inline bool operator==(const CommonEntityInfo &LHS,
LHS.SwiftPrivateSpecified == RHS.SwiftPrivateSpecified &&
LHS.SwiftPrivate == RHS.SwiftPrivate &&
LHS.SwiftSafetyAudited == RHS.SwiftSafetyAudited &&
- LHS.SwiftSafety == RHS.SwiftSafety && LHS.SwiftName == RHS.SwiftName;
+ LHS.SwiftSafety == RHS.SwiftSafety &&
+ LHS.SwiftName == RHS.SwiftName &&
+ LHS.SwiftAttributes == RHS.SwiftAttributes;
}
inline bool operator!=(const CommonEntityInfo &LHS,
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index bb423ccb2bfaf..db57c764dddb0 100644
--- a/clang/lib/APINotes/APINotesFormat.h
+++ b/clang/lib/APINotes/APINotesFormat.h
@@ -24,7 +24,7 @@ const uint16_t VERSION_MAJOR = 0;
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t VERSION_MINOR = 38; // SwiftSafety
+const uint16_t VERSION_MINOR = 39; // SwiftAttributes
const uint8_t kSwiftConforms = 1;
const uint8_t kSwiftDoesNotConform = 2;
diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp
index 7f9bb5f12cda7..97043460c2203 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -92,6 +92,16 @@ class VersionedTableInfo {
}
};
+/// Read serialized Attribute from a SwiftAttributes sequence.
+void ReadSwiftAttribute(const uint8_t *&Data, std::string &Attribute) {
+ unsigned AttributeLength =
+ endian::readNext<uint16_t, llvm::endianness::little>(Data);
+ Attribute =
+ std::string(reinterpret_cast<const char *>(Data),
+ reinterpret_cast<const char *>(Data) + AttributeLength);
+ Data += AttributeLength;
+}
+
/// Read serialized CommonEntityInfo.
void ReadCommonEntityInfo(const uint8_t *&Data, CommonEntityInfo &Info) {
uint8_t EncodedBits = *Data++;
@@ -116,6 +126,15 @@ void ReadCommonEntityInfo(const uint8_t *&Data, CommonEntityInfo &Info) {
std::string(reinterpret_cast<const char *>(Data),
reinterpret_cast<const char *>(Data) + SwiftNameLength);
Data += SwiftNameLength;
+
+ unsigned NumSwiftAttributes =
+ endian::readNext<uint16_t, llvm::endianness::little>(Data);
+ while (NumSwiftAttributes > 0) {
+ std::string Attribute;
+ ReadSwiftAttribute(Data, Attribute);
+ Info.SwiftAttributes.push_back(Attribute);
+ --NumSwiftAttributes;
+ }
}
/// Read serialized CommonTypeInfo.
diff --git a/clang/lib/APINotes/APINotesTypes.cpp b/clang/lib/APINotes/APINotesTypes.cpp
index bff4be104c6c8..2a6e620fa902a 100644
--- a/clang/lib/APINotes/APINotesTypes.cpp
+++ b/clang/lib/APINotes/APINotesTypes.cpp
@@ -35,6 +35,13 @@ LLVM_DUMP_METHOD void CommonEntityInfo::dump(llvm::raw_ostream &OS) const {
}
if (!SwiftName.empty())
OS << "Swift Name: " << SwiftName << ' ';
+ if (!SwiftAttributes.empty()) {
+ OS << "Swift Attrs: [";
+ for (const std::string &attr : SwiftAttributes) {
+ OS << '\"' << attr << "\", ";
+ }
+ OS << "] ";
+ }
OS << '\n';
}
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index 47ed93a567c0e..82ffb65e39ec6 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -502,6 +502,13 @@ class VersionedTableInfo {
}
};
+/// Emit a serialized representation of the Attribute from the SwifrAttributes sequence.
+void emitSwiftAttribute(raw_ostream &OS, const std::string &Attribute) {
+ llvm::support::endian::Writer writer(OS, llvm::endianness::little);
+ writer.write<uint16_t>(Attribute.size());
+ OS.write(Attribute.c_str(), Attribute.size());
+}
+
/// Emit a serialized representation of the common entity information.
void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
@@ -530,12 +537,26 @@ void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
writer.write<uint16_t>(CEI.SwiftName.size());
OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
+
+ writer.write<uint16_t>(CEI.SwiftAttributes.size());
+ for (const auto &Attribute : CEI.SwiftAttributes)
+ emitSwiftAttribute(OS, Attribute);
+}
+
+/// Retrieve the serialized size of the given an Attribute in a SwiftAttributes sequence,
+/// for use in on-disk hash tables.
+unsigned getSwiftAttributeSize(const std::string &Attribute) {
+ return sizeof(uint16_t) + Attribute.size(); // length and contents
}
/// Retrieve the serialized size of the given CommonEntityInfo, for use in
/// on-disk hash tables.
unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
- return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
+ unsigned size = 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
+ size += sizeof(uint16_t); // SwiftAttributes length
+ for (const auto &Attribute : CEI.SwiftAttributes)
+ size += getSwiftAttributeSize(Attribute);
+ return size;
}
// Retrieve the serialized size of the given CommonTypeInfo, for use
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 3be528feb325e..8283e7ceef1e2 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -79,6 +79,10 @@ template <> struct ScalarEnumerationTraits<MethodKind> {
} // namespace yaml
} // namespace llvm
+namespace {
+typedef std::vector<StringRef> SwiftAttributeSeq;
+} // namespace
+
namespace {
struct Param {
int Position;
@@ -176,6 +180,7 @@ struct Method {
StringRef ResultType;
StringRef SwiftReturnOwnership;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<Method> MethodsSeq;
@@ -213,6 +218,7 @@ template <> struct MappingTraits<Method> {
IO.mapOptional("SwiftReturnOwnership", M.SwiftReturnOwnership,
StringRef(""));
IO.mapOptional("SwiftSafety", M.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", M.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -229,6 +235,7 @@ struct Property {
std::optional<bool> SwiftImportAsAccessors;
StringRef Type;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<Property> PropertiesSeq;
@@ -251,6 +258,7 @@ template <> struct MappingTraits<Property> {
IO.mapOptional("SwiftImportAsAccessors", P.SwiftImportAsAccessors);
IO.mapOptional("Type", P.Type, StringRef(""));
IO.mapOptional("SwiftSafety", P.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", P.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -271,6 +279,7 @@ struct Class {
MethodsSeq Methods;
PropertiesSeq Properties;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<Class> ClassesSeq;
@@ -297,6 +306,7 @@ template <> struct MappingTraits<Class> {
IO.mapOptional("Methods", C.Methods);
IO.mapOptional("Properties", C.Properties);
IO.mapOptional("SwiftSafety", C.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", C.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -316,6 +326,7 @@ struct Function {
StringRef ResultType;
StringRef SwiftReturnOwnership;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<Function> FunctionsSeq;
@@ -341,6 +352,7 @@ template <> struct MappingTraits<Function> {
IO.mapOptional("SwiftReturnOwnership", F.SwiftReturnOwnership,
StringRef(""));
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", F.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -355,6 +367,7 @@ struct GlobalVariable {
StringRef SwiftName;
StringRef Type;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<GlobalVariable> GlobalVariablesSeq;
@@ -375,6 +388,7 @@ template <> struct MappingTraits<GlobalVariable> {
IO.mapOptional("SwiftName", GV.SwiftName, StringRef(""));
IO.mapOptional("Type", GV.Type, StringRef(""));
IO.mapOptional("SwiftSafety", GV.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", GV.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -449,6 +463,7 @@ struct Field {
StringRef SwiftName;
StringRef Type;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<Field> FieldsSeq;
@@ -469,6 +484,7 @@ template <> struct MappingTraits<Field> {
IO.mapOptional("SwiftName", F.SwiftName, StringRef(""));
IO.mapOptional("Type", F.Type, StringRef(""));
IO.mapOptional("SwiftSafety", F.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", F.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -497,6 +513,7 @@ struct Tag {
std::optional<bool> SwiftCopyable;
std::optional<bool> SwiftEscapable;
SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
FunctionsSeq Methods;
FieldsSeq Fields;
@@ -543,6 +560,7 @@ template <> struct MappingTraits<Tag> {
IO.mapOptional("Fields", T.Fields);
IO.mapOptional("Tags", T.Tags);
IO.mapOptional("SwiftSafety", T.SafetyKind, SwiftSafetyKind::None);
+ IO.mapOptional("SwiftAttributes", T.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -559,6 +577,7 @@ struct Typedef {
std::optional<SwiftNewTypeKind> SwiftType;
std::optional<std::string> SwiftConformance;
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
typedef std::vector<Typedef> TypedefsSeq;
@@ -588,6 +607,7 @@ template <> struct MappingTraits<Typedef> {
IO.mapOptional("NSErrorDomain", T.NSErrorDomain);
IO.mapOptional("SwiftWrapper", T.SwiftType);
IO.mapOptional("SwiftConformsTo", T.SwiftConformance);
+ IO.mapOptional("SwiftAttributes", T.SwiftAttributes, SwiftAttributeSeq());
}
};
} // namespace yaml
@@ -632,6 +652,7 @@ struct Namespace {
std::optional<bool> SwiftPrivate;
TopLevelItems Items;
const SwiftSafetyKind SafetyKind = SwiftSafetyKind::None;
+ SwiftAttributeSeq SwiftAttributes;
};
} // namespace
@@ -647,6 +668,7 @@ template <> struct MappingTraits<Namespace> {
IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef(""));
IO.mapOptional("SwiftPrivate", T.SwiftPrivate);
IO.mapOptional("SwiftName", T.SwiftName, StringRef(""));
+ IO.mapOptional("SwiftAttributes", T.SwiftAttributes, SwiftAttributeSeq());
mapTopLevelItems(IO, T.Items);
}
};
@@ -777,6 +799,15 @@ class YAMLConverter {
}
}
+ void convertSwiftAttributes(const SwiftAttributeSeq &SwiftAttributes,
+ CommonEntityInfo &OutInfo) {
+ // Convert StringRef attributes to std::vector<std::string> in CommonEntityInfo
+ OutInfo.SwiftAttributes.reserve(SwiftAttributes.size());
+ for (const StringRef &A : SwiftAttributes) {
+ OutInfo.SwiftAttributes.emplace_back(A);
+ }
+ }
+
void convertParams(const ParamsSeq &Params, FunctionInfo &OutInfo,
std::optional<ParamInfo> &thisOrSelf) {
for (const auto &P : Params) {
@@ -830,6 +861,7 @@ class YAMLConverter {
if (Common.SafetyKind != SwiftSafetyKind::None)
Info.setSwiftSafety(Common.SafetyKind);
Info.SwiftName = std::string(Common.SwiftName);
+ convertSwiftAttributes(Common.SwiftAttributes, Info);
}
/// Convert the common parts of a type entity from YAML.
@@ -893,6 +925,7 @@ class YAMLConverter {
convertAvailability(Entity.Availability, VI, Entity.Name);
VI.setSwiftPrivate(Entity.SwiftPrivate);
VI.SwiftName = std::string(Entity.SwiftName);
+ convertSwiftAttributes(Entity.SwiftAttributes, VI);
if (Entity.Nullability)
VI.setNullabilityAudited(*Entity.Nullability);
VI.setType(std::string(Entity.Type));
@@ -991,6 +1024,7 @@ class YAMLConverter {
if (Function.SafetyKind != SwiftSafetyKind::None)
FI.setSwiftSafety(Function.SafetyKind);
FI.SwiftName = std::string(Function.SwiftName);
+ convertSwiftAttributes(Function.SwiftAttributes, FI);
std::optional<ParamInfo> This;
convertParams(Function.Params, FI, This);
if constexpr (std::is_same_v<FuncOrMethodInfo, CXXMethodInfo>)
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 059eb0dd767b7..bf18f12ee203e 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -335,6 +335,11 @@ static void ProcessAPINotes(Sema &S, Decl *D,
ASTAllocateString(S.Context, Info.SwiftName));
});
}
+
+ // swift_attr
+ for (const std::string& swiftAttrName : Info.SwiftAttributes) {
+ D->addAttr(SwiftAttrAttr::Create(S.Context, swiftAttrName));
+ }
}
static void ProcessAPINotes(Sema &S, Decl *D,
diff --git a/clang/test/APINotes/Inputs/Headers/SwiftAttributes.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftAttributes.apinotes
new file mode 100644
index 0000000000000..926ff7c879433
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/SwiftAttributes.apinotes
@@ -0,0 +1,24 @@
+Name: SwiftAttributes
+Tags:
+- Name: IntWrapperStruct
+ SwiftAttributes: ["some Swift struct attribute"]
+ Fields:
+ - Name: value
+ SwiftAttributes: ["some Swift field attribute"]
+ Methods:
+ - Name: do_something
+ SwiftAttributes: ["some Swift struct method attribute"]
+- Name: some_ns
+ SwiftAttributes: ["some Swift namespace attribute"]
+Functions:
+- Name: some_operation
+ SwiftAttributes: [
+ "some Swift function attribute",
+ "some other Swift function attribute"
+ ]
+Globals:
+- Name: global_int
+ SwiftAttributes: ["some Swift global variable attribute"]
+Typedefs:
+- Name: int_typedef
+ SwiftAttributes: ["some Swift typedef attribute"]
diff --git a/clang/test/APINotes/Inputs/Headers/SwiftAttributes.h b/clang/test/APINotes/Inputs/Headers/SwiftAttributes.h
new file mode 100644
index 0000000000000..c251f0527c41e
--- /dev/null
+++ b/clang/test/APINotes/Inputs/Headers/SwiftAttributes.h
@@ -0,0 +1,11 @@
+struct IntWrapperStruct {
+ int value;
+
+ void do_something();
+};
+
+void some_operation(IntWrapperStruct &);
+
+int global_int = 123;
+
+typedef int int_typedef;
diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap
index bedb7d505f794..2c0939277f4e3 100644
--- a/clang/test/APINotes/Inputs/Headers/module.modulemap
+++ b/clang/test/APINotes/Inputs/Headers/module.modulemap
@@ -61,3 +61,7 @@ module SwiftImportAs {
module SwiftReturnOwnershipForObjC {
header "SwiftReturnOwnershipForObjC.h"
}
+
+module SwiftAttributes {
+ header "SwiftAttributes.h"
+}
diff --git a/clang/test/APINotes/swift-attributes.cpp b/clang/test/APINotes/swift-attributes.cpp
new file mode 100644
index 0000000000000..0d65336415604
--- /dev/null
+++ b/clang/test/APINotes/swift-attributes.cpp
@@ -0,0 +1,35 @@
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -x c++
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter IntWrapperStruct -x c++ | FileCheck --check-prefix=CHECK-STRUCT %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter IntWrapperStruct::value -x c++ | FileCheck --check-prefix=CHECK-FIELD %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter IntWrapperStruct::do_something -x c++ | FileCheck --check-prefix=CHECK-METHOD %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter some_operation -x c++ | FileCheck --check-prefix=CHECK-FUNC %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter global_int -x c++ | FileCheck --check-prefix=CHECK-VAR %s
+// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/SwiftAttributes -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter int_typedef -x c++ | FileCheck --check-prefix=CHECK-TYPEDEF %s
+
+#include "SwiftAttributes.h"
+
+// CHECK-STRUCT: Dumping IntWrapperStruct:
+// CHECK-STRUCT-NEXT: CXXRecordDecl {{.+}} struct IntWrapperStruct
+// CHECK-STRUCT: SwiftAttrAttr {{.+}} <<invalid sloc>> "some Swift struct attribute"
+
+// CHECK-FIELD: Dumping IntWrapperStruct::value:
+// CHECK-FIELD-NEXT: FieldDecl {{.+}} value
+// CHECK-FIELD: SwiftAttrAttr {{.+}} <<invalid sloc>> "some Swift field attribute"
+
+// CHECK-METHOD: Dumping IntWrapperStruct::do_something:
+// CHECK-METHOD-NEXT: CXXMethodDecl {{.+}} do_something
+// CHECK-METHOD: SwiftAttrAttr {{.+}} <<invalid sloc>> "some Swift struct method attribute"
+
+// CHECK-FUNC: Dumping some_operation:
+// CHECK-FUNC-NEXT: FunctionDecl {{.+}} some_operation
+// CHECK-FUNC: SwiftAttrAttr {{.+}} <<invalid sloc>> "some Swift function attribute"
+// CHECK-FUNC: SwiftAttrAttr {{.+}} <<invalid sloc>> "some other Swift function attribute"
+
+// CHECK-VAR: Dumping global_int:
+// CHECK-VAR-NEXT: VarDecl {{.+}} global_int
+// CHECK-VAR: SwiftAttrAttr {{.+}} <<invalid sloc>> "some Swift global variable attribute"
+
+// CHECK-TYPEDEF: Dumping int_typedef:
+// CHECK-TYPEDEF-NEXT: TypedefDecl {{.+}} int_typedef
+// CHECK-TYPEDEF: SwiftAttrAttr {{.+}} <<invalid sloc>> "some Swift typedef attribute"
>From 5c20abb0b4a75f640a40deb22b6fee9d808c067a Mon Sep 17 00:00:00 2001
From: Hunter Baker <62899372+literally-anything at users.noreply.github.com>
Date: Sat, 7 Feb 2026 20:54:55 -0500
Subject: [PATCH 2/3] [APINotes] Document SwiftAttributes key
---
clang/docs/APINotes.rst | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/clang/docs/APINotes.rst b/clang/docs/APINotes.rst
index e142cfa62e5a2..4909555476772 100644
--- a/clang/docs/APINotes.rst
+++ b/clang/docs/APINotes.rst
@@ -243,6 +243,26 @@ declaration kind), all of which are optional:
- Name: size
SwiftSafety: safe
+:SwiftAttributes:
+
+ Attach arbitrary Swift attributes to a declaration.
+ This is equivalent to applying the `swift_attr("")` attribute in the header.
+
+ ::
+
+ # Mark safe globals as nonisolated to make them accessible in Swift 6
+ Globals:
+ - Name: globalVariable
+ SwiftAttributes:
+ - "nonisolated(unsafe)"
+
+ # Apply Swift macros to C declarations on import
+ Functions:
+ - Name: cFunction
+ SwiftAttributes:
+ - "@MyModule.GenerateWrapper"
+
+
:Availability, AvailabilityMsg:
A value of "nonswift" is equivalent to ``NS_SWIFT_UNAVAILABLE``. A value of
>From 2fb5981f57ce41613d47a63ed458e31c49eebc0d Mon Sep 17 00:00:00 2001
From: Hunter Baker <62899372+literally-anything at users.noreply.github.com>
Date: Sat, 7 Feb 2026 21:22:11 -0500
Subject: [PATCH 3/3] [APINotes] Format SwiftAttributes changes
---
clang/include/clang/APINotes/Types.h | 6 +++---
clang/lib/APINotes/APINotesWriter.cpp | 7 ++++---
clang/lib/APINotes/APINotesYAMLCompiler.cpp | 3 ++-
clang/lib/Sema/SemaAPINotes.cpp | 2 +-
4 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index ca5b35954d027..152fa65e18f2b 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -137,7 +137,8 @@ class CommonEntityInfo {
SwiftName = RHS.SwiftName;
// Merge SwiftAttributes
- SwiftAttributes.insert(SwiftAttributes.end(), RHS.SwiftAttributes.begin(), RHS.SwiftAttributes.end());
+ SwiftAttributes.insert(SwiftAttributes.end(), RHS.SwiftAttributes.begin(),
+ RHS.SwiftAttributes.end());
return *this;
}
@@ -153,8 +154,7 @@ inline bool operator==(const CommonEntityInfo &LHS,
LHS.SwiftPrivateSpecified == RHS.SwiftPrivateSpecified &&
LHS.SwiftPrivate == RHS.SwiftPrivate &&
LHS.SwiftSafetyAudited == RHS.SwiftSafetyAudited &&
- LHS.SwiftSafety == RHS.SwiftSafety &&
- LHS.SwiftName == RHS.SwiftName &&
+ LHS.SwiftSafety == RHS.SwiftSafety && LHS.SwiftName == RHS.SwiftName &&
LHS.SwiftAttributes == RHS.SwiftAttributes;
}
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index 82ffb65e39ec6..28a9f94996c10 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -502,7 +502,8 @@ class VersionedTableInfo {
}
};
-/// Emit a serialized representation of the Attribute from the SwifrAttributes sequence.
+/// Emit a serialized representation of the Attribute from the SwifrAttributes
+/// sequence.
void emitSwiftAttribute(raw_ostream &OS, const std::string &Attribute) {
llvm::support::endian::Writer writer(OS, llvm::endianness::little);
writer.write<uint16_t>(Attribute.size());
@@ -543,8 +544,8 @@ void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
emitSwiftAttribute(OS, Attribute);
}
-/// Retrieve the serialized size of the given an Attribute in a SwiftAttributes sequence,
-/// for use in on-disk hash tables.
+/// Retrieve the serialized size of the given an Attribute in a SwiftAttributes
+/// sequence, for use in on-disk hash tables.
unsigned getSwiftAttributeSize(const std::string &Attribute) {
return sizeof(uint16_t) + Attribute.size(); // length and contents
}
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 8283e7ceef1e2..17e85c8407b12 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -801,7 +801,8 @@ class YAMLConverter {
void convertSwiftAttributes(const SwiftAttributeSeq &SwiftAttributes,
CommonEntityInfo &OutInfo) {
- // Convert StringRef attributes to std::vector<std::string> in CommonEntityInfo
+ // Convert StringRef attributes to std::vector<std::string> in
+ // CommonEntityInfo
OutInfo.SwiftAttributes.reserve(SwiftAttributes.size());
for (const StringRef &A : SwiftAttributes) {
OutInfo.SwiftAttributes.emplace_back(A);
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index bf18f12ee203e..2d641f6e505cc 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -337,7 +337,7 @@ static void ProcessAPINotes(Sema &S, Decl *D,
}
// swift_attr
- for (const std::string& swiftAttrName : Info.SwiftAttributes) {
+ for (const std::string &swiftAttrName : Info.SwiftAttributes) {
D->addAttr(SwiftAttrAttr::Create(S.Context, swiftAttrName));
}
}
More information about the cfe-commits
mailing list