Skip to content

Commit deab4cb

Browse files
authored
Merge pull request #62183 from ellishg/objc-direct-constructor
Allow Swift to call objc_direct constructors
2 parents d1d3c12 + 693a049 commit deab4cb

File tree

9 files changed

+62
-34
lines changed

9 files changed

+62
-34
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7634,22 +7634,10 @@ void ClangImporter::Implementation::importAttributes(
76347634
if (method->isDirectMethod() && !AnyUnavailable) {
76357635
assert(isa<AbstractFunctionDecl>(MappedDecl) &&
76367636
"objc_direct declarations are expected to be an AbstractFunctionDecl");
7637-
if (isa<ConstructorDecl>(MappedDecl)) {
7638-
// TODO: Teach Swift how to directly call these functions.
7639-
auto attr = AvailableAttr::createPlatformAgnostic(
7640-
C,
7641-
"Swift cannot call Objective-C initializers marked with "
7642-
"'objc_direct'",
7643-
/*Rename*/ "",
7644-
PlatformAgnosticAvailabilityKind::UnavailableInSwift);
7645-
MappedDecl->getAttrs().add(attr);
7646-
AnyUnavailable = true;
7647-
} else {
7648-
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
7649-
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
7650-
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
7651-
accessorDecl->getStorage()->getAttrs().add(attr);
7652-
}
7637+
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
7638+
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
7639+
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
7640+
accessorDecl->getStorage()->getAttrs().add(attr);
76537641
}
76547642
}
76557643
}

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,8 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
10321032
silConfig);
10331033
}
10341034

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

lib/SILGen/SILGenBridging.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/SIL/SILArgument.h"
3030
#include "swift/SIL/SILUndef.h"
3131
#include "swift/SIL/TypeLowering.h"
32+
#include "clang/AST/DeclObjC.h"
3233

3334
using namespace swift;
3435
using namespace Lowering;
@@ -2022,25 +2023,30 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
20222023
B.createReturn(loc, result);
20232024
}
20242025

