Skip to content
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

[cxx-interop] plain C++ enums should be importable into Swift #64313

Open
jpsim opened this issue Mar 13, 2023 · 4 comments
Open

[cxx-interop] plain C++ enums should be importable into Swift #64313

jpsim opened this issue Mar 13, 2023 · 4 comments
Labels
c++ interop Feature: Interoperability with C++ c++ to swift Feature → c++ interop: c++ to swift compiler The Swift compiler in itself enums c++ Feature → c++ interop: c++ enums feature A feature request or implementation

Comments

@jpsim
Copy link
Contributor

jpsim commented Mar 13, 2023

Motivation

Currently only C++ "class enums" can be imported into Swift. This is fine for enums that are entirely under the user's control, but in some cases those APIs come from external dependencies or can't be modified for some reason (e.g. API compatibility).

Ideally there would still be a way to import these into Swift without having to write a shim wrapper re-exposing them.

Currently if you have this C++ code:

namespace Parent {
namespace Child {
enum MyEnum { first, second };
}
}

constexpr Parent::Child::MyEnum kMyEnumFirst = Parent::Child::first;
// Alternatively: inline const Parent::Child::MyEnum kMyEnumFirst = Parent::Child::first;

As far as I know the only way to construct the first member of the Parent::Child::MyEnum enum from Swift is to use the kMyEnumFirst constant.

// This compiles:
print(kMyEnumFirst)
// This doesn't compile: error: type 'Parent.Child.MyEnum' has no member 'first'
// print(Parent.Child.MyEnum.first)
// This also doesn't compile: error: type 'Parent.Child' has no member 'first'
// print(Parent.Child.first)

If the enum is changed to a "class enum" then this works fine:

namespace Parent {
namespace Child {
enum class MyEnum { first, second };
}
}
print(Parent.Child.MyEnum.first)

Solution

Ideally it should be possible to construct the first member of the Parent::Child::MyEnum enum from Swift just like a class enum would be imported.

print(Parent.Child.MyEnum.first)

Alternatives considered

But if that isn't possible for some reason, then ideally the clang importer would generate accessors to all the enum fields in some other way:

print(Parent.Child.MyEnum.__first)
// or
print(Parent.Child.__MyEnum__first)

Additional context

Thread in Swift Open Source Slack: https://swift-open-source.slack.com/archives/C03FAHQK8F7/p1678459701676699
PRs changing plain enums to enum classes to work around this issue: envoyproxy/envoy#26036 and envoyproxy/envoy#26037

@jpsim jpsim added feature A feature request or implementation triage needed This issue needs more specific labels labels Mar 13, 2023
@hyp hyp added the c++ interop Feature: Interoperability with C++ label Mar 13, 2023
@hyp
Copy link
Contributor

hyp commented Mar 13, 2023

@zoecarver

@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler in itself c++ to swift Feature → c++ interop: c++ to swift enums c++ Feature → c++ interop: c++ enums and removed triage needed This issue needs more specific labels labels Mar 13, 2023
@hyp
Copy link
Contributor

hyp commented Mar 14, 2023

@AnthonyLatsis can we remove the C++ enums label? It's polluting the regular C++ interop label when creating PRs and completing the labels.

@AnthonyLatsis
Copy link
Collaborator

@hyp So you reckon we should use a single label for C++ and Swift features that share the same name? Enums are pretty similar, but what about macros? Or Cxx-specific features like templates?

@kambala-decapitator
Copy link

I noticed that this already works in Swift toolchain from Xcode 15.4, but doesn't in 15.2. Maybe also works in 15.3, but I don't have it to test.

namespace S {
enum B {
    Z,
    X,
};
}
public enum S {

    public struct B : Equatable, RawRepresentable {

        public init(_ rawValue: UInt32)

        public init(rawValue: UInt32)

        public var rawValue: UInt32
    }

    // these are missing in 15.2
    public static var Z: S.B { get }

    public static var X: S.B { get }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++ c++ to swift Feature → c++ interop: c++ to swift compiler The Swift compiler in itself enums c++ Feature → c++ interop: c++ enums feature A feature request or implementation
Projects
None yet
Development

No branches or pull requests

4 participants