Skip to content

Commit

Permalink
[cxx-interop] Support scoped enums (enum classes).
Browse files Browse the repository at this point in the history
Simply treat scoped enums as (pre-existing) "non frozen enums". C++
scoped enums are actually imported as Swift enums (unlike other enums)
and no global variables need be created (given their "scoped" nature).
  • Loading branch information
zoecarver committed Dec 16, 2020
1 parent d89ffe7 commit 3c5f2c9
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 8 deletions.
5 changes: 5 additions & 0 deletions lib/ClangImporter/ImportEnumInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ void EnumInfo::classifyEnum(const clang::EnumDecl *decl,
if (!nsErrorDomain.empty())
return;

if (decl->isScoped()) {
kind = EnumKind::NonFrozenEnum;
return;
}

// If API notes have /removed/ a FlagEnum or EnumExtensibility attribute,
// then we don't need to check the macros.
for (auto *attr : decl->specific_attrs<clang::SwiftVersionedAttr>()) {
Expand Down
4 changes: 4 additions & 0 deletions test/Interop/Cxx/enum/Inputs/module.modulemap
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
module BoolEnums {
header "bool-enums.h"
}

module ScopedEnums {
header "scoped-enums.h"
}
21 changes: 21 additions & 0 deletions test/Interop/Cxx/enum/Inputs/scoped-enums.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
enum class ScopedEnumDefined { x = 0, y = 2 };

enum class ScopedEnumBasic { x, y, z };

enum class ScopedEnumCharDefined : char { x = 0, y = 2 };

enum class ScopedEnumUnsignedDefined : unsigned int { x = 0, y = 2 };

enum class ScopedEnumUnsignedLongDefined : unsigned long { x = 0, y = 2 };

enum class ScopedEnumChar : char { x, y, z };

enum class ScopedEnumUnsigned : unsigned int { x, y, z };

enum class ScopedEnumUnsignedLong : unsigned long { x, y, z };

enum class ScopedEnumInt : int { x, y, z };

enum class ScopedEnumNegativeElement : int { x = -1, y = 0, z = 2 };

enum class MiddleDefinedScopedEnum { x, y = 42, z };
16 changes: 8 additions & 8 deletions test/Interop/Cxx/enum/bool-enums-module-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
// CHECK-NEXT: var rawValue: Bool
// CHECK-NEXT: typealias RawValue = Bool
// CHECK-NEXT: }

// CHECK: var No: Maybe { get }
// CHECK: var Yes: Maybe { get }

Expand All @@ -18,15 +17,16 @@
// CHECK-NEXT: var rawValue: Bool
// CHECK-NEXT: typealias RawValue = Bool
// CHECK-NEXT: }

// CHECK: var One: BinaryNumbers { get }
// CHECK: var Zero: BinaryNumbers { get }
// CHECK: struct EnumClass : Equatable, RawRepresentable {
// CHECK-NEXT: init(_ rawValue: Bool)
// CHECK-NEXT: init(rawValue: Bool)
// CHECK-NEXT: var rawValue: Bool
// CHECK-NEXT: typealias RawValue = Bool
// CHECK-NEXT: }

// CHECK: enum EnumClass : Bool {
// CHECK: init?(rawValue: Bool)
// CHECK: var rawValue: Bool { get }
// CHECK: typealias RawValue = Bool
// CHECK: case Foo
// CHECK: case Bar
// CHECK: }

// CHECK: struct WrapperStruct {
// TODO: where is "A" and "B"? They should be member variables.
Expand Down
87 changes: 87 additions & 0 deletions test/Interop/Cxx/enum/scoped-enums-module-interface.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=ScopedEnums -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s

// CHECK: enum ScopedEnumDefined : Int32 {
// CHECK: init?(rawValue: Int32)
// CHECK: var rawValue: Int32 { get }
// CHECK: typealias RawValue = Int32
// CHECK: case x
// CHECK: case y
// CHECK: }

// CHECK: enum ScopedEnumBasic : Int32 {
// CHECK: init?(rawValue: Int32)
// CHECK: var rawValue: Int32 { get }
// CHECK: typealias RawValue = Int32
// CHECK: case x
// CHECK: case y
// CHECK: case z
// CHECK: }

// CHECK: enum ScopedEnumCharDefined : CChar {
// CHECK: init?(rawValue: CChar)
// CHECK: var rawValue: CChar { get }
// CHECK: typealias RawValue = CChar
// CHECK: case x
// CHECK: case y
// CHECK: }

// CHECK: enum ScopedEnumUnsignedDefined : UInt32 {
// CHECK: init?(rawValue: UInt32)
// CHECK: var rawValue: UInt32 { get }
// CHECK: typealias RawValue = UInt32
// CHECK: case x
// CHECK: case y
// CHECK: }

// CHECK: enum ScopedEnumUnsignedLongDefined : [[UINT_T:UInt|UInt32]] {
// CHECK: init?(rawValue: [[UINT_T]])
// CHECK: var rawValue: [[UINT_T]] { get }
// CHECK: typealias RawValue = [[UINT_T]]
// CHECK: case x
// CHECK: case y
// CHECK: }

// CHECK: enum ScopedEnumChar : CChar {
// CHECK: init?(rawValue: CChar)
// CHECK: var rawValue: CChar { get }
// CHECK: typealias RawValue = CChar
// CHECK: case x
// CHECK: case y
// CHECK: case z
// CHECK: }

// CHECK: enum ScopedEnumUnsigned : UInt32 {
// CHECK: init?(rawValue: UInt32)
// CHECK: var rawValue: UInt32 { get }
// CHECK: typealias RawValue = UInt32
// CHECK: case x
// CHECK: case y
// CHECK: case z
// CHECK: }

// CHECK: enum ScopedEnumUnsignedLong : [[UINT_T]] {
// CHECK: init?(rawValue: [[UINT_T]])
// CHECK: var rawValue: [[UINT_T]] { get }
// CHECK: typealias RawValue = [[UINT_T]]
// CHECK: case x
// CHECK: case y
// CHECK: case z
// CHECK: }

// CHECK: enum ScopedEnumInt : Int32 {
// CHECK: init?(rawValue: Int32)
// CHECK: var rawValue: Int32 { get }
// CHECK: typealias RawValue = Int32
// CHECK: case x
// CHECK: case y
// CHECK: case z
// CHECK: }

// CHECK: enum ScopedEnumNegativeElement : Int32 {
// CHECK: init?(rawValue: Int32)
// CHECK: var rawValue: Int32 { get }
// CHECK: typealias RawValue = Int32
// CHECK: case x
// CHECK: case y
// CHECK: case z
// CHECK: }
28 changes: 28 additions & 0 deletions test/Interop/Cxx/enum/scoped-enums-silgen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

import ScopedEnums

// CHECK-LABEL: sil @$s4main24returnsScopedEnumDefinedSo0cdE0VyF : $@convention(thin) () -> ScopedEnumDefined
// CHECK: [[OUT:%.*]] = enum $ScopedEnumDefined, #ScopedEnumDefined.x!enumelt
// CHECK: return [[OUT]] : $ScopedEnumDefined
// CHECK-LABEL: end sil function '$s4main24returnsScopedEnumDefinedSo0cdE0VyF'
public func returnsScopedEnumDefined() -> ScopedEnumDefined {
return .x
}

// CHECK-LABEL: sil @$s4main22returnsScopedEnumBasicSo0cdE0VyF : $@convention(thin) () -> ScopedEnumBasic
// CHECK: [[OUT:%.*]] = enum $ScopedEnumBasic, #ScopedEnumBasic.x!enumelt
// CHECK: return [[OUT]] : $ScopedEnumBasic
// CHECK-LABEL: end sil function '$s4main22returnsScopedEnumBasicSo0cdE0VyF'
public func returnsScopedEnumBasic() -> ScopedEnumBasic {
return .x
}

// CHECK-LABEL: sil @$s4main28returnsScopedEnumCharDefinedSo0cdeF0VyF : $@convention(thin) () -> ScopedEnumCharDefined
// CHECK: [[OUT:%.*]] = enum $ScopedEnumCharDefined, #ScopedEnumCharDefined.x!enumelt
// CHECK: return [[OUT]] : $ScopedEnumCharDefined
// CHECK-LABEL: end sil function '$s4main28returnsScopedEnumCharDefinedSo0cdeF0VyF'
public func returnsScopedEnumCharDefined() -> ScopedEnumCharDefined {
return .x
}

43 changes: 43 additions & 0 deletions test/Interop/Cxx/enum/scoped-enums.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)

// REQUIRES: executable_test

import ScopedEnums
import StdlibUnittest

var ScopedEnumsTestSuite = TestSuite("Scoped Enums")

ScopedEnumsTestSuite.test("Make and compare") {
let val: ScopedEnumDefined = .x
expectEqual(val, .x)
}

ScopedEnumsTestSuite.test("Make and compare (not equal)") {
let val: ScopedEnumDefined = .x
expectNotEqual(val, .y)
}

func makeScopedEnumBasic() -> ScopedEnumBasic { .z }

ScopedEnumsTestSuite.test("Make and compare (ScopedEnumBasic)") {
let val: ScopedEnumBasic = .x
expectNotEqual(val, makeScopedEnumBasic())
expectEqual(.z, makeScopedEnumBasic())
}

ScopedEnumsTestSuite.test("Make and compare (ScopedEnumCharDefined)") {
expectEqual(ScopedEnumCharDefined(rawValue: 2), .y)
expectNotEqual(ScopedEnumCharDefined(rawValue: 2), ScopedEnumCharDefined(rawValue: 0))
}

ScopedEnumsTestSuite.test("Make and compare (ScopedEnumNegativeElement)") {
expectEqual(ScopedEnumNegativeElement(rawValue: -1), .x)
expectNotEqual(ScopedEnumNegativeElement(rawValue: 0), .x)
}

ScopedEnumsTestSuite.test("Make and compare (MiddleDefinedScopedEnum)") {
expectEqual(MiddleDefinedScopedEnum(rawValue: 42), .y)
expectEqual(MiddleDefinedScopedEnum(rawValue: 43), .z)
}

runAllTests()

0 comments on commit 3c5f2c9

Please sign in to comment.