Skip to content

[Interop][SwiftToCxx] Support printing methods and properties for enums #61004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/CppInteroperability/CppInteroperabilityStatus.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ This status table describes which of the following Swift language features have
| Copy and destroy semantics | Yes |
| Initializers | Partially, as static `init` methods. No failable support |

**Enums**

| **Swift Language Feature** | **Implemented Experimental Support For Using It In C++** |
|------------------------------|----------------------------------------------------------|
| Fixed layout enums | Yes |
| Resilient / opaque enums | Yes |
| Copy and destroy semantics | Yes |
| Creation | Yes |
| Enums with associated values | Partially: only support structs and enums |
| Enums with raw values | No |
| Indirect enums | No |

**Class types**

| **Swift Language Feature** | **Implemented Experimental Support For Using It In C++** |
Expand Down
14 changes: 6 additions & 8 deletions docs/CppInteroperability/UserGuide-CallingSwiftFromC++.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,10 @@ The following interface will be generated:
// "Navigation-Swift.h" - C++ interface for Swift's Navigation module.
class CompassDirection {
public:
static const struct { ... } north;
static const struct { ... } south;
static const struct { ... } east;
static const struct { ... } west;
inline const static struct { ... } north;
inline const static struct { ... } south;
inline const static struct { ... } east;
inline const static struct { ... } west;
private:
// type representation details.
...
Expand Down Expand Up @@ -549,15 +549,13 @@ class Barcode {
public:
Barcode() = delete;

static const struct { ... } qrCode;
static const struct { ... } upc;
inline const static struct { ... } qrCode;
inline const static struct { ... } upc;

bool isUpc() const;

using UpcType = swift::Tuple<swift::Int, swift::Int, swift::Int, swift::Int>;

bool isUpc() const;

// Extracts the associated valus from Barcode.upc enum case
UpcType getUpc() const;

Expand Down
2 changes: 2 additions & 0 deletions lib/PrintAsClang/DeclAndTypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ class DeclAndTypePrinter::Implementation
}
os << " }\n"; // operator cases()'s closing bracket
os << "\n";

printMembers(ED->getMembers());
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend %S/small-enums-pass-return-in-cxx.swift -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h
// RUN: %target-swift-frontend %S/small-enums-pass-return-in-cxx.swift -typecheck -module-name Enums -enable-experimental-cxx-interop -emit-clang-header-path %t/enums.h

// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-enums-execution.o
// RUN: %target-interop-build-swift %S/small-enums-pass-return-in-cxx.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h
// RUN: %target-swift-frontend %s -typecheck -module-name Enums -enable-experimental-cxx-interop -emit-clang-header-path %t/enums.h
// RUN: %FileCheck %s < %t/enums.h

// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function)

@_expose(Cxx)
public enum Tiny {
case first
case second
}

@_expose(Cxx)
public func makeTiny(_ x: Int) -> Tiny {
return x >= 0 ? .first : .second
}

@_expose(Cxx)
public func printTiny(_ en: Tiny) {
switch en {
case .first:
Expand All @@ -22,10 +25,12 @@ public func printTiny(_ en: Tiny) {
}
}

@_expose(Cxx)
public func passThroughTiny(_ en: Tiny) -> Tiny {
return en
}

@_expose(Cxx)
public func inoutTiny(_ en: inout Tiny, _ x: Int) {
if x >= 0 {
en = .first
Expand All @@ -34,15 +39,18 @@ public func inoutTiny(_ en: inout Tiny, _ x: Int) {
}
}

@_expose(Cxx)
public enum Small {
case first(Int)
case second(Double)
}

@_expose(Cxx)
public func makeSmall(_ x: Int) -> Small {
return x >= 0 ? .first(x) : .second(Double(-x))
}

@_expose(Cxx)
public func printSmall(_ en: Small) {
switch en {
case let .first(x):
Expand All @@ -52,10 +60,12 @@ public func printSmall(_ en: Small) {
}
}

@_expose(Cxx)
public func passThroughSmall(_ en: Small) -> Small {
return en
}

@_expose(Cxx)
public func inoutSmall(_ en: inout Small, _ x: Int) {
if x >= 0 {
en = .first(x)
Expand All @@ -64,6 +74,16 @@ public func inoutSmall(_ en: inout Small, _ x: Int) {
}
}

// CHECK: struct swift_interop_passStub_Enums_uint8_t_0_1 {
// CHECK-NEXT: uint8_t _1;
// CHECK-NEXT: };

// CHECK: static inline struct swift_interop_passStub_Enums_uint8_t_0_1 swift_interop_passDirect_Enums_uint8_t_0_1(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_passStub_Enums_uint8_t_0_1 result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 1);
// CHECK-NEXT: return result;
// CHECK-NEXT: }

// CHECK: SWIFT_EXTERN void $s5Enums10inoutSmallyyAA0C0Oz_SitF(void * _Nonnull en, ptrdiff_t x) SWIFT_NOEXCEPT SWIFT_CALL; // inoutSmall(_:_:)
// CHECK: SWIFT_EXTERN void $s5Enums9inoutTinyyyAA0C0Oz_SitF(void * _Nonnull en, ptrdiff_t x) SWIFT_NOEXCEPT SWIFT_CALL; // inoutTiny(_:_:)

Expand All @@ -82,16 +102,6 @@ public func inoutSmall(_ en: inout Small, _ x: Int) {
// CHECK: SWIFT_EXTERN struct swift_interop_returnStub_Enums_uint8_t_0_1 $s5Enums8makeTinyyAA0C0OSiF(ptrdiff_t x) SWIFT_NOEXCEPT SWIFT_CALL; // makeTiny(_:)
// CHECK: SWIFT_EXTERN struct swift_interop_returnStub_Enums_[[Small]] $s5Enums16passThroughSmallyAA0D0OADF(struct swift_interop_passStub_Enums_[[Small]] en) SWIFT_NOEXCEPT SWIFT_CALL; // passThroughSmall(_:)

// CHECK: struct swift_interop_passStub_Enums_uint8_t_0_1 {
// CHECK-NEXT: uint8_t _1;
// CHECK-NEXT: };

// CHECK: static inline struct swift_interop_passStub_Enums_uint8_t_0_1 swift_interop_passDirect_Enums_uint8_t_0_1(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_passStub_Enums_uint8_t_0_1 result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 1);
// CHECK-NEXT: return result;
// CHECK-NEXT: }

// CHECK: SWIFT_EXTERN struct swift_interop_returnStub_Enums_uint8_t_0_1 $s5Enums15passThroughTinyyAA0D0OADF(struct swift_interop_passStub_Enums_uint8_t_0_1 en) SWIFT_NOEXCEPT SWIFT_CALL; // passThroughTiny(_:)
// CHECK: SWIFT_EXTERN void $s5Enums10printSmallyyAA0C0OF(struct swift_interop_passStub_Enums_[[Small]] en) SWIFT_NOEXCEPT SWIFT_CALL; // printSmall(_:)
// CHECK: SWIFT_EXTERN void $s5Enums9printTinyyyAA0C0OF(struct swift_interop_passStub_Enums_uint8_t_0_1 en) SWIFT_NOEXCEPT SWIFT_CALL; // printTiny(_:)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// RUN: %target-interop-build-swift %S/swift-enum-implementation.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain

// RUN: %target-codesign %t/swift-enums-execution
// RUN: %target-run %t/swift-enums-execution
// RUN: %target-run %t/swift-enums-execution | %FileCheck %s

// REQUIRES: executable_test

Expand Down Expand Up @@ -73,5 +73,17 @@ int main() {
auto e = E::foobar();
assert(switchTest(e) == 5);
}

{
auto e = E::init();
assert(switchTest(e) == 5);
}

{
auto e = E::init();
assert(e.getTen() == 10);
e.printSelf();
}
// CHECK: self
return 0;
}
29 changes: 28 additions & 1 deletion test/Interop/SwiftToCxx/enums/swift-enum-implementation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ public enum E {
case w(i: Int)
case auto(UnsafeMutableRawPointer)
case foobar

public init() {
self = .foobar
}

public var ten: Int {
return 10
}

public func printSelf() {
print("self")
}
}

public struct S {
Expand Down Expand Up @@ -99,7 +111,11 @@ public struct S {
// CHECK-NEXT: default: abort();
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK: private:
// CHECK-EMPTY:
// CHECK-NEXT: static inline E init();
// CHECK-NEXT: inline swift::Int getTen() const;
// CHECK-NEXT: inline void printSelf() const;
// CHECK-NEXT: private:
// CHECK: inline char * _Nonnull _destructiveProjectEnumData() {
// CHECK-NEXT: auto metadata = _impl::$s5Enums1EOMa(0);
// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
Expand Down Expand Up @@ -257,3 +273,14 @@ public struct S {
// CHECK-NEXT: inline bool E::isFoobar() const {
// CHECK-NEXT: return *this == E::foobar;
// CHECK-NEXT: }
// CHECK-NEXT: inline E E::init() {
// CHECK-NEXT: return _impl::_impl_E::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Enums_uint64_t_0_8_uint8_t_8_9(result, _impl::$s5Enums1EOACycfC());
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK-NEXT: inline swift::Int E::getTen() const {
// CHECK-NEXT: return _impl::$s5Enums1EO3tenSivg(_impl::swift_interop_passDirect_Enums_uint64_t_0_8_uint8_t_8_9(_getOpaquePointer()));
// CHECK-NEXT: }
// CHECK-NEXT: inline void E::printSelf() const {
// CHECK-NEXT: return _impl::$s5Enums1EO9printSelfyyF(_impl::swift_interop_passDirect_Enums_uint64_t_0_8_uint8_t_8_9(_getOpaquePointer()));
// CHECK-NEXT: }