Description
Description
C enum
s marked as __attribute__((enum_extensibility(closed)))
(or using NS_CLOSED_ENUM
) will be imported as @frozen
Swift enum
s, not requiring default branches for switch
es. However, constructing such enum
s with init?(rawValue:)
will not fail. Switching on such enum
s will reproducibly trap at runtime with "unexpected enum case while switching".
Reproduction
enum __attribute__((enum_extensibility(closed))) ClosedEnum {
A0, A1
};
// import the ClosedEnum from C
let neither = ClosedEnum(rawValue: 2);
switch neither {
case .A0:
print("A0");
case .A1:
print("A1");
case .none:
print("none");
}
Stack dump
$ swift run
Building for debugging...
[1/1] Write swift-version-327D651943494526.txt
Build of product 'SLib' complete! (0.10s)
true
Fatal error: unexpected enum case while switching on value of type 'Optional<ClosedEnum>'
💣 Program crashed: System trap at 0x00000001a51c15f8
Thread 0 crashed:
0 SLib_main + 956 in SLib at tmp/Sources/SLib/main.swift:40:8
38│ case .A0:
39│ print("A0");
40│ case .A1:
│ ▲
41│ print("A1");
42│ case .none:
Backtrace took 0.10s
Expected behavior
init?(rawValue:)
should produce nil
when given rawValue
s which do not correspond to the values associated with the enumerators listed in the imported enum
's definition. This is consistent with Swift's behavior for initializing enum
s. According to old documentation, this "probably should" happening.
Environment
$ swiftc -version
Apple Swift version 6.1 (swift-6.1-RELEASE)
Target: arm64-apple-macosx15.0
Additional information
I came across this bug while playing around with -strict-memory-safety
on Apple Swift version 6.2-dev (LLVM 81ab6d9f7e4810f, Swift 9cc1947527bacea)
. It seems important to ensure safe interoperability.
This documentation explicitly talks about how imported enum
s interacting with switch
exhaustiveness checks is hazardous in the presence of unexpected bit patterns.