Skip to content

Commit 7bf7642

Browse files
committed
[interop][SwiftToCxx] support @_expose attribute on initializers
1 parent 06d9fd2 commit 7bf7642

File tree

6 files changed

+45
-3
lines changed

6 files changed

+45
-3
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ SIMPLE_DECL_ATTR(_alwaysEmitConformanceMetadata, AlwaysEmitConformanceMetadata,
758758
132)
759759

760760
DECL_ATTR(_expose, Expose,
761-
OnFunc | OnNominalType | OnVar |
761+
OnFunc | OnNominalType | OnVar | OnConstructor |
762762
LongAttribute | UserInaccessible |
763763
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
764764
133)

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,9 @@ ERROR(expose_only_non_other_attr,none,
14851485
"@_expose attribute cannot be applied to an '%0' declaration", (StringRef))
14861486
ERROR(expose_inside_unexposed_decl,none,
14871487
"@_expose attribute cannot be applied inside of unexposed declaration %0", (DeclName))
1488+
ERROR(expose_invalid_name_pattern_init,none,
1489+
"invalid declaration name '%0' specified in an @_expose attribute; "
1490+
"exposed initializer name must start with 'init'", (StringRef))
14881491

14891492
ERROR(attr_methods_only,none,
14901493
"only methods can be declared %0", (DeclAttribute))

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,16 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
697697
}
698698
}
699699

700+
static StringRef getConstructorName(const AbstractFunctionDecl *FD) {
701+
auto name = cxx_translation::getNameForCxx(
702+
FD, cxx_translation::CustomNamesOnly_t::CustomNamesOnly);
703+
if (!name.empty()) {
704+
assert(name.startswith("init"));
705+
return name;
706+
}
707+
return "init";
708+
}
709+
700710
void DeclAndTypeClangFunctionPrinter::printCxxMethod(
701711
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
702712
StringRef swiftSymbolName, Type resultTy, bool isDefinition) {
@@ -713,8 +723,10 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
713723
modifiers.isConst =
714724
!isa<ClassDecl>(typeDeclContext) && !isMutating && !isConstructor;
715725
auto result = printFunctionSignature(
716-
FD, isConstructor ? "init" : cxx_translation::getNameForCxx(FD), resultTy,
717-
FunctionSignatureKind::CxxInlineThunk, {}, modifiers);
726+
FD,
727+
isConstructor ? getConstructorName(FD)
728+
: cxx_translation::getNameForCxx(FD),
729+
resultTy, FunctionSignatureKind::CxxInlineThunk, {}, modifiers);
718730
assert(!result.isUnsupported() && "C signature should be unsupported too");
719731

720732
if (!isDefinition) {

lib/Sema/TypeCheckAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,14 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
18651865
diagnose(attr->getLocation(), diag::expose_inside_unexposed_decl,
18661866
decl->getName());
18671867
}
1868+
1869+
// Verify that the name mentioned in the expose
1870+
// attribute matches the supported name pattern.
1871+
if (!attr->Name.empty()) {
1872+
if (isa<ConstructorDecl>(VD) && !attr->Name.startswith("init"))
1873+
diagnose(attr->getLocation(), diag::expose_invalid_name_pattern_init,
1874+
attr->Name);
1875+
}
18681876
}
18691877

18701878
void AttributeChecker::visitUnsafeNoObjCTaggedPointerAttr(

test/Interop/SwiftToCxx/expose-attr/expose-swift-decls-to-cxx.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public struct NotExposedStruct {
4444
public struct ExposedStructRenamed {
4545
public var y: Int
4646

47+
@_expose(Cxx)
48+
public init() { y = 42; prop = 0; prop2 = 0; }
49+
50+
@_expose(Cxx, "initWithValue")
51+
public init(why x: Int) { y = x; prop = 0; prop2 = 0; }
52+
4753
@_expose(Cxx, "renamedProp")
4854
public var prop: Int
4955

@@ -74,6 +80,8 @@ public final class ExposedClass {
7480
// CHECK: ExposedStruct2(ExposedStruct2 &&) = default;
7581
// CHECK-NEXT: swift::Int getY() const;
7682
// CHECK-NEXT: void setY(swift::Int value);
83+
// CHECK-NEXT: static inline ExposedStruct2 init();
84+
// CHECK-NEXT: static inline ExposedStruct2 initWithValue(swift::Int x);
7785
// CHECK-NEXT: swift::Int getRenamedProp() const;
7886
// CHECK-NEXT: void setRenamedProp(swift::Int value);
7987
// CHECK-NEXT: swift::Int getProp3() const;
@@ -100,6 +108,8 @@ public final class ExposedClass {
100108
// CHECK: void ExposedStruct::method() const {
101109
// CHECK: swift::Int ExposedStruct2::getY() const {
102110
// CHECK: void ExposedStruct2::setY(swift::Int value) {
111+
// CHECK: ExposedStruct2 ExposedStruct2::init() {
112+
// CHECK: ExposedStruct2 ExposedStruct2::initWithValue(swift::Int x) {
103113
// CHECK: swift::Int ExposedStruct2::getRenamedProp() const {
104114
// CHECK: void ExposedStruct2::setRenamedProp(swift::Int value) {
105115
// CHECK: swift::Int ExposedStruct2::getProp3() const {

test/attr/attr_expose.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,12 @@ struct NotExposedStruct {
2424
@_expose(Cxx) // expected-error {{@_expose attribute cannot be applied inside of unexposed declaration 'NotExposedStruct'}}
2525
func errorOnInnerExpose() {}
2626
}
27+
28+
@_expose(Cxx)
29+
struct ExposedStruct {
30+
@_expose(Cxx, "create") // expected-error {{invalid declaration name 'create' specified in an @_expose attribute; exposed initializer name must start with 'init'}}
31+
init() {}
32+
33+
@_expose(Cxx, "initWith")
34+
init(with y: Int) {}
35+
}

0 commit comments

Comments
 (0)