Author: Egor Zhdan Date: 2024-08-13T12:47:23+01:00 New Revision: dc8c217db6329f03a116ef63dafa6de02913d311
URL: https://github.com/llvm/llvm-project/commit/dc8c217db6329f03a116ef63dafa6de02913d311 DIFF: https://github.com/llvm/llvm-project/commit/dc8c217db6329f03a116ef63dafa6de02913d311.diff LOG: [APINotes] Support C++ tag conformances to Swift protocols This allows adding a Clang attribute `swift_attr("conforms_to:ModuleName.ProtocolName")` to C++ structs via API Notes. The Swift compiler respects this attribute when importing C++ types into Swift by automatically declaring the C++ type as a conforming type to the given Swift protocol. rdar://131388824 Added: Modified: clang/docs/APINotes.rst 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/Headers/SwiftImportAs.apinotes clang/test/APINotes/swift-import-as.cpp Removed: ################################################################################ diff --git a/clang/docs/APINotes.rst b/clang/docs/APINotes.rst index bc09b16bab5d27..dcefa6810dac67 100644 --- a/clang/docs/APINotes.rst +++ b/clang/docs/APINotes.rst @@ -188,6 +188,18 @@ declaration kind), all of which are optional: - Name: tzdb SwiftCopyable: false +:SwiftConformsTo: + + Allows annotating a C++ class as conforming to a Swift protocol. Equivalent + to ``SWIFT_CONFORMS_TO_PROTOCOL``. The value is a module-qualified name of a + Swift protocol. + + :: + + Tags: + - Name: vector + SwiftConformsTo: Cxx.CxxSequence + :Availability, AvailabilityMsg: A value of "nonswift" is equivalent to ``NS_SWIFT_UNAVAILABLE``. A value of diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h index c8e5e4df25d173..f972d0cf26640d 100644 --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -685,6 +685,9 @@ class TagInfo : public CommonTypeInfo { std::optional<std::string> SwiftRetainOp; std::optional<std::string> SwiftReleaseOp; + /// The Swift protocol that this type should be automatically conformed to. + std::optional<std::string> SwiftConformance; + std::optional<EnumExtensibilityKind> EnumExtensibility; TagInfo() @@ -720,6 +723,9 @@ class TagInfo : public CommonTypeInfo { if (!SwiftReleaseOp) SwiftReleaseOp = RHS.SwiftReleaseOp; + if (!SwiftConformance) + SwiftConformance = RHS.SwiftConformance; + if (!HasFlagEnum) setFlagEnum(RHS.isFlagEnum()); @@ -742,6 +748,7 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) { LHS.SwiftImportAs == RHS.SwiftImportAs && LHS.SwiftRetainOp == RHS.SwiftRetainOp && LHS.SwiftReleaseOp == RHS.SwiftReleaseOp && + LHS.SwiftConformance == RHS.SwiftConformance && LHS.isFlagEnum() == RHS.isFlagEnum() && LHS.isSwiftCopyable() == RHS.isSwiftCopyable() && LHS.EnumExtensibility == RHS.EnumExtensibility; diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 9d254dcc1c9eff..fba5f4e8907dae 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 = 28; // nested tags +const uint16_t VERSION_MINOR = 29; // SwiftConformsTo const uint8_t kSwiftCopyable = 1; const uint8_t kSwiftNonCopyable = 2; diff --git a/clang/lib/APINotes/APINotesReader.cpp b/clang/lib/APINotes/APINotesReader.cpp index 871f782511d5f1..c05fdffe4a071b 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -572,6 +572,12 @@ class TagTableInfo ReleaseOpLength - 1); Data += ReleaseOpLength - 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 2a71922746ac5d..cf3a0bee393eee 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -1189,6 +1189,7 @@ class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> { return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) + 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) + 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) + + 2 + (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) + 2 + getCommonTypeInfoSize(TI); } @@ -1230,6 +1231,12 @@ 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 11cccc94a15f03..2205686c4d15c3 100644 --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -419,6 +419,7 @@ struct Tag { std::optional<std::string> SwiftImportAs; std::optional<std::string> SwiftRetainOp; std::optional<std::string> SwiftReleaseOp; + std::optional<std::string> SwiftConformance; std::optional<EnumExtensibilityKind> EnumExtensibility; std::optional<bool> FlagEnum; std::optional<EnumConvenienceAliasKind> EnumConvenienceKind; @@ -456,6 +457,7 @@ template <> struct MappingTraits<Tag> { IO.mapOptional("SwiftImportAs", T.SwiftImportAs); IO.mapOptional("SwiftReleaseOp", T.SwiftReleaseOp); IO.mapOptional("SwiftRetainOp", T.SwiftRetainOp); + IO.mapOptional("SwiftConformsTo", T.SwiftConformance); IO.mapOptional("EnumExtensibility", T.EnumExtensibility); IO.mapOptional("FlagEnum", T.FlagEnum); IO.mapOptional("EnumKind", T.EnumConvenienceKind); @@ -920,6 +922,8 @@ class YAMLConverter { TI.SwiftRetainOp = T.SwiftRetainOp; if (T.SwiftReleaseOp) TI.SwiftReleaseOp = T.SwiftReleaseOp; + if (T.SwiftConformance) + TI.SwiftConformance = T.SwiftConformance; if (T.SwiftCopyable) TI.setSwiftCopyable(T.SwiftCopyable); diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 2c49c1f64b2da8..65b56bd1c8efc7 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -605,6 +605,10 @@ static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info, D->addAttr( SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value())); + 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/Headers/SwiftImportAs.apinotes b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes index b0eead42869a41..f4f9c7a244e0a3 100644 --- a/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes +++ b/clang/test/APINotes/Inputs/Headers/SwiftImportAs.apinotes @@ -7,7 +7,9 @@ Tags: SwiftImportAs: reference SwiftReleaseOp: RCRelease SwiftRetainOp: RCRetain + SwiftConformsTo: MySwiftModule.MySwiftRefCountedProtocol - Name: NonCopyableType SwiftCopyable: false + SwiftConformsTo: MySwiftModule.MySwiftNonCopyableProtocol - Name: CopyableType SwiftCopyable: true diff --git a/clang/test/APINotes/swift-import-as.cpp b/clang/test/APINotes/swift-import-as.cpp index 62e6450e94e113..6457e1557618de 100644 --- a/clang/test/APINotes/swift-import-as.cpp +++ b/clang/test/APINotes/swift-import-as.cpp @@ -16,9 +16,11 @@ // CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "import_reference" // CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "retain:RCRetain" // CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "release:RCRelease" +// CHECK-REF-COUNTED: SwiftAttrAttr {{.+}} <<invalid sloc>> "conforms_to:MySwiftModule.MySwiftRefCountedProtocol" // 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-COPYABLE: Dumping CopyableType: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits