mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Allow Swift to call objc_direct constructors
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'}}
|
||||
|
||||
@@ -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: }
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user