diff --git a/lib/PrintAsClang/ClangSyntaxPrinter.cpp b/lib/PrintAsClang/ClangSyntaxPrinter.cpp index 48192ddea8bba..cd32dd8f6dfd1 100644 --- a/lib/PrintAsClang/ClangSyntaxPrinter.cpp +++ b/lib/PrintAsClang/ClangSyntaxPrinter.cpp @@ -19,6 +19,8 @@ using namespace swift; using namespace cxx_synthesis; +StringRef cxx_synthesis::getCxxSwiftNamespaceName() { return "swift"; } + StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; } StringRef cxx_synthesis::getCxxOpaqueStorageClassName() { diff --git a/lib/PrintAsClang/ClangSyntaxPrinter.h b/lib/PrintAsClang/ClangSyntaxPrinter.h index 6fc38c599027b..37ef51d0169e1 100644 --- a/lib/PrintAsClang/ClangSyntaxPrinter.h +++ b/lib/PrintAsClang/ClangSyntaxPrinter.h @@ -25,6 +25,9 @@ class NominalTypeDecl; namespace cxx_synthesis { +/// Return the name of the namespace for things exported from Swift stdlib +StringRef getCxxSwiftNamespaceName(); + /// Return the name of the implementation namespace that is used to hide /// declarations from the namespace that corresponds to the imported Swift /// module in C++. diff --git a/lib/PrintAsClang/DeclAndTypePrinter.cpp b/lib/PrintAsClang/DeclAndTypePrinter.cpp index 4f75066753b8a..34e0c206ec24c 100644 --- a/lib/PrintAsClang/DeclAndTypePrinter.cpp +++ b/lib/PrintAsClang/DeclAndTypePrinter.cpp @@ -398,15 +398,262 @@ class DeclAndTypePrinter::Implementation ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS, owningPrinter.typeMapping, owningPrinter.interopContext); - valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() { - ClangSyntaxPrinter syntaxPrinter(os); - auto elementTagMapping = - owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED); - // Sort cases based on their assigned tag indices - llvm::stable_sort(elementTagMapping, [](const auto &p1, const auto &p2) { - return p1.second.tag < p2.second.tag; - }); + ClangSyntaxPrinter syntaxPrinter(os); + DeclAndTypeClangFunctionPrinter clangFuncPrinter( + os, owningPrinter.prologueOS, owningPrinter.typeMapping, + owningPrinter.interopContext, owningPrinter); + + auto &outOfLineOS = owningPrinter.outOfLineDefinitionsOS; + ClangSyntaxPrinter outOfLineSyntaxPrinter(outOfLineOS); + DeclAndTypeClangFunctionPrinter outOfLineFuncPrinter( + owningPrinter.outOfLineDefinitionsOS, owningPrinter.prologueOS, + owningPrinter.typeMapping, owningPrinter.interopContext, owningPrinter); + ClangValueTypePrinter outOfLineValTyPrinter( + owningPrinter.outOfLineDefinitionsOS, owningPrinter.prologueOS, + owningPrinter.typeMapping, owningPrinter.interopContext); + + auto elementTagMapping = + owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED); + // Sort cases based on their assigned tag indices + llvm::stable_sort(elementTagMapping, [](const auto &p1, const auto &p2) { + return p1.second.tag < p2.second.tag; + }); + + auto printIsFunction = [&](StringRef caseName, EnumDecl *ED) { + std::string declName, defName, name; + llvm::raw_string_ostream declOS(declName), defOS(defName), nameOS(name); + ClangSyntaxPrinter(nameOS).printIdentifier(caseName); + name[0] = std::toupper(name[0]); + + os << " inline bool is" << name << "() const;\n"; + + outOfLineOS << " inline bool "; + outOfLineSyntaxPrinter.printBaseName(ED); + outOfLineOS << "::is" << name << "() const {\n"; + outOfLineOS << " return *this == "; + outOfLineSyntaxPrinter.printBaseName(ED); + outOfLineOS << "::"; + outOfLineSyntaxPrinter.printIdentifier(caseName); + outOfLineOS << ";\n"; + outOfLineOS << " }\n"; + }; + + auto printGetFunction = [&](EnumElementDecl *elementDecl) { + auto associatedValueList = elementDecl->getParameterList(); + // TODO: add tuple type support + if (!elementDecl->hasAssociatedValues() || + associatedValueList->size() > 1) { + return; + } + auto paramType = associatedValueList->front()->getType(); + Type objectType; + OptionalTypeKind optKind; + std::tie(objectType, optKind) = getObjectTypeAndOptionality( + paramType->getNominalOrBoundGenericNominal(), paramType); + auto objectTypeDecl = objectType->getNominalOrBoundGenericNominal(); + + std::string declName, defName, name; + llvm::raw_string_ostream declOS(declName), defOS(defName), nameOS(name); + ClangSyntaxPrinter(nameOS).printIdentifier(elementDecl->getNameStr()); + name[0] = std::toupper(name[0]); + + clangFuncPrinter.printCustomCxxFunction( + {paramType}, + [&](auto &types) { + // Printing function name and return type + os << " inline " << types[paramType] << " get" << name; + outOfLineOS << " inline " << types[paramType] << ' '; + outOfLineSyntaxPrinter.printBaseName(ED); + outOfLineOS << "::get" << name; + }, + [&](auto &types) {}, true, + [&](auto &types) { + // Printing function body + outOfLineOS << " if (!is" << name << "()) abort();\n"; + outOfLineOS << " alignas("; + outOfLineSyntaxPrinter.printBaseName(elementDecl->getParentEnum()); + outOfLineOS << ") unsigned char buffer[sizeof("; + outOfLineSyntaxPrinter.printBaseName(elementDecl->getParentEnum()); + outOfLineOS << ")];\n"; + outOfLineOS << " auto *thisCopy = new(buffer) "; + outOfLineSyntaxPrinter.printBaseName(elementDecl->getParentEnum()); + outOfLineOS << "(*this);\n"; + outOfLineOS << " char * _Nonnull payloadFromDestruction = " + "thisCopy->_destructiveProjectEnumData();\n"; + if (auto knownCxxType = + owningPrinter.typeMapping.getKnownCxxTypeInfo( + objectTypeDecl)) { + outOfLineOS << " " << types[paramType] << " result;\n"; + outOfLineOS << " " + "memcpy(&result, payloadFromDestruction, " + "sizeof(result));\n"; + outOfLineOS << " return result;\n "; + } else { + outOfLineOS << " return swift::"; + outOfLineOS << cxx_synthesis::getCxxImplNamespaceName(); + outOfLineOS << "::implClassFor<"; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + elementDecl->getParentEnum()->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << ">::type"; + outOfLineOS << "::returnNewValue([&](char * _Nonnull result) {\n"; + outOfLineOS << " swift::" + << cxx_synthesis::getCxxImplNamespaceName(); + outOfLineOS << "::implClassFor<"; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + elementDecl->getParentEnum()->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << ">::type"; + outOfLineOS + << "::initializeWithTake(result, payloadFromDestruction);\n"; + outOfLineOS << " });\n "; + } + }, + ED->getModuleContext(), outOfLineOS); + }; + + auto printStruct = [&](StringRef caseName, EnumElementDecl *elementDecl, + Optional + elementInfo) { + os << " inline const static struct { " + << "// impl struct for case " << caseName << '\n'; + os << " inline constexpr operator cases() const {\n"; + os << " return cases::"; + syntaxPrinter.printIdentifier(caseName); + os << ";\n"; + os << " }\n"; + + if (elementDecl != nullptr) { + assert(elementInfo.hasValue()); + + Type paramType, objectType; + NominalTypeDecl *objectTypeDecl = nullptr; + OptionalTypeKind optKind; + + // TODO: support tuple type + if (elementDecl->hasAssociatedValues() && + elementDecl->getParameterList()->size() == 1) { + paramType = elementDecl->getParameterList()->front()->getType(); + std::tie(objectType, optKind) = getObjectTypeAndOptionality( + paramType->getNominalOrBoundGenericNominal(), paramType); + objectTypeDecl = objectType->getNominalOrBoundGenericNominal(); + } + + SmallVector neededTypes; + if (paramType) { + neededTypes.push_back(paramType); + } + clangFuncPrinter.printCustomCxxFunction( + neededTypes, + [&](auto &types) { + // Printing function name and return type + os << " inline "; + syntaxPrinter.printBaseName(elementDecl->getParentEnum()); + os << " operator()"; + + outOfLineOS << " inline "; + outOfLineSyntaxPrinter.printBaseName( + elementDecl->getParentEnum()); + outOfLineOS << ' '; + outOfLineSyntaxPrinter.printBaseName( + elementDecl->getParentEnum()); + outOfLineOS << "::_impl_" << elementDecl->getNameStr() + << "::operator()"; + }, + [&](auto &types) { + // Printing parameters + if (!paramType) { + return; + } + assert(objectTypeDecl != nullptr); + if (owningPrinter.typeMapping.getKnownCxxTypeInfo( + objectTypeDecl)) { + os << types[paramType] << " val"; + outOfLineOS << types[paramType] << " val"; + } else { + os << "const " << types[paramType] << " &val"; + outOfLineOS << "const " << types[paramType] << " &val"; + } + }, + true, + [&](auto &types) { + // Printing function body + outOfLineOS << " auto result = "; + outOfLineSyntaxPrinter.printBaseName( + elementDecl->getParentEnum()); + outOfLineOS << "::_make();\n"; + + if (paramType) { + assert(objectTypeDecl != nullptr); + + if (owningPrinter.typeMapping.getKnownCxxTypeInfo( + objectTypeDecl)) { + outOfLineOS << " memcpy(result._getOpaquePointer(), &val, " + "sizeof(val));\n"; + } else { + outOfLineOS << " alignas("; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + ED->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << ") unsigned char buffer[sizeof("; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + ED->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << ")];\n"; + outOfLineOS << " auto *valCopy = new(buffer) "; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + ED->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << "(val);\n"; + outOfLineOS << " "; + outOfLineOS << cxx_synthesis::getCxxSwiftNamespaceName() + << "::"; + outOfLineOS << cxx_synthesis::getCxxImplNamespaceName(); + outOfLineOS << "::implClassFor<"; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + ED->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << ">::type::initializeWithTake(result._" + "getOpaquePointer(), "; + outOfLineOS << cxx_synthesis::getCxxSwiftNamespaceName() + << "::"; + outOfLineOS << cxx_synthesis::getCxxImplNamespaceName(); + outOfLineOS << "::implClassFor<"; + outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded( + objectTypeDecl->getModuleContext(), + ED->getModuleContext()); + outOfLineSyntaxPrinter.printBaseName(objectTypeDecl); + outOfLineOS << ">::type::getOpaquePointer(*valCopy)"; + outOfLineOS << ");\n"; + } + } + + outOfLineOS << " result._destructiveInjectEnumTag("; + if (ED->isResilient()) { + outOfLineOS << cxx_synthesis::getCxxImplNamespaceName() + << "::" << elementInfo->globalVariableName; + } else { + outOfLineOS << elementInfo->tag; + } + outOfLineOS << ");\n"; + outOfLineOS << " return result;\n"; + outOfLineOS << " "; + }, + ED->getModuleContext(), outOfLineOS); + } + os << " } "; + syntaxPrinter.printIdentifier(caseName); + os << ";\n"; + }; + + valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() { os << '\n'; os << " enum class cases {"; llvm::interleave( @@ -419,117 +666,17 @@ class DeclAndTypePrinter::Implementation // TODO: allow custom name for this special case auto resilientUnknownDefaultCaseName = "unknownDefault"; if (ED->isResilient()) { - os << ",\n " << resilientUnknownDefaultCaseName; + os << (ED->getNumElements() > 0 ? ",\n " : "\n ") + << resilientUnknownDefaultCaseName; } os << "\n };\n\n"; // enum class cases' closing bracket - // Printing struct, is, and get functions for each case - DeclAndTypeClangFunctionPrinter clangFuncPrinter( - os, owningPrinter.prologueOS, owningPrinter.typeMapping, - owningPrinter.interopContext, owningPrinter); - - auto printIsFunction = [&](StringRef caseName, EnumDecl *ED) { - os << " inline bool is"; - std::string name; - llvm::raw_string_ostream nameStream(name); - ClangSyntaxPrinter(nameStream).printIdentifier(caseName); - name[0] = std::toupper(name[0]); - os << name << "() const {\n"; - os << " return *this == "; - syntaxPrinter.printBaseName(ED); - os << "::"; - syntaxPrinter.printIdentifier(caseName); - os << ";\n"; - os << " }\n"; - }; - - auto printGetFunction = [&](EnumElementDecl *elementDecl) { - auto associatedValueList = elementDecl->getParameterList(); - // TODO: add tuple type support - if (associatedValueList->size() > 1) { - return; - } - auto firstType = associatedValueList->front()->getType(); - auto firstTypeDecl = firstType->getNominalOrBoundGenericNominal(); - OptionalTypeKind optKind; - std::tie(firstType, optKind) = - getObjectTypeAndOptionality(firstTypeDecl, firstType); - - auto name = elementDecl->getNameStr().str(); - name[0] = std::toupper(name[0]); - - // FIXME: may have to forward declare return type - os << " inline "; - clangFuncPrinter.printClangFunctionReturnType( - firstType, optKind, firstTypeDecl->getModuleContext(), - owningPrinter.outputLang); - os << " get" << name << "() const {\n"; - os << " if (!is" << name << "()) abort();\n"; - os << " alignas("; - syntaxPrinter.printBaseName(elementDecl->getParentEnum()); - os << ") unsigned char buffer[sizeof("; - syntaxPrinter.printBaseName(elementDecl->getParentEnum()); - os << ")];\n"; - os << " auto *thisCopy = new(buffer) "; - syntaxPrinter.printBaseName(elementDecl->getParentEnum()); - os << "(*this);\n"; - os << " char * _Nonnull payloadFromDestruction = " - "thisCopy->_destructiveProjectEnumData();\n"; - if (auto knownCxxType = - owningPrinter.typeMapping.getKnownCxxTypeInfo(firstTypeDecl)) { - os << " "; - clangFuncPrinter.printClangFunctionReturnType( - firstType, optKind, firstTypeDecl->getModuleContext(), - owningPrinter.outputLang); - os << " result;\n"; - os << " " - "memcpy(&result, payloadFromDestruction, sizeof(result));\n"; - os << " return result;\n"; - } else { - os << " return "; - syntaxPrinter.printModuleNamespaceQualifiersIfNeeded( - firstTypeDecl->getModuleContext(), - elementDecl->getParentEnum()->getModuleContext()); - os << cxx_synthesis::getCxxImplNamespaceName(); - os << "::"; - ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl); - os << "::returnNewValue([&](char * _Nonnull result) {\n"; - os << " " << cxx_synthesis::getCxxImplNamespaceName(); - os << "::"; - ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl); - os << "::initializeWithTake(result, payloadFromDestruction);\n"; - os << " });\n"; - } - os << " }\n"; // closing bracket of get function - }; - - auto printStruct = [&](StringRef caseName, EnumElementDecl *elementDecl) { - os << " static struct { // impl struct for case " << caseName << '\n'; - os << " inline constexpr operator cases() const {\n"; - os << " return cases::"; - syntaxPrinter.printIdentifier(caseName); - os << ";\n"; - os << " }\n"; - if (elementDecl != nullptr) { - os << " inline "; - syntaxPrinter.printBaseName(elementDecl->getParentEnum()); - os << " operator()("; - // TODO: implement parameter for associated value - os << ") const {\n"; - // TODO: print _make for now; need to print actual code making an enum - os << " return "; - syntaxPrinter.printBaseName(elementDecl->getParentEnum()); - os << "::_make();\n"; - os << " }\n"; - } - os << " } "; - syntaxPrinter.printIdentifier(caseName); - os << ";\n"; - }; - + os << "#pragma clang diagnostic push\n"; + os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\" " + << "// allow use of inline static data member\n"; for (const auto &pair : elementTagMapping) { // Printing struct - printStruct(pair.first->getNameStr(), pair.first); + printStruct(pair.first->getNameStr(), pair.first, pair.second); // Printing `is` function printIsFunction(pair.first->getNameStr(), ED); if (pair.first->hasAssociatedValues()) { @@ -541,17 +688,20 @@ class DeclAndTypePrinter::Implementation if (ED->isResilient()) { // Printing struct for unknownDefault - printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr); + printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr, + /* elementInfo */ None); // Printing isUnknownDefault printIsFunction(resilientUnknownDefaultCaseName, ED); os << '\n'; } - os << '\n'; + os << "#pragma clang diagnostic pop\n"; // Printing operator cases() os << " inline operator cases() const {\n"; if (ED->isResilient()) { - os << " auto tag = _getEnumTag();\n"; + if (!elementTagMapping.empty()) { + os << " auto tag = _getEnumTag();\n"; + } for (const auto &pair : elementTagMapping) { os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName(); os << "::" << pair.second.globalVariableName << ") return cases::"; diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index 0e5b54696acd9..b59143de5ba6d 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -503,7 +503,11 @@ class ModuleWriter { bool writeEnum(const EnumDecl *ED) { if (addImport(ED)) return true; - + + if (outputLangMode == OutputLanguageMode::Cxx) { + forwardDeclareMemberTypes(ED->getMembers(), ED); + } + if (seenTypes[ED].first == EmissionState::Defined) return true; diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 9d4addff2641e..292703ded8f06 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -824,3 +824,44 @@ bool DeclAndTypeClangFunctionPrinter::hasKnownOptionalNullableCxxMapping( } return false; } + +void DeclAndTypeClangFunctionPrinter::printCustomCxxFunction( + const SmallVector &neededTypes, PrinterTy retTypeAndNamePrinter, + PrinterTy paramPrinter, bool isConstFunc, PrinterTy bodyPrinter, + ModuleDecl *emittedModule, raw_ostream &outOfLineOS) { + llvm::MapVector types; + + for (auto &type : neededTypes) { + std::string typeStr; + llvm::raw_string_ostream typeOS(typeStr); + OptionalTypeKind optKind; + Type objectType; + std::tie(objectType, optKind) = + DeclAndTypePrinter::getObjectTypeAndOptionality( + type->getNominalOrBoundGenericNominal(), type); + + // Use FunctionSignatureTypeUse::ReturnType to avoid printing extra const or + // references + CFunctionSignatureTypePrinter typePrinter( + typeOS, cPrologueOS, typeMapping, OutputLanguageMode::Cxx, + interopContext, CFunctionSignatureTypePrinterModifierDelegate(), + emittedModule, declPrinter, FunctionSignatureTypeUse::ReturnType); + typePrinter.visit(objectType, optKind, /* isInOutParam */ false); + + types.insert({type, typeStr}); + } + + retTypeAndNamePrinter(types); + os << '('; + outOfLineOS << '('; + paramPrinter(types); + os << ')'; + outOfLineOS << ')'; + if (isConstFunc) { + os << " const;\n"; + outOfLineOS << " const"; + } + outOfLineOS << " {\n"; + bodyPrinter(types); + outOfLineOS << "}\n"; +} diff --git a/lib/PrintAsClang/PrintClangFunction.h b/lib/PrintAsClang/PrintClangFunction.h index d575f6481a7dc..3e112f3414a76 100644 --- a/lib/PrintAsClang/PrintClangFunction.h +++ b/lib/PrintAsClang/PrintClangFunction.h @@ -19,6 +19,7 @@ #include "swift/Basic/LLVM.h" #include "swift/ClangImporter/ClangImporter.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" @@ -140,6 +141,16 @@ class DeclAndTypeClangFunctionPrinter { ModuleDecl *moduleContext, OutputLanguageMode outputLang); + using PrinterTy = + llvm::function_ref &)>; + + /// Print generated C++ helper function + void printCustomCxxFunction(const SmallVector &neededTypes, + PrinterTy retTypeAndNamePrinter, + PrinterTy paramPrinter, bool isConstFunc, + PrinterTy bodyPrinter, ModuleDecl *emittedModule, + raw_ostream &outOfLineOS); + private: void printCxxToCFunctionParameterUse( Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut, diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp index 75f0bca7879f5..e7c54b074292b 100644 --- a/lib/PrintAsClang/PrintClangValueType.cpp +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -270,11 +270,23 @@ void ClangValueTypePrinter::printValueTypeDecl( "metadata._0);\n"; os << " return _getOpaquePointer();\n"; os << " }\n"; + os << " inline void _destructiveInjectEnumTag(unsigned tag) {\n"; + printEnumVWTableVariable(); + os << " enumVWTable->destructiveInjectEnumTag(_getOpaquePointer(), tag, " + "metadata._0);\n"; + os << " }\n"; os << " inline unsigned _getEnumTag() const {\n"; printEnumVWTableVariable(); os << " return enumVWTable->getEnumTag(_getOpaquePointer(), " "metadata._0);\n"; os << " }\n"; + + for (const auto &pair : interopContext.getIrABIDetails().getEnumTagMapping( + cast(typeDecl))) { + os << " using _impl_" << pair.first->getNameStr() << " = decltype("; + ClangSyntaxPrinter(os).printIdentifier(pair.first->getNameStr()); + os << ");\n"; + } } // Print out the storage for the value type. os << " "; @@ -290,34 +302,6 @@ void ClangValueTypePrinter::printValueTypeDecl( printCxxImplClassName(os, typeDecl); os << ";\n"; os << "};\n"; - // Print the definition of enum static struct data memebers - if (isa(typeDecl)) { - auto tagMapping = interopContext.getIrABIDetails().getEnumTagMapping( - cast(typeDecl)); - for (const auto &pair : tagMapping) { - os << "decltype("; - printer.printBaseName(typeDecl); - os << "::"; - printer.printIdentifier(pair.first->getNameStr()); - os << ") "; - printer.printBaseName(typeDecl); - os << "::"; - printer.printIdentifier(pair.first->getNameStr()); - os << ";\n"; - } - if (isOpaqueLayout) { - os << "decltype("; - printer.printBaseName(typeDecl); - // TODO: allow custom name for this special case - os << "::"; - printer.printIdentifier("unknownDefault"); - os << ") "; - printer.printBaseName(typeDecl); - os << "::"; - printer.printIdentifier("unknownDefault"); - os << ";\n"; - } - } os << '\n'; const auto *moduleContext = typeDecl->getModuleContext(); diff --git a/test/Interop/SwiftToCxx/enums/resilient-enum-in-cxx.swift b/test/Interop/SwiftToCxx/enums/resilient-enum-in-cxx.swift index 22f3502a8b130..46a7b96d231e8 100644 --- a/test/Interop/SwiftToCxx/enums/resilient-enum-in-cxx.swift +++ b/test/Interop/SwiftToCxx/enums/resilient-enum-in-cxx.swift @@ -32,6 +32,29 @@ public func printFoo(_ x: Foo) { print(x) } +public enum Empty { + +} + +// CHECK: // Tags for resilient enum Empty +// CHECK-NEXT: extern "C" { +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace _impl +// CHECK-EMPTY: +// CHECK-NEXT: class Empty final { +// CHECK: enum class cases { +// CHECK-NEXT: unknownDefault +// CHECK-NEXT: }; +// CHECK: inline const static struct { // impl struct for case unknownDefault +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::unknownDefault; +// CHECK-NEXT: } +// CHECK-NEXT: } unknownDefault; +// CHECK-NEXT: inline bool isUnknownDefault() const; +// CHECK: inline operator cases() const { +// CHECK-NEXT: return cases::unknownDefault; +// CHECK-NEXT: } // CHECK: // Tags for resilient enum Foo // CHECK-NEXT: extern "C" { // CHECK-NEXT: extern unsigned $s5Enums3FooO1ayACSdcACmFWC; @@ -47,17 +70,28 @@ public func printFoo(_ x: Foo) { // NEW_CASE-NEXT: b, // CHECK-NEXT: unknownDefault // CHECK-NEXT: } -// CHECK: static struct { // impl struct for case unknownDefault -// CHECK-NEXT: constexpr operator cases() const { +// CHECK: inline const static struct { // impl struct for case unknownDefault +// CHECK-NEXT: inline constexpr operator cases() const { // CHECK-NEXT: return cases::unknownDefault; // CHECK-NEXT: } // CHECK-NEXT: } unknownDefault; -// CHECK-NEXT: inline bool isUnknownDefault() const { -// CHECK-NEXT: return *this == Foo::unknownDefault; -// CHECK-NEXT: } +// CHECK-NEXT: inline bool isUnknownDefault() const; +// CHECK-EMPTY: // CHECK: inline operator cases() const { // CHECK-NEXT: auto tag = _getEnumTag(); // CHECK-NEXT: if (tag == _impl::$s5Enums3FooO1ayACSdcACmFWC) return cases::a; // NEW_CASE-NEXT: if (tag == _impl::$s5Enums3FooO1byACSicACmFWC) return cases::b; // CHECK-NEXT: return cases::unknownDefault; // CHECK-NEXT: } +// CHECK: inline Foo Foo::_impl_a::operator()(double val) const { +// CHECK-NEXT: auto result = Foo::_make(); +// CHECK-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val)); +// CHECK-NEXT: result._destructiveInjectEnumTag(_impl::$s5Enums3FooO1ayACSdcACmFWC); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// NEW_CASE: inline Foo Foo::_impl_b::operator()(swift::Int val) const { +// NEW_CASE-NEXT: auto result = Foo::_make(); +// NEW_CASE-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val)); +// NEW_CASE-NEXT: result._destructiveInjectEnumTag(_impl::$s5Enums3FooO1byACSicACmFWC); +// NEW_CASE-NEXT: return result; +// NEW_CASE-NEXT: } diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-case-functions-execution.cpp b/test/Interop/SwiftToCxx/enums/swift-enum-case-functions-execution.cpp deleted file mode 100644 index 80b58deab69aa..0000000000000 --- a/test/Interop/SwiftToCxx/enums/swift-enum-case-functions-execution.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// RUN: %empty-directory(%t) - -// RUN: %target-swift-frontend %S/swift-enum-case-functions.swift -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h - -// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-enums-execution.o -// RUN: %target-interop-build-swift %S/swift-enum-case-functions.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain - -// RUN: %target-codesign %t/swift-enums-execution -// RUN: %target-run %t/swift-enums-execution - -// REQUIRES: executable_test - -#include -#include "enums.h" - -using namespace Enums; - -void cxxCheckEnum(const DataCase &e) { - assert(e.isOne()); -} - -void cxxCheckEnum(const CLikeEnum &e) { - switch (e) { - case CLikeEnum::cases::one: - assert(checkCLikeEnum(e, 1)); - assert(e.isOne()); - break; - case CLikeEnum::cases::two: - assert(checkCLikeEnum(e, 2)); - assert(e.isTwo()); - break; - case CLikeEnum::cases::three: - assert(checkCLikeEnum(e, 3)); - assert(e.isThree()); - break; - } -} - -void cxxCheckEnum(const BoolWithCase &e) { - switch (e) { - case BoolWithCase::cases::first: - assert(checkBoolWithCase(e, 1)); - assert(e.isFirst()); - break; - case BoolWithCase::cases::second: - assert(checkBoolWithCase(e, 2)); - assert(e.isSecond()); - break; - case BoolWithCase::cases::third: - assert(checkBoolWithCase(e, 3)); - assert(e.isThird()); - break; - } -} - -void cxxCheckEnum(const IntOrInfinity &e) { - switch (e) { - case IntOrInfinity::cases::NegInfinity: - assert(checkIntOrInfinity(e, 1)); - assert(e.isNegInfinity()); - break; - case IntOrInfinity::cases::Int: - assert(checkIntOrInfinity(e, 2)); - assert(e.isInt()); - break; - case IntOrInfinity::cases::PosInfinity: - assert(checkIntOrInfinity(e, 3)); - assert(e.isPosInfinity()); - break; - } -} - -void cxxCheckEnum(const MultipleBoolWithCase &e) { - switch (e) { - case MultipleBoolWithCase::cases::first: - assert(checkMultipleBoolWithCase(e, 1)); - assert(e.isFirst()); - break; - case MultipleBoolWithCase::cases::second: - assert(checkMultipleBoolWithCase(e, 2)); - assert(e.isSecond()); - break; - case MultipleBoolWithCase::cases::third: - assert(checkMultipleBoolWithCase(e, 3)); - assert(e.isThird()); - break; - case MultipleBoolWithCase::cases::fourth: - assert(checkMultipleBoolWithCase(e, 4)); - assert(e.isFourth()); - break; - } -} - -void cxxCheckEnum(const IntDoubleOrBignum &e) { - switch (e) { - case IntDoubleOrBignum::cases::Int: - assert(checkIntDoubleOrBignum(e, 1)); - assert(e.isInt()); - break; - case IntDoubleOrBignum::cases::Double: - assert(checkIntDoubleOrBignum(e, 2)); - assert(e.isDouble()); - break; - case IntDoubleOrBignum::cases::Bignum: - assert(checkIntDoubleOrBignum(e, 3)); - assert(e.isBignum()); - break; - } -} - -int main() { - { - auto e1 = makeDataCase(); - cxxCheckEnum(e1); - } - - { - auto e1 = makeCLikeEnum(1); - auto e2 = makeCLikeEnum(2); - auto e3 = makeCLikeEnum(3); - - cxxCheckEnum(e1); - cxxCheckEnum(e2); - cxxCheckEnum(e3); - } - - { - auto e1 = makeBoolWithCase(1); - auto e2 = makeBoolWithCase(2); - auto e3 = makeBoolWithCase(3); - - cxxCheckEnum(e1); - cxxCheckEnum(e2); - cxxCheckEnum(e3); - } - - { - auto e1 = makeIntOrInfinity(1); - auto e2 = makeIntOrInfinity(2); - auto e3 = makeIntOrInfinity(3); - - cxxCheckEnum(e1); - cxxCheckEnum(e2); - cxxCheckEnum(e3); - } - - { - auto e1 = makeMultipleBoolWithCase(1); - auto e2 = makeMultipleBoolWithCase(2); - auto e3 = makeMultipleBoolWithCase(3); - auto e4 = makeMultipleBoolWithCase(4); - - cxxCheckEnum(e1); - cxxCheckEnum(e2); - cxxCheckEnum(e3); - cxxCheckEnum(e4); - } - - { - auto e1 = makeIntDoubleOrBignum(1); - auto e2 = makeIntDoubleOrBignum(2); - auto e3 = makeIntDoubleOrBignum(3); - - cxxCheckEnum(e1); - cxxCheckEnum(e2); - cxxCheckEnum(e3); - } - return 0; -} diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-case-functions.swift b/test/Interop/SwiftToCxx/enums/swift-enum-case-functions.swift deleted file mode 100644 index 92fa83885ff45..0000000000000 --- a/test/Interop/SwiftToCxx/enums/swift-enum-case-functions.swift +++ /dev/null @@ -1,584 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h -// RUN: %FileCheck %s < %t/enums.h - -// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function) - -// test case-related member functions and structs - -public enum DataCase { case one(_ x: Int) } - -public func makeDataCase() -> DataCase { return .one(10) } - -public enum CLikeEnum { case one, two, three } - -public func makeCLikeEnum(_ tag: Int) -> CLikeEnum { - switch tag { - case 1: - return .one - case 2: - return .two - default: - return .three - } -} - -public func checkCLikeEnum(_ x: CLikeEnum, tag: Int) -> Bool { - switch x { - case .one: - return tag == 1 - case .two: - return tag == 2 - case .three: - return ![1, 2].contains(tag) - } -} - -public enum BoolWithCase { - case first - case second(Bool) - case third -} - -public func makeBoolWithCase(_ tag: Int) -> BoolWithCase { - switch tag { - case 1: - return .first - case 2: - return .second(true) - default: - return .third - } -} - -public func checkBoolWithCase(_ x: BoolWithCase, tag: Int) -> Bool { - switch x { - case .first: - return tag == 1 - case .second: - return tag == 2 - case .third: - return ![1, 2].contains(tag) - } -} - -public enum IntOrInfinity { - case NegInfinity - case Int(Int) - case PosInfinity -} - -public func makeIntOrInfinity(_ tag: Int) -> IntOrInfinity { - switch tag { - case 1: - return .NegInfinity - case 2: - return .Int(123) - default: - return .PosInfinity - } -} - -public func checkIntOrInfinity(_ x: IntOrInfinity, tag: Int) -> Bool { - switch x { - case .NegInfinity: - return tag == 1 - case .Int: - return tag == 2 - case .PosInfinity: - return ![1, 2].contains(tag) - } -} - -public enum MultipleBoolWithCase { - case first - case second(Bool) - case third(Bool) - case fourth -} - -public func makeMultipleBoolWithCase(_ tag: Int) -> MultipleBoolWithCase { - switch tag { - case 1: - return .first - case 2: - return .second(true) - case 3: - return .third(false) - default: - return .fourth - } -} - -public func checkMultipleBoolWithCase(_ x: MultipleBoolWithCase, tag: Int) -> Bool { - switch x { - case .first: - return tag == 1 - case .second: - return tag == 2 - case .third: - return tag == 3 - case .fourth: - return ![1, 2, 3].contains(tag) - } -} - -public enum IntDoubleOrBignum { - case Int(Int) - case Double(Double) - case Bignum -} - -public func makeIntDoubleOrBignum(_ tag: Int) -> IntDoubleOrBignum { - switch tag { - case 1: - return .Int(10) - case 2: - return .Double(3.14) - default: - return .Bignum - } -} - -public func checkIntDoubleOrBignum(_ x: IntDoubleOrBignum, tag: Int) -> Bool { - switch x { - case .Int: - return tag == 1 - case .Double: - return tag == 2 - case .Bignum: - return ![1, 2].contains(tag) - } -} - -// CHECK: class BoolWithCase final { - -// CHECK: static struct { // impl struct for case second -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::second; -// CHECK-NEXT: } -// CHECK-NEXT: inline BoolWithCase operator()() const { -// CHECK-NEXT: return BoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } second; -// CHECK-NEXT: inline bool isSecond() const { -// CHECK-NEXT: return *this == BoolWithCase::second; -// CHECK-NEXT: } -// CHECK-NEXT: inline bool getSecond() const { -// CHECK-NEXT: if (!isSecond()) abort(); -// CHECK-NEXT: alignas(BoolWithCase) unsigned char buffer[sizeof(BoolWithCase)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) BoolWithCase(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: bool result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case first -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::first; -// CHECK-NEXT: } -// CHECK-NEXT: inline BoolWithCase operator()() const { -// CHECK-NEXT: return BoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } first; -// CHECK-NEXT: inline bool isFirst() const { -// CHECK-NEXT: return *this == BoolWithCase::first; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case third -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::third; -// CHECK-NEXT: } -// CHECK-NEXT: inline BoolWithCase operator()() const { -// CHECK-NEXT: return BoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } third; -// CHECK-NEXT: inline bool isThird() const { -// CHECK-NEXT: return *this == BoolWithCase::third; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-EMPTY: -// CHECK-NEXT: inline operator cases() const { -// CHECK-NEXT: switch (_getEnumTag()) { -// CHECK-NEXT: case 0: return cases::second; -// CHECK-NEXT: case 1: return cases::first; -// CHECK-NEXT: case 2: return cases::third; -// CHECK-NEXT: default: abort(); -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK: inline unsigned _getEnumTag() const { -// CHECK-NEXT: auto metadata = _impl::$s5Enums12BoolWithCaseOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: } -// CHECK: }; -// CHECK-NEXT: decltype(BoolWithCase::first) BoolWithCase::first; -// CHECK-NEXT: decltype(BoolWithCase::second) BoolWithCase::second; -// CHECK-NEXT: decltype(BoolWithCase::third) BoolWithCase::third; - -// CHECK: class CLikeEnum final { - -// CHECK: static struct { // impl struct for case one -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::one; -// CHECK-NEXT: } -// CHECK-NEXT: inline CLikeEnum operator()() const { -// CHECK-NEXT: return CLikeEnum::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } one; -// CHECK-NEXT: inline bool isOne() const { -// CHECK-NEXT: return *this == CLikeEnum::one; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case two -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::two; -// CHECK-NEXT: } -// CHECK-NEXT: inline CLikeEnum operator()() const { -// CHECK-NEXT: return CLikeEnum::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } two; -// CHECK-NEXT: inline bool isTwo() const { -// CHECK-NEXT: return *this == CLikeEnum::two; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case three -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::three; -// CHECK-NEXT: } -// CHECK-NEXT: inline CLikeEnum operator()() const { -// CHECK-NEXT: return CLikeEnum::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } three; -// CHECK-NEXT: inline bool isThree() const { -// CHECK-NEXT: return *this == CLikeEnum::three; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-EMPTY: -// CHECK-NEXT: inline operator cases() const { -// CHECK-NEXT: switch (_getEnumTag()) { -// CHECK-NEXT: case 0: return cases::one; -// CHECK-NEXT: case 1: return cases::two; -// CHECK-NEXT: case 2: return cases::three; -// CHECK-NEXT: default: abort(); -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK: inline unsigned _getEnumTag() const { -// CHECK-NEXT: auto metadata = _impl::$s5Enums9CLikeEnumOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: } -// CHECK: }; -// CHECK-NEXT: decltype(CLikeEnum::one) CLikeEnum::one; -// CHECK-NEXT: decltype(CLikeEnum::two) CLikeEnum::two; -// CHECK-NEXT: decltype(CLikeEnum::three) CLikeEnum::three; - -// CHECK: class DataCase final { - -// CHECK: static struct { // impl struct for case one -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::one; -// CHECK-NEXT: } -// CHECK-NEXT: inline DataCase operator()() const { -// CHECK-NEXT: return DataCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } one; -// CHECK-NEXT: inline bool isOne() const { -// CHECK-NEXT: return *this == DataCase::one; -// CHECK-NEXT: } -// CHECK-NEXT: inline swift::Int getOne() const { -// CHECK-NEXT: if (!isOne()) abort(); -// CHECK-NEXT: alignas(DataCase) unsigned char buffer[sizeof(DataCase)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) DataCase(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: swift::Int result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-EMPTY: -// CHECK-NEXT: inline operator cases() const { -// CHECK-NEXT: switch (_getEnumTag()) { -// CHECK-NEXT: case 0: return cases::one; -// CHECK-NEXT: default: abort(); -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK: inline unsigned _getEnumTag() const { -// CHECK-NEXT: auto metadata = _impl::$s5Enums8DataCaseOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: } -// CHECK: }; -// CHECK-NEXT: decltype(DataCase::one) DataCase::one; - -// CHECK: class IntDoubleOrBignum final { - -// CHECK: enum class cases { -// CHECK-NEXT: Int, -// CHECK-NEXT: Double, -// CHECK-NEXT: Bignum -// CHECK-NEXT: }; -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case Int -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::Int; -// CHECK-NEXT: } -// CHECK-NEXT: inline IntDoubleOrBignum operator()() const { -// CHECK-NEXT: return IntDoubleOrBignum::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } Int; -// CHECK-NEXT: inline bool isInt() const { -// CHECK-NEXT: return *this == IntDoubleOrBignum::Int; -// CHECK-NEXT: } -// CHECK-NEXT: inline swift::Int getInt() const { -// CHECK-NEXT: if (!isInt()) abort(); -// CHECK-NEXT: alignas(IntDoubleOrBignum) unsigned char buffer[sizeof(IntDoubleOrBignum)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) IntDoubleOrBignum(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: swift::Int result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case Double -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::Double; -// CHECK-NEXT: } -// CHECK-NEXT: inline IntDoubleOrBignum operator()() const { -// CHECK-NEXT: return IntDoubleOrBignum::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } Double; -// CHECK-NEXT: inline bool isDouble() const { -// CHECK-NEXT: return *this == IntDoubleOrBignum::Double; -// CHECK-NEXT: } -// CHECK-NEXT: inline double getDouble() const { -// CHECK-NEXT: if (!isDouble()) abort(); -// CHECK-NEXT: alignas(IntDoubleOrBignum) unsigned char buffer[sizeof(IntDoubleOrBignum)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) IntDoubleOrBignum(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: double result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case Bignum -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::Bignum; -// CHECK-NEXT: } -// CHECK-NEXT: inline IntDoubleOrBignum operator()() const { -// CHECK-NEXT: return IntDoubleOrBignum::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } Bignum; -// CHECK-NEXT: inline bool isBignum() const { -// CHECK-NEXT: return *this == IntDoubleOrBignum::Bignum; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-EMPTY: -// CHECK-NEXT: inline operator cases() const { -// CHECK-NEXT: switch (_getEnumTag()) { -// CHECK-NEXT: case 0: return cases::Int; -// CHECK-NEXT: case 1: return cases::Double; -// CHECK-NEXT: case 2: return cases::Bignum; -// CHECK-NEXT: default: abort(); -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK: inline unsigned _getEnumTag() const { -// CHECK-NEXT: auto metadata = _impl::$s5Enums17IntDoubleOrBignumOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: } -// CHECK: }; -// CHECK-NEXT: decltype(IntDoubleOrBignum::Int) IntDoubleOrBignum::Int; -// CHECK-NEXT: decltype(IntDoubleOrBignum::Double) IntDoubleOrBignum::Double; -// CHECK-NEXT: decltype(IntDoubleOrBignum::Bignum) IntDoubleOrBignum::Bignum; - -// CHECK: class IntOrInfinity final { - -// CHECK: static struct { // impl struct for case Int -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::Int; -// CHECK-NEXT: } -// CHECK-NEXT: inline IntOrInfinity operator()() const { -// CHECK-NEXT: return IntOrInfinity::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } Int; -// CHECK-NEXT: inline bool isInt() const { -// CHECK-NEXT: return *this == IntOrInfinity::Int; -// CHECK-NEXT: } -// CHECK-NEXT: inline swift::Int getInt() const { -// CHECK-NEXT: if (!isInt()) abort(); -// CHECK-NEXT: alignas(IntOrInfinity) unsigned char buffer[sizeof(IntOrInfinity)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) IntOrInfinity(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: swift::Int result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case NegInfinity -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::NegInfinity; -// CHECK-NEXT: } -// CHECK-NEXT: inline IntOrInfinity operator()() const { -// CHECK-NEXT: return IntOrInfinity::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } NegInfinity; -// CHECK-NEXT: inline bool isNegInfinity() const { -// CHECK-NEXT: return *this == IntOrInfinity::NegInfinity; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case PosInfinity -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::PosInfinity; -// CHECK-NEXT: } -// CHECK-NEXT: inline IntOrInfinity operator()() const { -// CHECK-NEXT: return IntOrInfinity::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } PosInfinity; -// CHECK-NEXT: inline bool isPosInfinity() const { -// CHECK-NEXT: return *this == IntOrInfinity::PosInfinity; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-EMPTY: -// CHECK-NEXT: inline operator cases() const { -// CHECK-NEXT: switch (_getEnumTag()) { -// CHECK-NEXT: case 0: return cases::Int; -// CHECK-NEXT: case 1: return cases::NegInfinity; -// CHECK-NEXT: case 2: return cases::PosInfinity; -// CHECK-NEXT: default: abort(); -// CHECK-NEXT: } -// CHECK: inline unsigned _getEnumTag() const { -// CHECK-NEXT: auto metadata = _impl::$s5Enums13IntOrInfinityOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: } -// CHECK: }; -// CHECK-NEXT: decltype(IntOrInfinity::NegInfinity) IntOrInfinity::NegInfinity; -// CHECK-NEXT: decltype(IntOrInfinity::Int) IntOrInfinity::Int; -// CHECK-NEXT: decltype(IntOrInfinity::PosInfinity) IntOrInfinity::PosInfinity; - -// CHECK: class MultipleBoolWithCase final { - -// CHECK: static struct { // impl struct for case second -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::second; -// CHECK-NEXT: } -// CHECK-NEXT: inline MultipleBoolWithCase operator()() const { -// CHECK-NEXT: return MultipleBoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } second; -// CHECK-NEXT: inline bool isSecond() const { -// CHECK-NEXT: return *this == MultipleBoolWithCase::second; -// CHECK-NEXT: } -// CHECK-NEXT: inline bool getSecond() const { -// CHECK-NEXT: if (!isSecond()) abort(); -// CHECK-NEXT: alignas(MultipleBoolWithCase) unsigned char buffer[sizeof(MultipleBoolWithCase)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) MultipleBoolWithCase(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: bool result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case third -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::third; -// CHECK-NEXT: } -// CHECK-NEXT: inline MultipleBoolWithCase operator()() const { -// CHECK-NEXT: return MultipleBoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } third; -// CHECK-NEXT: inline bool isThird() const { -// CHECK-NEXT: return *this == MultipleBoolWithCase::third; -// CHECK-NEXT: } -// CHECK-NEXT: inline bool getThird() const { -// CHECK-NEXT: if (!isThird()) abort(); -// CHECK-NEXT: alignas(MultipleBoolWithCase) unsigned char buffer[sizeof(MultipleBoolWithCase)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) MultipleBoolWithCase(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: bool result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case first -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::first; -// CHECK-NEXT: } -// CHECK-NEXT: inline MultipleBoolWithCase operator()() const { -// CHECK-NEXT: return MultipleBoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } first; -// CHECK-NEXT: inline bool isFirst() const { -// CHECK-NEXT: return *this == MultipleBoolWithCase::first; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-NEXT: static struct { // impl struct for case fourth -// CHECK-NEXT: inline constexpr operator cases() const { -// CHECK-NEXT: return cases::fourth; -// CHECK-NEXT: } -// CHECK-NEXT: inline MultipleBoolWithCase operator()() const { -// CHECK-NEXT: return MultipleBoolWithCase::_make(); -// CHECK-NEXT: } -// CHECK-NEXT: } fourth; -// CHECK-NEXT: inline bool isFourth() const { -// CHECK-NEXT: return *this == MultipleBoolWithCase::fourth; -// CHECK-NEXT: } -// CHECK-EMPTY: -// CHECK-EMPTY: -// CHECK-NEXT: inline operator cases() const { -// CHECK-NEXT: switch (_getEnumTag()) { -// CHECK-NEXT: case 0: return cases::second; -// CHECK-NEXT: case 1: return cases::third; -// CHECK-NEXT: case 2: return cases::first; -// CHECK-NEXT: case 3: return cases::fourth; -// CHECK-NEXT: default: abort(); -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK: inline unsigned _getEnumTag() const { -// CHECK-NEXT: auto metadata = _impl::$s5Enums20MultipleBoolWithCaseOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: } -// CHECK: }; -// CHECK-NEXT: decltype(MultipleBoolWithCase::first) MultipleBoolWithCase::first; -// CHECK-NEXT: decltype(MultipleBoolWithCase::second) MultipleBoolWithCase::second; -// CHECK-NEXT: decltype(MultipleBoolWithCase::third) MultipleBoolWithCase::third; -// CHECK-NEXT: decltype(MultipleBoolWithCase::fourth) MultipleBoolWithCase::fourth; diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-cases-in-cxx.swift b/test/Interop/SwiftToCxx/enums/swift-enum-cases-in-cxx.swift deleted file mode 100644 index 991d9be94de7c..0000000000000 --- a/test/Interop/SwiftToCxx/enums/swift-enum-cases-in-cxx.swift +++ /dev/null @@ -1,47 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h -// RUN: %FileCheck %s < %t/enums.h - -// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function) - -public enum EnumMultipleElementsInSingleCase { case first, second } - -public enum EnumSingleElementInSingleCase { - case first - case second -} - -public enum EnumCaseIsSwiftKeyword { - case first(a: Int) - case `protocol`(b: Double) -} - -public enum EnumCaseIsCxxKeyword { - case first, second(x: Float) - case const -} - -// CHECK: class EnumCaseIsCxxKeyword final { -// CHECK: enum class cases { -// CHECK-NEXT: second, -// CHECK-NEXT: first, -// CHECK-NEXT: const_ -// CHECK-NEXT: }; - -// CHECK: class EnumCaseIsSwiftKeyword final { -// CHECK: enum class cases { -// CHECK-NEXT: first, -// CHECK-NEXT: protocol -// CHECK-NEXT: }; - -// CHECK: class EnumMultipleElementsInSingleCase final { -// CHECK: enum class cases { -// CHECK-NEXT: first, -// CHECK-NEXT: second -// CHECK-NEXT: }; - -// CHECK: class EnumSingleElementInSingleCase final { -// CHECK: enum class cases { -// CHECK-NEXT: first, -// CHECK-NEXT: second -// CHECK-NEXT: }; diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-extract-payload-execution.cpp b/test/Interop/SwiftToCxx/enums/swift-enum-extract-payload-execution.cpp deleted file mode 100644 index f6db08694b13d..0000000000000 --- a/test/Interop/SwiftToCxx/enums/swift-enum-extract-payload-execution.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// RUN: %empty-directory(%t) - -// RUN: %target-swift-frontend %S/swift-enum-extract-payload.swift -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h - -// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-enums-execution.o -// RUN: %target-interop-build-swift %S/swift-enum-extract-payload.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain - -// RUN: %target-codesign %t/swift-enums-execution -// RUN: %target-run %t/swift-enums-execution - -// REQUIRES: executable_test - -#include -#include "enums.h" - -using namespace Enums; - -int main() { - { - auto xyz = makeXyz(1); - assert(xyz.isFirst()); - assert(checkFoo(Foo::init(1234), xyz.getFirst())); - assert(1234 == xyz.getFirst().getX()); - } - { - auto xyz = makeXyz(2); - assert(xyz.isSecond()); - assert(checkUvw(makeUvw(2), xyz.getSecond())); - assert(xyz.getSecond().isTwo()); - } - { - auto xyz = makeXyz(3); - assert(xyz.isThird()); - assert(checkBar(Bar::init(1.1, 2.2, 3.3, 4.4, 5.5, 6.6), xyz.getThird())); - assert(1.1 == xyz.getThird().getX1()); - assert(2.2 == xyz.getThird().getX2()); - assert(3.3 == xyz.getThird().getX3()); - assert(4.4 == xyz.getThird().getX4()); - assert(5.5 == xyz.getThird().getX5()); - assert(6.6 == xyz.getThird().getX6()); - } - { - auto e = makePrimitivePayload(1); - assert(e.isX()); - assert(e.getX() == 9999); - } - { - auto e = makePrimitivePayload(2); - assert(e.isY()); - assert(e.getY() == 3.14); - } - { - auto e = makePrimitivePayload(3); - assert(e.isZ()); - assert(e.getZ()); - } - return 0; -} diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-extract-payload.swift b/test/Interop/SwiftToCxx/enums/swift-enum-extract-payload.swift deleted file mode 100644 index f492bb907ba65..0000000000000 --- a/test/Interop/SwiftToCxx/enums/swift-enum-extract-payload.swift +++ /dev/null @@ -1,218 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h -// RUN: %FileCheck %s < %t/enums.h - -// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function) - -public enum PrimitivePayload { - case x(Int64) - case y(Double) - case z(Bool) -} - -public func makePrimitivePayload(_ x: Int) -> PrimitivePayload { - switch x { - case 1: - return .x(9999) - case 2: - return .y(3.14) - default: - return .z(true) - } -} - -public enum Uvw { - case one, two ,three -} - -public enum Xyz { - case first(Foo) - case second(Uvw) - case third(Bar) -} - -public struct Foo { - public var x: Int64 - public init(x: Int64) { - self.x = x - } -} - -public struct Bar { - public var x1, x2, x3, x4, x5, x6: Double - public init(x1: Double, x2: Double, x3: Double, x4: Double, x5: Double, x6: Double) { - self.x1 = x1 - self.x2 = x2 - self.x3 = x3 - self.x4 = x4 - self.x5 = x5 - self.x6 = x6 - } -} - -public func checkFoo(_ lhs: Foo, _ rhs: Foo) -> Bool { - return lhs.x == rhs.x -} - -public func checkBar(_ lhs: Bar, _ rhs: Bar) -> Bool { - return lhs.x1 == rhs.x1 && lhs.x2 == rhs.x2 && lhs.x3 == rhs.x3 && lhs.x4 == rhs.x4 && lhs.x5 == rhs.x5 && lhs.x6 == rhs.x6 -} - -public func checkUvw(_ lhs: Uvw, _ rhs: Uvw) -> Bool { - return lhs == rhs -} - -public func makeXyz(_ x: Int) -> Xyz { - switch x { - case 1: - return .first(Foo(x: 1234)) - case 2: - return .second(.two) - default: - return .third(Bar(x1: 1.1, x2: 2.2, x3: 3.3, x4: 4.4, x5: 5.5, x6: 6.6)) - } -} - -public func makeUvw(_ x: Int) -> Uvw { - switch x { - case 1: - return .one - case 2: - return .two - default: - return .three - } -} - -// CHECK: class _impl_Bar { -// CHECK: static inline void initializeWithTake(char * _Nonnull destStorage, char * _Nonnull srcStorage) { -// CHECK-NEXT: auto metadata = _impl::$s5Enums3BarVMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: vwTable->initializeWithTake(destStorage, srcStorage, metadata._0); -// CHECK-NEXT: } - -// CHECK: class _impl_Foo { -// CHECK: static inline void initializeWithTake(char * _Nonnull destStorage, char * _Nonnull srcStorage) { -// CHECK-NEXT: auto metadata = _impl::$s5Enums3FooVMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: vwTable->initializeWithTake(destStorage, srcStorage, metadata._0); -// CHECK-NEXT: } - -// CHECK: class PrimitivePayload final { -// CHECK: inline int64_t getX() const { -// CHECK-NEXT: if (!isX()) abort(); -// CHECK-NEXT: alignas(PrimitivePayload) unsigned char buffer[sizeof(PrimitivePayload)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) PrimitivePayload(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: int64_t result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK: inline double getY() const { -// CHECK-NEXT: if (!isY()) abort(); -// CHECK-NEXT: alignas(PrimitivePayload) unsigned char buffer[sizeof(PrimitivePayload)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) PrimitivePayload(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: double result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK: inline bool getZ() const { -// CHECK-NEXT: if (!isZ()) abort(); -// CHECK-NEXT: alignas(PrimitivePayload) unsigned char buffer[sizeof(PrimitivePayload)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) PrimitivePayload(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: bool result; -// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); -// CHECK-NEXT: return result; -// CHECK-NEXT: } -// CHECK: private: -// CHECK: inline char * _Nonnull _destructiveProjectEnumData() { -// CHECK-NEXT: auto metadata = _impl::$s5Enums16PrimitivePayloadOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: enumVWTable->destructiveProjectEnumData(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: return _getOpaquePointer(); -// CHECK-NEXT: } -// CHECK: class _impl_PrimitivePayload { -// CHECK: static inline void initializeWithTake(char * _Nonnull destStorage, char * _Nonnull srcStorage) { -// CHECK-NEXT: auto metadata = _impl::$s5Enums16PrimitivePayloadOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: vwTable->initializeWithTake(destStorage, srcStorage, metadata._0); -// CHECK-NEXT: } - -// CHECK: class _impl_Uvw { -// CHECK: static inline void initializeWithTake(char * _Nonnull destStorage, char * _Nonnull srcStorage) { -// CHECK-NEXT: auto metadata = _impl::$s5Enums3UvwOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: vwTable->initializeWithTake(destStorage, srcStorage, metadata._0); -// CHECK-NEXT: } - -// CHECK: class Xyz final { -// CHECK: inline Foo getFirst() const { -// CHECK-NEXT: if (!isFirst()) abort(); -// CHECK-NEXT: alignas(Xyz) unsigned char buffer[sizeof(Xyz)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) Xyz(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: return _impl::_impl_Foo::returnNewValue([&](char * _Nonnull result) { -// CHECK-NEXT: _impl::_impl_Foo::initializeWithTake(result, payloadFromDestruction); -// CHECK-NEXT: }); -// CHECK-NEXT: } -// CHECK: inline Bar getThird() const { -// CHECK-NEXT: if (!isThird()) abort(); -// CHECK-NEXT: alignas(Xyz) unsigned char buffer[sizeof(Xyz)]; -// CHECK-NEXT: auto *thisCopy = new(buffer) Xyz(*this); -// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); -// CHECK-NEXT: return _impl::_impl_Bar::returnNewValue([&](char * _Nonnull result) { -// CHECK-NEXT: _impl::_impl_Bar::initializeWithTake(result, payloadFromDestruction); -// CHECK-NEXT: }); -// CHECK-NEXT: } -// CHECK: private: -// CHECK: inline char * _Nonnull _destructiveProjectEnumData() { -// CHECK-NEXT: auto metadata = _impl::$s5Enums3XyzOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); -// CHECK-NEXT: enumVWTable->destructiveProjectEnumData(_getOpaquePointer(), metadata._0); -// CHECK-NEXT: return _getOpaquePointer(); -// CHECK-NEXT: } -// CHECK: class _impl_Xyz { -// CHECK: static inline void initializeWithTake(char * _Nonnull destStorage, char * _Nonnull srcStorage) { -// CHECK-NEXT: auto metadata = _impl::$s5Enums3XyzOMa(0); -// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; -// CHECK-NEXT: #ifdef __arm64e__ -// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); -// CHECK-NEXT: #else -// CHECK-NEXT: auto *vwTable = *vwTableAddr; -// CHECK-NEXT: #endif -// CHECK-NEXT: vwTable->initializeWithTake(destStorage, srcStorage, metadata._0); -// CHECK-NEXT: } diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-implementation-execution.cpp b/test/Interop/SwiftToCxx/enums/swift-enum-implementation-execution.cpp new file mode 100644 index 0000000000000..bba31a8c2c6b3 --- /dev/null +++ b/test/Interop/SwiftToCxx/enums/swift-enum-implementation-execution.cpp @@ -0,0 +1,77 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %S/swift-enum-implementation.swift -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h + +// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-enums-execution.o +// RUN: %target-interop-build-swift %S/swift-enum-implementation.swift -o %t/swift-enums-execution -Xlinker %t/swift-enums-execution.o -module-name Enums -Xfrontend -entry-point-function-name -Xfrontend swiftMain + +// RUN: %target-codesign %t/swift-enums-execution +// RUN: %target-run %t/swift-enums-execution + +// REQUIRES: executable_test + +#include +#include "enums.h" + +using namespace Enums; + +int switchTest(const E &e) { + switch (e) { + case E::x: + assert(e.isX()); + assert(e.getX() == 3.14); + return 0; + case E::y: + assert(e.isY()); + assert(e.getY() == nullptr); + return 1; + case E::z: + assert(e.isZ()); + assert(e.getZ().getX() == 1234); + return 2; + case E::w: + assert(e.isW()); + assert(e.getW() == 5678); + return 3; + case E::auto_: + assert(e.isAuto_()); + assert(e.getAuto_() == reinterpret_cast(1)); + return 4; + case E::foobar: + assert(e.isFoobar()); + return 5; + } +} + +int main() { + { + auto e = E::x(3.14); + assert(switchTest(e) == 0); + } + + { + auto e = E::y(nullptr); + assert(switchTest(e) == 1); + } + + { + auto e = E::z(S::init(1234)); + assert(switchTest(e) == 2); + } + + { + auto e = E::w(5678); + assert(switchTest(e) == 3); + } + + { + auto e = E::auto_(reinterpret_cast(1)); + assert(switchTest(e) == 4); + } + + { + auto e = E::foobar(); + assert(switchTest(e) == 5); + } + return 0; +} diff --git a/test/Interop/SwiftToCxx/enums/swift-enum-implementation.swift b/test/Interop/SwiftToCxx/enums/swift-enum-implementation.swift new file mode 100644 index 0000000000000..1da0d54dda955 --- /dev/null +++ b/test/Interop/SwiftToCxx/enums/swift-enum-implementation.swift @@ -0,0 +1,259 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-public-decls -emit-clang-header-path %t/enums.h +// RUN: %FileCheck %s < %t/enums.h + +// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function) + +public enum E { + case x(Double) + case y(UnsafeRawPointer?) + case z(S) + case w(i: Int) + case auto(UnsafeMutableRawPointer) + case foobar +} + +public struct S { + public var x: Int64 + + public init(x: Int64) { + print("S.init()") + self.x = x + } +} + +// CHECK: class E final { +// CHECK: enum class cases { +// CHECK-NEXT: x, +// CHECK-NEXT: y, +// CHECK-NEXT: z, +// CHECK-NEXT: w, +// CHECK-NEXT: auto_, +// CHECK-NEXT: foobar +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: #pragma clang diagnostic push +// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions" // allow use of inline static data member +// CHECK-NEXT: inline const static struct { // impl struct for case x +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::x; +// CHECK-NEXT: } +// CHECK-NEXT: inline E operator()(double val) const; +// CHECK-NEXT: } x; +// CHECK-NEXT: inline bool isX() const; +// CHECK-NEXT: inline double getX() const; +// CHECK-EMPTY: +// CHECK-NEXT: inline const static struct { // impl struct for case y +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::y; +// CHECK-NEXT: } +// CHECK-NEXT: inline E operator()(void const * _Nullable val) const; +// CHECK-NEXT: } y; +// CHECK-NEXT: inline bool isY() const; +// CHECK-NEXT: inline void const * _Nullable getY() const; +// CHECK-EMPTY: +// CHECK-NEXT: inline const static struct { // impl struct for case z +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::z; +// CHECK-NEXT: } +// CHECK-NEXT: inline E operator()(const S &val) const; +// CHECK-NEXT: } z; +// CHECK-NEXT: inline bool isZ() const; +// CHECK-NEXT: inline S getZ() const; +// CHECK-EMPTY: +// CHECK-NEXT: inline const static struct { // impl struct for case w +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::w; +// CHECK-NEXT: } +// CHECK-NEXT: inline E operator()(swift::Int val) const; +// CHECK-NEXT: } w; +// CHECK-NEXT: inline bool isW() const; +// CHECK-NEXT: inline swift::Int getW() const; +// CHECK-EMPTY: +// CHECK-NEXT: inline const static struct { // impl struct for case auto +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::auto_; +// CHECK-NEXT: } +// CHECK-NEXT: inline E operator()(void * _Nonnull val) const; +// CHECK-NEXT: } auto_; +// CHECK-NEXT: inline bool isAuto_() const; +// CHECK-NEXT: inline void * _Nonnull getAuto_() const; +// CHECK-EMPTY: +// CHECK-NEXT: inline const static struct { // impl struct for case foobar +// CHECK-NEXT: inline constexpr operator cases() const { +// CHECK-NEXT: return cases::foobar; +// CHECK-NEXT: } +// CHECK-NEXT: inline E operator()() const; +// CHECK-NEXT: } foobar; +// CHECK-NEXT: inline bool isFoobar() const; +// CHECK-EMPTY: +// CHECK-NEXT: #pragma clang diagnostic pop +// CHECK-NEXT: inline operator cases() const { +// CHECK-NEXT: switch (_getEnumTag()) { +// CHECK-NEXT: case 0: return cases::x; +// CHECK-NEXT: case 1: return cases::y; +// CHECK-NEXT: case 2: return cases::z; +// CHECK-NEXT: case 3: return cases::w; +// CHECK-NEXT: case 4: return cases::auto_; +// CHECK-NEXT: case 5: return cases::foobar; +// CHECK-NEXT: default: abort(); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK: private: +// CHECK: inline char * _Nonnull _destructiveProjectEnumData() { +// CHECK-NEXT: auto metadata = _impl::$s5Enums1EOMa(0); +// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; +// CHECK-NEXT: #ifdef __arm64e__ +// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); +// CHECK-NEXT: #else +// CHECK-NEXT: auto *vwTable = *vwTableAddr; +// CHECK-NEXT: #endif +// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); +// CHECK-NEXT: enumVWTable->destructiveProjectEnumData(_getOpaquePointer(), metadata._0); +// CHECK-NEXT: return _getOpaquePointer(); +// CHECK-NEXT: } +// CHECK-NEXT: inline void _destructiveInjectEnumTag(unsigned tag) { +// CHECK-NEXT: auto metadata = _impl::$s5Enums1EOMa(0); +// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; +// CHECK-NEXT: #ifdef __arm64e__ +// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); +// CHECK-NEXT: #else +// CHECK-NEXT: auto *vwTable = *vwTableAddr; +// CHECK-NEXT: #endif +// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); +// CHECK-NEXT: enumVWTable->destructiveInjectEnumTag(_getOpaquePointer(), tag, metadata._0); +// CHECK-NEXT: } +// CHECK-NEXT: inline unsigned _getEnumTag() const { +// CHECK-NEXT: auto metadata = _impl::$s5Enums1EOMa(0); +// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; +// CHECK-NEXT: #ifdef __arm64e__ +// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); +// CHECK-NEXT: #else +// CHECK-NEXT: auto *vwTable = *vwTableAddr; +// CHECK-NEXT: #endif +// CHECK-NEXT: const auto *enumVWTable = reinterpret_cast(vwTable); +// CHECK-NEXT: return enumVWTable->getEnumTag(_getOpaquePointer(), metadata._0); +// CHECK-NEXT: } +// CHECK-NEXT: using _impl_x = decltype(x); +// CHECK-NEXT: using _impl_y = decltype(y); +// CHECK-NEXT: using _impl_z = decltype(z); +// CHECK-NEXT: using _impl_w = decltype(w); +// CHECK-NEXT: using _impl_auto = decltype(auto_); +// CHECK-NEXT: using _impl_foobar = decltype(foobar); +// CHECK: }; +// CHECK-EMPTY: +// CHECK-NEXT: namespace _impl { +// CHECK-EMPTY: +// CHECK-NEXT: class _impl_E { +// CHECK-NEXT: public: +// CHECK: static inline void initializeWithTake(char * _Nonnull destStorage, char * _Nonnull srcStorage) { +// CHECK-NEXT: auto metadata = _impl::$s5Enums1EOMa(0); +// CHECK-NEXT: auto *vwTableAddr = reinterpret_cast(metadata._0) - 1; +// CHECK-NEXT: #ifdef __arm64e__ +// CHECK-NEXT: auto *vwTable = reinterpret_cast(ptrauth_auth_data(reinterpret_cast(*vwTableAddr), ptrauth_key_process_independent_data, ptrauth_blend_discriminator(vwTableAddr, 11839))); +// CHECK-NEXT: #else +// CHECK-NEXT: auto *vwTable = *vwTableAddr; +// CHECK-NEXT: #endif +// CHECK-NEXT: vwTable->initializeWithTake(destStorage, srcStorage, metadata._0); +// CHECK-NEXT: } +// CHECK: namespace Enums { +// CHECK: inline E E::_impl_x::operator()(double val) const { +// CHECK-NEXT: auto result = E::_make(); +// CHECK-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val)); +// CHECK-NEXT: result._destructiveInjectEnumTag(0); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline bool E::isX() const { +// CHECK-NEXT: return *this == E::x; +// CHECK-NEXT: } +// CHECK-NEXT: inline double E::getX() const { +// CHECK-NEXT: if (!isX()) abort(); +// CHECK-NEXT: alignas(E) unsigned char buffer[sizeof(E)]; +// CHECK-NEXT: auto *thisCopy = new(buffer) E(*this); +// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); +// CHECK-NEXT: double result; +// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline E E::_impl_y::operator()(void const * _Nullable val) const { +// CHECK-NEXT: auto result = E::_make(); +// CHECK-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val)); +// CHECK-NEXT: result._destructiveInjectEnumTag(1); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline bool E::isY() const { +// CHECK-NEXT: return *this == E::y; +// CHECK-NEXT: } +// CHECK-NEXT: inline void const * _Nullable E::getY() const { +// CHECK-NEXT: if (!isY()) abort(); +// CHECK-NEXT: alignas(E) unsigned char buffer[sizeof(E)]; +// CHECK-NEXT: auto *thisCopy = new(buffer) E(*this); +// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); +// CHECK-NEXT: void const * _Nullable result; +// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline E E::_impl_z::operator()(const S &val) const { +// CHECK-NEXT: auto result = E::_make(); +// CHECK-NEXT: alignas(S) unsigned char buffer[sizeof(S)]; +// CHECK-NEXT: auto *valCopy = new(buffer) S(val); +// CHECK-NEXT: swift::_impl::implClassFor::type::initializeWithTake(result._getOpaquePointer(), swift::_impl::implClassFor::type::getOpaquePointer(*valCopy)); +// CHECK-NEXT: result._destructiveInjectEnumTag(2); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline bool E::isZ() const { +// CHECK-NEXT: return *this == E::z; +// CHECK-NEXT: } +// CHECK-NEXT: inline S E::getZ() const { +// CHECK-NEXT: if (!isZ()) abort(); +// CHECK-NEXT: alignas(E) unsigned char buffer[sizeof(E)]; +// CHECK-NEXT: auto *thisCopy = new(buffer) E(*this); +// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); +// CHECK-NEXT: return swift::_impl::implClassFor::type::returnNewValue([&](char * _Nonnull result) { +// CHECK-NEXT: swift::_impl::implClassFor::type::initializeWithTake(result, payloadFromDestruction); +// CHECK-NEXT: }); +// CHECK-NEXT: } +// CHECK-NEXT: inline E E::_impl_w::operator()(swift::Int val) const { +// CHECK-NEXT: auto result = E::_make(); +// CHECK-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val)); +// CHECK-NEXT: result._destructiveInjectEnumTag(3); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline bool E::isW() const { +// CHECK-NEXT: return *this == E::w; +// CHECK-NEXT: } +// CHECK-NEXT: inline swift::Int E::getW() const { +// CHECK-NEXT: if (!isW()) abort(); +// CHECK-NEXT: alignas(E) unsigned char buffer[sizeof(E)]; +// CHECK-NEXT: auto *thisCopy = new(buffer) E(*this); +// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); +// CHECK-NEXT: swift::Int result; +// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline E E::_impl_auto::operator()(void * _Nonnull val) const { +// CHECK-NEXT: auto result = E::_make(); +// CHECK-NEXT: memcpy(result._getOpaquePointer(), &val, sizeof(val)); +// CHECK-NEXT: result._destructiveInjectEnumTag(4); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline bool E::isAuto_() const { +// CHECK-NEXT: return *this == E::auto_; +// CHECK-NEXT: } +// CHECK-NEXT: inline void * _Nonnull E::getAuto_() const { +// CHECK-NEXT: if (!isAuto_()) abort(); +// CHECK-NEXT: alignas(E) unsigned char buffer[sizeof(E)]; +// CHECK-NEXT: auto *thisCopy = new(buffer) E(*this); +// CHECK-NEXT: char * _Nonnull payloadFromDestruction = thisCopy->_destructiveProjectEnumData(); +// CHECK-NEXT: void * _Nonnull result; +// CHECK-NEXT: memcpy(&result, payloadFromDestruction, sizeof(result)); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline E E::_impl_foobar::operator()() const { +// CHECK-NEXT: auto result = E::_make(); +// CHECK-NEXT: result._destructiveInjectEnumTag(5); +// CHECK-NEXT: return result; +// CHECK-NEXT: } +// CHECK-NEXT: inline bool E::isFoobar() const { +// CHECK-NEXT: return *this == E::foobar; +// CHECK-NEXT: }