Skip to content

Commit 56665d5

Browse files
authored
Merge pull request #61882 from hyp/eng/actor-expose
[interop][SwiftToCxx] add support for exposing non-isolated actor declarations
2 parents 5014d7f + 1a277f2 commit 56665d5

File tree

8 files changed

+165
-16
lines changed

8 files changed

+165
-16
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5
1+
6

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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 -disable-availability-checking
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 -Xfrontend -disable-availability-checking
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 -disable-availability-checking
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 -Xfrontend -disable-availability-checking
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+
// REQUIRES: concurrency
24+
25+
#include <assert.h>
26+
#include "actor.h"
27+
#include <cstdio>
28+
29+
extern "C" size_t swift_retainCount(void * _Nonnull obj);
30+
31+
size_t getRetainCount(const Actor::ActorWithField & swiftClass) {
32+
void *p = swift::_impl::_impl_RefCountedClass::getOpaquePointer(swiftClass);
33+
return swift_retainCount(p);
34+
}
35+
36+
int main() {
37+
using namespace Actor;
38+
39+
// Ensure that the actor class is released.
40+
{
41+
auto x = ActorWithField::init();
42+
assert(getRetainCount(x) == 1);
43+
}
44+
// CHECK: init ActorWithField
45+
// CHECK-NEXT: destroy ActorWithField
46+
47+
{
48+
auto x = ActorWithField::init();
49+
{
50+
takeActorWithIntField(x);
51+
assert(getRetainCount(x) == 1);
52+
}
53+
assert(getRetainCount(x) == 1);
54+
}
55+
// CHECK-NEXT: init ActorWithField
56+
// CHECK-NEXT: takeActorWithIntField
57+
// CHECK-NEXT: destroy ActorWithField
58+
59+
{
60+
auto x = ActorWithField::init();
61+
x.method();
62+
}
63+
// CHECK-NEXT: init ActorWithField
64+
// CHECK-NEXT: nonisolated method
65+
// CHECK-NEXT: destroy ActorWithField
66+
return 0;
67+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 -disable-availability-checking
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 -disable-availability-checking
8+
// RUN: %FileCheck %s < %t/actor-evo.h
9+
10+
// RUN: %check-interop-cxx-header-in-clang(%t/actor-evo.h)
11+
12+
// REQUIRES: concurrency
13+
14+
@_expose(Cxx)
15+
public final actor ActorWithField {
16+
var field: Int64
17+
18+
public init() {
19+
field = 0
20+
print("init ActorWithField")
21+
}
22+
deinit {
23+
print("destroy ActorWithField")
24+
}
25+
26+
public func isolatedMethod() {}
27+
28+
public nonisolated func method() {
29+
print("nonisolated method")
30+
}
31+
}
32+
33+
// CHECK: namespace Actor {
34+
// CHECK: SWIFT_EXTERN void * _Nonnull $s5Actor0A9WithFieldCACycfC(SWIFT_CONTEXT void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // init()
35+
// CHECK: SWIFT_EXTERN void $s5Actor0A9WithFieldC6methodyyF(SWIFT_CONTEXT void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // method()
36+
37+
// CHECK: class ActorWithField final : public swift::_impl::RefCountedClass {
38+
// CHECK: static inline ActorWithField init();
39+
// CHECK: inline void method();
40+
41+
@_expose(Cxx)
42+
public func takeActorWithIntField(_ x: ActorWithField) {
43+
print("takeActorWithIntField")
44+
}

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)