Skip to content

Commit 3f88561

Browse files
authored
Merge pull request #79514 from swiftlang/gaborh/objc-in-generics
[cxx-interop] Support ObjC classes in generic context in reverse interop
2 parents be035a6 + a6c6a00 commit 3f88561

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "swift/Strings.h"
3636

3737
#include "clang/AST/Decl.h"
38+
#include "clang/AST/DeclObjC.h"
3839
#include "clang/Basic/Module.h"
3940

4041
#include "llvm/Support/raw_ostream.h"
@@ -539,10 +540,20 @@ class ModuleWriter {
539540
}
540541

541542
void emitReferencedClangTypeMetadata(const TypeDecl *typeDecl) {
542-
if (!isa<clang::TypeDecl>(typeDecl->getClangDecl()))
543+
const auto *clangDecl = typeDecl->getClangDecl();
544+
if (const auto *objCInt = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
545+
auto clangType = clangDecl->getASTContext()
546+
.getObjCInterfaceType(objCInt)
547+
.getCanonicalType();
548+
auto it = seenClangTypes.insert(clangType.getTypePtr());
549+
if (it.second)
550+
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M,
551+
printer);
552+
return;
553+
}
554+
if (!isa<clang::TypeDecl>(clangDecl))
543555
return;
544556
// Get the underlying clang type from a type alias decl or record decl.
545-
auto clangDecl = typeDecl->getClangDecl();
546557
auto clangType = clangDecl->getASTContext()
547558
.getTypeDeclType(cast<clang::TypeDecl>(clangDecl))
548559
.getCanonicalType();
@@ -568,6 +579,8 @@ class ModuleWriter {
568579
forwardDeclareCxxValueTypeIfNeeded(NTD);
569580
else if (isa<StructDecl>(TD) && NTD->hasClangNode())
570581
emitReferencedClangTypeMetadata(NTD);
582+
else if (isa<ClassDecl>(TD) && TD->isObjC())
583+
emitReferencedClangTypeMetadata(NTD);
571584
} else if (auto TAD = dyn_cast<TypeAliasDecl>(TD)) {
572585
if (TAD->hasClangNode())
573586
emitReferencedClangTypeMetadata(TAD);

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
641641
typeDecl, typeMetadataFuncName, typeMetadataFuncRequirements);
642642
});
643643
}
644+
bool addPointer = typeDecl->isObjC();
644645

645646
os << "#pragma clang diagnostic push\n";
646647
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
@@ -649,6 +650,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
649650
os << "template<>\n";
650651
os << "inline const constexpr bool isUsableInGenericContext<";
651652
printer.printClangTypeReference(typeDecl->getClangDecl());
653+
if (addPointer)
654+
os << "*";
652655
os << "> = true;\n";
653656
}
654657
if (!NTD || printer.printNominalTypeOutsideMemberDeclTemplateSpecifiers(NTD))
@@ -658,6 +661,8 @@ void ClangValueTypePrinter::printTypeGenericTraits(
658661
os << " TypeMetadataTrait<";
659662
if (typeDecl->hasClangNode()) {
660663
printer.printClangTypeReference(typeDecl->getClangDecl());
664+
if (addPointer)
665+
os << "*";
661666
} else {
662667
assert(NTD);
663668
printer.printNominalTypeReference(NTD,
@@ -682,7 +687,7 @@ void ClangValueTypePrinter::printTypeGenericTraits(
682687

683688
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n";
684689

685-
if (typeDecl->hasClangNode()) {
690+
if (typeDecl->hasClangNode() && !typeDecl->isObjC()) {
686691
os << "template<>\n";
687692
os << "inline const constexpr bool isSwiftBridgedCxxRecord<";
688693
printer.printClangTypeReference(typeDecl->getClangDecl());

test/Interop/ObjCToSwiftToObjCxx/bridge-objc-types-back-to-objcxx-execution.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public func retObjCProtocolNullable() -> ObjCProtocol? {
8686
return ObjCKlassConforming(2)
8787
}
8888

89+
public func retObjClassArray() -> [ObjCKlass] {
90+
return [ObjCKlass(1)]
91+
}
92+
8993
//--- use-swift-objc-types.mm
9094

9195
#include "header.h"
@@ -188,5 +192,14 @@ int main() {
188192
// CHECK-NEXT: ObjCKlassConforming: 2
189193
// CHECK-NEXT: destroy ObjCKlassConforming
190194
// DESTROY: destroy ObjCKlassConforming
195+
puts("Part4");
196+
@autoreleasepool {
197+
swift::Array<ObjCKlass*> val = retObjClassArray();
198+
assert(val[0].getValue == 1);
199+
assert(globalCounter == 1);
200+
}
201+
assert(globalCounter == 0);
202+
// CHECK: create ObjCKlass
203+
// DESTROY: destroy ObjCKlass
191204
return 0;
192205
}

test/Interop/ObjCToSwiftToObjCxx/bridge-objc-types-back-to-objcxx.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ public func retObjCProtocolNullable() -> ObjCProtocol? {
6969
return nil
7070
}
7171

72+
public func retObjCClassArray() -> [ObjCKlass] {
73+
return []
74+
}
75+
7276
// CHECK: SWIFT_EXTERN id <ObjCProtocol> _Nonnull $s9UseObjCTy03retB9CProtocolSo0bE0_pyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // retObjCProtocol()
7377
// CHECK-NEXT: #endif
7478
// CHECK-NEXT: #if defined(__OBJC__)
@@ -86,6 +90,14 @@ public func retObjCProtocolNullable() -> ObjCProtocol? {
8690
// CHECK-NEXT: SWIFT_EXTERN void $s9UseObjCTy04takeB17CProtocolNullableyySo0bE0_pSgF(id <ObjCProtocol> _Nullable x) SWIFT_NOEXCEPT SWIFT_CALL; // takeObjCProtocolNullable(_:)
8791
// CHECK-NEXT: #endif
8892

93+
// CHECK: inline const constexpr bool isUsableInGenericContext<ObjCKlass*> = true;
94+
// CHECK-NEXT: template<>
95+
// CHECK-NEXT: struct TypeMetadataTrait<ObjCKlass*> {
96+
// CHECK-NEXT: static SWIFT_INLINE_PRIVATE_HELPER void * _Nonnull getTypeMetadata() {
97+
// CHECK-NEXT: return _impl::$sSo9ObjCKlassCMa(0)._0;
98+
// CHECK-NEXT: }
99+
// CHECK-NEXT: };
100+
89101
// CHECK: #if defined(__OBJC__)
90102
// CHECK-NEXT: SWIFT_INLINE_THUNK id <ObjCProtocol> _Nonnull retObjCProtocol() noexcept SWIFT_SYMBOL("s:9UseObjCTy03retB9CProtocolSo0bE0_pyF") SWIFT_WARN_UNUSED_RESULT {
91103
// CHECK-NEXT: return (__bridge_transfer id <ObjCProtocol>)(__bridge void *)UseObjCTy::_impl::$s9UseObjCTy03retB9CProtocolSo0bE0_pyF();

0 commit comments

Comments
 (0)