Skip to content

Commit f0aa860

Browse files
authored
Merge pull request #65496 from hyp/eng/reverse-interop-5.9-enums
[5.9\[interop][SwiftToCxx] add additional type representation emission checks
2 parents 7069e5f + 1927ee1 commit f0aa860

File tree

7 files changed

+80
-5
lines changed

7 files changed

+80
-5
lines changed

lib/AST/SwiftNameTranslation.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,11 @@ swift::cxx_translation::getDeclRepresentation(const ValueDecl *VD) {
249249
return {Unsupported, UnrepresentableEnumCaseTuple};
250250
for (const auto *param : *params) {
251251
auto paramType = param->getInterfaceType();
252-
if (!paramType->is<GenericTypeParamType>() &&
253-
!paramType->getNominalOrBoundGenericNominal())
254-
return {Unsupported, UnrepresentableEnumCaseType};
252+
if (!paramType->is<GenericTypeParamType>()) {
253+
auto *nominal = paramType->getNominalOrBoundGenericNominal();
254+
if (!nominal || isa<ProtocolDecl>(nominal))
255+
return {Unsupported, UnrepresentableEnumCaseType};
256+
}
255257
}
256258
}
257259
}

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,6 @@ class DeclAndTypePrinter::Implementation
406406
void visitEnumDeclCxx(EnumDecl *ED) {
407407
assert(owningPrinter.outputLang == OutputLanguageMode::Cxx);
408408

409-
// FIXME: Print enum's availability
410409
ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS,
411410
owningPrinter.interopContext);
412411
ClangSyntaxPrinter syntaxPrinter(os);
@@ -2793,12 +2792,43 @@ static bool isExposedToThisModule(const ModuleDecl &M, const ValueDecl *VD,
27932792
return exposedModules.count(mc->getName().str());
27942793
}
27952794

2795+
static bool isEnumExposableToCxx(const ValueDecl *VD,
2796+
DeclAndTypePrinter &printer) {
2797+
auto *enumDecl = dyn_cast<EnumDecl>(VD);
2798+
if (!enumDecl)
2799+
return true;
2800+
// The supported set of enum elements is restricted by
2801+
// the types that can be represented in C++. We already
2802+
// check for different type categories in `getDeclRepresentation`, however,
2803+
// we also need to perform additional check on whether the type can be
2804+
// emitted here as well, to ensure that we don't emit types from dependent
2805+
// modules that do not have a C++ representation.
2806+
for (const auto *enumCase : enumDecl->getAllCases()) {
2807+
for (const auto *elementDecl : enumCase->getElements()) {
2808+
if (!elementDecl->hasAssociatedValues())
2809+
continue;
2810+
if (auto *params = elementDecl->getParameterList()) {
2811+
for (const auto *param : *params) {
2812+
auto paramType = param->getInterfaceType();
2813+
if (DeclAndTypeClangFunctionPrinter::getTypeRepresentation(
2814+
printer.getTypeMapping(), printer.getInteropContext(),
2815+
printer, enumDecl->getModuleContext(), paramType)
2816+
.isUnsupported())
2817+
return false;
2818+
}
2819+
}
2820+
}
2821+
}
2822+
return true;
2823+
}
2824+
27962825
bool DeclAndTypePrinter::shouldInclude(const ValueDecl *VD) {
27972826
return !VD->isInvalid() && (!requiresExposedAttribute || hasExposeAttr(VD)) &&
27982827
(outputLang == OutputLanguageMode::Cxx
27992828
? cxx_translation::isVisibleToCxx(VD, minRequiredAccess) &&
28002829
isExposedToThisModule(M, VD, exposedModules) &&
2801-
cxx_translation::isExposableToCxx(VD)
2830+
cxx_translation::isExposableToCxx(VD) &&
2831+
isEnumExposableToCxx(VD, *this)
28022832
: isVisibleToObjC(VD, minRequiredAccess)) &&
28032833
!VD->getAttrs().hasAttribute<ImplementationOnlyAttr>() &&
28042834
!isAsyncAlternativeOfOtherDecl(VD) &&

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class DeclAndTypePrinter {
7575
requiresExposedAttribute(requiresExposedAttribute),
7676
exposedModules(exposedModules), outputLang(outputLang) {}
7777

78+
PrimitiveTypeMapping &getTypeMapping() { return typeMapping; }
79+
7880
SwiftToClangInteropContext &getInteropContext() { return interopContext; }
7981

8082
/// Returns true if \p VD should be included in a compatibility header for

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,3 +1581,16 @@ void DeclAndTypeClangFunctionPrinter::printCustomCxxFunction(
15811581
bodyPrinter(typeRefs);
15821582
outOfLineOS << "}\n";
15831583
}
1584+
1585+
ClangRepresentation DeclAndTypeClangFunctionPrinter::getTypeRepresentation(
1586+
PrimitiveTypeMapping &typeMapping,
1587+
SwiftToClangInteropContext &interopContext, DeclAndTypePrinter &declPrinter,
1588+
const ModuleDecl *emittedModule, Type ty) {
1589+
CFunctionSignatureTypePrinterModifierDelegate delegate;
1590+
CFunctionSignatureTypePrinter typePrinter(
1591+
llvm::nulls(), llvm::nulls(), typeMapping, OutputLanguageMode::Cxx,
1592+
interopContext, delegate, emittedModule, declPrinter,
1593+
FunctionSignatureTypeUse::TypeReference);
1594+
return typePrinter.visit(ty, OptionalTypeKind::OTK_None,
1595+
/*isInOutParam=*/false);
1596+
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ class DeclAndTypeClangFunctionPrinter {
164164
ModuleDecl *emittedModule,
165165
raw_ostream &outOfLineOS);
166166

167+
static ClangRepresentation
168+
getTypeRepresentation(PrimitiveTypeMapping &typeMapping,
169+
SwiftToClangInteropContext &interopContext,
170+
DeclAndTypePrinter &declPrinter,
171+
const ModuleDecl *emittedModule, Type ty);
172+
167173
private:
168174
void printCxxToCFunctionParameterUse(Type type, StringRef name,
169175
const ModuleDecl *moduleContext,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -typecheck %s -typecheck -module-name UseFoundation -enable-experimental-cxx-interop -emit-clang-header-path %t/UseFoundation.h
4+
// RUN: %FileCheck %s < %t/UseFoundation.h
5+
6+
#if canImport(Foundation)
7+
8+
import Foundation
9+
10+
public enum UseFoundationEnum {
11+
case A(Data)
12+
case B
13+
}
14+
15+
#endif
16+
17+
// CHECK-NOT: UseFoundationEnum

test/Interop/SwiftToCxx/unsupported/unsupported-enums-in-cxx.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ public indirect enum unsupportedEnumIndirect {
2727
case B
2828
}
2929

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

0 commit comments

Comments
 (0)