[interop][SwiftToCxx] pass / return Swift struct values between C/C++ and Swift

This commit is contained in:
Alex Lorenz
2022-06-08 07:00:47 -07:00
parent 1c76e22c84
commit 132729906c
25 changed files with 1360 additions and 54 deletions

View File

@@ -13,13 +13,17 @@
#ifndef SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
#define SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
#include "swift/AST/Type.h"
#include "clang/AST/CharUnits.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdint>
#include <memory>
#include <utility>
namespace swift {
class ASTContext;
class IRGenOptions;
class ModuleDecl;
class NominalTypeDecl;
@@ -45,6 +49,24 @@ public:
llvm::Optional<SizeAndAlignment>
getTypeSizeAlignment(const NominalTypeDecl *TD);
/// Returns true if the given type should be passed indirectly into a swiftcc
/// function.
bool shouldPassIndirectly(Type t);
/// Returns true if the given type should be returned indirectly from a
/// swiftcc function.
bool shouldReturnIndirectly(Type t);
/// Enumerates all of the members of the underlying record in terms of their
/// primitive types that needs to be stored in a Clang/LLVM record when this
/// type is passed or returned directly to/from swiftcc function.
///
/// Returns true if an error occurred when a particular member can't be
/// represented with an AST type.
bool enumerateDirectPassingRecordMembers(
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
callback);
private:
std::unique_ptr<IRABIDetailsProviderImpl> impl;
};

View File

@@ -15,15 +15,45 @@
#include "GenType.h"
#include "IRGen.h"
#include "IRGenModule.h"
#include "NativeConventionSchema.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/Types.h"
#include "swift/SIL/SILModule.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/CodeGen/SwiftCallingConv.h"
#include "llvm/IR/DerivedTypes.h"
using namespace swift;
using namespace irgen;
static Optional<Type> getPrimitiveTypeFromLLVMType(ASTContext &ctx,
const llvm::Type *type) {
if (const auto *intType = dyn_cast<llvm::IntegerType>(type)) {
switch (intType->getBitWidth()) {
case 8:
return ctx.getUInt8Type();
case 16:
return ctx.getUInt16Type();
case 32:
return ctx.getUInt32Type();
case 64:
return ctx.getUInt64Type();
default:
return None;
}
} else if (type->isFloatTy()) {
return ctx.getFloatType();
} else if (type->isDoubleTy()) {
return ctx.getDoubleType();
} else if (type->isPointerTy()) {
return ctx.getOpaquePointerType();
}
// FIXME: Handle vector type.
return None;
}
namespace swift {
class IRABIDetailsProviderImpl {
@@ -44,6 +74,39 @@ public:
fixedTI->getFixedAlignment().getValue()};
}
bool shouldPassIndirectly(Type type) {
auto *TI = &IGM.getTypeInfoForUnlowered(type);
NativeConventionSchema schema(IGM, TI, /*isResult=*/false);
return schema.requiresIndirect();
}
bool shouldReturnIndirectly(Type type) {
if (type->isVoid())
return false;
auto *TI = &IGM.getTypeInfoForUnlowered(type);
NativeConventionSchema schema(IGM, TI, /*isResult=*/true);
return schema.requiresIndirect();
}
bool enumerateDirectPassingRecordMembers(
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
callback) {
auto *TI = &IGM.getTypeInfoForUnlowered(t);
NativeConventionSchema schema(IGM, TI, /*isResult=*/false);
bool hasError = false;
schema.enumerateComponents(
[&](clang::CharUnits offset, clang::CharUnits end, llvm::Type *type) {
auto primitiveType = getPrimitiveTypeFromLLVMType(
IGM.getSwiftModule()->getASTContext(), type);
if (!primitiveType) {
hasError = true;
return;
}
callback(offset, end, *primitiveType);
});
return hasError;
}
private:
Lowering::TypeConverter typeConverter;
// Default silOptions are sufficient, as we don't need to generated SIL.
@@ -65,3 +128,17 @@ llvm::Optional<IRABIDetailsProvider::SizeAndAlignment>
IRABIDetailsProvider::getTypeSizeAlignment(const NominalTypeDecl *TD) {
return impl->getTypeSizeAlignment(TD);
}
bool IRABIDetailsProvider::shouldPassIndirectly(Type t) {
return impl->shouldPassIndirectly(t);
}
bool IRABIDetailsProvider::shouldReturnIndirectly(Type t) {
return impl->shouldReturnIndirectly(t);
}
bool IRABIDetailsProvider::enumerateDirectPassingRecordMembers(
Type t, llvm::function_ref<void(clang::CharUnits, clang::CharUnits, Type)>
callback) {
return impl->enumerateDirectPassingRecordMembers(t, callback);
}

View File

@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSyntaxPrinter.h"
#include "swift/AST/Module.h"
using namespace swift;
using namespace cxx_synthesis;
@@ -43,6 +44,10 @@ void ClangSyntaxPrinter::printIdentifier(StringRef name) {
os << '_';
}
void ClangSyntaxPrinter::printModuleNameCPrefix(const ModuleDecl &mod) {
os << mod.getName().str() << '_';
}
/// Print a C++ namespace declaration with the give name and body.
void ClangSyntaxPrinter::printNamespace(
llvm::function_ref<void(raw_ostream &OS)> namePrinter,

View File

@@ -20,6 +20,8 @@
namespace swift {
class ModuleDecl;
namespace cxx_synthesis {
/// Return the name of the implementation namespace that is used to hide
@@ -37,6 +39,10 @@ public:
/// trailing underscore.
void printIdentifier(StringRef name);
/// Print the C-style prefix for the given module name, that's used for
/// C type names inside the module.
void printModuleNameCPrefix(const ModuleDecl &mod);
/// Print a C++ namespace declaration with the give name and body.
void
printNamespace(llvm::function_ref<void(raw_ostream &OS)> namePrinter,

View File

@@ -332,7 +332,9 @@ private:
if (outputLang != OutputLanguageMode::Cxx)
return;
// FIXME: Print struct's availability.
ClangValueTypePrinter printer(os, owningPrinter.interopContext);
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
owningPrinter.typeMapping,
owningPrinter.interopContext);
printer.printStructDecl(SD);
}
@@ -834,7 +836,9 @@ private:
os << "SWIFT_EXTERN ";
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.prologueOS,
owningPrinter.typeMapping,
owningPrinter.interopContext);
funcPrinter.printFunctionSignature(
FD, funcABI.getSymbolName(), resultTy,
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CFunctionProto);
@@ -873,7 +877,9 @@ private:
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
os << "inline ";
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.prologueOS,
owningPrinter.typeMapping,
owningPrinter.interopContext);
funcPrinter.printFunctionSignature(
FD, FD->getName().getBaseIdentifier().get(), resultTy,
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CxxInlineThunk);
@@ -882,27 +888,8 @@ private:
printFunctionClangAttributes(FD, funcTy);
printAvailability(FD);
os << " {\n";
os << " return " << cxx_synthesis::getCxxImplNamespaceName()
<< "::" << funcABI.getSymbolName() << '(';
auto params = FD->getParameters();
if (params->size()) {
size_t index = 1;
interleaveComma(*params, os, [&](const ParamDecl *param) {
if (param->isInOut()) {
os << "&";
}
if (param->hasName()) {
ClangSyntaxPrinter(os).printIdentifier(param->getName().str());
} else {
os << "_" << index;
}
++index;
});
}
os << ");\n";
funcPrinter.printCxxThunkBody(funcABI.getSymbolName(), resultTy,
FD->getParameters());
os << "}\n";
}
@@ -1112,8 +1099,11 @@ private:
if (outputLang == OutputLanguageMode::Cxx) {
// Emit the underlying C signature that matches the Swift ABI
// in the generated C++ implementation prologue for the module.
auto funcABI = getModuleProloguePrinter()
std::string cFuncDecl;
llvm::raw_string_ostream cFuncPrologueOS(cFuncDecl);
auto funcABI = Implementation(cFuncPrologueOS, owningPrinter, outputLang)
.printSwiftABIFunctionSignatureAsCxxFunction(FD);
owningPrinter.prologueOS << cFuncPrologueOS.str();
printAbstractFunctionAsCxxFunctionThunk(FD, funcABI);
return;
}

View File

