Skip to content

Commit 8214b85

Browse files
authored
Merge pull request #60842 from WANGJIEKE/cxx-interop-enum-creation
[Interop][SwiftToCxx] Support enum creation from Cxx
2 parents 860cc27 + 911cfe9 commit 8214b85

15 files changed

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

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"
@@ -141,6 +142,16 @@ class DeclAndTypeClangFunctionPrinter {
141142
ModuleDecl *moduleContext,
142143
OutputLanguageMode outputLang);
143144

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

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 12 additions & 28 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 << " ";
@@ -290,34 +302,6 @@ void ClangValueTypePrinter::printValueTypeDecl(
290302
printCxxImplClassName(os, typeDecl);
291303
os << ";\n";
292304
os << "};\n";
293-
// Print the definition of enum static struct data memebers
294-
if (isa<EnumDecl>(typeDecl)) {
295-
auto tagMapping = interopContext.getIrABIDetails().getEnumTagMapping(
296-
cast<EnumDecl>(typeDecl));
297-
for (const auto &pair : tagMapping) {
298-
os << "decltype(";
299-
printer.printBaseName(typeDecl);
300-
os << "::";
301-
printer.printIdentifier(pair.first->getNameStr());
302-
os << ") ";
303-
printer.printBaseName(typeDecl);
304-
os << "::";
305-
printer.printIdentifier(pair.first->getNameStr());
306-
os << ";\n";
307-
}
308-
if (isOpaqueLayout) {
309-
os << "decltype(";
310-
printer.printBaseName(typeDecl);
311-
// TODO: allow custom name for this special case
312-
os << "::";
313-
printer.printIdentifier("unknownDefault");
314-
os << ") ";
315-
printer.printBaseName(typeDecl);
316-
os << "::";
317-
printer.printIdentifier("unknownDefault");
318-
os << ";\n";
319-
}
320-
}
321305
os << '\n';
322306

323307
const auto *moduleContext = typeDecl->getModuleContext();

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

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,29 @@ 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: inline const static struct { // impl struct for case unknownDefault
50+
// CHECK-NEXT: inline constexpr operator cases() const {
51+
// CHECK-NEXT: return cases::unknownDefault;
52+
// CHECK-NEXT: }
53+
// CHECK-NEXT: } unknownDefault;
54+
// CHECK-NEXT: inline bool isUnknownDefault() const;
55+
// CHECK: inline operator cases() const {
56+
// CHECK-NEXT: return cases::unknownDefault;
57+
// CHECK-NEXT: }
3558
// CHECK: // Tags for resilient enum Foo
3659
// CHECK-NEXT: extern "C" {
3760
// CHECK-NEXT: extern unsigned $s5Enums3FooO1ayACSdcACmFWC;
@@ -47,17 +70,28 @@ public func printFoo(_ x: Foo) {
4770
// NEW_CASE-NEXT: b,
4871
// CHECK-NEXT: unknownDefault
4972
// CHECK-NEXT: }
50-
// CHECK: static struct { // impl struct for case unknownDefault
51-
// CHECK-NEXT: constexpr operator cases() const {
73+
// CHECK: inline const static struct { // impl struct for case unknownDefault
74+
// CHECK-NEXT: inline constexpr operator cases() const {
5275
// CHECK-NEXT: return cases::unknownDefault;
5376
// CHECK-NEXT: }
5477
// CHECK-NEXT: } unknownDefault;
55-
// CHECK-NEXT: inline bool isUnknownDefault() const {
56-
// CHECK-NEXT: return *this == Foo::unknownDefault;
57-
// CHECK-NEXT: }
78+
// CHECK-NEXT: inline bool isUnknownDefault() const;
79+
// CHECK-EMPTY:
5880
// CHECK: inline operator cases() const {
5981
// CHECK-NEXT: auto tag = _getEnumTag();
6082
// CHECK-NEXT: if (tag == _impl::$s5Enums3FooO1ayACSdcACmFWC) return cases::a;
6183
// NEW_CASE-NEXT: if (tag == _impl::$s5Enums3FooO1byACSicACmFWC) return cases::b;
6284
// CHECK-NEXT: return cases::unknownDefault;
6385
// CHECK-NEXT: }
86+
// CHECK: inline Foo Foo::_impl_a::operator()(double val) const {
87+
// CHECK-NEXT: auto result = Foo::_make();
88+
// CHECK-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val));
89+
// CHECK-NEXT: result._destructiveInjectEnumTag(_impl::$s5Enums3FooO1ayACSdcACmFWC);
90+
// CHECK-NEXT: return result;
91+
// CHECK-NEXT: }
92+
// NEW_CASE: inline Foo Foo::_impl_b::operator()(swift::Int val) const {
93+
// NEW_CASE-NEXT: auto result = Foo::_make();
94+
// NEW_CASE-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val));
95+
// NEW_CASE-NEXT: result._destructiveInjectEnumTag(_impl::$s5Enums3FooO1byACSicACmFWC);
96+
// NEW_CASE-NEXT: return result;
97+
// NEW_CASE-NEXT: }

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)