[cxx-interop] Support ObjC classes in generic context in reverse interop

We have the sufficient type metadata on the Swift side so this PR only
makes sure the type traits are correctly generated.

rdar://145211212
This commit is contained in:
Gabor Horvath
2025-02-20 13:07:06 +00:00
parent 63b7f05d74
commit a6c6a005d7
4 changed files with 46 additions and 3 deletions

View File

@@ -35,6 +35,7 @@
#include "swift/Strings.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/Module.h"
#include "llvm/Support/raw_ostream.h"
@@ -285,10 +286,20 @@ public:
}
void emitReferencedClangTypeMetadata(const TypeDecl *typeDecl) {
if (!isa<clang::TypeDecl>(typeDecl->getClangDecl()))
const auto *clangDecl = typeDecl->getClangDecl();
if (const auto *objCInt = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
auto clangType = clangDecl->getASTContext()
.getObjCInterfaceType(objCInt)
.getCanonicalType();
auto it = seenClangTypes.insert(clangType.getTypePtr());
if (it.second)
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M,
printer);
return;
}
if (!isa<clang::TypeDecl>(clangDecl))
return;
// Get the underlying clang type from a type alias decl or record decl.
auto clangDecl = typeDecl->getClangDecl();
auto clangType = clangDecl->getASTContext()
.getTypeDeclType(cast<clang::TypeDecl>(clangDecl))
.getCanonicalType();
@@ -314,6 +325,8 @@ public:
forwardDeclareCxxValueTypeIfNeeded(NTD);
else if (isa<StructDecl>(TD) && NTD->hasClangNode())
emitReferencedClangTypeMetadata(NTD);
else if (isa<ClassDecl>(TD) && TD->isObjC())
emitReferencedClangTypeMetadata(NTD);
} else if (auto TAD = dyn_cast<TypeAliasDecl>(TD)) {
if (TAD->hasClangNode())
emitReferencedClangTypeMetadata(TAD);

View File

@@ -641,6 +641,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
typeDecl, typeMetadataFuncName, typeMetadataFuncRequirements);
});
}
bool addPointer = typeDecl->isObjC();
os << "#pragma clang diagnostic push\n";
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
@@ -649,6 +650,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
os << "template<>\n";
os << "inline const constexpr bool isUsableInGenericContext<";
printer.printClangTypeReference(typeDecl->getClangDecl());
if (addPointer)
os << "*";
os << "> = true;\n";
}
if (!NTD || printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(NTD))
@@ -658,6 +661,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
os << " TypeMetadataTrait<";
if (typeDecl->hasClangNode()) {
printer.printClangTypeReference(typeDecl->getClangDecl());
if (addPointer)
os << "*";
} else {
assert(NTD);
printer.printNominalTypeReference(NTD,
@@ -682,7 +687,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n";
if (typeDecl->hasClangNode()) {
if (typeDecl->hasClangNode() && !typeDecl->isObjC()) {
os << "template<>\n";
os << "inline const constexpr bool isSwiftBridgedCxxRecord<";
printer.printClangTypeReference(typeDecl->getClangDecl());

View File

@@ -86,6 +86,10 @@ public func retObjCProtocolNullable() -> ObjCProtocol? {
return ObjCKlassConforming(2)
}
public func retObjClassArray() -> [ObjCKlass] {
return [ObjCKlass(1)]
}
//--- use-swift-objc-types.mm
#include "header.h"
@@ -188,5 +192,14 @@ int main() {
// CHECK-NEXT: ObjCKlassConforming: 2
// CHECK-NEXT: destroy ObjCKlassConforming
// DESTROY: destroy ObjCKlassConforming
puts("Part4");
@autoreleasepool {
swift::Array<ObjCKlass*> val = retObjClassArray();
assert(val[0].getValue == 1);
assert(globalCounter == 1);
}
assert(globalCounter == 0);
// CHECK: create ObjCKlass
// DESTROY: destroy ObjCKlass
return 0;
}

View File

@@ -69,6 +69,10 @@ public func retObjCProtocolNullable() -> ObjCProtocol? {
return nil
}
public func retObjCClassArray() -> [ObjCKlass] {
return []
}
// CHECK: SWIFT_EXTERN id <ObjCProtocol> _Nonnull $s9UseObjCTy03retB9CProtocolSo0bE0_pyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // retObjCProtocol()
// CHECK-NEXT: #endif
// CHECK-NEXT: #if defined(__OBJC__)
@@ -86,6 +90,14 @@ public func retObjCProtocolNullable() -> ObjCProtocol? {
// CHECK-NEXT: SWIFT_EXTERN void $s9UseObjCTy04takeB17CProtocolNullableyySo0bE0_pSgF(id <ObjCProtocol> _Nullable x) SWIFT_NOEXCEPT SWIFT_CALL; // takeObjCProtocolNullable(_:)
// CHECK-NEXT: #endif
// CHECK: inline const constexpr bool isUsableInGenericContext<ObjCKlass*> = true;
// CHECK-NEXT: template<>
// CHECK-NEXT: struct TypeMetadataTrait<ObjCKlass*> {
// CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() {
// CHECK-NEXT: return _impl::$sSo9ObjCKlassCMa(0)._0;
// CHECK-NEXT: }
// CHECK-NEXT: };
// CHECK: #if defined(__OBJC__)
// CHECK-NEXT: SWIFT_INLINE_THUNK id <ObjCProtocol> _Nonnull retObjCProtocol() noexcept SWIFT_SYMBOL("s:9UseObjCTy03retB9CProtocolSo0bE0_pyF") SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return (__bridge_transfer id <ObjCProtocol>)(__bridge void *)UseObjCTy::_impl::$s9UseObjCTy03retB9CProtocolSo0bE0_pyF();