@@ -265,6 +265,9 @@ public:
forwardDeclare(ED);
} else if (isa<AbstractTypeParamDecl>(TD)) {
llvm_unreachable("should not see type params here");
} else if (isa<StructDecl>(TD)) {
// FIXME: add support here.
return;
} else {
assert(false && "unknown local type decl");
}
@@ -668,6 +671,7 @@ void swift::printModuleContentsAsCxx(
M.ValueDecl::getName().print(os);
os << " {\n";
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << " {\n";
os << "extern \"C\" {\n";
os << "#endif\n\n";
os << prologueOS.str();
@@ -675,6 +679,7 @@ void swift::printModuleContentsAsCxx(
os << "\n#ifdef __cplusplus\n";
os << "}\n";
os << "}\n";
os << "}\n";
}
// Construct a C++ namespace for the module.

View File

@@ -89,12 +89,14 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
[&] {
out << "#include <cstdint>\n"
"#include <cstddef>\n"
"#include <cstdbool>\n";
"#include <cstdbool>\n"
"#include <cstring>\n";
},
[&] {
out << "#include <stdint.h>\n"
"#include <stddef.h>\n"
"#include <stdbool.h>\n";
"#include <stdbool.h>\n"
"#include <string.h>\n";
});
out << "\n"
"#if !defined(SWIFT_TYPEDEFS)\n"
@@ -301,6 +303,7 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
out << "#endif\n";
};
emitMacro("SWIFT_CALL", "__attribute__((swiftcall))");
emitMacro("SWIFT_INDIRECT_RESULT", "__attribute__((swift_indirect_result))");
// SWIFT_NOEXCEPT applies 'noexcept' in C++ mode only.
emitCxxConditional(
out, [&] { emitMacro("SWIFT_NOEXCEPT", "noexcept"); },

View File

@@ -15,17 +15,42 @@
#include "DeclAndTypePrinter.h"
#include "OutputLanguageMode.h"
#include "PrimitiveTypeMapping.h"
#include "PrintClangValueType.h"
#include "SwiftToClangInteropContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeVisitor.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/IRGen/IRABIDetailsProvider.h"
#include "llvm/ADT/STLExtras.h"
using namespace swift;
namespace {
enum class FunctionSignatureTypeUse { ParamType, ReturnType };
Optional<PrimitiveTypeMapping::ClangTypeInfo>
getKnownTypeInfo(const TypeDecl *typeDecl, PrimitiveTypeMapping &typeMapping,
OutputLanguageMode languageMode) {
return languageMode == OutputLanguageMode::Cxx
? typeMapping.getKnownCxxTypeInfo(typeDecl)
: typeMapping.getKnownCTypeInfo(typeDecl);
}
bool isKnownCxxType(Type t, PrimitiveTypeMapping &typeMapping) {
const TypeDecl *typeDecl;
if (auto *typeAliasType = dyn_cast<TypeAliasType>(t.getPointer()))
typeDecl = typeAliasType->getDecl();
else if (auto *structDecl = t->getStructOrBoundGenericStruct())
typeDecl = structDecl;
else
return false;
return getKnownTypeInfo(typeDecl, typeMapping, OutputLanguageMode::Cxx) !=
None;
}
// Prints types in the C function signature that corresponds to the
// native Swift function/method.
class CFunctionSignatureTypePrinter
@@ -33,17 +58,19 @@ class CFunctionSignatureTypePrinter
Optional<OptionalTypeKind>>,
private ClangSyntaxPrinter {
public:
CFunctionSignatureTypePrinter(raw_ostream &os,
CFunctionSignatureTypePrinter(raw_ostream &os, raw_ostream &cPrologueOS,
PrimitiveTypeMapping &typeMapping,
OutputLanguageMode languageMode)
: ClangSyntaxPrinter(os), typeMapping(typeMapping),
languageMode(languageMode) {}
OutputLanguageMode languageMode,
SwiftToClangInteropContext &interopContext,
FunctionSignatureTypeUse typeUseKind =
FunctionSignatureTypeUse::ParamType)
: ClangSyntaxPrinter(os), cPrologueOS(cPrologueOS),
typeMapping(typeMapping), interopContext(interopContext),
languageMode(languageMode), typeUseKind(typeUseKind) {}
bool printIfKnownSimpleType(const TypeDecl *typeDecl,
Optional<OptionalTypeKind> optionalKind) {
auto knownTypeInfo = languageMode == OutputLanguageMode::Cxx
? typeMapping.getKnownCxxTypeInfo(typeDecl)
: typeMapping.getKnownCTypeInfo(typeDecl);
auto knownTypeInfo = getKnownTypeInfo(typeDecl, typeMapping, languageMode);
if (!knownTypeInfo)
return false;
os << knownTypeInfo->name;
@@ -81,7 +108,19 @@ public:
// Handle known type names.
if (printIfKnownSimpleType(SD, optionalKind))
return;
// FIXME: Handle struct types.
// FIXME: Handle optional structures.
if (typeUseKind == FunctionSignatureTypeUse::ParamType) {
if (languageMode != OutputLanguageMode::Cxx &&
interopContext.getIrABIDetails().shouldPassIndirectly(ST)) {
// FIXME: it would be nice to print out the C struct type here.
os << "const void * _Nonnull";
} else {
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
.printValueTypeParameterType(SD, languageMode);
}
} else
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
.printValueTypeReturnType(SD, languageMode);
}
void visitPart(Type Ty, Optional<OptionalTypeKind> optionalKind) {
@@ -89,8 +128,11 @@ public:
}
private:
raw_ostream &cPrologueOS;
PrimitiveTypeMapping &typeMapping;
SwiftToClangInteropContext &interopContext;
OutputLanguageMode languageMode;
FunctionSignatureTypeUse typeUseKind;
};
} // end namespace
@@ -105,7 +147,8 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
StringRef name, bool isInOutParam) {
// FIXME: add support for noescape and PrintMultiPartType,
// see DeclAndTypePrinter::print.
CFunctionSignatureTypePrinter typePrinter(os, typeMapping, outputLang);
CFunctionSignatureTypePrinter typePrinter(os, cPrologueOS, typeMapping,
outputLang, interopContext);
typePrinter.visit(ty, optionalKind);
if (isInOutParam) {
@@ -119,18 +162,37 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
};
// Print out the return type.
OptionalTypeKind retKind;
Type objTy;
std::tie(objTy, retKind) =
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
CFunctionSignatureTypePrinter typePrinter(os, typeMapping, outputLang);
typePrinter.visit(objTy, retKind);
bool isIndirectReturnType =
kind == FunctionSignatureKind::CFunctionProto &&
interopContext.getIrABIDetails().shouldReturnIndirectly(resultTy);
if (!isIndirectReturnType) {
OptionalTypeKind retKind;
Type objTy;
std::tie(objTy, retKind) =
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
CFunctionSignatureTypePrinter typePrinter(
os, cPrologueOS, typeMapping, outputLang, interopContext,
FunctionSignatureTypeUse::ReturnType);
typePrinter.visit(objTy, retKind);
} else {
os << "void";
}
os << ' ' << name << '(';
bool HasParams = false;
// Indirect result is passed in as the first parameter.
if (isIndirectReturnType) {
assert(kind == FunctionSignatureKind::CFunctionProto);
HasParams = true;
// FIXME: it would be nice to print out the C struct type here.
os << "SWIFT_INDIRECT_RESULT void * _Nonnull";
}
// Print out the parameter types.
auto params = FD->getParameters();
if (params->size()) {
if (HasParams)
os << ", ";
size_t paramIndex = 1;
llvm::interleaveComma(*params, os, [&](const ParamDecl *param) {
OptionalTypeKind argKind;
@@ -149,9 +211,89 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
print(objTy, argKind, paramName, param->isInOut());
++paramIndex;
});
} else if (kind == FunctionSignatureKind::CFunctionProto) {
} else if (kind == FunctionSignatureKind::CFunctionProto && !HasParams) {
// Emit 'void' in an empty parameter list for C function declarations.
os << "void";
}
os << ')';
}
void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
const ParamDecl *param, StringRef name) {
auto namePrinter = [&]() { ClangSyntaxPrinter(os).printIdentifier(name); };
auto type = param->getType();
if (!isKnownCxxType(type, typeMapping)) {
if (auto *structDecl = type->getStructOrBoundGenericStruct()) {
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
.printParameterCxxToCUseScaffold(
interopContext.getIrABIDetails().shouldPassIndirectly(type),
structDecl, namePrinter);
return;
}
}
// Primitive types are passed directly without any conversions.
namePrinter();
}
void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
StringRef swiftSymbolName, Type resultTy, ParameterList *params) {
auto printCallToCFunc = [&](Optional<StringRef> additionalParam) {
os << cxx_synthesis::getCxxImplNamespaceName() << "::" << swiftSymbolName
<< '(';
bool hasParams = false;
if (additionalParam) {
hasParams = true;
os << *additionalParam;
}
if (params->size()) {
if (hasParams)
os << ", ";
size_t index = 1;
interleaveComma(*params, os, [&](const ParamDecl *param) {
if (param->isInOut()) {
os << "&";
}
if (param->hasName()) {
printCxxToCFunctionParameterUse(param, param->getName().str());
} else {
std::string paramName;
llvm::raw_string_ostream paramOS(paramName);
paramOS << "_" << index;
printCxxToCFunctionParameterUse(param, paramOS.str());
}
++index;
});
}
os << ')';
};
// Values types are returned either direcly in their C representation, or
// indirectly by a pointer.
if (!isKnownCxxType(resultTy, typeMapping)) {
if (auto *structDecl = resultTy->getStructOrBoundGenericStruct()) {
bool isIndirect =
interopContext.getIrABIDetails().shouldReturnIndirectly(resultTy);
ClangValueTypePrinter valueTypePrinter(os, cPrologueOS, typeMapping,
interopContext);
if (isIndirect) {
valueTypePrinter.printValueTypeIndirectReturnScaffold(
structDecl, [&](StringRef returnParam) {
printCallToCFunc(/*additionalParam=*/returnParam);
});
} else {
valueTypePrinter.printValueTypeDirectReturnScaffold(
structDecl, [&]() { printCallToCFunc(/*additionalParam=*/None); });
}
return;
}
}
// Primitive values are returned directly without any conversions.
os << " return ";
printCallToCFunc(/*additionalParam=*/None);
os << ";\n";
}

