Skip to content

Commit 0d754e1

Browse files
committed
[interop][SwiftToCxx] add support for exposing non-isolated actor declarations
1 parent a0cb7a6 commit 0d754e1

File tree

7 files changed

+160
-15
lines changed

7 files changed

+160
-15
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,8 +1538,8 @@ ERROR(expose_inside_unexposed_decl,none,
15381538
ERROR(expose_invalid_name_pattern_init,none,
15391539
"invalid declaration name '%0' specified in an @_expose attribute; "
15401540
"exposed initializer name must start with 'init'", (StringRef))
1541-
ERROR(expose_unsupported_actor_to_cxx,none,
1542-
"actor %0 can not be exposed to C++", (DeclName))
1541+
ERROR(expose_unsupported_actor_isolated_to_cxx,none,
1542+
"actor-isolated %0 %1 can not be exposed to C++", (DescriptiveDeclKind, ValueDecl *))
15431543

15441544
ERROR(attr_methods_only,none,
15451545
"only methods can be declared %0", (DeclAttribute))

include/swift/AST/SwiftNameTranslation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ getNameForCxx(const ValueDecl *VD,
6565

6666
enum RepresentationKind { Representable, Unsupported };
6767

68-
enum RepresentationError { UnrepresentableActorClass };
68+
enum RepresentationError { UnrepresentableIsolatedInActor };
6969

7070
struct DeclRepresentation {
7171
RepresentationKind kind;

lib/AST/SwiftNameTranslation.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,8 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
167167

168168
swift::cxx_translation::DeclRepresentation
169169
swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
170-
if (auto *CD = dyn_cast<ClassDecl>(VD)) {
171-
// Actors are not exposable to C++.
172-
if (CD->isAnyActor())
173-
return {Unsupported, UnrepresentableActorClass};
174-
}
170+
if (getActorIsolation(const_cast<ValueDecl *>(VD)).isActorIsolated())
171+
return {Unsupported, UnrepresentableIsolatedInActor};
175172
return {Representable, llvm::None};
176173
}
177174

lib/Sema/TypeCheckAttr.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,7 +1931,7 @@ void AttributeChecker::visitCDeclAttr(CDeclAttr *attr) {
19311931
}
19321932

19331933
void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
1934-
const auto *VD = cast<ValueDecl>(D);
1934+
auto *VD = cast<ValueDecl>(D);
19351935
// Expose cannot be mixed with '@objc'/'@_cdecl' declarations.
19361936
if (VD->isObjC())
19371937
diagnose(attr->getLocation(), diag::expose_only_non_other_attr, "@objc");
@@ -1957,9 +1957,10 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
19571957
if (repr.isUnsupported()) {
19581958
using namespace cxx_translation;
19591959
switch (*repr.error) {
1960-
case UnrepresentableActorClass:
1961-
diagnose(attr->getLocation(), diag::expose_unsupported_actor_to_cxx,
1962-
decl->getName());
1960+
case UnrepresentableIsolatedInActor:
1961+
diagnose(attr->getLocation(),
1962+
diag::expose_unsupported_actor_isolated_to_cxx,
1963+
VD->getDescriptiveKind(), VD);
19631964
break;
19641965
}
19651966
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/swift-actor-in-cxx.swift -typecheck -module-name Actor -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/actor.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-actor-execution.o
6+
// RUN: %target-interop-build-swift %S/swift-actor-in-cxx.swift -o %t/swift-actor-execution -Xlinker %t/swift-actor-execution.o -module-name Actor -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-actor-execution
9+
// RUN: %target-run %t/swift-actor-execution | %FileCheck %s
10+
11+
// RUN: %empty-directory(%t-evo)
12+
13+
// RUN: %target-swift-frontend %S/swift-actor-in-cxx.swift -typecheck -module-name Actor -clang-header-expose-decls=has-expose-attr -enable-library-evolution -emit-clang-header-path %t-evo/actor.h
14+
15+
// RUN: %target-interop-build-clangxx -c %s -I %t-evo -o %t-evo/swift-actor-execution.o
16+
// RUN: %target-interop-build-swift %S/swift-actor-in-cxx.swift -o %t-evo/swift-actor-execution-evo -Xlinker %t-evo/swift-actor-execution.o -module-name Actor -enable-library-evolution -Xfrontend -entry-point-function-name -Xfrontend swiftMain
17+
18+
// RUN: %target-codesign %t-evo/swift-actor-execution-evo
19+
// RUN: %target-run %t-evo/swift-actor-execution-evo | %FileCheck %s
20+
21+
// REQUIRES: executable_test
22+
23+
#include <assert.h>
24+
#include "actor.h"
25+
#include <cstdio>
26+
27+
extern "C" size_t swift_retainCount(void * _Nonnull obj);
28+
29+
size_t getRetainCount(const Actor::ActorWithField & swiftClass) {
30+
void *p = swift::_impl::_impl_RefCountedClass::getOpaquePointer(swiftClass);
31+
return swift_retainCount(p);
32+
}
33+
34+
int main() {
35+
using namespace Actor;
36+
37+
// Ensure that the actor class is released.
38+
{
39+
auto x = ActorWithField::init();
40+
assert(getRetainCount(x) == 1);
41+
}
42+
// CHECK: init ActorWithField
43+
// CHECK-NEXT: destroy ActorWithField
44+
45+
{
46+
auto x = ActorWithField::init();
47+
{
48+
takeActorWithIntField(x);
49+
assert(getRetainCount(x) == 1);
50+
}
51+
assert(getRetainCount(x) == 1);
52+
}
53+
// CHECK-NEXT: init ActorWithField
54+
// CHECK-NEXT: takeActorWithIntField
55+
// CHECK-NEXT: destroy ActorWithField
56+
57+
{
58+
auto x = ActorWithField::init();
59+
x.method();
60+
}
61+
// CHECK-NEXT: init ActorWithField
62+
// CHECK-NEXT: nonisolated method
63+
// CHECK-NEXT: destroy ActorWithField
64+
return 0;
65+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Actor -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/actor.h
3+
// RUN: %FileCheck %s < %t/actor.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/actor.h)
6+
7+
// RUN: %target-swift-frontend %s -typecheck -module-name Actor -enable-library-evolution -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/actor-evo.h
8+
// RUN: %FileCheck %s < %t/actor-evo.h
9+
10+
// RUN: %check-interop-cxx-header-in-clang(%t/actor-evo.h)
11+
12+
@_expose(Cxx)
13+
public final actor ActorWithField {
14+
var field: Int64
15+
16+
public init() {
17+
field = 0
18+
print("init ActorWithField")
19+
}
20+
deinit {
21+
print("destroy ActorWithField")
22+
}
23+
24+
public func isolatedMethod() {}
25+
26+
public nonisolated func method() {
27+
print("nonisolated method")
28+
}
29+
}
30+
31+
// CHECK: namespace Actor {
32+
// CHECK: SWIFT_EXTERN void * _Nonnull $s5Actor0A9WithFieldCACycfC(SWIFT_CONTEXT void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // init()
33+
// CHECK: SWIFT_EXTERN void $s5Actor0A9WithFieldC6methodyyF(SWIFT_CONTEXT void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // method()
34+
35+
// CHECK: class ActorWithField final : public swift::_impl::RefCountedClass {
36+
// CHECK: static inline ActorWithField init();
37+
// CHECK: inline void method();
38+
39+
@_expose(Cxx)
40+
public func takeActorWithIntField(_ x: ActorWithField) {
41+
print("takeActorWithIntField")
42+
}

test/Interop/SwiftToCxx/unsupported/unsupported-decls-in-cxx.swift

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,49 @@
1010
// CHECK-NOT: Unsupported
1111
// CHECK: supported
1212

13+
import Distributed
14+
1315
public func supported() {}
1416

15-
@_expose(Cxx) // expected-error {{actor 'ActorClassUnsupported' can not be exposed to C++}}
16-
public actor ActorClassUnsupported {
17-
public func test() {}
17+
@_expose(Cxx)
18+
public actor ActorClass {
19+
@_expose(Cxx) // expected-error {{actor-isolated instance method 'unsupported()' can not be exposed to C++}}
20+
public func unsupported() {}
21+
22+
@_expose(Cxx) // expected-error {{actor-isolated property 'prop' can not be exposed to C++}}
23+
public var prop: Int { 42 }
24+
25+
@_expose(Cxx) // ok
26+
public init() {
27+
}
28+
29+
@_expose(Cxx) // ok
30+
nonisolated public func supported() {}
31+
32+
@_expose(Cxx) // ok
33+
nonisolated public var prop2: Int { 42 }
34+
}
35+
36+
@_expose(Cxx)
37+
public distributed actor DistributedActorClass {
38+
public typealias ActorSystem = LocalTestingDistributedActorSystem
39+
40+
@_expose(Cxx) // expected-error {{actor-isolated instance method 'unsupported()' can not be exposed to C++}}
41+
public func unsupported() {}
42+
43+
@_expose(Cxx) // expected-error {{actor-isolated property 'prop' can not be exposed to C++}}
44+
public var prop: Int { 42 }
45+
46+
@_expose(Cxx) // expected-error {{actor-isolated distributed instance method 'dist()' can not be exposed to C++}}
47+
distributed public func dist() {}
48+
49+
@_expose(Cxx) // ok
50+
public init() {
51+
}
52+
53+
@_expose(Cxx) // ok
54+
nonisolated public func supported() {}
55+
56+
@_expose(Cxx) // ok
57+
nonisolated public var prop2: Int { 42 }
1858
}

0 commit comments

Comments
 (0)