Skip to content

[interop][SwiftToCxx] do not expose unsupported enums yet #65351

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
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
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,12 @@ ERROR(expose_generic_requirement_to_cxx,none,
"generic requirements for %0 %1 can not yet be represented in C++", (DescriptiveDeclKind, ValueDecl *))
ERROR(expose_throwing_to_cxx,none,
"%0 %1 can not yet be represented in C++ as it may throw an error", (DescriptiveDeclKind, ValueDecl *))
ERROR(expose_indirect_enum_cxx,none,
"indirect enum %0 can not yet be represented in C++", (ValueDecl *))
ERROR(expose_enum_case_type_to_cxx,none,
"enum %0 can not be represented in C++ as one of its cases has an associated value with type that can't be represented in C++", (ValueDecl *))
ERROR(expose_enum_case_tuple_to_cxx,none,
"enum %0 can not yet be represented in C++ as one of its cases has multiple associated values", (ValueDecl *))

ERROR(attr_methods_only,none,
"only methods can be declared %0", (DeclAttribute))
Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/SwiftNameTranslation.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ enum RepresentationError {
UnrepresentableRequiresClientEmission,
UnrepresentableGeneric,
UnrepresentableGenericRequirements,
UnrepresentableThrows
UnrepresentableThrows,
UnrepresentableIndirectEnum,
UnrepresentableEnumCaseType,
UnrepresentableEnumCaseTuple,
};

struct DeclRepresentation {
Expand Down
23 changes: 23 additions & 0 deletions lib/AST/SwiftNameTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,29 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
return {Unsupported, UnrepresentableThrows};
}
}
if (const auto *enumDecl = dyn_cast<EnumDecl>(VD)) {
if (enumDecl->isIndirect())
return {Unsupported, UnrepresentableIndirectEnum};
for (const auto *enumCase : enumDecl->getAllCases()) {
for (const auto *elementDecl : enumCase->getElements()) {
if (!elementDecl->hasAssociatedValues())
continue;
// Do not expose any enums with > 1
// enum parameter, or any enum parameter
// whose type we do not yet support.
if (auto *params = elementDecl->getParameterList()) {
if (params->size() > 1)
return {Unsupported, UnrepresentableEnumCaseTuple};
for (const auto *param : *params) {
auto paramType = param->getInterfaceType();
if (!paramType->is<GenericTypeParamType>() &&
!paramType->getNominalOrBoundGenericNominal())
return {Unsupported, UnrepresentableEnumCaseType};
}
}
}
}
}
// Generic requirements are not yet supported in C++.
if (genericSignature && !genericSignature->getRequirements().empty())
return {Unsupported, UnrepresentableGenericRequirements};
Expand Down
9 changes: 9 additions & 0 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2067,6 +2067,15 @@ void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
diagnose(attr->getLocation(), diag::expose_throwing_to_cxx,
VD->getDescriptiveKind(), VD);
break;
case UnrepresentableIndirectEnum:
diagnose(attr->getLocation(), diag::expose_indirect_enum_cxx, VD);
break;
case UnrepresentableEnumCaseType:
diagnose(attr->getLocation(), diag::expose_enum_case_type_to_cxx, VD);
break;
case UnrepresentableEnumCaseTuple:
diagnose(attr->getLocation(), diag::expose_enum_case_tuple_to_cxx, VD);
break;
}
}

Expand Down
7 changes: 6 additions & 1 deletion test/Interop/SwiftToCxx/cross-module-refs/Inputs/enums.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

public struct IntTuple {
let values: (Int64, Int64, Int64, Int64, Int64, Int64)
}

// Large enum passed indirectly.
public enum LargeEnum {
case A(x1: Int64, x2: Int64, x3: Int64, x4: Int64, x5: Int64)
case A(IntTuple)
case B
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@

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

public struct IntTuple {
let values: (Int64, Int64, Int64, Int64, Int64, Int64)
}

public enum Large {
case first(Int64, Int64, Int64, Int64, Int64, Int64)
case first(IntTuple)
case second
}

public func makeLarge(_ x: Int) -> Large {
return x >= 0 ? .first(0, 1, 2, 3, 4, 5) : .second
return x >= 0 ? .first(IntTuple(values: (0, 1, 2, 3, 4, 5))) : .second
}

public func printLarge(_ en: Large) {
switch en {
case let .first(a, b, c, d, e, f):
let x = (a, b, c, d, e, f)
print("Large.first\(x)")
case let .first(x):
print("Large.first\(x.values)")
case .second:
print("Large.second")
}
Expand All @@ -29,7 +32,7 @@ public func passThroughLarge(_ en: Large) -> Large {

public func inoutLarge(_ en: inout Large, _ x: Int) {
if x >= 0 {
en = .first(-1, -2, -3, -4, -5, -6)
en = .first(IntTuple(values: (-1, -2, -3, -4, -5, -6)))
} else {
en = .second
}
Expand Down
29 changes: 29 additions & 0 deletions test/Interop/SwiftToCxx/unsupported/unsupported-enums-in-cxx.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -verify -clang-header-expose-decls=has-expose-attr -disable-availability-checking -emit-clang-header-path %t/functions.h

// RUN: cat %s | grep -v _expose > %t/clean.swift
// RUN: %target-swift-frontend %t/clean.swift -typecheck -module-name Functions -clang-header-expose-decls=all-public -disable-availability-checking -emit-clang-header-path %t/header.h
// RUN: %FileCheck %s < %t/header.h

// CHECK-NOT: unsupported

public typealias FnType = () -> ()

@_expose(Cxx) // expected-error {{enum 'unsupportedEnumAssociatedValueType' can not be represented in C++ as one of its cases has an associated value with type that can't be represented in C++}}
public enum unsupportedEnumAssociatedValueType {
case A
case B(FnType)
}

@_expose(Cxx) // expected-error {{enum 'unsupportedEnumMultipleAssociatedValues' can not yet be represented in C++ as one of its cases has multiple associated values}}
public enum unsupportedEnumMultipleAssociatedValues {
case A
case B(Int, Int)
}

@_expose(Cxx) // expected-error {{indirect enum 'unsupportedEnumIndirect' can not yet be represented in C++}}
public indirect enum unsupportedEnumIndirect {
case A
case B
}