[Interop][SwiftToCxx] Support enum creation from Cxx

This commit is contained in:
Tongjie Wang
2022-08-29 19:55:16 -07:00
parent 095226f411
commit cbc23cbafc
15 changed files with 705 additions and 1198 deletions

View File

@@ -19,6 +19,8 @@
using namespace swift;
using namespace cxx_synthesis;
StringRef cxx_synthesis::getCxxSwiftNamespaceName() { return "swift"; }
StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; }
StringRef cxx_synthesis::getCxxOpaqueStorageClassName() {

View File

@@ -25,6 +25,9 @@ class NominalTypeDecl;
namespace cxx_synthesis {
/// Return the name of the namespace for things exported from Swift stdlib
StringRef getCxxSwiftNamespaceName();
/// Return the name of the implementation namespace that is used to hide
/// declarations from the namespace that corresponds to the imported Swift
/// module in C++.

View File

@@ -398,8 +398,20 @@ private:
ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS,
owningPrinter.typeMapping,
owningPrinter.interopContext);
valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
ClangSyntaxPrinter syntaxPrinter(os);
DeclAndTypeClangFunctionPrinter clangFuncPrinter(
os, owningPrinter.prologueOS, owningPrinter.typeMapping,
owningPrinter.interopContext, owningPrinter);
auto &outOfLineOS = owningPrinter.outOfLineDefinitionsOS;
ClangSyntaxPrinter outOfLineSyntaxPrinter(outOfLineOS);
DeclAndTypeClangFunctionPrinter outOfLineFuncPrinter(
owningPrinter.outOfLineDefinitionsOS, owningPrinter.prologueOS,
owningPrinter.typeMapping, owningPrinter.interopContext, owningPrinter);
ClangValueTypePrinter outOfLineValTyPrinter(
owningPrinter.outOfLineDefinitionsOS, owningPrinter.prologueOS,
owningPrinter.typeMapping, owningPrinter.interopContext);
auto elementTagMapping =
owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED);
// Sort cases based on their assigned tag indices
@@ -407,6 +419,240 @@ private:
return p1.second.tag < p2.second.tag;
});
auto printIsFunction = [&](StringRef caseName, EnumDecl *ED) {
std::string declName, defName, name;
llvm::raw_string_ostream declOS(declName), defOS(defName), nameOS(name);
ClangSyntaxPrinter(nameOS).printIdentifier(caseName);
name[0] = std::toupper(name[0]);
os << " inline bool is" << name << "() const;\n";
outOfLineOS << " inline bool ";
outOfLineSyntaxPrinter.printBaseName(ED);
outOfLineOS << "::is" << name << "() const {\n";
outOfLineOS << " return *this == ";
outOfLineSyntaxPrinter.printBaseName(ED);
outOfLineOS << "::";
outOfLineSyntaxPrinter.printIdentifier(caseName);
outOfLineOS << ";\n";
outOfLineOS << " }\n";
};
auto printGetFunction = [&](EnumElementDecl *elementDecl) {
auto associatedValueList = elementDecl->getParameterList();
// TODO: add tuple type support
if (!elementDecl->hasAssociatedValues() ||
associatedValueList->size() > 1) {
return;
}
auto paramType = associatedValueList->front()->getType();
Type objectType;
OptionalTypeKind optKind;
std::tie(objectType, optKind) = getObjectTypeAndOptionality(
paramType->getNominalOrBoundGenericNominal(), paramType);
auto objectTypeDecl = objectType->getNominalOrBoundGenericNominal();
std::string declName, defName, name;
llvm::raw_string_ostream declOS(declName), defOS(defName), nameOS(name);
ClangSyntaxPrinter(nameOS).printIdentifier(elementDecl->getNameStr());
name[0] = std::toupper(name[0]);
clangFuncPrinter.printCustomCxxFunction(
{paramType},
[&](auto &types) {
// Printing function name and return type
os << " inline " << types[paramType] << " get" << name;
outOfLineOS << " inline " << types[paramType] << ' ';
outOfLineSyntaxPrinter.printBaseName(ED);
outOfLineOS << "::get" << name;
},
[&](auto &types) {}, true,
[&](auto &types) {
// Printing function body
outOfLineOS << " if (!is" << name << "()) abort();\n";
outOfLineOS << " alignas(";
outOfLineSyntaxPrinter.printBaseName(elementDecl->getParentEnum());
outOfLineOS << ") unsigned char buffer[sizeof(";
outOfLineSyntaxPrinter.printBaseName(elementDecl->getParentEnum());
outOfLineOS << ")];\n";
outOfLineOS << " auto *thisCopy = new(buffer) ";
outOfLineSyntaxPrinter.printBaseName(elementDecl->getParentEnum());
outOfLineOS << "(*this);\n";
outOfLineOS << " char * _Nonnull payloadFromDestruction = "
"thisCopy->_destructiveProjectEnumData();\n";
if (auto knownCxxType =
owningPrinter.typeMapping.getKnownCxxTypeInfo(
objectTypeDecl)) {
outOfLineOS << " " << types[paramType] << " result;\n";
outOfLineOS << " "
"memcpy(&result, payloadFromDestruction, "
"sizeof(result));\n";
outOfLineOS << " return result;\n ";
} else {
outOfLineOS << " return swift::";
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName();
outOfLineOS << "::implClassFor<";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
elementDecl->getParentEnum()->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << ">::type";
outOfLineOS << "::returnNewValue([&](char * _Nonnull result) {\n";
outOfLineOS << " swift::"
<< cxx_synthesis::getCxxImplNamespaceName();
outOfLineOS << "::implClassFor<";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
elementDecl->getParentEnum()->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << ">::type";
outOfLineOS
<< "::initializeWithTake(result, payloadFromDestruction);\n";
outOfLineOS << " });\n ";
}
},
ED->getModuleContext(), outOfLineOS);
};
auto printStruct = [&](StringRef caseName, EnumElementDecl *elementDecl,
Optional<IRABIDetailsProvider::EnumElementInfo>
elementInfo) {
os << " static struct { // impl struct for case " << caseName << '\n';
os << " inline constexpr operator cases() const {\n";
os << " return cases::";
syntaxPrinter.printIdentifier(caseName);
os << ";\n";
os << " }\n";
if (elementDecl != nullptr) {
assert(elementInfo.hasValue());
Type paramType, objectType;
NominalTypeDecl *objectTypeDecl = nullptr;
OptionalTypeKind optKind;
// TODO: support tuple type
if (elementDecl->hasAssociatedValues() &&
elementDecl->getParameterList()->size() == 1) {
paramType = elementDecl->getParameterList()->front()->getType();
std::tie(objectType, optKind) = getObjectTypeAndOptionality(
paramType->getNominalOrBoundGenericNominal(), paramType);
objectTypeDecl = objectType->getNominalOrBoundGenericNominal();
}
SmallVector<Type> neededTypes;
if (paramType) {
neededTypes.push_back(paramType);
}
clangFuncPrinter.printCustomCxxFunction(
neededTypes,
[&](auto &types) {
// Printing function name and return type
os << " inline ";
syntaxPrinter.printBaseName(elementDecl->getParentEnum());
os << " operator()";
outOfLineOS << " inline ";
outOfLineSyntaxPrinter.printBaseName(
elementDecl->getParentEnum());
outOfLineOS << ' ';
outOfLineSyntaxPrinter.printBaseName(
elementDecl->getParentEnum());
outOfLineOS << "::_impl_" << elementDecl->getNameStr()
<< "::operator()";
},
[&](auto &types) {
// Printing parameters
if (!paramType) {
return;
}
assert(objectTypeDecl != nullptr);
if (owningPrinter.typeMapping.getKnownCxxTypeInfo(
objectTypeDecl)) {
os << types[paramType] << " val";
outOfLineOS << types[paramType] << " val";
} else {
os << "const " << types[paramType] << " &val";
outOfLineOS << "const " << types[paramType] << " &val";
}
},
true,
[&](auto &types) {
// Printing function body
outOfLineOS << " auto result = ";
outOfLineSyntaxPrinter.printBaseName(
elementDecl->getParentEnum());
outOfLineOS << "::_make();\n";
if (paramType) {
assert(objectTypeDecl != nullptr);
if (owningPrinter.typeMapping.getKnownCxxTypeInfo(
objectTypeDecl)) {
outOfLineOS << " memcpy(result._getOpaquePointer(), &val, "
"sizeof(val));\n";
} else {
outOfLineOS << " alignas(";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
ED->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << ") unsigned char buffer[sizeof(";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
ED->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << ")];\n";
outOfLineOS << " auto *valCopy = new(buffer) ";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
ED->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << "(val);\n";
outOfLineOS << " ";
outOfLineOS << cxx_synthesis::getCxxSwiftNamespaceName()
<< "::";
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName();
outOfLineOS << "::implClassFor<";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
ED->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << ">::type::initializeWithTake(result._"
"getOpaquePointer(), ";
outOfLineOS << cxx_synthesis::getCxxSwiftNamespaceName()
<< "::";
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName();
outOfLineOS << "::implClassFor<";
outOfLineSyntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
objectTypeDecl->getModuleContext(),
ED->getModuleContext());
outOfLineSyntaxPrinter.printBaseName(objectTypeDecl);
outOfLineOS << ">::type::getOpaquePointer(*valCopy)";
outOfLineOS << ");\n";
}
}
outOfLineOS << " result._destructiveInjectEnumTag(";
if (ED->isResilient()) {
outOfLineOS << cxx_synthesis::getCxxImplNamespaceName()
<< "::" << elementInfo->globalVariableName;
} else {
outOfLineOS << elementInfo->tag;
}
outOfLineOS << ");\n";
outOfLineOS << " return result;\n";
outOfLineOS << " ";
},
ED->getModuleContext(), outOfLineOS);
}
os << " } ";
syntaxPrinter.printIdentifier(caseName);
os << ";\n";
};
valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
os << '\n';
os << " enum class cases {";
llvm::interleave(
@@ -419,117 +665,14 @@ private:
// TODO: allow custom name for this special case
auto resilientUnknownDefaultCaseName = "unknownDefault";
if (ED->isResilient()) {
os << ",\n " << resilientUnknownDefaultCaseName;
os << (ED->getNumElements() > 0 ? ",\n " : "\n ")
<< resilientUnknownDefaultCaseName;
}
os << "\n };\n\n"; // enum class cases' closing bracket
// Printing struct, is, and get functions for each case
DeclAndTypeClangFunctionPrinter clangFuncPrinter(
os, owningPrinter.prologueOS, owningPrinter.typeMapping,
owningPrinter.interopContext, owningPrinter);
auto printIsFunction = [&](StringRef caseName, EnumDecl *ED) {
os << " inline bool is";
std::string name;
llvm::raw_string_ostream nameStream(name);
ClangSyntaxPrinter(nameStream).printIdentifier(caseName);
name[0] = std::toupper(name[0]);
os << name << "() const {\n";
os << " return *this == ";
syntaxPrinter.printBaseName(ED);
os << "::";
syntaxPrinter.printIdentifier(caseName);
os << ";\n";
os << " }\n";
};
auto printGetFunction = [&](EnumElementDecl *elementDecl) {
auto associatedValueList = elementDecl->getParameterList();
// TODO: add tuple type support
if (associatedValueList->size() > 1) {
return;
}
auto firstType = associatedValueList->front()->getType();
auto firstTypeDecl = firstType->getNominalOrBoundGenericNominal();
OptionalTypeKind optKind;
std::tie(firstType, optKind) =
getObjectTypeAndOptionality(firstTypeDecl, firstType);
auto name = elementDecl->getNameStr().str();
name[0] = std::toupper(name[0]);
// FIXME: may have to forward declare return type
os << " inline ";
clangFuncPrinter.printClangFunctionReturnType(
firstType, optKind, firstTypeDecl->getModuleContext(),
owningPrinter.outputLang);
os << " get" << name << "() const {\n";
os << " if (!is" << name << "()) abort();\n";
os << " alignas(";
syntaxPrinter.printBaseName(elementDecl->getParentEnum());
os << ") unsigned char buffer[sizeof(";
syntaxPrinter.printBaseName(elementDecl->getParentEnum());
os << ")];\n";
os << " auto *thisCopy = new(buffer) ";
syntaxPrinter.printBaseName(elementDecl->getParentEnum());
os << "(*this);\n";
os << " char * _Nonnull payloadFromDestruction = "
"thisCopy->_destructiveProjectEnumData();\n";
if (auto knownCxxType =
owningPrinter.typeMapping.getKnownCxxTypeInfo(firstTypeDecl)) {
os << " ";
clangFuncPrinter.printClangFunctionReturnType(
firstType, optKind, firstTypeDecl->getModuleContext(),
owningPrinter.outputLang);
os << " result;\n";
os << " "
"memcpy(&result, payloadFromDestruction, sizeof(result));\n";
os << " return result;\n";
} else {
os << " return ";
syntaxPrinter.printModuleNamespaceQualifiersIfNeeded(
firstTypeDecl->getModuleContext(),
elementDecl->getParentEnum()->getModuleContext());
os << cxx_synthesis::getCxxImplNamespaceName();
os << "::";
ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl);
os << "::returnNewValue([&](char * _Nonnull result) {\n";
os << " " << cxx_synthesis::getCxxImplNamespaceName();
os << "::";
ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl);
os << "::initializeWithTake(result, payloadFromDestruction);\n";
os << " });\n";
}
os << " }\n"; // closing bracket of get function
};
auto printStruct = [&](StringRef caseName, EnumElementDecl *elementDecl) {
os << " static struct { // impl struct for case " << caseName << '\n';
os << " inline constexpr operator cases() const {\n";
os << " return cases::";
syntaxPrinter.printIdentifier(caseName);
os << ";\n";
os << " }\n";
if (elementDecl != nullptr) {
os << " inline ";
syntaxPrinter.printBaseName(elementDecl->getParentEnum());
os << " operator()(";
// TODO: implement parameter for associated value
os << ") const {\n";
// TODO: print _make for now; need to print actual code making an enum
os << " return ";
syntaxPrinter.printBaseName(elementDecl->getParentEnum());
os << "::_make();\n";
os << " }\n";
}
os << " } ";
syntaxPrinter.printIdentifier(caseName);
os << ";\n";
};
for (const auto &pair : elementTagMapping) {
// Printing struct
printStruct(pair.first->getNameStr(), pair.first);
printStruct(pair.first->getNameStr(), pair.first, pair.second);
// Printing `is` function
printIsFunction(pair.first->getNameStr(), ED);
if (pair.first->hasAssociatedValues()) {
@@ -541,7 +684,8 @@ private:
if (ED->isResilient()) {
// Printing struct for unknownDefault
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr);
printStruct(resilientUnknownDefaultCaseName, /* elementDecl */ nullptr,
/* elementInfo */ None);
// Printing isUnknownDefault
printIsFunction(resilientUnknownDefaultCaseName, ED);
os << '\n';
@@ -551,7 +695,9 @@ private:
// Printing operator cases()
os << " inline operator cases() const {\n";
if (ED->isResilient()) {
if (!elementTagMapping.empty()) {
os << " auto tag = _getEnumTag();\n";
}
for (const auto &pair : elementTagMapping) {
os << " if (tag == " << cxx_synthesis::getCxxImplNamespaceName();
os << "::" << pair.second.globalVariableName << ") return cases::";

View File

@@ -504,6 +504,10 @@ public:
if (addImport(ED))
return true;
if (outputLangMode == OutputLanguageMode::Cxx) {
forwardDeclareMemberTypes(ED->getMembers(), ED);
}
if (seenTypes[ED].first == EmissionState::Defined)
return true;

View File

@@ -824,3 +824,44 @@ bool DeclAndTypeClangFunctionPrinter::hasKnownOptionalNullableCxxMapping(
}
return false;
}
void DeclAndTypeClangFunctionPrinter::printCustomCxxFunction(
const SmallVector<Type> &neededTypes, PrinterTy retTypeAndNamePrinter,
PrinterTy paramPrinter, bool isConstFunc, PrinterTy bodyPrinter,
ModuleDecl *emittedModule, raw_ostream &outOfLineOS) {
llvm::MapVector<Type, std::string> types;
for (auto &type : neededTypes) {
std::string typeStr;
llvm::raw_string_ostream typeOS(typeStr);
OptionalTypeKind optKind;
Type objectType;
std::tie(objectType, optKind) =
DeclAndTypePrinter::getObjectTypeAndOptionality(
type->getNominalOrBoundGenericNominal(), type);
// Use FunctionSignatureTypeUse::ReturnType to avoid printing extra const or
// references
CFunctionSignatureTypePrinter typePrinter(
typeOS, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
interopContext, CFunctionSignatureTypePrinterModifierDelegate(),
emittedModule, declPrinter, FunctionSignatureTypeUse::ReturnType);
typePrinter.visit(objectType, optKind, /* isInOutParam */ false);
types.insert({type, typeStr});
}
retTypeAndNamePrinter(types);
os << '(';
outOfLineOS << '(';
paramPrinter(types);
os << ')';
outOfLineOS << ')';
if (isConstFunc) {
os << " const;\n";
outOfLineOS << " const";
}
outOfLineOS << " {\n";
bodyPrinter(types);
outOfLineOS << "}\n";
}

View File

@@ -19,6 +19,7 @@
#include "swift/Basic/LLVM.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
@@ -140,6 +141,16 @@ public:
ModuleDecl *moduleContext,
OutputLanguageMode outputLang);
using PrinterTy =
llvm::function_ref<void(llvm::MapVector<Type, std::string> &)>;
/// Print generated C++ helper function
void printCustomCxxFunction(const SmallVector<Type> &neededTypes,
PrinterTy retTypeAndNamePrinter,
PrinterTy paramPrinter, bool isConstFunc,
PrinterTy bodyPrinter, ModuleDecl *emittedModule,
raw_ostream &outOfLineOS);
private:
void printCxxToCFunctionParameterUse(
Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,

View File

@@ -270,11 +270,23 @@ void ClangValueTypePrinter::printValueTypeDecl(
"metadata._0);\n";
os << " return _getOpaquePointer();\n";
os << " }\n";
os << " inline void _destructiveInjectEnumTag(unsigned tag) {\n";
printEnumVWTableVariable();
os << " enumVWTable->destructiveInjectEnumTag(_getOpaquePointer(), tag, "
"metadata._0);\n";
os << " }\n";
os << " inline unsigned _getEnumTag() const {\n";
printEnumVWTableVariable();
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
"metadata._0);\n";
os << " }\n";
for (const auto &pair : interopContext.getIrABIDetails().getEnumTagMapping(
cast<EnumDecl>(typeDecl))) {
os << " using _impl_" << pair.first->getNameStr() << " = decltype(";
ClangSyntaxPrinter(os).printIdentifier(pair.first->getNameStr());
os << ");\n";
}
}
// Print out the storage for the value type.
os << " ";

View File

@@ -32,6 +32,30 @@ public func printFoo(_ x: Foo) {
print(x)
}
public enum Empty {
}
// CHECK: // Tags for resilient enum Empty
// CHECK-NEXT: extern "C" {
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace _impl
// CHECK-EMPTY:
// CHECK-NEXT: class Empty final {
// CHECK: enum class cases {
// CHECK-NEXT: unknownDefault
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: static struct { // impl struct for case unknownDefault
// CHECK-NEXT: inline constexpr operator cases() const {
// CHECK-NEXT: return cases::unknownDefault;
// CHECK-NEXT: }
// CHECK-NEXT: } unknownDefault;
// CHECK-NEXT: inline bool isUnknownDefault() const;
// CHECK: inline operator cases() const {
// CHECK-NEXT: return cases::unknownDefault;
// CHECK-NEXT: }
// CHECK: // Tags for resilient enum Foo
// CHECK-NEXT: extern "C" {
// CHECK-NEXT: extern unsigned $s5Enums3FooO1ayACSdcACmFWC;
@@ -48,14 +72,14 @@ public func printFoo(_ x: Foo) {
// CHECK-NEXT: unknownDefault
// CHECK-NEXT: }
// CHECK: static struct { // impl struct for case unknownDefault
// CHECK-NEXT: constexpr operator cases() const {
// CHECK-NEXT: inline constexpr operator cases() const {
// CHECK-NEXT: return cases::unknownDefault;
// CHECK-NEXT: }
// CHECK-NEXT: } unknownDefault;
// CHECK-NEXT: inline bool isUnknownDefault() const {
// CHECK-NEXT: return *this == Foo::unknownDefault;
// CHECK-NEXT: }
// CHECK: inline operator cases() const {
// CHECK-NEXT: inline bool isUnknownDefault() const;
// CHECK-EMPTY:
// CHECK-EMPTY:
// CHECK-NEXT: inline operator cases() const {
// CHECK-NEXT: auto tag = _getEnumTag();
// CHECK-NEXT: if (tag == _impl::$s5Enums3FooO1ayACSdcACmFWC) return cases::a;
// NEW_CASE-NEXT: if (tag == _impl::$s5Enums3FooO1byACSicACmFWC) return cases::b;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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: };

View File

@@ -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;
}

View File

@@ -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: }

View File

@@ -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;
}

View 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: }