Skip to content

Commit 7642d41

Browse files
authored
Merge pull request swiftlang#83814 from xymus/cdecl-enum-layout
IRGen: Use C compatible representation for `@cdecl` enums
2 parents 14eb1e4 + a8cf1a4 commit 7642d41

File tree

7 files changed

+73
-10
lines changed

7 files changed

+73
-10
lines changed

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4888,6 +4888,16 @@ class EnumDecl final : public NominalTypeDecl {
48884888
return getAttrs().hasAttribute<IndirectAttr>();
48894889
}
48904890

4891+
/// True if the enum is marked with `@cdecl`.
4892+
bool isCDeclEnum() const {
4893+
return getAttrs().hasAttribute<CDeclAttr>();
4894+
}
4895+
4896+
/// True if the enum is marked with `@cdecl` or `@objc`.
4897+
bool isCCompatibleEnum() const {
4898+
return isCDeclEnum() || isObjC();
4899+
}
4900+
48914901
/// True if the enum can be exhaustively switched within \p useDC.
48924902
///
48934903
/// Note that this property is \e not necessarily true for all children of

lib/AST/ClangTypeConverter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ clang::QualType ClangTypeConverter::visitEnumType(EnumType *type) {
654654
return convert(Context.TheEmptyTupleType);
655655

656656
auto ED = type->getDecl();
657-
if (!ED->isObjC() && !ED->getAttrs().hasAttribute<CDeclAttr>())
657+
if (!ED->isCCompatibleEnum())
658658
// Can't translate something not marked with @objc or @cdecl.
659659
return clang::QualType();
660660

lib/IRGen/GenEnum.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6536,8 +6536,9 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
65366536
std::move(elementsWithPayload), std::move(elementsWithNoPayload)));
65376537
}
65386538

6539-
// Enums imported from Clang or marked with @objc use C-compatible layout.
6540-
if (theEnum->hasClangNode() || theEnum->isObjC()) {
6539+
// Enums imported from Clang or marked with @objc or @cdecl use a
6540+
// C-compatible layout.
6541+
if (theEnum->hasClangNode() || theEnum->isCCompatibleEnum()) {
65416542
assert(elementsWithPayload.empty() && "C enum with payload?!");
65426543
assert(alwaysFixedSize == IsFixedSize && "C enum with resilient payload?!");
65436544
return std::unique_ptr<EnumImplStrategy>(
@@ -6982,7 +6983,7 @@ CCompatibleEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
69826983
llvm::StructType *enumTy){
69836984
// The type should have come from Clang or be @objc,
69846985
// and should have a raw type.
6985-
assert((theEnum->hasClangNode() || theEnum->isObjC())
6986+
assert((theEnum->hasClangNode() || theEnum->isCCompatibleEnum())
69866987
&& "c-compatible enum didn't come from clang!");
69876988
assert(theEnum->hasRawType()
69886989
&& "c-compatible enum doesn't have raw type!");

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2414,7 +2414,7 @@ class DeclAndTypePrinter::Implementation
24142414
void maybePrintTagKeyword(const TypeDecl *NTD) {
24152415
auto *ED = dyn_cast<EnumDecl>(NTD);
24162416
if (ED && !NTD->hasClangNode()) {
2417-
if (ED->getAttrs().hasAttribute<CDeclAttr>()) {
2417+
if (ED->isCDeclEnum()) {
24182418
// We should be able to use the tag macro for all printed enums but
24192419
// for now restrict it to @cdecl to guard it behind the feature flag.
24202420
os << "SWIFT_ENUM_TAG ";

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,8 +539,7 @@ class ModuleWriter {
539539
}
540540

541541
void forwardDeclare(const EnumDecl *ED) {
542-
assert(ED->isObjC() || ED->getAttrs().getAttribute<CDeclAttr>() ||
543-
ED->hasClangNode());
542+
assert(ED->isCCompatibleEnum() || ED->hasClangNode());
544543

545544
forwardDeclare(ED, [&]{
546545
if (ED->getASTContext().LangOpts.hasFeature(Feature::CDecl)) {

test/Interpreter/cdecl_enum_run.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-run-simple-swift(-enable-experimental-feature CDecl) > %t.out
2+
// RUN: %FileCheck --input-file %t.out %s
3+
4+
// REQUIRES: swift_feature_CDecl
5+
// REQUIRES: executable_test
6+
7+
@cdecl
8+
enum CDecl8: UInt8 {
9+
case a
10+
case b
11+
}
12+
13+
@cdecl
14+
enum CDecl16: UInt16 {
15+
case a
16+
case b
17+
}
18+
19+
@cdecl(SomeName)
20+
enum CDecl32: UInt32 {
21+
case a
22+
case b
23+
}
24+
25+
@objc
26+
enum ObjCEnum: UInt32 {
27+
case a
28+
case b
29+
}
30+
31+
enum SwiftEnum: Int32 {
32+
case a
33+
case b
34+
}
35+
36+
print("@cdecl enum 8 is \(MemoryLayout<CDecl8>.size) bytes")
37+
// CHECK: @cdecl enum 8 is 1 bytes
38+
print("@cdecl enum 16 is \(MemoryLayout<CDecl16>.size) bytes")
39+
// CHECK: @cdecl enum 16 is 2 bytes
40+
print("@cdecl enum 32 is \(MemoryLayout<CDecl32>.size) bytes")
41+
// CHECK: @cdecl enum 32 is 4 bytes
42+
print("@objc enum is \(MemoryLayout<ObjCEnum>.size) bytes")
43+
// CHECK: @objc enum is 4 bytes
44+
print("Swift enum is \(MemoryLayout<SwiftEnum>.size) bytes")
45+
// CHECK: Swift enum is 1 bytes

test/Interpreter/cdecl_official_run.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
@cdecl func useEnum(e: CEnum) -> CEnum {
4141
print(e)
42+
print(e.rawValue)
4243
return e
4344
}
4445

@@ -59,8 +60,15 @@ int main() {
5960
primitiveTypes(1, 2, 3, 'a', 1.0f, 2.0, true);
6061
// CHECK-NEXT: 1 2 3 97 1.0 2.0 true
6162

62-
CEnum e = useEnum(CEnumB);
63-
// CHECK-NEXT: B
64-
printf("%d\n", e);
63+
CEnum a = useEnum(CEnumA);
64+
// CHECK-NEXT: CEnum
65+
// CHECK-NEXT: 0
66+
printf("%d\n", a);
67+
// CHECK-NEXT: 0
68+
69+
CEnum b = useEnum(CEnumB);
70+
// CHECK-NEXT: CEnum
71+
// CHECK-NEXT: 1
72+
printf("%d\n", b);
6573
// CHECK-NEXT: 1
6674
}

0 commit comments

Comments
 (0)