Author: Doug Gregor Date: 2025-08-12T19:57:43+01:00 New Revision: 2b37471f7284f2a7baa44f638efc73b8095b9a67
URL: https://github.com/llvm/llvm-project/commit/2b37471f7284f2a7baa44f638efc73b8095b9a67 DIFF: https://github.com/llvm/llvm-project/commit/2b37471f7284f2a7baa44f638efc73b8095b9a67.diff LOG: [API notes] Allow SwiftConformsTo on Typedefs SwiftConformsTo specifies an additional conformance that should be applied on import. Allow this on typedefs, because those can be imported as wrapper types. Added: Modified: clang/include/clang/APINotes/Types.h clang/lib/APINotes/APINotesFormat.h clang/lib/APINotes/APINotesReader.cpp clang/lib/APINotes/APINotesWriter.cpp clang/lib/APINotes/APINotesYAMLCompiler.cpp clang/lib/Sema/SemaAPINotes.cpp clang/test/APINotes/Inputs/Frameworks/Simple.framework/Headers/Simple.apinotes clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes clang/test/APINotes/Inputs/Headers/SwiftImportAs.h clang/test/APINotes/swift-import-as.cpp clang/test/APINotes/yaml-roundtrip.test Removed: ################################################################################ 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..8b3812613b166 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/Inputs/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes index c096822fb92b5..cf739ee81c0a9 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes @@ -39,3 +39,7 @@ Functions: SwiftReturnOwnership: unretained - Name: functionReturningFrt_returns_retained SwiftReturnOwnership: retained +Typedefs: + - Name: WrappedOptions + SwiftWrapper: struct + SwiftConformsTo: Swift.OptionSet diff --git a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h index 5f817ac89bdd3..4ff45c754fe88 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.h @@ -29,3 +29,5 @@ struct OpaqueRefCountedType; // redeclaration inline void ORCRetain(struct OpaqueRefCountedType *x); inline void ORCRelease(struct OpaqueRefCountedType *x); + +typedef unsigned WrappedOptions; diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp index 179170fbc0994..64c8c6f202f98 100644 --- a/clang/test/APINotes/swift-import-as.cpp +++ b/clang/test/APINotes/swift-import-as.cpp @@ -14,6 +14,7 @@ // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt__ | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT %s // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_unretained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-UNRETAINED %s // RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter methodReturningFrt_returns_retained | FileCheck -check-prefix=CHECK-METHOD-RETURNING-FRT-RETAINED %s +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -x c++ -ast-dump -ast-dump-filter WrappedOptions | FileCheck -check-prefix=CHECK-WRAPPED-OPTIONS %s #include <SwiftImportAs.h> @@ -51,8 +52,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 @@ -91,3 +92,8 @@ // CHECK-METHOD-RETURNING-FRT-RETAINED: Dumping ImmortalRefType::methodReturningFrt_returns_retained: // CHECK-METHOD-RETURNING-FRT-RETAINED: CXXMethodDecl {{.+}} imported in SwiftImportAs methodReturningFrt_returns_retained 'ImmortalRefType *()' // CHECK-METHOD-RETURNING-FRT-RETAINED: `-SwiftAttrAttr {{.+}} "returns_retained" + +// CHECK-WRAPPED-OPTIONS: Dumping WrappedOptions +// CHECK-WRAPPED-OPTIONS: TypedefDecl{{.*}}WrappedOptions 'unsigned int' +// CHECK-WRAPPED-OPTIONS: SwiftNewTypeAttr {{.*}} swift_wrapper NK_Struct +// CHECK-WRAPPED-OPTIONS: SwiftAttrAttr {{.*}} "conforms_to:Swift.OptionSet" 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
