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 swift;
|
||||||
using namespace cxx_synthesis;
|
using namespace cxx_synthesis;
|
||||||
|
|
||||||
|
StringRef cxx_synthesis::getCxxSwiftNamespaceName() { return "swift"; }
|
||||||
|
|
||||||
StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; }
|
StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; }
|
||||||
|
|
||||||
StringRef cxx_synthesis::getCxxOpaqueStorageClassName() {
|
StringRef cxx_synthesis::getCxxOpaqueStorageClassName() {
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ class NominalTypeDecl;
|
|||||||
|
|
||||||
namespace cxx_synthesis {
|
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
|
/// Return the name of the implementation namespace that is used to hide
|
||||||
/// declarations from the namespace that corresponds to the imported Swift
|
/// declarations from the namespace that corresponds to the imported Swift
|
||||||
/// module in C++.
|
/// module in C++.
|
||||||
|
|||||||
@@ -398,15 +398,261 @@ private:
|
|||||||
ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS,
|
ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS,
|
||||||
owningPrinter.typeMapping,
|
owningPrinter.typeMapping,
|
||||||
owningPrinter.interopContext);
|
owningPrinter.interopContext);
|
||||||
valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
|
ClangSyntaxPrinter syntaxPrinter(os);
|
||||||
ClangSyntaxPrinter syntaxPrinter(os);
|
DeclAndTypeClangFunctionPrinter clangFuncPrinter(
|
||||||
auto elementTagMapping =
|
os, owningPrinter.prologueOS, owningPrinter.typeMapping,
|
||||||
owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED);
|
owningPrinter.interopContext, owningPrinter);
|
||||||
// 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 &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 << '\n';
|
||||||
os << " enum class cases {";
|
os << " enum class cases {";
|
||||||
llvm::interleave(
|
llvm::interleave(
|
||||||
@@ -419,117 +665,14 @@ private:
|
|||||||
// TODO: allow custom name for this special case
|
// TODO: allow custom name for this special case
|
||||||
auto resilientUnknownDefaultCaseName = "unknownDefault";
|
auto resilientUnknownDefaultCaseName = "unknownDefault";
|
||||||
if (ED->isResilient()) {
|
if (ED->isResilient()) {
|
||||||
os << ",\n " << resilientUnknownDefaultCaseName;
|
os << (ED->getNumElements() > 0 ? ",\n " : "\n ")
|
||||||
|
<< resilientUnknownDefaultCaseName;
|
||||||
}
|
}
|
||||||
os << "\n };\n\n"; // enum class cases' closing bracket
|
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) {
|
for (const auto &pair : elementTagMapping) {
|
||||||
// Printing struct
|
// Printing struct
|
||||||
printStruct(pair.first->getNameStr(), pair.first);
|
printStruct(pair.first->getNameStr(), pair.first, pair.second);
|
||||||
// Printing `is` function
|
// Printing `is` function
|
||||||
printIsFunction(pair.first->getNameStr(), ED);
|
printIsFunction(pair.first->getNameStr(), ED);
|
||||||
if (pair.first->hasAssociatedValues()) {
|
if (pair.first->hasAssociatedValues()) {
|
||||||
@@ -541,7 +684,8 @@ private:
|
|||||||
|
|
||||||
if (ED->isResilient()) {
|
if (ED->isResilient()) {
|
||||||
// Printing struct for unknownDefault
|
// Printing struct for unknownDefault
|
||||||
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr);
|
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr,
|
||||||
|
/* elementInfo */ None);
|
||||||
// Printing isUnknownDefault
|
// Printing isUnknownDefault
|
||||||
printIsFunction(resilientUnknownDefaultCaseName, ED);
|
printIsFunction(resilientUnknownDefaultCaseName, ED);
|
||||||
os << '\n';
|
os << '\n';
|
||||||
@@ -551,7 +695,9 @@ private:
|
|||||||
// Printing operator cases()
|
// Printing operator cases()
|
||||||
os << " inline operator cases() const {\n";
|
os << " inline operator cases() const {\n";
|
||||||
if (ED->isResilient()) {
|
if (ED->isResilient()) {
|
||||||
os << " auto tag = _getEnumTag();\n";
|
if (!elementTagMapping.empty()) {
|
||||||
|
os << " auto tag = _getEnumTag();\n";
|
||||||
|
}
|
||||||
for (const auto &pair : elementTagMapping) {
|
for (const auto &pair : elementTagMapping) {
|
||||||
os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName();
|
os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName();
|
||||||
os << "::" << pair.second.globalVariableName << ") return cases::";
|
os << "::" << pair.second.globalVariableName << ") return cases::";
|
||||||
|
|||||||
@@ -503,7 +503,11 @@ public:
|
|||||||
bool writeEnum(const EnumDecl *ED) {
|
bool writeEnum(const EnumDecl *ED) {
|
||||||
if (addImport(ED))
|
if (addImport(ED))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (outputLangMode == OutputLanguageMode::Cxx) {
|
||||||
|
forwardDeclareMemberTypes(ED->getMembers(), ED);
|
||||||
|
}
|
||||||
|
|
||||||
if (seenTypes[ED].first == EmissionState::Defined)
|
if (seenTypes[ED].first == EmissionState::Defined)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
@@ -824,3 +824,44 @@ bool DeclAndTypeClangFunctionPrinter::hasKnownOptionalNullableCxxMapping(
|
|||||||
}
|
}
|
||||||
return false;
|
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/Basic/LLVM.h"
|
||||||
#include "swift/ClangImporter/ClangImporter.h"
|
#include "swift/ClangImporter/ClangImporter.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
|
#include "llvm/ADT/MapVector.h"
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
@@ -140,6 +141,16 @@ public:
|
|||||||
ModuleDecl *moduleContext,
|
ModuleDecl *moduleContext,
|
||||||
OutputLanguageMode outputLang);
|
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:
|
private:
|
||||||
void printCxxToCFunctionParameterUse(
|
void printCxxToCFunctionParameterUse(
|
||||||
Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,
|
Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,
|
||||||
|
|||||||
@@ -270,11 +270,23 @@ void ClangValueTypePrinter::printValueTypeDecl(
|
|||||||
"metadata._0);\n";
|
"metadata._0);\n";
|
||||||
os << " return _getOpaquePointer();\n";
|
os << " return _getOpaquePointer();\n";
|
||||||
os << " }\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";
|
os << " inline unsigned _getEnumTag() const {\n";
|
||||||
printEnumVWTableVariable();
|
printEnumVWTableVariable();
|
||||||
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
|
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
|
||||||
"metadata._0);\n";
|
"metadata._0);\n";
|
||||||
os << " }\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.
|
// Print out the storage for the value type.
|
||||||
os << " ";
|
os << " ";
|
||||||
|
|||||||
@@ -32,6 +32,30 @@ public func printFoo(_ x: Foo) {
|
|||||||
print(x)
|
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: // Tags for resilient enum Foo
|
||||||
// CHECK-NEXT: extern "C" {
|
// CHECK-NEXT: extern "C" {
|
||||||
// CHECK-NEXT: extern unsigned $s5Enums3FooO1ayACSdcACmFWC;
|
// CHECK-NEXT: extern unsigned $s5Enums3FooO1ayACSdcACmFWC;
|
||||||
@@ -48,14 +72,14 @@ public func printFoo(_ x: Foo) {
|
|||||||
// CHECK-NEXT: unknownDefault
|
// CHECK-NEXT: unknownDefault
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK: static struct { // impl struct for case unknownDefault
|
// 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: return cases::unknownDefault;
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-NEXT: } unknownDefault;
|
// CHECK-NEXT: } unknownDefault;
|
||||||
// CHECK-NEXT: inline bool isUnknownDefault() const {
|
// CHECK-NEXT: inline bool isUnknownDefault() const;
|
||||||
// CHECK-NEXT: return *this == Foo::unknownDefault;
|
// CHECK-EMPTY:
|
||||||
// CHECK-NEXT: }
|
// CHECK-EMPTY:
|
||||||
// CHECK: inline operator cases() const {
|
// CHECK-NEXT: inline operator cases() const {
|
||||||
// CHECK-NEXT: auto tag = _getEnumTag();
|
// CHECK-NEXT: auto tag = _getEnumTag();
|
||||||
// CHECK-NEXT: if (tag == _impl::$s5Enums3FooO1ayACSdcACmFWC) return cases::a;
|
// CHECK-NEXT: if (tag == _impl::$s5Enums3FooO1ayACSdcACmFWC) return cases::a;
|
||||||
// NEW_CASE-NEXT: if (tag == _impl::$s5Enums3FooO1byACSicACmFWC) return cases::b;
|
// 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