Allow Swift to call objc_direct constructors

This commit is contained in:
Ellis Hoag
2022-11-17 16:06:17 -08:00
parent 20aa5b510d
commit 693a049fe4
9 changed files with 62 additions and 34 deletions

View File

@@ -7630,22 +7630,10 @@ void ClangImporter::Implementation::importAttributes(
if (method->isDirectMethod() && !AnyUnavailable) {
assert(isa<AbstractFunctionDecl>(MappedDecl) &&
"objc_direct declarations are expected to be an AbstractFunctionDecl");
if (isa<ConstructorDecl>(MappedDecl)) {
// TODO: Teach Swift how to directly call these functions.
auto attr = AvailableAttr::createPlatformAgnostic(
C,
"Swift cannot call Objective-C initializers marked with "
"'objc_direct'",
/*Rename*/ "",
PlatformAgnosticAvailabilityKind::UnavailableInSwift);
MappedDecl->getAttrs().add(attr);
AnyUnavailable = true;
} else {
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
accessorDecl->getStorage()->getAttrs().add(attr);
}
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
accessorDecl->getStorage()->getAttrs().add(attr);
}
}
}

View File

@@ -1032,7 +1032,8 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
silConfig);
}
// As a special case, Clang functions and globals don't get mangled at all.
// As a special case, Clang functions and globals don't get mangled at all
// - except \c objc_direct decls.
if (hasDecl()) {
if (auto clangDecl = getDecl()->getClangDecl()) {
if (!isForeignToNativeThunk() && !isNativeToForeignThunk()) {
@@ -1050,7 +1051,7 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
}
return namedClangDecl->getName().str();
} else if (auto objcDecl = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
if (objcDecl->isDirectMethod()) {
if (objcDecl->isDirectMethod() && isForeign) {
std::string storage;
llvm::raw_string_ostream SS(storage);
clang::ASTContext &ctx = clangDecl->getASTContext();

View File

@@ -29,6 +29,7 @@
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.h"
#include "clang/AST/DeclObjC.h"
using namespace swift;
using namespace Lowering;
@@ -2022,25 +2023,30 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
B.createReturn(loc, result);
}
static SILValue
getThunkedForeignFunctionRef(SILGenFunction &SGF,
SILLocation loc,
SILDeclRef foreign,
ArrayRef<ManagedValue> args,
const SILConstantInfo &foreignCI) {
static SILValue getThunkedForeignFunctionRef(SILGenFunction &SGF,
AbstractFunctionDecl *fd,
SILDeclRef foreign,
ArrayRef<ManagedValue> args,
const SILConstantInfo &foreignCI) {
assert(foreign.isForeign);
// Produce an objc_method when thunking ObjC methods.
if (foreignCI.SILFnType->getRepresentation()
== SILFunctionTypeRepresentation::ObjCMethod) {
SILValue thisArg = args.back().getValue();
if (foreignCI.SILFnType->getRepresentation() ==
SILFunctionTypeRepresentation::ObjCMethod) {
auto *objcDecl =
dyn_cast_or_null<clang::ObjCMethodDecl>(fd->getClangDecl());
const bool isObjCDirect = objcDecl && objcDecl->isDirectMethod();
if (isObjCDirect) {
auto *fn = SGF.SGM.getFunction(foreign, NotForDefinition);
return SGF.B.createFunctionRef(fd, fn);
}
return SGF.B.createObjCMethod(loc, thisArg, foreign,
foreignCI.getSILType());
SILValue thisArg = args.back().getValue();
return SGF.B.createObjCMethod(fd, thisArg, foreign, foreignCI.getSILType());
}
// Otherwise, emit a function_ref.
return SGF.emitGlobalFunctionRef(loc, foreign);
return SGF.emitGlobalFunctionRef(fd, foreign);
}
/// Generate code to emit a thunk with native conventions that calls a

View File

@@ -2,8 +2,6 @@
// REQUIRES: objc_interop
let _ = Bar(value: 4) // expected-error {{'init(value:)' is unavailable in Swift}}
let _ = Bar.init(value: 5) // expected-error {{'init(value:)' is unavailable in Swift}}
var something = Bar() as AnyObject
something.directProperty = 123 // expected-error {{value of type 'AnyObject' has no member 'directProperty'}}

View File

@@ -11,6 +11,10 @@ protocol BarProtocol {
extension Bar: BarProtocol {}
let bar = Bar()
markUsed(Bar(value: 0))
// CHECK: call swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfC"
markUsed(Bar.init(value: 0))
// CHECK: call swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfC"
bar.directProperty = 123
// CHECK: call void @"\01-[Bar setDirectProperty:]"({{.*}}, i8* undef, i32 {{.*}})
@@ -53,6 +57,10 @@ markUsed(Bar.directClassMethod2())
markUsed(bar.directProtocolMethod())
// CHECK: call {{.*}} @"\01-[Bar directProtocolMethod]"({{.*}}, i8* undef)
// CHECK: define {{.*}} swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfC"
// CHECK: call swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfcTO"
// CHECK: }
// CHECK-DAG: declare i32 @"\01-[Bar directProperty]"
// CHECK-DAG: declare void @"\01-[Bar setDirectProperty:]"
// CHECK-DAG: declare i32 @"\01-[Bar directProperty2]"
@@ -64,3 +72,7 @@ markUsed(bar.directProtocolMethod())
// CHECK-DAG: declare {{.*}} @"\01+[Bar directClassMethod]"
// CHECK-DAG: declare {{.*}} @"\01+[Bar directClassMethod2]"
// CHECK-DAG: declare {{.*}} @"\01-[Bar directProtocolMethod]"
// CHECK: define {{.*}} swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfcTO"
// CHECK: call {{.*}} @"\01-[Bar initWithValue:]"
// CHECK: }

View File

@@ -1,7 +1,6 @@
#import <Foundation/Foundation.h>
@interface Bar : NSObject
+ (instancetype)barWithValue:(int)value __attribute__((objc_direct));
- (instancetype)initWithValue:(int)value __attribute__((objc_direct));
@property(direct) int directProperty;
- (int)objectAtIndexedSubscript:(int)i __attribute__((objc_direct));

View File

@@ -1,6 +1,12 @@
#import "objc_direct.h"
@implementation Bar
- (instancetype)initWithValue:(int)value {
printf("called %s with %d\n", __FUNCTION__, value);
self = [super init];
_directProperty = value;
return self;
}
- (int)objectAtIndexedSubscript:(int)i {
return 789;
}

View File

@@ -15,6 +15,11 @@ extension Bar: BarProtocol {}
let bar = Bar()
let _ = Bar(value: 22)
// CHECK: called -[Bar initWithValue:] with 22
let _ = Bar.init(value: 33)
// CHECK: called -[Bar initWithValue:] with 33
bar.directProperty = 123
print(bar.directProperty)
// CHECK: 123

View File

@@ -13,6 +13,10 @@ protocol BarProtocol {
extension Bar: BarProtocol {}
let bar = Bar()
markUsed(Bar(value: 0))
// CHECK: function_ref @$sSo3BarC5valueABSgs5Int32V_tcfC
markUsed(Bar.init(value: 0))
// CHECK: function_ref @$sSo3BarC5valueABSgs5Int32V_tcfC
bar.directProperty = 123
// CHECK: function_ref @[[BYTE01:.]]-[Bar setDirectProperty:]
@@ -47,6 +51,12 @@ markUsed(Bar.directClassMethod2())
markUsed(bar.directProtocolMethod())
// CHECK: function_ref @[[BYTE01]]-[Bar directProtocolMethod]
// CHECK: sil [clang Bar.directProtocolMethod] @[[BYTE01]]-[Bar directProtocolMethod] : $@convention(objc_method)
// CHECK-LABEL: sil shared [serialized] [ossa] @$sSo3BarC5valueABSgs5Int32V_tcfC : $@convention(method) (Int32, @thick Bar.Type) -> @owned Optional<Bar> {
// CHECK: {{.*}} = function_ref @$sSo3BarC5valueABSgs5Int32V_tcfcTO : $@convention(method)
// CHECK: } // end sil function '$sSo3BarC5valueABSgs5Int32V_tcfC'
// CHECK-DAG: sil @[[BYTE01]]-[Bar setDirectProperty:] : $@convention(objc_method)
// CHECK-DAG: sil @[[BYTE01]]-[Bar directProperty] : $@convention(objc_method)
// CHECK-DAG: sil @[[BYTE01]]-[Bar setDirectProperty2:] : $@convention(objc_method)
@@ -54,7 +64,10 @@ markUsed(bar.directProtocolMethod())
// CHECK-DAG: sil @[[BYTE01]]-[Bar objectAtIndexedSubscript:] : $@convention(objc_method)
// CHECK-DAG: sil @[[BYTE01]]-[Bar setObject:atIndexedSubscript:] : $@convention(objc_method)
// CHECK-DAG: sil [clang Bar.directMethod] @[[BYTE01]]-[Bar directMethod] : $@convention(objc_method)
// CHECK-DAG: sil [clang Bar.directProtocolMethod] @[[BYTE01]]-[Bar directProtocolMethod] : $@convention(objc_method)
// CHECK-DAG: sil [clang Bar.directMethod2] @[[BYTE01]]-[Bar directMethod2] : $@convention(objc_method)
// CHECK-DAG: sil [clang Bar.directClassMethod] @[[BYTE01]]+[Bar directClassMethod] : $@convention(objc_method)
// CHECK-DAG: sil [clang Bar.directClassMethod2] @[[BYTE01]]+[Bar directClassMethod2] : $@convention(objc_method)
// CHECK-LABEL: sil{{.*}}@$sSo3BarC5valueABSgs5Int32V_tcfcTO : $@convention(method) (Int32, @owned Bar) -> @owned Optional<Bar> {
// CHECK: function_ref @[[BYTE01]]-[Bar initWithValue:]
// CHECK: } // end sil function '$sSo3BarC5valueABSgs5Int32V_tcfcTO'