mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Interop][SwiftToCxx] Support enum creation from Cxx
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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++.
|
||||
|
||||
@@ -398,15 +398,261 @@ private:
|
||||
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<IRABIDetailsProvider::EnumElementInfo>
|
||||
elementInfo) {
|
||||
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) {
|
||||
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<Type> 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 +665,14 @@ private:
|
||||
// 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";
|
||||
};
|
||||
|
||||
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,7 +684,8 @@ private:
|
||||
|
||||
if (ED->isResilient()) {
|
||||
// Printing struct for unknownDefault
|
||||
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr);
|
||||
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr,
|
||||
/* elementInfo */ None);
|
||||
// Printing isUnknownDefault
|
||||
printIsFunction(resilientUnknownDefaultCaseName, ED);
|
||||
os << '\n';
|
||||
@@ -551,7 +695,9 @@ private:
|
||||
// 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::";
|
||||
|
||||
@@ -504,6 +504,10 @@ public:
|
||||
if (addImport(ED))
|
||||
return true;
|
||||
|
||||
if (outputLangMode == OutputLanguageMode::Cxx) {
|
||||
forwardDeclareMemberTypes(ED->getMembers(), ED);
|
||||
}
|
||||
|
||||
if (seenTypes[ED].first == EmissionState::Defined)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -824,3 +824,44 @@ bool DeclAndTypeClangFunctionPrinter::hasKnownOptionalNullableCxxMapping(
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printCustomCxxFunction(
|
||||
const SmallVector<Type> &neededTypes, PrinterTy retTypeAndNamePrinter,
|
||||
PrinterTy paramPrinter, bool isConstFunc, PrinterTy bodyPrinter,
|
||||
ModuleDecl *emittedModule, raw_ostream &outOfLineOS) {
|
||||
llvm::MapVector<Type, std::string> 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";
|
||||
}
|
||||
|
||||
@@ -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 @@ public:
|
||||
ModuleDecl *moduleContext,
|
||||
OutputLanguageMode outputLang);
|
||||
|
||||
using PrinterTy =
|
||||
llvm::function_ref<void(llvm::MapVector<Type, std::string> &)>;
|
||||
|
||||
/// Print generated C++ helper function
|
||||
void printCustomCxxFunction(const SmallVector<Type> &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,
|
||||
|
||||
@@ -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<EnumDecl>(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 << " ";
|
||||
|
||||
@@ -32,6 +32,30 @@ 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-EMPTY:
|
||||
// CHECK-NEXT: 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;
|
||||
@@ -48,14 +72,14 @@ public func printFoo(_ x: Foo) {
|
||||
// CHECK-NEXT: unknownDefault
|
||||
// CHECK-NEXT: }
|
||||
// CHECK: static struct { // impl struct for case unknownDefault
|
||||
// CHECK-NEXT: constexpr operator cases() const {
|
||||
// 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: inline operator cases() const {
|
||||
// CHECK-NEXT: inline bool isUnknownDefault() const;
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-NEXT: 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;
|
||||
|
||||
@@ -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 <cassert>
|
||||
#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;
|
||||
}
|
||||
@@ -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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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;
|
||||
@@ -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: };
|
||||
@@ -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 <cassert>
|
||||
#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;
|
||||
}
|
||||
@@ -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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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: }
|
||||
@@ -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 <cassert>
|
||||
#include "enums.h"
|
||||
|
||||
using namespace Enums;
|
||||
|
||||
void switchTest(const E &e) {
|
||||
switch (e) {
|
||||
case E::x:
|
||||
assert(e.isX());
|
||||
assert(e.getX() == 3.14);
|
||||
break;
|
||||
case E::y:
|
||||
assert(e.isY());
|
||||
assert(e.getY() == nullptr);
|
||||
break;
|
||||
case E::z:
|
||||
assert(e.isZ());
|
||||
assert(e.getZ().getX() == 1234);
|
||||
break;
|
||||
case E::w:
|
||||
assert(e.isW());
|
||||
assert(e.getW() == 5678);
|
||||
break;
|
||||
case E::auto_:
|
||||
assert(e.isAuto_());
|
||||
assert(e.getAuto_() == reinterpret_cast<void *>(1));
|
||||
break;
|
||||
case E::foobar:
|
||||
assert(e.isFoobar());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
{
|
||||
auto e = E::x(3.14);
|
||||
switchTest(e);
|
||||
}
|
||||
|
||||
{
|
||||
auto e = E::y(nullptr);
|
||||
switchTest(e);
|
||||
}
|
||||
|
||||
{
|
||||
auto e = E::z(S::init(1234));
|
||||
switchTest(e);
|
||||
}
|
||||
|
||||
{
|
||||
auto e = E::w(5678);
|
||||
switchTest(e);
|
||||
}
|
||||
|
||||
{
|
||||
auto e = E::auto_(reinterpret_cast<void *>(1));
|
||||
switchTest(e);
|
||||
}
|
||||
|
||||
{
|
||||
auto e = E::foobar();
|
||||
switchTest(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
263
test/Interop/SwiftToCxx/enums/swift-enum-implementation.swift
Normal file
263
test/Interop/SwiftToCxx/enums/swift-enum-implementation.swift
Normal file
@@ -0,0 +1,263 @@
|
||||
// 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: 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: 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: 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: 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: 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: 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-EMPTY:
|
||||
// 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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<swift::_impl::EnumValueWitnessTable *>(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-NEXT: decltype(E::x) E::x;
|
||||
// CHECK-NEXT: decltype(E::y) E::y;
|
||||
// CHECK-NEXT: decltype(E::z) E::z;
|
||||
// CHECK-NEXT: decltype(E::w) E::w;
|
||||
// CHECK-NEXT: decltype(E::auto_) E::auto_;
|
||||
// CHECK-NEXT: decltype(E::foobar) E::foobar;
|
||||
// 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<swift::_impl::ValueWitnessTable **>(metadata._0) - 1;
|
||||
// CHECK-NEXT: #ifdef __arm64e__
|
||||
// CHECK-NEXT: auto *vwTable = reinterpret_cast<swift::_impl::ValueWitnessTable *>(ptrauth_auth_data(reinterpret_cast<void *>(*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<S>::type::initializeWithTake(result._getOpaquePointer(), swift::_impl::implClassFor<S>::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<S>::type::returnNewValue([&](char * _Nonnull result) {
|
||||
// CHECK-NEXT: swift::_impl::implClassFor<S>::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: }
|
||||
Reference in New Issue
Block a user