Skip to content

Commit 96bc821

Browse files
ellishgEllis Hoag
authored andcommitted
Do not import objc_direct constructors
Unlike normal Objective-C functions, Swift does not directly call Objective-C constructors because it creates a thunk to allocate the object and call then constructor dynamically. This can be fixed, but for now emit a compile-time error rather than a runtime error.
1 parent d9fd6cb commit 96bc821

File tree

3 files changed

+20
-4
lines changed

3 files changed

+20
-4
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8788,10 +8788,22 @@ void ClangImporter::Implementation::importAttributes(
87888788
if (method->isDirectMethod() && !AnyUnavailable) {
87898789
assert(isa<AbstractFunctionDecl>(MappedDecl) &&
87908790
"objc_direct declarations are expected to be an AbstractFunctionDecl");
8791-
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
8792-
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
8793-
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
8794-
accessorDecl->getStorage()->getAttrs().add(attr);
8791+
if (isa<ConstructorDecl>(MappedDecl)) {
8792+
// TODO: Teach Swift how to directly call these functions.
8793+
auto attr = AvailableAttr::createPlatformAgnostic(
8794+
C,
8795+
"Swift cannot call Objective-C initializers marked with "
8796+
"'objc_direct'",
8797+
/*Rename*/ "",
8798+
PlatformAgnosticAvailabilityKind::UnavailableInSwift);
8799+
MappedDecl->getAttrs().add(attr);
8800+
AnyUnavailable = true;
8801+
} else {
8802+
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
8803+
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
8804+
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
8805+
accessorDecl->getStorage()->getAttrs().add(attr);
8806+
}
87958807
}
87968808
}
87978809
}

test/ClangImporter/objc_direct.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
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}}
57
var something = Bar() as AnyObject
68

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

test/Inputs/objc_direct.h

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

33
@interface Bar : NSObject
4+
+ (instancetype)barWithValue:(int)value __attribute__((objc_direct));
5+
- (instancetype)initWithValue:(int)value __attribute__((objc_direct));
46
@property(direct) int directProperty;
57
- (int)objectAtIndexedSubscript:(int)i __attribute__((objc_direct));
68
- (void)setObject:(int)obj atIndexedSubscript:(int)i __attribute__((objc_direct));

0 commit comments

Comments
 (0)