[clang] [API notes] Allow SwiftConformsTo on Typedefs (PR #151213)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 29 12:47:45 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Doug Gregor (DougGregor)
<details>
<summary>Changes</summary>
SwiftConformsTo specifies an additional conformance that should be applied on import. Allow this on typedefs, because those can be imported as wrapper types.
---
Full diff: https://github.com/llvm/llvm-project/pull/151213.diff
9 Files Affected:
- (modified) clang/include/clang/APINotes/Types.h (+15-8)
- (modified) clang/lib/APINotes/APINotesFormat.h (+1-1)
- (modified) clang/lib/APINotes/APINotesReader.cpp (+7-6)
- (modified) clang/lib/APINotes/APINotesWriter.cpp (+8-8)
- (modified) clang/lib/APINotes/APINotesYAMLCompiler.cpp (+6-2)
- (modified) clang/lib/Sema/SemaAPINotes.cpp (+4-4)
- (modified) clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes (+3)
- (modified) clang/test/APINotes/swift-import-as.cpp (+1-1)
- (modified) clang/test/APINotes/yaml-roundtrip.test (+1-1)
``````````diff
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 0f2e49613b514..8708b4b092f28 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -141,6 +141,9 @@ class CommonTypeInfo : public CommonEntityInfo {
/// The NS error domain for this type.
std::optional<std::string> NSErrorDomain;
+ /// The Swift protocol that this type should be automatically conformed to.
+ std::optional<std::string> SwiftConformance;
+
public:
CommonTypeInfo() {}
@@ -165,6 +168,14 @@ class CommonTypeInfo : public CommonEntityInfo {
: std::nullopt;
}
+ std::optional<std::string> getSwiftConformance() const {
+ return SwiftConformance;
+ }
+
+ void setSwiftConformance(std::optional<std::string> conformance) {
+ SwiftConformance = conformance;
+ }
+
friend bool operator==(const CommonTypeInfo &, const CommonTypeInfo &);
CommonTypeInfo &operator|=(const CommonTypeInfo &RHS) {
@@ -175,6 +186,8 @@ class CommonTypeInfo : public CommonEntityInfo {
setSwiftBridge(RHS.getSwiftBridge());
if (!NSErrorDomain)
setNSErrorDomain(RHS.getNSErrorDomain());
+ if (SwiftConformance)
+ setSwiftConformance(RHS.getSwiftConformance());
return *this;
}
@@ -185,7 +198,8 @@ class CommonTypeInfo : public CommonEntityInfo {
inline bool operator==(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
return static_cast<const CommonEntityInfo &>(LHS) == RHS &&
LHS.SwiftBridge == RHS.SwiftBridge &&
- LHS.NSErrorDomain == RHS.NSErrorDomain;
+ LHS.NSErrorDomain == RHS.NSErrorDomain &&
+ LHS.SwiftConformance == RHS.SwiftConformance;
}
inline bool operator!=(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
@@ -739,9 +753,6 @@ class TagInfo : public CommonTypeInfo {
std::optional<std::string> SwiftReleaseOp;
std::optional<std::string> SwiftDefaultOwnership;
- /// The Swift protocol that this type should be automatically conformed to.
- std::optional<std::string> SwiftConformance;
-
std::optional<EnumExtensibilityKind> EnumExtensibility;
TagInfo()
@@ -790,9 +801,6 @@ class TagInfo : public CommonTypeInfo {
if (!SwiftDefaultOwnership)
SwiftDefaultOwnership = RHS.SwiftDefaultOwnership;
- if (!SwiftConformance)
- SwiftConformance = RHS.SwiftConformance;
-
if (!HasFlagEnum)
setFlagEnum(RHS.isFlagEnum());
@@ -819,7 +827,6 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
LHS.SwiftDefaultOwnership == RHS.SwiftDefaultOwnership &&
- LHS.SwiftConformance == RHS.SwiftConformance &&
LHS.isFlagEnum() == RHS.isFlagEnum() &&
LHS.isSwiftCopyable() == RHS.isSwiftCopyable() &&
LHS.isSwiftEscapable() == RHS.isSwiftEscapable() &&
diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h
index bb0c276e74964..1ac486a2dd94c 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 = 35; // SwiftDefaultOwnership
+const uint16_t VERSION_MINOR = 36; // Typedef SwiftConformsTo
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 7cc4df2a99369..538b950f8712d 100644
--- a/clang/lib/APINotes/APINotesReader.cpp
+++ b/clang/lib/APINotes/APINotesReader.cpp
@@ -134,6 +134,13 @@ void ReadCommonTypeInfo(const uint8_t *&Data, CommonTypeInfo &Info) {
reinterpret_cast<const char *>(Data), ErrorDomainLength - 1)));
Data += ErrorDomainLength - 1;
}
+
+ if (unsigned ConformanceLength =
+ endian::readNext<uint16_t, llvm::endianness::little>(Data)) {
+ Info.setSwiftConformance(std::string(reinterpret_cast<const char *>(Data),
+ ConformanceLength - 1));
+ Data += ConformanceLength - 1;
+ }
}
/// Used to deserialize the on-disk identifier table.
@@ -629,12 +636,6 @@ class TagTableInfo
reinterpret_cast<const char *>(Data), DefaultOwnershipLength - 1);
Data += DefaultOwnershipLength - 1;
}
- if (unsigned ConformanceLength =
- endian::readNext<uint16_t, llvm::endianness::little>(Data)) {
- Info.SwiftConformance = std::string(reinterpret_cast<const char *>(Data),
- ConformanceLength - 1);
- Data += ConformanceLength - 1;
- }
ReadCommonTypeInfo(Data, Info);
return Info;
diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp
index ffc5473988735..c013201d677bf 100644
--- a/clang/lib/APINotes/APINotesWriter.cpp
+++ b/clang/lib/APINotes/APINotesWriter.cpp
@@ -536,7 +536,8 @@ unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
// in on-disk hash tables.
unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
- (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
+ (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) + 2 +
+ (CTI.getSwiftConformance() ? CTI.getSwiftConformance()->size() : 0) +
getCommonEntityInfoSize(CTI);
}
@@ -557,6 +558,12 @@ void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
} else {
writer.write<uint16_t>(0);
}
+ if (auto conformance = CTI.getSwiftConformance()) {
+ writer.write<uint16_t>(conformance->size() + 1);
+ OS.write(conformance->c_str(), conformance->size());
+ } else {
+ writer.write<uint16_t>(0);
+ }
}
/// Used to serialize the on-disk Objective-C property table.
@@ -1274,7 +1281,6 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
2 + (TI.SwiftDefaultOwnership ? TI.SwiftDefaultOwnership->size() : 0) +
- 2 + (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) +
3 + getCommonTypeInfoSize(TI);
// clang-format on
}
@@ -1328,12 +1334,6 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
} else {
writer.write<uint16_t>(0);
}
- if (auto Conformance = TI.SwiftConformance) {
- writer.write<uint16_t>(Conformance->size() + 1);
- OS.write(Conformance->c_str(), Conformance->size());
- } else {
- writer.write<uint16_t>(0);
- }
emitCommonTypeInfo(OS, TI);
}
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 803410c54c646..fcc1d9d54b1c6 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -251,6 +251,7 @@ struct Class {
std::optional<StringRef> NSErrorDomain;
std::optional<bool> SwiftImportAsNonGeneric;
std::optional<bool> SwiftObjCMembers;
+ std::optional<std::string> SwiftConformance;
MethodsSeq Methods;
PropertiesSeq Properties;
};
@@ -275,6 +276,7 @@ template <> struct MappingTraits<Class> {
IO.mapOptional("NSErrorDomain", C.NSErrorDomain);
IO.mapOptional("SwiftImportAsNonGeneric", C.SwiftImportAsNonGeneric);
IO.mapOptional("SwiftObjCMembers", C.SwiftObjCMembers);
+ IO.mapOptional("SwiftConformsTo", C.SwiftConformance);
IO.mapOptional("Methods", C.Methods);
IO.mapOptional("Properties", C.Properties);
}
@@ -525,6 +527,7 @@ struct Typedef {
std::optional<StringRef> SwiftBridge;
std::optional<StringRef> NSErrorDomain;
std::optional<SwiftNewTypeKind> SwiftType;
+ std::optional<std::string> SwiftConformance;
};
typedef std::vector<Typedef> TypedefsSeq;
@@ -553,6 +556,7 @@ template <> struct MappingTraits<Typedef> {
IO.mapOptional("SwiftBridge", T.SwiftBridge);
IO.mapOptional("NSErrorDomain", T.NSErrorDomain);
IO.mapOptional("SwiftWrapper", T.SwiftType);
+ IO.mapOptional("SwiftConformsTo", T.SwiftConformance);
}
};
} // namespace yaml
@@ -802,6 +806,8 @@ class YAMLConverter {
if (Common.SwiftBridge)
Info.setSwiftBridge(std::string(*Common.SwiftBridge));
Info.setNSErrorDomain(Common.NSErrorDomain);
+ if (auto conformance = Common.SwiftConformance)
+ Info.setSwiftConformance(conformance);
}
// Translate from Method into ObjCMethodInfo and write it out.
@@ -990,8 +996,6 @@ class YAMLConverter {
TI.SwiftRetainOp = T.SwiftRetainOp;
if (T.SwiftReleaseOp)
TI.SwiftReleaseOp = T.SwiftReleaseOp;
- if (T.SwiftConformance)
- TI.SwiftConformance = T.SwiftConformance;
if (T.SwiftDefaultOwnership)
TI.SwiftDefaultOwnership = T.SwiftDefaultOwnership;
diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp
index 044abb0ee08a8..272069e5fcc7d 100644
--- a/clang/lib/Sema/SemaAPINotes.cpp
+++ b/clang/lib/Sema/SemaAPINotes.cpp
@@ -336,6 +336,10 @@ static void ProcessAPINotes(Sema &S, Decl *D,
});
}
+ if (auto ConformsTo = Info.getSwiftConformance())
+ D->addAttr(
+ SwiftAttrAttr::Create(S.Context, "conforms_to:" + ConformsTo.value()));
+
ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
Metadata);
}
@@ -698,10 +702,6 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
D->addAttr(SwiftAttrAttr::Create(
S.Context, "returned_as_" + DefaultOwnership.value() + "_by_default"));
- if (auto ConformsTo = Info.SwiftConformance)
- D->addAttr(
- SwiftAttrAttr::Create(S.Context, "conforms_to:" + ConformsTo.value()));
-
if (auto Copyable = Info.isSwiftCopyable()) {
if (!*Copyable)
D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
diff --git a/clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes b/clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes
index 8c915bd8b5913..9ba38edb8a6f1 100644
--- a/clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes
+++ b/clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes
@@ -26,3 +26,6 @@ Classes:
- Name: scalarNewProperty
PropertyKind: Instance
Nullability: Scalar
+Typedefs:
+ - Name: MyTypedef
+ SwiftConformsTo: Swift.Equatable
diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp
index 179170fbc0994..747aa29e95761 100644
--- a/clang/test/APINotes/swift-import-as.cpp
+++ b/clang/test/APINotes/swift-import-as.cpp
@@ -51,8 +51,8 @@
// CHECK-OPAQUE-REF-COUNTED-NOT: SwiftAttrAttr {{.+}} <<invalid sloc>> "release:
// CHECK-NON-COPYABLE: Dumping NonCopyableType:
// CHECK-NON-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct NonCopyableType
-// CHECK-NON-COPYABLE: SwiftAttrAttr {{.+}} <<invalid sloc>> "conforms_to:MySwiftModule.MySwiftNonCopyableProtocol"
// CHECK-NON-COPYABLE: SwiftAttrAttr {{.+}} <<invalid sloc>> "~Copyable"
+// CHECK-NON-COPYABLE: SwiftAttrAttr {{.+}} <<invalid sloc>> "conforms_to:MySwiftModule.MySwiftNonCopyableProtocol"
// CHECK-COPYABLE: Dumping CopyableType:
// CHECK-COPYABLE-NEXT: CXXRecordDecl {{.+}} imported in SwiftImportAs {{.+}} struct CopyableType
diff --git a/clang/test/APINotes/yaml-roundtrip.test b/clang/test/APINotes/yaml-roundtrip.test
index bcf84afda8df0..f69038ca828b1 100644
--- a/clang/test/APINotes/yaml-roundtrip.test
+++ b/clang/test/APINotes/yaml-roundtrip.test
@@ -24,7 +24,7 @@ CHECK-NEXT: 25c26
CHECK-NEXT: < Nullability: S
CHECK-NEXT: ---
CHECK-NEXT: > Nullability: Unspecified
-CHECK-NEXT: 28c29,30
+CHECK-NEXT: 28c29
CHECK-NEXT: < Nullability: Scalar
CHECK-NEXT: ---
CHECK-NEXT: > Nullability: Unspecified
``````````
</details>
https://github.com/llvm/llvm-project/pull/151213
More information about the cfe-commits
mailing list