View File

@@ -21,15 +21,20 @@
namespace swift {
class FuncDecl;
class ParamDecl;
class ParameterList;
class PrimitiveTypeMapping;
class SwiftToClangInteropContext;
/// Responsible for printing a Swift function decl or type in C or C++ mode, to
/// be included in a Swift module's generated clang header.
class DeclAndTypeClangFunctionPrinter {
public:
DeclAndTypeClangFunctionPrinter(raw_ostream &os,
PrimitiveTypeMapping &typeMapping)
: os(os), typeMapping(typeMapping) {}
DeclAndTypeClangFunctionPrinter(raw_ostream &os, raw_ostream &cPrologueOS,
PrimitiveTypeMapping &typeMapping,
SwiftToClangInteropContext &interopContext)
: os(os), cPrologueOS(cPrologueOS), typeMapping(typeMapping),
interopContext(interopContext) {}
/// What kind of function signature should be emitted for the given Swift
/// function.
@@ -45,9 +50,20 @@ public:
void printFunctionSignature(FuncDecl *FD, StringRef name, Type resultTy,
FunctionSignatureKind kind);
/// Print the use of the C++ function thunk parameter as it's passed to the C
/// function declaration.
void printCxxToCFunctionParameterUse(const ParamDecl *param, StringRef name);
/// Print the body of the inline C++ function thunk that calls the underlying
/// Swift function.
void printCxxThunkBody(StringRef swiftSymbolName, Type resultTy,
ParameterList *params);
private:
raw_ostream &os;
raw_ostream &cPrologueOS;
PrimitiveTypeMapping &typeMapping;
SwiftToClangInteropContext &interopContext;
};
} // end namespace swift

View File

@@ -13,6 +13,7 @@
#include "PrintClangValueType.h"
#include "ClangSyntaxPrinter.h"
#include "OutputLanguageMode.h"
#include "PrimitiveTypeMapping.h"
#include "SwiftToClangInteropContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ParameterList.h"
@@ -24,6 +25,32 @@
using namespace swift;
/// Print out the C type name of a struct/enum declaration.
static void printCTypeName(raw_ostream &os, const NominalTypeDecl *type) {
ClangSyntaxPrinter printer(os);
printer.printModuleNameCPrefix(*type->getParentModule());
// FIXME: add nested type qualifiers to fully disambiguate the name.
printer.printIdentifier(type->getName().str());
}
/// Print out the C++ type name of a struct/enum declaration.
static void printCxxTypeName(raw_ostream &os, const NominalTypeDecl *type) {
// FIXME: Print namespace qualifiers for references from other modules.
// FIXME: Print class qualifiers for nested class references.
ClangSyntaxPrinter(os).printIdentifier(type->getName().str());
}
static void
printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
IRABIDetailsProvider::SizeAndAlignment layout) {
os << "struct ";
printCTypeName(os, typeDecl);
os << " {\n";
os << " _Alignas(" << layout.alignment << ") ";
os << "char _storage[" << layout.size << "];\n";
os << "};\n\n";
}
void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
auto typeSizeAlign =
interopContext.getIrABIDetails().getTypeSizeAlignment(SD);
@@ -36,12 +63,230 @@ void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) {
return;
}
ClangSyntaxPrinter printer(os);
// Print out a forward declaration of the "hidden" _impl class.
printer.printNamespace(cxx_synthesis::getCxxImplNamespaceName(),
[&](raw_ostream &os) {
os << "class _impl_";
printer.printIdentifier(SD->getName().str());
os << ";\n";
});
// Print out the C++ class itself.
os << "class ";
ClangSyntaxPrinter(os).printIdentifier(SD->getName().str());
os << " final {\n";
// FIXME: Print the other members of the struct.
os << "private:\n";
// Print out private default constructor.
os << " inline ";
printer.printIdentifier(SD->getName().str());
os << "() {}\n";
// Print out '_make' function which returns an unitialized instance for
// passing to Swift.
os << " static inline ";
printer.printIdentifier(SD->getName().str());
os << " _make() { return ";
printer.printIdentifier(SD->getName().str());
os << "(); }\n";
// Print out the private accessors to the underlying Swift value storage.
os << " inline const char * _Nonnull _getOpaquePointer() const { return "
"_storage; }\n";
os << " inline char * _Nonnull _getOpaquePointer() { return _storage; }\n";
os << "\n";
// Print out the storage for the value type.
os << " alignas(" << typeSizeAlign->alignment << ") ";
os << "char _storage[" << typeSizeAlign->size << "];\n";
os << "};\n";
// Wrap up the value type.
os << " friend class " << cxx_synthesis::getCxxImplNamespaceName()
<< "::_impl_";
ClangSyntaxPrinter(os).printIdentifier(SD->getName().str());
os << ";\n";
os << "};\n\n";
// Print out the "hidden" _impl class.
printer.printNamespace(
cxx_synthesis::getCxxImplNamespaceName(), [&](raw_ostream &os) {
os << "class _impl_";
printer.printIdentifier(SD->getName().str());
os << " {\n";
os << "public:\n";
os << " static inline char * _Nonnull getOpaquePointer(";
printCxxTypeName(os, SD);
os << " &object) { return object._getOpaquePointer(); }\n";
os << " static inline const char * _Nonnull getOpaquePointer(const ";
printCxxTypeName(os, SD);
os << " &object) { return object._getOpaquePointer(); }\n";
os << " template<class T>\n";
os << " static inline ";
printCxxTypeName(os, SD);
os << " returnNewValue(T callable) {\n";
os << " auto result = ";
printCxxTypeName(os, SD);
os << "::_make();\n";
os << " callable(result._getOpaquePointer());\n";
os << " return result;\n";
os << " }\n";
os << "};\n";
});
printCValueTypeStorageStruct(cPrologueOS, SD, *typeSizeAlign);
}
/// Print out the C stub struct that's used to pass/return a value type directly
/// to/from swiftcc function.
static void
printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
PrimitiveTypeMapping &typeMapping,
SwiftToClangInteropContext &interopContext) {
auto printStubCTypeName = [&]() {
os << "swift_interop_stub_";
printCTypeName(os, SD);
};
// Print out a C stub for this value type.
os << "// Stub struct to be used to pass/return values to/from Swift "
"functions.\n";
os << "struct ";
printStubCTypeName();
os << " {\n";
llvm::SmallVector<std::pair<clang::CharUnits, clang::CharUnits>, 8> fields;
interopContext.getIrABIDetails().enumerateDirectPassingRecordMembers(
SD->getDeclaredType(),
[&](clang::CharUnits offset, clang::CharUnits end, Type t) {
auto info =
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
if (!info)
return;
os << " " << info->name;
if (info->canBeNullable)
os << " _Null_unspecified";
os << " _" << (fields.size() + 1) << ";\n";
fields.push_back(std::make_pair(offset, end));
});
// cPrologueOS << " _Alignas(" << typeSizeAlign->alignment << ") ";
// cPrologueOS << "char _storage[" << typeSizeAlign->size << "];\n";
os << "};\n\n";
// Emit a stub that returns a value directly from swiftcc function.
os << "static inline void swift_interop_returnDirect_";
printCTypeName(os, SD);
os << "(char * _Nonnull result, struct ";
printStubCTypeName();
os << " value";
os << ") __attribute__((always_inline)) {\n";
for (size_t i = 0; i < fields.size(); ++i) {
os << " memcpy(result + " << fields[i].first.getQuantity() << ", "
<< "&value._" << (i + 1) << ", "
<< (fields[i].second - fields[i].first).getQuantity() << ");\n";
}
os << "}\n\n";
// Emit a stub that is used to pass value type directly to swiftcc function.
os << "static inline struct ";
printStubCTypeName();
os << " swift_interop_passDirect_";
printCTypeName(os, SD);
os << "(const char * _Nonnull value) __attribute__((always_inline)) {\n";
os << " struct ";
printStubCTypeName();
os << " result;\n";
for (size_t i = 0; i < fields.size(); ++i) {
os << " memcpy(&result._" << (i + 1) << ", value + "
<< fields[i].first.getQuantity() << ", "
<< (fields[i].second - fields[i].first).getQuantity() << ");\n";
}
os << " return result;\n";
os << "}\n\n";
}
void ClangValueTypePrinter::printCStubTypeName(const NominalTypeDecl *type) {
os << "swift_interop_stub_";
printCTypeName(os, type);
// Ensure the stub is declared in the header.
interopContext.runIfStubForDeclNotEmitted(type, [&]() {
printCStructStubForDirectPassing(cPrologueOS, type, typeMapping,
interopContext);
});
}
void ClangValueTypePrinter::printValueTypeParameterType(
const NominalTypeDecl *type, OutputLanguageMode outputLang) {
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
if (outputLang != OutputLanguageMode::Cxx) {
// C functions only take stub values directly as parameters.
os << "struct ";
printCStubTypeName(type);
return;
}
os << "const ";
printCxxTypeName(os, type);
os << '&';
}
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
bool isIndirect, const NominalTypeDecl *type,
llvm::function_ref<void()> cxxParamPrinter) {
// A Swift value type is passed to its underlying Swift function
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
if (!isIndirect) {
os << cxx_synthesis::getCxxImplNamespaceName() << "::"
<< "swift_interop_passDirect_";
printCTypeName(os, type);
os << '(';
}
os << cxx_synthesis::getCxxImplNamespaceName() << "::_impl_";
ClangSyntaxPrinter(os).printIdentifier(type->getName().str());
os << "::getOpaquePointer(";
cxxParamPrinter();
os << ')';
if (!isIndirect)
os << ')';
}
void ClangValueTypePrinter::printValueTypeReturnType(
const NominalTypeDecl *type, OutputLanguageMode outputLang) {
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
if (outputLang == OutputLanguageMode::Cxx) {
printCxxTypeName(os, type);
} else {
os << "struct ";
printCStubTypeName(type);
}
}
void ClangValueTypePrinter::printValueTypeIndirectReturnScaffold(
const NominalTypeDecl *type,
llvm::function_ref<void(StringRef)> bodyPrinter) {
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
os << " return " << cxx_synthesis::getCxxImplNamespaceName() << "::_impl_";
ClangSyntaxPrinter(os).printIdentifier(type->getName().str());
os << "::returnNewValue([&](void * _Nonnull result) {\n ";
bodyPrinter("result");
os << ";\n";
os << " });\n";
}
void ClangValueTypePrinter::printValueTypeDirectReturnScaffold(
const NominalTypeDecl *type, llvm::function_ref<void()> bodyPrinter) {
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
os << " return " << cxx_synthesis::getCxxImplNamespaceName() << "::_impl_";
ClangSyntaxPrinter(os).printIdentifier(type->getName().str());
os << "::returnNewValue([&](char * _Nonnull result) {\n";
os << " ";
os << cxx_synthesis::getCxxImplNamespaceName() << "::"
<< "swift_interop_returnDirect_";
printCTypeName(os, type);
os << "(result, ";
bodyPrinter();
os << ");\n";
os << " });\n";
}

