Skip to content

Commit cbc23cb

Browse files
committed
[Interop][SwiftToCxx] Support enum creation from Cxx
1 parent 095226f commit cbc23cb

15 files changed

+705
-1198
lines changed

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
using namespace swift;
2020
using namespace cxx_synthesis;
2121

22+
StringRef cxx_synthesis::getCxxSwiftNamespaceName() { return "swift"; }
23+
2224
StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; }
2325

2426
StringRef cxx_synthesis::getCxxOpaqueStorageClassName() {

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class NominalTypeDecl;
2525

2626
namespace cxx_synthesis {
2727

28+
/// Return the name of the namespace for things exported from Swift stdlib
29+
StringRef getCxxSwiftNamespaceName();
30+
2831
/// Return the name of the implementation namespace that is used to hide
2932
/// declarations from the namespace that corresponds to the imported Swift
3033
/// module in C++.

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 262 additions & 116 deletions
Large diffs are not rendered by default.

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,11 @@ class ModuleWriter {
503503
bool writeEnum(const EnumDecl *ED) {
504504
if (addImport(ED))
505505
return true;
506-
506+
507+
if (outputLangMode == OutputLanguageMode::Cxx) {
508+
forwardDeclareMemberTypes(ED->getMembers(), ED);
509+
}
510+
507511
if (seenTypes[ED].first == EmissionState::Defined)
508512
return true;
509513

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,44 @@ bool DeclAndTypeClangFunctionPrinter::hasKnownOptionalNullableCxxMapping(
824824
}
825825
return false;
826826
}
827+
828+
void DeclAndTypeClangFunctionPrinter::printCustomCxxFunction(
829+
const SmallVector<Type> &neededTypes, PrinterTy retTypeAndNamePrinter,
830+
PrinterTy paramPrinter, bool isConstFunc, PrinterTy bodyPrinter,
831+
ModuleDecl *emittedModule, raw_ostream &outOfLineOS) {
832+
llvm::MapVector<Type, std::string> types;
833+
834+
for (auto &type : neededTypes) {
835+
std::string typeStr;
836+
llvm::raw_string_ostream typeOS(typeStr);
837+
OptionalTypeKind optKind;
838+
Type objectType;
839+
std::tie(objectType, optKind) =
840+
DeclAndTypePrinter::getObjectTypeAndOptionality(
841+
type->getNominalOrBoundGenericNominal(), type);
842+
843+
// Use FunctionSignatureTypeUse::ReturnType to avoid printing extra const or
844+
// references
845+
CFunctionSignatureTypePrinter typePrinter(
846+
typeOS, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
847+
interopContext, CFunctionSignatureTypePrinterModifierDelegate(),
848+
emittedModule, declPrinter, FunctionSignatureTypeUse::ReturnType);
849+
typePrinter.visit(objectType, optKind, /* isInOutParam */ false);
850+
851+
types.insert({type, typeStr});
852+
}
853+
854+
retTypeAndNamePrinter(types);
855+
os << '(';
856+
outOfLineOS << '(';
857+
paramPrinter(types);
858+
os << ')';
859+
outOfLineOS << ')';
860+
if (isConstFunc) {
861+
os << " const;\n";
862+
outOfLineOS << " const";
863+
}
864+
outOfLineOS << " {\n";
865+
bodyPrinter(types);
866+
outOfLineOS << "}\n";
867+
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/Basic/LLVM.h"
2020
#include "swift/ClangImporter/ClangImporter.h"
2121
#include "llvm/ADT/ArrayRef.h"
22+
#include "llvm/ADT/MapVector.h"
2223
#include "llvm/ADT/Optional.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/Support/raw_ostream.h"
@@ -140,6 +141,16 @@ class DeclAndTypeClangFunctionPrinter {
140141
ModuleDecl *moduleContext,
141142
OutputLanguageMode outputLang);
142143

144+
using PrinterTy =
145+
llvm::function_ref<void(llvm::MapVector<Type, std::string> &)>;
146+
147+
/// Print generated C++ helper function
148+
void printCustomCxxFunction(const SmallVector<Type> &neededTypes,
149+
PrinterTy retTypeAndNamePrinter,
150+
PrinterTy paramPrinter, bool isConstFunc,
151+
PrinterTy bodyPrinter, ModuleDecl *emittedModule,
152+
raw_ostream &outOfLineOS);
153+
143154
private:
144155
void printCxxToCFunctionParameterUse(
145156
Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,23 @@ void ClangValueTypePrinter::printValueTypeDecl(
270270
"metadata._0);\n";
271271
os << " return _getOpaquePointer();\n";
272272
os << " }\n";
273+
os << " inline void _destructiveInjectEnumTag(unsigned tag) {\n";
274+
printEnumVWTableVariable();
275+
os << " enumVWTable->destructiveInjectEnumTag(_getOpaquePointer(), tag, "
276+
"metadata._0);\n";
277+
os << " }\n";
273278
os << " inline unsigned _getEnumTag() const {\n";
274279
printEnumVWTableVariable();
275280
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
276281
"metadata._0);\n";
277282
os << " }\n";
283+
284+
for (const auto &pair : interopContext.getIrABIDetails().getEnumTagMapping(
285+
cast<EnumDecl>(typeDecl))) {
286+
os << " using _impl_" << pair.first->getNameStr() << " = decltype(";
287+
ClangSyntaxPrinter(os).printIdentifier(pair.first->getNameStr());
288+
os << ");\n";
289+
}
278290
}
279291
// Print out the storage for the value type.
280292
os << " ";

test/Interop/SwiftToCxx/enums/resilient-enum-in-cxx.swift

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ public func printFoo(_ x: Foo) {
3232
print(x)
3333
}
3434

35+
public enum Empty {
36+
37+
}
38+
39+
// CHECK: // Tags for resilient enum Empty
40+
// CHECK-NEXT: extern "C" {
41+
// CHECK-NEXT: }
42+
// CHECK-EMPTY:
43+
// CHECK-NEXT: } // namespace _impl
44+
// CHECK-EMPTY:
45+
// CHECK-NEXT: class Empty final {
46+
// CHECK: enum class cases {
47+
// CHECK-NEXT: unknownDefault
48+
// CHECK-NEXT: };
49+
// CHECK-EMPTY:
50+
// CHECK-NEXT: static struct { // impl struct for case unknownDefault
51+
// CHECK-NEXT: inline constexpr operator cases() const {
52+
// CHECK-NEXT: return cases::unknownDefault;
53+
// CHECK-NEXT: }
54+
// CHECK-NEXT: } unknownDefault;
55+
// CHECK-NEXT: inline bool isUnknownDefault() const;
56+
// CHECK: inline operator cases() const {
57+
// CHECK-NEXT: return cases::unknownDefault;
58+
// CHECK-NEXT: }
3559
// CHECK: // Tags for resilient enum Foo
3660
// CHECK-NEXT: extern "C" {
3761
// CHECK-NEXT: extern unsigned $s5Enums3FooO1ayACSdcACmFWC;
@@ -48,14 +72,14 @@ public func printFoo(_ x: Foo) {
4872
// CHECK-NEXT: unknownDefault
4973
// CHECK-NEXT: }
5074
// CHECK: static struct { // impl struct for case unknownDefault
51-
// CHECK-NEXT: constexpr operator cases() const {
75+
// CHECK-NEXT: inline constexpr operator cases() const {
5276
// CHECK-NEXT: return cases::unknownDefault;
5377
// CHECK-NEXT: }
5478
// CHECK-NEXT: } unknownDefault;
55-
// CHECK-NEXT: inline bool isUnknownDefault() const {
56-
// CHECK-NEXT: return *this == Foo::unknownDefault;
57-
// CHECK-NEXT: }
58-
// CHECK: inline operator cases() const {
79+
// CHECK-NEXT: inline bool isUnknownDefault() const;
80+
// CHECK-EMPTY:
81+
// CHECK-EMPTY:
82+
// CHECK-NEXT: inline operator cases() const {
5983
// CHECK-NEXT: auto tag = _getEnumTag();
6084
// CHECK-NEXT: if (tag == _impl::$s5Enums3FooO1ayACSdcACmFWC) return cases::a;
6185
// NEW_CASE-NEXT: if (tag == _impl::$s5Enums3FooO1byACSicACmFWC) return cases::b;

test/Interop/SwiftToCxx/enums/swift-enum-case-functions-execution.cpp

Lines changed: 0 additions & 169 deletions
This file was deleted.

0 commit comments

Comments
 (0)