Skip to content

Commit a6c6a00

Browse files
author
Gabor Horvath
committed
[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
1 parent 63b7f05 commit a6c6a00

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"
@@ -285,10 +286,20 @@ class ModuleWriter {
285286
}
286287

287288
void emitReferencedClangTypeMetadata(const TypeDecl *typeDecl) {
288-
if (!isa<clang::TypeDecl>(typeDecl->getClangDecl()))
289+
const auto *clangDecl = typeDecl->getClangDecl();
290+
if (const auto *objCInt = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
291+
auto clangType = clangDecl->getASTContext()
292+
.getObjCInterfaceType(objCInt)
293+
.getCanonicalType();
294+
auto it = seenClangTypes.insert(clangType.getTypePtr());
295+
if (it.second)
296+
ClangValueTypePrinter::printClangTypeSwiftGenericTraits(os, typeDecl, &M,
297+
printer);
298+
return;
299+
}
300+
if (!isa<clang::TypeDecl>(clangDecl))
289301
return;
290302
// Get the underlying clang type from a type alias decl or record decl.
291-
auto clangDecl = typeDecl->getClangDecl();
292303
auto clangType = clangDecl->getASTContext()
293304
.getTypeDeclType(cast<clang::TypeDecl>(clangDecl))
294305
.getCanonicalType();
@@ -314,6 +325,8 @@ class ModuleWriter {
314325
forwardDeclareCxxValueTypeIfNeeded(NTD);
315326
else if (isa<StructDecl>(TD) && NTD->hasClangNode())
316327
emitReferencedClangTypeMetadata(NTD);
328+
else if (isa<ClassDecl>(TD) && TD->isObjC())
329+
emitReferencedClangTypeMetadata(NTD);
317330
} else if (auto TAD = dyn_cast<TypeAliasDecl>(TD)) {
318331
if (TAD->hasClangNode())
319332
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)