View File

@@ -13,11 +13,15 @@
#ifndef SWIFT_PRINTASCLANG_PRINTCLANGVALUETYPE_H
#define SWIFT_PRINTASCLANG_PRINTCLANGVALUETYPE_H
#include "OutputLanguageMode.h"
#include "swift/AST/Type.h"
#include "swift/Basic/LLVM.h"
#include "llvm/Support/raw_ostream.h"
namespace swift {
class NominalTypeDecl;
class PrimitiveTypeMapping;
class StructDecl;
class SwiftToClangInteropContext;
@@ -25,16 +29,55 @@ class SwiftToClangInteropContext;
/// be included in a Swift module's generated clang header.
class ClangValueTypePrinter {
public:
ClangValueTypePrinter(raw_ostream &os,
ClangValueTypePrinter(raw_ostream &os, raw_ostream &cPrologueOS,
PrimitiveTypeMapping &typeMapping,
SwiftToClangInteropContext &interopContext)
: os(os), interopContext(interopContext) {}
: os(os), cPrologueOS(cPrologueOS), typeMapping(typeMapping),
interopContext(interopContext) {}
/// Print the C struct thunk or the C++ class definition that
/// corresponds to the given structure declaration.
void printStructDecl(const StructDecl *SD);
/// Print the pararameter type that referes to a Swift struct type in C/C++.
void printValueTypeParameterType(const NominalTypeDecl *type,
OutputLanguageMode outputLang);
/// Print the use of a C++ struct/enum parameter value as it's passed to the
/// underlying C function that represents the native Swift function.
void
printParameterCxxToCUseScaffold(bool isIndirect, const NominalTypeDecl *type,
llvm::function_ref<void()> cxxParamPrinter);
/// Print the return type that refers to a Swift struct type in C/C++.
void printValueTypeReturnType(const NominalTypeDecl *typeDecl,
OutputLanguageMode outputLang);
/// Print the supporting code that's required to indirectly return a C++
/// class that represents a Swift value type as it's being indirectly passed
/// from the C function that represents the native Swift function.
void printValueTypeIndirectReturnScaffold(
const NominalTypeDecl *typeDecl,
llvm::function_ref<void(StringRef)> bodyPrinter);
/// Print the supporting code that's required to directly return a C++ class
/// that represents a Swift value type as it's being returned from the C
/// function that represents the native Swift function.
void
printValueTypeDirectReturnScaffold(const NominalTypeDecl *typeDecl,
llvm::function_ref<void()> bodyPrinter);
private:
/// Prints out the C stub name used to pass/return value directly for the
/// given value type.
///
/// If the C stub isn't declared yet in the emitted header, that declaration
/// will be emitted by this function.
void printCStubTypeName(const NominalTypeDecl *type);
raw_ostream &os;
raw_ostream &cPrologueOS;
PrimitiveTypeMapping &typeMapping;
SwiftToClangInteropContext &interopContext;
};

View File

@@ -26,3 +26,10 @@ IRABIDetailsProvider &SwiftToClangInteropContext::getIrABIDetails() {
irABIDetails = std::make_unique<IRABIDetailsProvider>(mod, irGenOpts);
return *irABIDetails;
}
void SwiftToClangInteropContext::runIfStubForDeclNotEmitted(
const Decl *d, llvm::function_ref<void(void)> function) {
auto result = emittedStubs.insert(d);
if (result.second)
function();
}

View File

@@ -13,10 +13,13 @@
#ifndef SWIFT_PRINTASCLANG_SWIFTTOCLANGINTEROPCONTEXT_H
#define SWIFT_PRINTASCLANG_SWIFTTOCLANGINTEROPCONTEXT_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include <memory>
namespace swift {
class Decl;
class IRABIDetailsProvider;
class IRGenOptions;
class ModuleDecl;
@@ -32,10 +35,16 @@ public:
IRABIDetailsProvider &getIrABIDetails();
// Runs the given function if we haven't emitted some context-specific stub
// for the given declaration yet.
void runIfStubForDeclNotEmitted(const Decl *d,
llvm::function_ref<void(void)> function);
private:
ModuleDecl &mod;
const IRGenOptions &irGenOpts;
std::unique_ptr<IRABIDetailsProvider> irABIDetails;
llvm::DenseSet<const Decl *> emittedStubs;
};
} // end namespace swift

View File

@@ -0,0 +1,29 @@
#ifndef SDK_STRING_H
#define SDK_STRING_H
#include <stdint.h>
void* memcpy(void* s1, const void* s2, size_t n);
void* memmove(void* s1, const void* s2, size_t n);
char* strcpy (char* s1, const char* s2);
char* strncpy(char* s1, const char* s2, size_t n);
char* strcat (char* s1, const char* s2);
char* strncat(char* s1, const char* s2, size_t n);
int memcmp(const void* s1, const void* s2, size_t n);
int strcmp (const char* s1, const char* s2);
int strncmp(const char* s1, const char* s2, size_t n);
int strcoll(const char* s1, const char* s2);
size_t strxfrm(char* s1, const char* s2, size_t n);
const void* memchr(const void* s, int c, size_t n);
const char* strchr(const char* s, int c);
size_t strcspn(const char* s1, const char* s2);
const char* strpbrk(const char* s1, const char* s2);
const char* strrchr(const char* s, int c);
size_t strspn(const char* s1, const char* s2);
const char* strstr(const char* s1, const char* s2);
char* strtok(char* s1, const char* s2);
void* memset(void* s, int c, size_t n);
char* strerror(int errnum);
size_t strlen(const char* s);
#endif // SDK_STRING_H

View File

@@ -0,0 +1,30 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %S/large-structs-pass-return-indirect-in-c.swift -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %target-interop-build-clang -c %s -I %t -o %t/swift-structs-execution.o
// RUN: %target-interop-build-swift %S/large-structs-pass-return-indirect-in-c.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain
// RUN: %target-codesign %t/swift-structs-execution
// RUN: %target-run %t/swift-structs-execution | %FileCheck %s
// REQUIRES: executable_test
#include <assert.h>
#include "structs.h"
int main() {
// printStructSeveralI64(returnNewStructSeveralI64(42))
struct Structs_StructSeveralI64 structSeveralI64;
$s7Structs25returnNewStructSeveralI641iAA0deF0Vs5Int64V_tF(&structSeveralI64, 42);
$s7Structs21printStructSeveralI64yyAA0cdE0VF(&structSeveralI64);
// CHECK: StructSeveralI64.1 = 42, .2 = 0, .3 = -17, .4 = 12345612, .5 = -65535
// printStructSeveralI64(passThroughStructSeveralI64(581, returnNewStructSeveralI64(42), 5.0))
struct Structs_StructSeveralI64 structSeveralI64_copy;
$s7Structs27passThroughStructSeveralI641i_1jAA0deF0Vs5Int64V_AFSftF(&structSeveralI64_copy,
581, &structSeveralI64, 5.0f);
$s7Structs21printStructSeveralI64yyAA0cdE0VF(&structSeveralI64_copy);
// CHECK-NEXT: StructSeveralI64.1 = 42, .2 = 581, .3 = -17, .4 = -12345612, .5 = -65530
return 0;
}

View File

@@ -0,0 +1,32 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %FileCheck %s < %t/structs.h
// RUN: %check-interop-c-header-in-clang(%t/structs.h)
public struct StructSeveralI64 {
let x1, x2, x3, x4, x5: Int64
}
// CHECK: struct Structs_StructSeveralI64 {
// CHECK-NEXT: _Alignas(8) char _storage[40];
// CHECK-NEXT: };
// CHECK_NOT: swift_interop
public func returnNewStructSeveralI64(i: Int64) -> StructSeveralI64 {
return StructSeveralI64(x1: i, x2: 0, x3: -17, x4: 12345612, x5: -0xFFFF)
}
public func passThroughStructSeveralI64(i: Int64, _ x: StructSeveralI64, j: Float) -> StructSeveralI64 {
return StructSeveralI64(x1: x.x1, x2: x.x2 + i, x3: x.x3, x4: -x.x4, x5: x.x5 + Int64(j))
}
public func printStructSeveralI64(_ x: StructSeveralI64) {
print("StructSeveralI64.1 = \(x.x1), .2 = \(x.x2), .3 = \(x.x3), .4 = \(x.x4), .5 = \(x.x5)")
}
// CHECK: SWIFT_EXTERN void $s7Structs27passThroughStructSeveralI641i_1jAA0deF0Vs5Int64V_AFSftF(SWIFT_INDIRECT_RESULT void * _Nonnull, int64_t i, const void * _Nonnull x, float j) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN void $s7Structs21printStructSeveralI64yyAA0cdE0VF(const void * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN void $s7Structs25returnNewStructSeveralI641iAA0deF0Vs5Int64V_tF(SWIFT_INDIRECT_RESULT void * _Nonnull, int64_t i) SWIFT_NOEXCEPT SWIFT_CALL;

View File

@@ -0,0 +1,90 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %S/small-structs-pass-return-direct-in-c.swift -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %target-interop-build-clang -c %s -I %t -o %t/swift-structs-execution.o -Wno-incompatible-pointer-types
// RUN: %target-interop-build-swift %S/small-structs-pass-return-direct-in-c.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain
// RUN: %target-codesign %t/swift-structs-execution
// RUN: %target-run %t/swift-structs-execution | %FileCheck %s
// REQUIRES: executable_test
#include <assert.h>
#include "structs.h"
int main() {
// printStructOneI64(returnNewStructOneI64())
struct Structs_StructOneI64 structOneI64;
swift_interop_returnDirect_Structs_StructOneI64(&structOneI64, $s7Structs21returnNewStructOneI64AA0deF0VyF());
$s7Structs17printStructOneI64yyAA0cdE0VF(swift_interop_passDirect_Structs_StructOneI64(&structOneI64));
// CHECK: StructOneI64.x = 42
// printStructOneI64(passThroughStructOneI64(...))
struct Structs_StructOneI64 structOneI64_copy;
swift_interop_returnDirect_Structs_StructOneI64(&structOneI64_copy,
$s7Structs23passThroughStructOneI64yAA0deF0VADF(
swift_interop_passDirect_Structs_StructOneI64(&structOneI64)));
$s7Structs17printStructOneI64yyAA0cdE0VF(swift_interop_passDirect_Structs_StructOneI64(&structOneI64_copy));
// CHECK-NEXT: StructOneI64.x = 42
$s7Structs17printStructOneI64yyAA0cdE0VF(swift_interop_passDirect_Structs_StructOneI64(&structOneI64));
// CHECK-NEXT: StructOneI64.x = 42
// printStructTwoI32(returnNewStructTwoI32(11))
struct Structs_StructTwoI32 structTwoI32;
swift_interop_returnDirect_Structs_StructTwoI32(&structTwoI32,
$s7Structs21returnNewStructTwoI32yAA0deF0Vs5Int32VF(11));
$s7Structs17printStructTwoI32yyAA0cdE0VF(swift_interop_passDirect_Structs_StructTwoI32(&structTwoI32));
// CHECK-NEXT: StructTwoI32.x = 11, y = 22
// printStructTwoI32(passThroughStructTwoI32(4, ..., 6))
struct Structs_StructTwoI32 structTwoI32_copy;
swift_interop_returnDirect_Structs_StructTwoI32(&structTwoI32_copy,
$s7Structs23passThroughStructTwoI32yAA0deF0Vs5Int32V_AdFtF(4, swift_interop_passDirect_Structs_StructTwoI32(&structTwoI32), 6));
$s7Structs17printStructTwoI32yyAA0cdE0VF(swift_interop_passDirect_Structs_StructTwoI32(&structTwoI32_copy));
// CHECK-NEXT: StructTwoI32.x = 15, y = 28
// printStructStructTwoI32_and_OneI16AndOneStruct(... , returnNewStructOneI16AndOneStruct());
struct Structs_StructOneI16AndOneStruct structOneI16AndOneStruct;
swift_interop_returnDirect_Structs_StructOneI16AndOneStruct(&structOneI16AndOneStruct,
$s7Structs024returnNewStructOneI16AndeD0AA0defgeD0VyF());
$s7Structs011printStructc20TwoI32_and_OneI16AndgC0yyAA0cdE0V_AA0cghigC0VtF(
swift_interop_passDirect_Structs_StructTwoI32(&structTwoI32),
swift_interop_passDirect_Structs_StructOneI16AndOneStruct(&structOneI16AndOneStruct));
// CHECK-NEXT: StructTwoI32.x = 11, y = 22
// CHECK-NEXT: StructOneI16AndOneStruct.x = 255, y.x = 5, y.y = 72
// let x = returnNewStructU16AndPointer(...)
// getStructU16AndPointer_x(x)
// getStructU16AndPointer_y(y)
char c = 'A';
struct Structs_StructU16AndPointer structU16AndPointer;
swift_interop_returnDirect_Structs_StructU16AndPointer(&structU16AndPointer,
$s7Structs28returnNewStructU16AndPointeryAA0defG0VSvF(&c));
assert($s7Structs24getStructU16AndPointer_xys5UInt8VAA0cdeF0VF(
swift_interop_passDirect_Structs_StructU16AndPointer(&structU16AndPointer)) == 55);
assert($s7Structs24getStructU16AndPointer_yySvAA0cdeF0VF(
swift_interop_passDirect_Structs_StructU16AndPointer(&structU16AndPointer)) == &c);
// let x = returnNewStructDoubleAndFloat()
// getStructDoubleAndFloat_x(x)
// getStructDoubleAndFloat_y(x)
double doubleValue = 1.25;
float floatValue = -5.0f;
struct Structs_StructDoubleAndFloat structDoubleAndFloat;
swift_interop_returnDirect_Structs_StructDoubleAndFloat(&structDoubleAndFloat,
$s7Structs29returnNewStructDoubleAndFloatyAA0defG0VSf_SdtF(floatValue, doubleValue));
assert($s7Structs25getStructDoubleAndFloat_xySdAA0cdeF0VF(
swift_interop_passDirect_Structs_StructDoubleAndFloat(&structDoubleAndFloat)) == doubleValue);
assert($s7Structs25getStructDoubleAndFloat_yySfAA0cdeF0VF(
swift_interop_passDirect_Structs_StructDoubleAndFloat(&structDoubleAndFloat)) == floatValue);
// printStructI8AndU32AndI16(returnNewStructI8AndU32AndI16())
struct Structs_StructI8AndU32AndI16 structI8AndU32AndI16;
swift_interop_returnDirect_Structs_StructI8AndU32AndI16(&structI8AndU32AndI16,
$s7Structs023returnNewStructI8AndU32F3I16AA0defgfH0VyF());
$s7Structs019printStructI8AndU32E3I16yyAA0cdefeG0VF(
swift_interop_passDirect_Structs_StructI8AndU32AndI16(&structI8AndU32AndI16));
// CHECK-NEXT: StructI8AndU32AndI16.x = -100, y = 123456, z = -3456
return 0;
}

View File

@@ -0,0 +1,237 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %FileCheck %s < %t/structs.h
// RUN: %check-interop-c-header-in-clang(%t/structs.h -Wno-unused-function)
public struct StructOneI64 {
let x: Int64
}
public struct StructTwoI32 {
let x, y: Int32
}
public struct StructOneI16AndOneStruct {
let x: Int16
let y: StructTwoI32
}
public struct StructU16AndPointer {
let x: UInt8
let y: UnsafeMutableRawPointer
}
public struct StructDoubleAndFloat {
let x: Double
let y: Float
}
public struct StructI8AndU32AndI16 {
let x: Int8
let y: UInt32
let z: Int16
}
// CHECK: struct Structs_StructDoubleAndFloat {
// CHECK_NEXT: _Alignas(8) char _storage[12];
// CHECK_NEXT: };
// CHECK: struct Structs_StructI8AndU32AndI16 {
// CHECK_NEXT: _Alignas(4) char _storage[10];
// CHECK_NEXT: };
// CHECK: struct Structs_StructOneI16AndOneStruct {
// CHECK_NEXT: _Alignas(4) char _storage[12];
// CHECK_NEXT: };
// CHECK: struct Structs_StructOneI64 {
// CHECK_NEXT: _Alignas(8) char _storage[8];
// CHECK_NEXT: };
// CHECK: struct Structs_StructTwoI32 {
// CHECK_NEXT: _Alignas(4) char _storage[8];
// CHECK_NEXT: };
// CHECK: struct Structs_StructU16AndPointer {
// CHECK_NEXT: _Alignas(8) char _storage[16];
// CHECK_NEXT: };
public func returnNewStructOneI64() -> StructOneI64 { return StructOneI64(x: 42 ) }
public func passThroughStructOneI64(_ x: StructOneI64) -> StructOneI64 { return x }
public func printStructOneI64(_ x: StructOneI64) {
print("StructOneI64.x = \(x.x)")
}
public func returnNewStructTwoI32(_ x: Int32) -> StructTwoI32 { return StructTwoI32(x: x, y: x * 2) }
public func passThroughStructTwoI32(_ i: Int32, _ x: StructTwoI32, _ j: Int32) -> StructTwoI32 {
return StructTwoI32(x: x.x + i, y: x.y + j)
}
public func printStructTwoI32(_ x: StructTwoI32) {
print("StructTwoI32.x = \(x.x), y = \(x.y)")
}
public func returnNewStructOneI16AndOneStruct() -> StructOneI16AndOneStruct {
return StructOneI16AndOneStruct(x: 0xFF, y: StructTwoI32(x: 5, y: 72))
}
public func printStructStructTwoI32_and_OneI16AndOneStruct(_ y: StructTwoI32, _ x: StructOneI16AndOneStruct) {
printStructTwoI32(y)
print("StructOneI16AndOneStruct.x = \(x.x), y.x = \(x.y.x), y.y = \(x.y.y)")
}
public func returnNewStructU16AndPointer(_ x: UnsafeMutableRawPointer) -> StructU16AndPointer {
return StructU16AndPointer(x: 55, y: x)
}
public func getStructU16AndPointer_x(_ x: StructU16AndPointer) -> UInt8 { return x.x }
public func getStructU16AndPointer_y(_ x: StructU16AndPointer) -> UnsafeMutableRawPointer { return x.y }
public func returnNewStructDoubleAndFloat(_ y: Float, _ x: Double) -> StructDoubleAndFloat {
return StructDoubleAndFloat(x: x, y: y)
}
public func getStructDoubleAndFloat_x(_ x: StructDoubleAndFloat) -> Double { return x.x }
public func getStructDoubleAndFloat_y(_ x: StructDoubleAndFloat) -> Float { return x.y }
public func returnNewStructI8AndU32AndI16() -> StructI8AndU32AndI16 {
return StructI8AndU32AndI16(x: -100, y: 123456, z: -3456)
}
public func printStructI8AndU32AndI16(_ x: StructI8AndU32AndI16) {
print("StructI8AndU32AndI16.x = \(x.x), y = \(x.y), z = \(x.z)")
}
// CHECK: struct swift_interop_stub_Structs_StructDoubleAndFloat {
// CHECK-NEXT: double _1;
// CHECK-NEXT: float _2;
// CHECK-NEXT: };
// CHECK: static inline void swift_interop_returnDirect_Structs_StructDoubleAndFloat(char * _Nonnull result, struct swift_interop_stub_Structs_StructDoubleAndFloat value) __attribute__((always_inline)) {
// CHECK-NEXT: memcpy(result + 0, &value._1, 8);
// CHECK-NEXT: memcpy(result + 8, &value._2, 4);
// CHECK-NEXT: }
// CHECK: static inline struct swift_interop_stub_Structs_StructDoubleAndFloat swift_interop_passDirect_Structs_StructDoubleAndFloat(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_stub_Structs_StructDoubleAndFloat result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 8);
// CHECK-NEXT: memcpy(&result._2, value + 8, 4);
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK: SWIFT_EXTERN double $s7Structs25getStructDoubleAndFloat_xySdAA0cdeF0VF(struct swift_interop_stub_Structs_StructDoubleAndFloat x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN float $s7Structs25getStructDoubleAndFloat_yySfAA0cdeF0VF(struct swift_interop_stub_Structs_StructDoubleAndFloat x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: struct swift_interop_stub_Structs_StructU16AndPointer {
// CHECK-NEXT: uint8_t _1;
// CHECK-NEXT: void * _Null_unspecified _2;
// CHECK-NEXT: };
// CHECK: static inline void swift_interop_returnDirect_Structs_StructU16AndPointer(char * _Nonnull result, struct swift_interop_stub_Structs_StructU16AndPointer value) __attribute__((always_inline)) {
// CHECK-NEXT: memcpy(result + 0, &value._1, 1);
// CHECK-NEXT: memcpy(result + 8, &value._2, 8);
// CHECK-NEXT: }
// CHECK: static inline struct swift_interop_stub_Structs_StructU16AndPointer swift_interop_passDirect_Structs_StructU16AndPointer(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_stub_Structs_StructU16AndPointer result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 1);
// CHECK-NEXT: memcpy(&result._2, value + 8, 8);
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK: SWIFT_EXTERN uint8_t $s7Structs24getStructU16AndPointer_xys5UInt8VAA0cdeF0VF(struct swift_interop_stub_Structs_StructU16AndPointer x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN void * _Nonnull $s7Structs24getStructU16AndPointer_yySvAA0cdeF0VF(struct swift_interop_stub_Structs_StructU16AndPointer x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: struct swift_interop_stub_Structs_StructOneI64 {
// CHECK-NEXT: uint64_t _1;
// CHECK-NEXT: };
// CHECK: static inline void swift_interop_returnDirect_Structs_StructOneI64(char * _Nonnull result, struct swift_interop_stub_Structs_StructOneI64 value) __attribute__((always_inline)) {
// CHECK-NEXT: memcpy(result + 0, &value._1, 8);
// CHECK-NEXT: }
// CHECK: static inline struct swift_interop_stub_Structs_StructOneI64 swift_interop_passDirect_Structs_StructOneI64(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_stub_Structs_StructOneI64 result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 8);
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructOneI64 $s7Structs23passThroughStructOneI64yAA0deF0VADF(struct swift_interop_stub_Structs_StructOneI64 x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: struct swift_interop_stub_Structs_StructTwoI32 {
// CHECK-NEXT: uint64_t _1;
// CHECK-NEXT: };
// CHECK: static inline void swift_interop_returnDirect_Structs_StructTwoI32(char * _Nonnull result, struct swift_interop_stub_Structs_StructTwoI32 value) __attribute__((always_inline)) {
// CHECK-NEXT: memcpy(result + 0, &value._1, 8);
// CHECK-NEXT: }
// CHECK: static inline struct swift_interop_stub_Structs_StructTwoI32 swift_interop_passDirect_Structs_StructTwoI32(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_stub_Structs_StructTwoI32 result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 8);
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructTwoI32 $s7Structs23passThroughStructTwoI32yAA0deF0Vs5Int32V_AdFtF(int32_t i, struct swift_interop_stub_Structs_StructTwoI32 x, int32_t j) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: struct swift_interop_stub_Structs_StructI8AndU32AndI16 {
// CHECK-NEXT: uint64_t _1;
// CHECK-NEXT: uint16_t _2;
// CHECK-NEXT: };
// CHECK: static inline void swift_interop_returnDirect_Structs_StructI8AndU32AndI16(char * _Nonnull result, struct swift_interop_stub_Structs_StructI8AndU32AndI16 value) __attribute__((always_inline)) {
// CHECK-NEXT: memcpy(result + 0, &value._1, 8);
// CHECK-NEXT: memcpy(result + 8, &value._2, 2);
// CHECK-NEXT: }
// CHECK: static inline struct swift_interop_stub_Structs_StructI8AndU32AndI16 swift_interop_passDirect_Structs_StructI8AndU32AndI16(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_stub_Structs_StructI8AndU32AndI16 result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 8);
// CHECK-NEXT: memcpy(&result._2, value + 8, 2);
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK: SWIFT_EXTERN void $s7Structs019printStructI8AndU32E3I16yyAA0cdefeG0VF(struct swift_interop_stub_Structs_StructI8AndU32AndI16 x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN void $s7Structs17printStructOneI64yyAA0cdE0VF(struct swift_interop_stub_Structs_StructOneI64 x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: struct swift_interop_stub_Structs_StructOneI16AndOneStruct {
// CHECK-NEXT: uint64_t _1;
// CHECK-NEXT: uint32_t _2;
// CHECK-NEXT: };
// CHECK: static inline void swift_interop_returnDirect_Structs_StructOneI16AndOneStruct(char * _Nonnull result, struct swift_interop_stub_Structs_StructOneI16AndOneStruct value) __attribute__((always_inline)) {
// CHECK-NEXT: memcpy(result + 0, &value._1, 8);
// CHECK-NEXT: memcpy(result + 8, &value._2, 4);
// CHECK-NEXT: }
// CHECK: static inline struct swift_interop_stub_Structs_StructOneI16AndOneStruct swift_interop_passDirect_Structs_StructOneI16AndOneStruct(const char * _Nonnull value) __attribute__((always_inline)) {
// CHECK-NEXT: struct swift_interop_stub_Structs_StructOneI16AndOneStruct result;
// CHECK-NEXT: memcpy(&result._1, value + 0, 8);
// CHECK-NEXT: memcpy(&result._2, value + 8, 4);
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK: SWIFT_EXTERN void $s7Structs011printStructc20TwoI32_and_OneI16AndgC0yyAA0cdE0V_AA0cghigC0VtF(struct swift_interop_stub_Structs_StructTwoI32 y, struct swift_interop_stub_Structs_StructOneI16AndOneStruct x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN void $s7Structs17printStructTwoI32yyAA0cdE0VF(struct swift_interop_stub_Structs_StructTwoI32 x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructDoubleAndFloat $s7Structs29returnNewStructDoubleAndFloatyAA0defG0VSf_SdtF(float y, double x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructI8AndU32AndI16 $s7Structs023returnNewStructI8AndU32F3I16AA0defgfH0VyF(void) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructOneI16AndOneStruct $s7Structs024returnNewStructOneI16AndeD0AA0defgeD0VyF(void) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructOneI64 $s7Structs21returnNewStructOneI64AA0deF0VyF(void) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructTwoI32 $s7Structs21returnNewStructTwoI32yAA0deF0Vs5Int32VF(int32_t x) SWIFT_NOEXCEPT SWIFT_CALL;
// CHECK: SWIFT_EXTERN struct swift_interop_stub_Structs_StructU16AndPointer $s7Structs28returnNewStructU16AndPointeryAA0defG0VSvF(void * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL;

View File

@@ -0,0 +1,28 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %S/large-structs-pass-return-indirect-in-cxx.swift -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-structs-execution.o
// RUN: %target-interop-build-swift %S/large-structs-pass-return-indirect-in-cxx.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain
// RUN: %target-codesign %t/swift-structs-execution
// RUN: %target-run %t/swift-structs-execution | %FileCheck %s
// REQUIRES: executable_test
#include <assert.h>
#include "structs.h"
int main() {
using namespace Structs;
static_assert(sizeof(StructSeveralI64) == 40);
printStructSeveralI64(returnNewStructSeveralI64(42));
// CHECK: StructSeveralI64.1 = 42, .2 = 0, .3 = -17, .4 = 12345612, .5 = -65535
StructSeveralI64 structSeveralI64_copy = passThroughStructSeveralI64(100, returnNewStructSeveralI64(11), 6.0);
printStructSeveralI64(structSeveralI64_copy);
// CHECK-NEXT: StructSeveralI64.1 = 11, .2 = 100, .3 = -17, .4 = -12345612, .5 = -65529
return 0;
}

View File

@@ -0,0 +1,41 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %FileCheck %s < %t/structs.h
// RUN: %check-interop-cxx-header-in-clang(%t/structs.h)
public struct StructSeveralI64 {
let x1, x2, x3, x4, x5: Int64
}
// CHECK: class StructSeveralI64 final {
public func returnNewStructSeveralI64(i: Int64) -> StructSeveralI64 {
return StructSeveralI64(x1: i, x2: 0, x3: -17, x4: 12345612, x5: -0xFFFF)
}
public func passThroughStructSeveralI64(i: Int64, _ x: StructSeveralI64, j: Float) -> StructSeveralI64 {
return StructSeveralI64(x1: x.x1, x2: x.x2 + i, x3: x.x3, x4: -x.x4, x5: x.x5 + Int64(j))
}
public func printStructSeveralI64(_ x: StructSeveralI64) {
print("StructSeveralI64.1 = \(x.x1), .2 = \(x.x2), .3 = \(x.x3), .4 = \(x.x4), .5 = \(x.x5)")
}
// CHECK: inline StructSeveralI64 passThroughStructSeveralI64(int64_t i, const StructSeveralI64& x, float j) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructSeveralI64::returnNewValue([&](void * _Nonnull result) {
// CHECK-NEXT: _impl::$s7Structs27passThroughStructSeveralI641i_1jAA0deF0Vs5Int64V_AFSftF(result, i, _impl::_impl_StructSeveralI64::getOpaquePointer(x), j);
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline void printStructSeveralI64(const StructSeveralI64& x) noexcept {
// CHECK-NEXT: return _impl::$s7Structs21printStructSeveralI64yyAA0cdE0VF(_impl::_impl_StructSeveralI64::getOpaquePointer(x));
// CHECK-NEXT: }
// CHECK: inline StructSeveralI64 returnNewStructSeveralI64(int64_t i) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructSeveralI64::returnNewValue([&](void * _Nonnull result) {
// CHECK-NEXT: _impl::$s7Structs25returnNewStructSeveralI641iAA0deF0Vs5Int64V_tF(result, i);
// CHECK-NEXT: });
// CHECK-NEXT: }

View File

@@ -0,0 +1,51 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %S/small-structs-pass-return-direct-in-cxx.swift -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-structs-execution.o -Wno-incompatible-pointer-types
// RUN: %target-interop-build-swift %S/small-structs-pass-return-direct-in-cxx.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain
// RUN: %target-codesign %t/swift-structs-execution
// RUN: %target-run %t/swift-structs-execution | %FileCheck %s
// REQUIRES: executable_test
#include <assert.h>
#include "structs.h"
int main() {
using namespace Structs;
static_assert(sizeof(StructOneI64) == 8, "");
static_assert(sizeof(StructTwoI32) == 8, "");
static_assert(sizeof(StructOneI16AndOneStruct) == 12, "");
static_assert(sizeof(StructU16AndPointer) == (sizeof(void *) * 2), "");
static_assert(sizeof(StructDoubleAndFloat) == 16, "");
StructOneI64 structOneI64 = returnNewStructOneI64();
printStructOneI64(structOneI64);
// CHECK: StructOneI64.x = 42
printStructOneI64(passThroughStructOneI64(structOneI64));
// CHECK-NEXT: StructOneI64.x = 42
printStructTwoI32(passThroughStructTwoI32(1, returnNewStructTwoI32(5), 4));
// CHECK-NEXT: StructTwoI32.x = 6, y = 14
printStructStructTwoI32_and_OneI16AndOneStruct(
returnNewStructTwoI32(7), returnNewStructOneI16AndOneStruct());
// CHECK-NEXT: StructTwoI32.x = 7, y = 14
// CHECK-NEXT: StructOneI16AndOneStruct.x = 255, y.x = 5, y.y = 72
char c = 'A';
auto structU16AndPointer = returnNewStructU16AndPointer(&c);
assert(getStructU16AndPointer_x(structU16AndPointer) == 55);
assert(getStructU16AndPointer_y(structU16AndPointer) == &c);
double doubleValue = 1.25;
float floatValue = -5.0f;
auto structDoubleAndFloat = returnNewStructDoubleAndFloat(floatValue, doubleValue);
assert(getStructDoubleAndFloat_x(structDoubleAndFloat) == doubleValue);
assert(getStructDoubleAndFloat_y(structDoubleAndFloat) == floatValue);
return 0;
}

View File

@@ -0,0 +1,164 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h
// RUN: %FileCheck %s < %t/structs.h
// RUN: %check-interop-cxx-header-in-clang(%t/structs.h)
public struct StructOneI64 {
let x: Int64
}
public struct StructTwoI32 {
let x, y: Int32
}
public struct StructOneI16AndOneStruct {
let x: Int16
let y: StructTwoI32
}
public struct StructU16AndPointer {
let x: UInt8
let y: UnsafeMutableRawPointer
}
public struct StructDoubleAndFloat {
let x: Double
let y: Float
}
// CHECK: class StructDoubleAndFloat final {
// CHECK: class StructOneI16AndOneStruct final {
// CHECK: class StructOneI64 final {
// CHECK: class StructTwoI32 final {
// CHECK: class StructU16AndPointer final {
public func returnNewStructOneI64() -> StructOneI64 { return StructOneI64(x: 42 ) }
public func passThroughStructOneI64(_ x: StructOneI64) -> StructOneI64 { return x }
public func printStructOneI64(_ x: StructOneI64) {
print("StructOneI64.x = \(x.x)")
}
public func returnNewStructTwoI32(_ x: Int32) -> StructTwoI32 { return StructTwoI32(x: x, y: x * 2) }
public func passThroughStructTwoI32(_ i: Int32, _ x: StructTwoI32, _ j: Int32) -> StructTwoI32 {
return StructTwoI32(x: x.x + i, y: x.y + j)
}
public func printStructTwoI32(_ x: StructTwoI32) {
print("StructTwoI32.x = \(x.x), y = \(x.y)")
}
public func returnNewStructOneI16AndOneStruct() -> StructOneI16AndOneStruct {
return StructOneI16AndOneStruct(x: 0xFF, y: StructTwoI32(x: 5, y: 72))
}
public func printStructStructTwoI32_and_OneI16AndOneStruct(_ y: StructTwoI32, _ x: StructOneI16AndOneStruct) {
printStructTwoI32(y)
print("StructOneI16AndOneStruct.x = \(x.x), y.x = \(x.y.x), y.y = \(x.y.y)")
}
public func returnNewStructU16AndPointer(_ x: UnsafeMutableRawPointer) -> StructU16AndPointer {
return StructU16AndPointer(x: 55, y: x)
}
public func getStructU16AndPointer_x(_ x: StructU16AndPointer) -> UInt8 { return x.x }
public func getStructU16AndPointer_y(_ x: StructU16AndPointer) -> UnsafeMutableRawPointer { return x.y }
public func returnNewStructDoubleAndFloat(_ y: Float, _ x: Double) -> StructDoubleAndFloat {
return StructDoubleAndFloat(x: x, y: y)
}
public func getStructDoubleAndFloat_x(_ x: StructDoubleAndFloat) -> Double { return x.x }
public func getStructDoubleAndFloat_y(_ x: StructDoubleAndFloat) -> Float { return x.y }
// CHECK: inline double getStructDoubleAndFloat_x(const StructDoubleAndFloat& x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::$s7Structs25getStructDoubleAndFloat_xySdAA0cdeF0VF(_impl::swift_interop_passDirect_Structs_StructDoubleAndFloat(_impl::_impl_StructDoubleAndFloat::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline float getStructDoubleAndFloat_y(const StructDoubleAndFloat& x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::$s7Structs25getStructDoubleAndFloat_yySfAA0cdeF0VF(_impl::swift_interop_passDirect_Structs_StructDoubleAndFloat(_impl::_impl_StructDoubleAndFloat::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline uint8_t getStructU16AndPointer_x(const StructU16AndPointer& x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::$s7Structs24getStructU16AndPointer_xys5UInt8VAA0cdeF0VF(_impl::swift_interop_passDirect_Structs_StructU16AndPointer(_impl::_impl_StructU16AndPointer::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline void * _Nonnull getStructU16AndPointer_y(const StructU16AndPointer& x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::$s7Structs24getStructU16AndPointer_yySvAA0cdeF0VF(_impl::swift_interop_passDirect_Structs_StructU16AndPointer(_impl::_impl_StructU16AndPointer::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline StructOneI64 passThroughStructOneI64(const StructOneI64& x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructOneI64::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructOneI64(result, _impl::$s7Structs23passThroughStructOneI64yAA0deF0VADF(_impl::swift_interop_passDirect_Structs_StructOneI64(_impl::_impl_StructOneI64::getOpaquePointer(x))));
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline StructTwoI32 passThroughStructTwoI32(int32_t i, const StructTwoI32& x, int32_t j) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructTwoI32::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructTwoI32(result, _impl::$s7Structs23passThroughStructTwoI32yAA0deF0Vs5Int32V_AdFtF(i, _impl::swift_interop_passDirect_Structs_StructTwoI32(_impl::_impl_StructTwoI32::getOpaquePointer(x)), j));
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline void printStructOneI64(const StructOneI64& x) noexcept {
// CHECK-NEXT: return _impl::$s7Structs17printStructOneI64yyAA0cdE0VF(_impl::swift_interop_passDirect_Structs_StructOneI64(_impl::_impl_StructOneI64::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline void printStructStructTwoI32_and_OneI16AndOneStruct(const StructTwoI32& y, const StructOneI16AndOneStruct& x) noexcept {
// CHECK-NEXT: return _impl::$s7Structs011printStructc20TwoI32_and_OneI16AndgC0yyAA0cdE0V_AA0cghigC0VtF(_impl::swift_interop_passDirect_Structs_StructTwoI32(_impl::_impl_StructTwoI32::getOpaquePointer(y)), _impl::swift_interop_passDirect_Structs_StructOneI16AndOneStruct(_impl::_impl_StructOneI16AndOneStruct::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline void printStructTwoI32(const StructTwoI32& x) noexcept {
// CHECK-NEXT: return _impl::$s7Structs17printStructTwoI32yyAA0cdE0VF(_impl::swift_interop_passDirect_Structs_StructTwoI32(_impl::_impl_StructTwoI32::getOpaquePointer(x)));
// CHECK-NEXT: }
// CHECK: inline StructDoubleAndFloat returnNewStructDoubleAndFloat(float y, double x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructDoubleAndFloat::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructDoubleAndFloat(result, _impl::$s7Structs29returnNewStructDoubleAndFloatyAA0defG0VSf_SdtF(y, x));
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline StructOneI16AndOneStruct returnNewStructOneI16AndOneStruct() noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructOneI16AndOneStruct::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructOneI16AndOneStruct(result, _impl::$s7Structs024returnNewStructOneI16AndeD0AA0defgeD0VyF());
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline StructOneI64 returnNewStructOneI64() noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructOneI64::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructOneI64(result, _impl::$s7Structs21returnNewStructOneI64AA0deF0VyF());
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline StructTwoI32 returnNewStructTwoI32(int32_t x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructTwoI32::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructTwoI32(result, _impl::$s7Structs21returnNewStructTwoI32yAA0deF0Vs5Int32VF(x));
// CHECK-NEXT: });
// CHECK-NEXT: }
// CHECK: inline StructU16AndPointer returnNewStructU16AndPointer(void * _Nonnull x) noexcept SWIFT_WARN_UNUSED_RESULT {
// CHECK-NEXT: return _impl::_impl_StructU16AndPointer::returnNewValue([&](char * _Nonnull result) {
// CHECK-NEXT: _impl::swift_interop_returnDirect_Structs_StructU16AndPointer(result, _impl::$s7Structs28returnNewStructU16AndPointeryAA0defG0VSvF(x));
// CHECK-NEXT: });
// CHECK-NEXT: }

View File

@@ -5,11 +5,42 @@
// RUN: %check-interop-cxx-header-in-clang(%t/structs.h -Wno-unused-private-field)
// CHECK: namespace Structs {
// CHECK: namespace _impl {
// CHECK: namespace Structs {
// CHECK: namespace _impl {
// CHECK-EMPTY:
// CHECK-NEXT: class _impl_StructWithIntField;
// CHECK-EMPTY:
// CHECK-NEXT: }
// CHECK: class StructWithIntField final {
// CHECK-NEXT: private:
// CHECK-NEXT: inline StructWithIntField() {}
// CHECK-NEXT: static inline StructWithIntField _make() { return StructWithIntField(); }
// CHECK-NEXT: inline const char * _Nonnull _getOpaquePointer() const { return _storage; }
// CHECK-NEXT: inline char * _Nonnull _getOpaquePointer() { return _storage; }
// CHECK-EMPTY:
// CHECK-NEXT: alignas(8) char _storage[8];
// CHECK-NEXT: friend class _impl::_impl_StructWithIntField;
// CHECK-NEXT: };
// CHECK: namespace _impl {
// CHECK-EMPTY:
// CHECK-NEXT: class _impl_StructWithIntField {
// CHECK-NEXT: public:
// CHECK-NEXT: static inline char * _Nonnull getOpaquePointer(StructWithIntField &object) { return object._getOpaquePointer(); }
// CHECK-NEXT: static inline const char * _Nonnull getOpaquePointer(const StructWithIntField &object) { return object._getOpaquePointer(); }
// CHECK-NEXT: template<class T>
// CHECK-NEXT: static inline StructWithIntField returnNewValue(T callable) {
// CHECK-NEXT: auto result = StructWithIntField::_make();
// CHECK-NEXT: callable(result._getOpaquePointer());
// CHECK-NEXT: return result;
// CHECK-NEXT: }
// CHECK-NEXT: };
// CHECK-EMPTY:
// CHECK-NEXT: }
public struct StructWithIntField {
let field: Int64
}
@@ -17,6 +48,7 @@ public struct StructWithIntField {
// Special name gets renamed in C++.
// CHECK: class register_ final {
// CHECK: alignas(8) char _storage[16];
// CHECK-NEXT: friend class
// CHECK-NEXT: };
public struct register {
let field1: Int64

View File

@@ -29,11 +29,11 @@ config.substitutions.insert(0, ('%target-interop-build-clangxx', '%target-clangx
# Test parsing of the generated C++ header in different C++ language modes.
config.substitutions.insert(0, ('%check-interop-cxx-header-in-clang\(([^)]+)\)',
SubstituteCaptures(r'%check-cxx-header-in-clang -std=c++14 \1 && '
r'%check-cxx-header-in-clang -std=c++17 \1 && '
r'%check-cxx-header-in-clang -std=c++20 \1')))
SubstituteCaptures(r'%check-cxx-header-in-clang -std=c++14 -Wno-padded -Wno-c11-extensions \1 && '
r'%check-cxx-header-in-clang -std=c++17 -Wno-padded -Wno-c11-extensions \1 && '
r'%check-cxx-header-in-clang -std=c++20 -Wno-padded -Wno-c11-extensions \1')))
# Test parsing of the generated C header in different C language modes.
config.substitutions.insert(0, ('%check-interop-c-header-in-clang\(([^)]+)\)',
SubstituteCaptures(r'%check-c-header-in-clang -std=c99 \1 && '
r'%check-c-header-in-clang -std=c11 \1')))
SubstituteCaptures(r'%check-c-header-in-clang -std=c99 -Wno-padded -Wno-c11-extensions \1 && '
r'%check-c-header-in-clang -std=c11 -Wno-padded \1')))

View File

@@ -28,10 +28,12 @@
// CHECK-NEXT: #include <cstdint>
// CHECK-NEXT: #include <cstddef>
// CHECK-NEXT: #include <cstdbool>
// CHECK-NEXT: #include <cstring>
// CHECK-NEXT: #else
// CHECK-NEXT: #include <stdint.h>
// CHECK-NEXT: #include <stddef.h>
// CHECK-NEXT: #include <stdbool.h>
// CHECK-NEXT: #include <string.h>
// CHECK-NEXT: #endif
// CHECK-LABEL: !defined(SWIFT_TYPEDEFS)