2025-
static SILValue
2026-
getThunkedForeignFunctionRef(SILGenFunction &SGF,
2027-
SILLocation loc,
2028-
SILDeclRef foreign,
2029-
ArrayRef<ManagedValue> args,
2030-
const SILConstantInfo &foreignCI) {
2026+
static SILValue getThunkedForeignFunctionRef(SILGenFunction &SGF,
2027+
AbstractFunctionDecl *fd,
2028+
SILDeclRef foreign,
2029+
ArrayRef<ManagedValue> args,
2030+
const SILConstantInfo &foreignCI) {
20312031
assert(foreign.isForeign);
20322032

20332033
// Produce an objc_method when thunking ObjC methods.
2034-
if (foreignCI.SILFnType->getRepresentation()
2035-
== SILFunctionTypeRepresentation::ObjCMethod) {
2036-
SILValue thisArg = args.back().getValue();
2034+
if (foreignCI.SILFnType->getRepresentation() ==
2035+
SILFunctionTypeRepresentation::ObjCMethod) {
2036+
auto *objcDecl =
2037+
dyn_cast_or_null<clang::ObjCMethodDecl>(fd->getClangDecl());
2038+
const bool isObjCDirect = objcDecl && objcDecl->isDirectMethod();
2039+
if (isObjCDirect) {
2040+
auto *fn = SGF.SGM.getFunction(foreign, NotForDefinition);
2041+
return SGF.B.createFunctionRef(fd, fn);
2042+
}
20372043

2038-
return SGF.B.createObjCMethod(loc, thisArg, foreign,
2039-
foreignCI.getSILType());
2044+
SILValue thisArg = args.back().getValue();
2045+
return SGF.B.createObjCMethod(fd, thisArg, foreign, foreignCI.getSILType());
20402046
}
20412047

20422048
// Otherwise, emit a function_ref.
2043-
return SGF.emitGlobalFunctionRef(loc, foreign);
2049+
return SGF.emitGlobalFunctionRef(fd, foreign);
20442050
}
20452051

20462052
/// Generate code to emit a thunk with native conventions that calls a

test/ClangImporter/objc_direct.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
// REQUIRES: objc_interop
44

5-
let _ = Bar(value: 4) // expected-error {{'init(value:)' is unavailable in Swift}}
6-
let _ = Bar.init(value: 5) // expected-error {{'init(value:)' is unavailable in Swift}}
75
var something = Bar() as AnyObject
86

97
something.directProperty = 123 // expected-error {{value of type 'AnyObject' has no member 'directProperty'}}

test/IRGen/objc_direct.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ protocol BarProtocol {
1111
extension Bar: BarProtocol {}
1212

1313
let bar = Bar()
14+
markUsed(Bar(value: 0))
15+
// CHECK: call swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfC"
16+
markUsed(Bar.init(value: 0))
17+
// CHECK: call swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfC"
1418

1519
bar.directProperty = 123
1620
// CHECK: call void @"\01-[Bar setDirectProperty:]"({{.*}}, i8* undef, i32 {{.*}})
@@ -53,6 +57,10 @@ markUsed(Bar.directClassMethod2())
5357
markUsed(bar.directProtocolMethod())
5458
// CHECK: call {{.*}} @"\01-[Bar directProtocolMethod]"({{.*}}, i8* undef)
5559

60+
// CHECK: define {{.*}} swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfC"
61+
// CHECK: call swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfcTO"
62+
// CHECK: }
63+
5664
// CHECK-DAG: declare i32 @"\01-[Bar directProperty]"
5765
// CHECK-DAG: declare void @"\01-[Bar setDirectProperty:]"
5866
// CHECK-DAG: declare i32 @"\01-[Bar directProperty2]"
@@ -64,3 +72,7 @@ markUsed(bar.directProtocolMethod())
6472
// CHECK-DAG: declare {{.*}} @"\01+[Bar directClassMethod]"
6573
// CHECK-DAG: declare {{.*}} @"\01+[Bar directClassMethod2]"
6674
// CHECK-DAG: declare {{.*}} @"\01-[Bar directProtocolMethod]"
75+
76+
// CHECK: define {{.*}} swiftcc i64 @"$sSo3BarC5valueABSgs5Int32V_tcfcTO"
77+
// CHECK: call {{.*}} @"\01-[Bar initWithValue:]"
78+
// CHECK: }

test/Inputs/objc_direct.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#import <Foundation/Foundation.h>
22

33
@interface Bar : NSObject
4-
+ (instancetype)barWithValue:(int)value __attribute__((objc_direct));
54
- (instancetype)initWithValue:(int)value __attribute__((objc_direct));
65
@property(direct) int directProperty;
76
- (int)objectAtIndexedSubscript:(int)i __attribute__((objc_direct));

test/Interpreter/Inputs/objc_direct.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#import "objc_direct.h"
22

33
@implementation Bar
4+
- (instancetype)initWithValue:(int)value {
5+
printf("called %s with %d\n", __FUNCTION__, value);
6+
self = [super init];
7+
_directProperty = value;
8+
return self;
9+
}
410
- (int)objectAtIndexedSubscript:(int)i {
511
return 789;
612
}

test/Interpreter/objc_direct.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ extension Bar: BarProtocol {}
1515

1616
let bar = Bar()
1717

18+
let _ = Bar(value: 22)
19+
// CHECK: called -[Bar initWithValue:] with 22
20+
let _ = Bar.init(value: 33)
21+
// CHECK: called -[Bar initWithValue:] with 33
22+
1823
bar.directProperty = 123
1924
print(bar.directProperty)
2025
// CHECK: 123

test/SILGen/objc_direct.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ protocol BarProtocol {
1313
extension Bar: BarProtocol {}
1414

1515
let bar = Bar()
16+
markUsed(Bar(value: 0))
17+
// CHECK: function_ref @$sSo3BarC5valueABSgs5Int32V_tcfC
18+
markUsed(Bar.init(value: 0))
19+
// CHECK: function_ref @$sSo3BarC5valueABSgs5Int32V_tcfC
1620

1721
bar.directProperty = 123
1822
// CHECK: function_ref @[[BYTE01:.]]-[Bar setDirectProperty:]
@@ -47,14 +51,23 @@ markUsed(Bar.directClassMethod2())
4751
markUsed(bar.directProtocolMethod())
4852
// CHECK: function_ref @[[BYTE01]]-[Bar directProtocolMethod]
4953

54+
// CHECK: sil [clang Bar.directProtocolMethod] @[[BYTE01]]-[Bar directProtocolMethod] : $@convention(objc_method)
55+
56+
// CHECK-LABEL: sil shared [serialized] [ossa] @$sSo3BarC5valueABSgs5Int32V_tcfC : $@convention(method) (Int32, @thick Bar.Type) -> @owned Optional<Bar> {
57+
// CHECK: {{.*}} = function_ref @$sSo3BarC5valueABSgs5Int32V_tcfcTO : $@convention(method)
58+
// CHECK: } // end sil function '$sSo3BarC5valueABSgs5Int32V_tcfC'
59+
5060
// CHECK-DAG: sil @[[BYTE01]]-[Bar setDirectProperty:] : $@convention(objc_method)
5161
// CHECK-DAG: sil @[[BYTE01]]-[Bar directProperty] : $@convention(objc_method)
5262
// CHECK-DAG: sil @[[BYTE01]]-[Bar setDirectProperty2:] : $@convention(objc_method)
5363
// CHECK-DAG: sil @[[BYTE01]]-[Bar directProperty2] : $@convention(objc_method)
5464
// CHECK-DAG: sil @[[BYTE01]]-[Bar objectAtIndexedSubscript:] : $@convention(objc_method)
5565
// CHECK-DAG: sil @[[BYTE01]]-[Bar setObject:atIndexedSubscript:] : $@convention(objc_method)
5666
// CHECK-DAG: sil [clang Bar.directMethod] @[[BYTE01]]-[Bar directMethod] : $@convention(objc_method)
57-
// CHECK-DAG: sil [clang Bar.directProtocolMethod] @[[BYTE01]]-[Bar directProtocolMethod] : $@convention(objc_method)
5867
// CHECK-DAG: sil [clang Bar.directMethod2] @[[BYTE01]]-[Bar directMethod2] : $@convention(objc_method)
5968
// CHECK-DAG: sil [clang Bar.directClassMethod] @[[BYTE01]]+[Bar directClassMethod] : $@convention(objc_method)
6069
// CHECK-DAG: sil [clang Bar.directClassMethod2] @[[BYTE01]]+[Bar directClassMethod2] : $@convention(objc_method)
70+
71+
// CHECK-LABEL: sil{{.*}}@$sSo3BarC5valueABSgs5Int32V_tcfcTO : $@convention(method) (Int32, @owned Bar) -> @owned Optional<Bar> {
72+
// CHECK: function_ref @[[BYTE01]]-[Bar initWithValue:]
73+
// CHECK: } // end sil function '$sSo3BarC5valueABSgs5Int32V_tcfcTO'

0 commit comments

Comments
 (0)