Skip to content

Commit a949ca9

Browse files
committed
[interop][SwiftToCxx] do not expose actor classes in the generated header
1 parent 2d961d9 commit a949ca9

File tree

6 files changed

+65
-1
lines changed

6 files changed

+65
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,8 @@ ERROR(expose_inside_unexposed_decl,none,
15061506
ERROR(expose_invalid_name_pattern_init,none,
15071507
"invalid declaration name '%0' specified in an @_expose attribute; "
15081508
"exposed initializer name must start with 'init'", (StringRef))
1509+
ERROR(expose_unsupported_actor_to_cxx,none,
1510+
"actor %0 can not be exposed to C++", (DeclName))
15091511

15101512
ERROR(attr_methods_only,none,
15111513
"only methods can be declared %0", (DeclAttribute))

include/swift/AST/SwiftNameTranslation.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ StringRef
6363
getNameForCxx(const ValueDecl *VD,
6464
CustomNamesOnly_t customNamesOnly = objc_translation::Normal);
6565

66+
enum RepresentationKind { Representable, Unsupported };
67+
68+
enum RepresentationError { UnrepresentableActorClass };
69+
70+
struct DeclRepresentation {
71+
RepresentationKind kind;
72+
llvm::Optional<RepresentationError> error;
73+
74+
/// Returns true if the given Swift node is unsupported in Clang in any
75+
/// language mode.
76+
bool isUnsupported() const { return kind == Unsupported; }
77+
};
78+
79+
/// Returns the C++ representation info for the given declaration.
80+
DeclRepresentation getDeclRepresentation(const ValueDecl *VD);
81+
82+
/// Returns true if the given value decl is exposable to C++.
83+
inline bool isExposableToCxx(const ValueDecl *VD) {
84+
return !getDeclRepresentation(VD).isUnsupported();
85+
}
86+
6687
/// Returns true if the given value decl D is visible to C++ of its
6788
/// own accord (i.e. without considering its context)
6889
bool isVisibleToCxx(const ValueDecl *VD, AccessLevel minRequiredAccess,

lib/AST/SwiftNameTranslation.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,16 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
165165
return VD->getBaseIdentifier().str();
166166
}
167167

168+
swift::cxx_translation::DeclRepresentation
169+
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+
}
175+
return {Representable, llvm::None};
176+
}
177+
168178
bool swift::cxx_translation::isVisibleToCxx(const ValueDecl *VD,
169179
AccessLevel minRequiredAccess,
170180
bool checkParent) {

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2609,7 +2609,8 @@ static bool hasExposeAttr(const ValueDecl *VD, bool isExtension = false) {
26092609
bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
26102610
return !VD->isInvalid() && (!requiresExposedAttribute || hasExposeAttr(VD)) &&
26112611
(outputLang == OutputLanguageMode::Cxx
2612-
? cxx_translation::isVisibleToCxx(VD, minRequiredAccess)
2612+
? cxx_translation::isVisibleToCxx(VD, minRequiredAccess) &&
2613+
cxx_translation::isExposableToCxx(VD)
26132614
: isVisibleToObjC(VD, minRequiredAccess)) &&
26142615
!VD->getAttrs().hasAttribute<ImplementationOnlyAttr>() &&
26152616
!isAsyncAlternativeOfOtherDecl(VD);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,18 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
19051905
decl->getName());
19061906
}
19071907

1908+
// Verify that the declaration is exposable.
1909+
auto repr = cxx_translation::getDeclRepresentation(VD);
1910+
if (repr.isUnsupported()) {
1911+
using namespace cxx_translation;
1912+
switch (*repr.error) {
1913+
case UnrepresentableActorClass:
1914+
diagnose(attr->getLocation(), diag::expose_unsupported_actor_to_cxx,
1915+
decl->getName());
1916+
break;
1917+
}
1918+
}
1919+
19081920
// Verify that the name mentioned in the expose
19091921
// attribute matches the supported name pattern.
19101922
if (!attr->Name.empty()) {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -verify -clang-header-expose-decls=has-expose-attr -disable-availability-checking -emit-clang-header-path %t/functions.h
3+
4+
// RUN: cat %s | grep -v _expose > %t/clean.swift
5+
// RUN: %target-swift-frontend %t/clean.swift -typecheck -module-name Functions -clang-header-expose-decls=all-public -disable-availability-checking -emit-clang-header-path %t/header.h
6+
// RUN: %FileCheck %s < %t/header.h
7+
8+
// REQUIRES: concurrency
9+
10+
// CHECK-NOT: Unsupported
11+
// CHECK: supported
12+
13+
public func supported() {}
14+
15+
@_expose(Cxx) // expected-error {{actor 'ActorClassUnsupported' can not be exposed to C++}}
16+
public actor ActorClassUnsupported {
17+
public func test() {}
18+
}

0 commit comments

Comments
 (0)