[interop][SwiftToCxx] initial generic function support: pass generic parameters

Only primitive types are supported at the moment from C++ as the type traits aren't emitted for all types yet
This commit is contained in:
Alex Lorenz
2022-07-27 18:16:11 +01:00
parent 32f2b71fdf
commit 32723f7e67
18 changed files with 568 additions and 59 deletions

View File

@@ -14,6 +14,7 @@
#define SWIFT_IRGEN_IRABIDETAILSPROVIDER_H
#include "swift/AST/Decl.h"
#include "swift/AST/GenericRequirement.h"
#include "swift/AST/Type.h"
#include "clang/AST/CharUnits.h"
#include "llvm/ADT/MapVector.h"
@@ -49,14 +50,13 @@ public:
/// Information about any ABI additional parameters.
struct ABIAdditionalParam {
enum class ABIParameterRole { Self, Error };
enum class ABIParameterRole { GenericRequirementRole, Self, Error };
ABIParameterRole role;
llvm::Optional<GenericRequirement> genericRequirement;
TypeDecl *type;
};
SmallVector<ABIAdditionalParam, 1> ABIAdditionalParams;
/// Returns the size and alignment for the given type, or \c None if the type
/// is not a fixed layout type.
llvm::Optional<SizeAndAlignment>

View File

@@ -396,11 +396,14 @@ namespace {
unsigned AsyncContextIdx;
unsigned AsyncResumeFunctionSwiftSelfIdx = 0;
FunctionPointerKind FnKind;
bool ShouldComputeABIDetails;
SmallVector<GenericRequirement, 4> GenericRequirements;
SignatureExpansion(IRGenModule &IGM, CanSILFunctionType fnType,
FunctionPointerKind fnKind)
: IGM(IGM), FnType(fnType), FnKind(fnKind) {
}
FunctionPointerKind fnKind,
bool ShouldComputeABIDetails = false)
: IGM(IGM), FnType(fnType), FnKind(fnKind),
ShouldComputeABIDetails(ShouldComputeABIDetails) {}
/// Expand the components of the primary entrypoint of the function type.
void expandFunctionType();
@@ -1628,7 +1631,9 @@ void SignatureExpansion::expandParameters() {
// Next, the generic signature.
if (hasPolymorphicParameters(FnType) &&
!FnKind.shouldSuppressPolymorphicArguments())
expandPolymorphicSignature(IGM, FnType, ParamIRTypes);
expandPolymorphicSignature(IGM, FnType, ParamIRTypes,
ShouldComputeABIDetails ? &GenericRequirements
: nullptr);
// Certain special functions are passed the continuation directly.
if (FnKind.shouldPassContinuationDirectly()) {
@@ -1925,14 +1930,19 @@ Signature SignatureExpansion::getSignature() {
} else {
result.ExtraDataKind = ExtraData::kindForMember<void>();
}
if (ShouldComputeABIDetails)
result.ABIDetails =
SignatureExpansionABIDetails{std::move(GenericRequirements)};
return result;
}
Signature Signature::getUncached(IRGenModule &IGM,
CanSILFunctionType formalType,
FunctionPointerKind fpKind) {
FunctionPointerKind fpKind,
bool shouldComputeABIDetails) {
GenericContextScope scope(IGM, formalType->getInvocationGenericSignature());
SignatureExpansion expansion(IGM, formalType, fpKind);
SignatureExpansion expansion(IGM, formalType, fpKind,
shouldComputeABIDetails);
expansion.expandFunctionType();
return expansion.getSignature();
}

View File

@@ -3459,11 +3459,14 @@ namespace {
ExpandPolymorphicSignature(IRGenModule &IGM, CanSILFunctionType fn)
: PolymorphicConvention(IGM, fn) {}
void expand(SmallVectorImpl<llvm::Type*> &out) {
void expand(SmallVectorImpl<llvm::Type *> &out,
SmallVectorImpl<GenericRequirement> *reqs) {
for (auto &source : getSources())
addEarlySource(source, out);
enumerateUnfulfilledRequirements([&](GenericRequirement reqt) {
if (reqs)
reqs->push_back(reqt);
out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy
: IGM.TypeMetadataPtrTy);
});
@@ -3490,10 +3493,11 @@ namespace {
} // end anonymous namespace
/// Given a generic signature, add the argument types required in order to call it.
void irgen::expandPolymorphicSignature(IRGenModule &IGM,
CanSILFunctionType polyFn,
SmallVectorImpl<llvm::Type*> &out) {
ExpandPolymorphicSignature(IGM, polyFn).expand(out);
void irgen::expandPolymorphicSignature(
IRGenModule &IGM, CanSILFunctionType polyFn,
SmallVectorImpl<llvm::Type *> &out,
SmallVectorImpl<GenericRequirement> *outReqs) {
ExpandPolymorphicSignature(IGM, polyFn).expand(out, outReqs);
}
void irgen::expandTrailingWitnessSignature(IRGenModule &IGM,

View File

@@ -99,9 +99,10 @@ namespace irgen {
/// Add the witness parameters necessary for calling a function with
/// the given generics clause.
void expandPolymorphicSignature(IRGenModule &IGM,
CanSILFunctionType type,
SmallVectorImpl<llvm::Type*> &types);
void expandPolymorphicSignature(
IRGenModule &IGM, CanSILFunctionType type,
SmallVectorImpl<llvm::Type *> &types,
SmallVectorImpl<GenericRequirement> *outReqs = nullptr);
/// Return the number of trailing arguments necessary for calling a
/// witness method.

View File

@@ -148,17 +148,24 @@ public:
auto silFuncType = function->getLoweredFunctionType();
auto funcPointerKind =
FunctionPointerKind(FunctionPointerKind::BasicKind::Function);
auto signature = Signature::getUncached(IGM, silFuncType, funcPointerKind);
auto signature = Signature::getUncached(IGM, silFuncType, funcPointerKind,
/*shouldComputeABIDetail=*/true);
for (const auto &reqt : signature.getABIDetails().GenericRequirements) {
params.push_back({IRABIDetailsProvider::ABIAdditionalParam::
ABIParameterRole::GenericRequirementRole,
reqt, typeConverter.Context.getOpaquePointerDecl()});
}
for (auto attrSet : signature.getAttributes()) {
if (attrSet.hasAttribute(llvm::Attribute::AttrKind::SwiftSelf))
params.push_back(
{IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self,
typeConverter.Context.getOpaquePointerDecl()});
llvm::None, typeConverter.Context.getOpaquePointerDecl()});
if (attrSet.hasAttribute(llvm::Attribute::AttrKind::SwiftError))
params.push_back(
{IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Error,
typeConverter.Context.getOpaquePointerDecl()});
llvm::None, typeConverter.Context.getOpaquePointerDecl()});
}
return params;
}

View File

@@ -18,10 +18,12 @@
#ifndef SWIFT_IRGEN_SIGNATURE_H
#define SWIFT_IRGEN_SIGNATURE_H
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
#include "swift/AST/GenericRequirement.h"
#include "swift/AST/Types.h"
#include "swift/Basic/ExternalUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
namespace llvm {
class FunctionType;
@@ -94,6 +96,12 @@ public:
uint32_t AsyncResumeFunctionSwiftSelfIdx = 0;
};
/// Recorded information about the specific ABI details.
struct SignatureExpansionABIDetails {
/// Generic requirements added to the signature during expansion.
llvm::SmallVector<GenericRequirement, 2> GenericRequirements;
};
/// A signature represents something which can actually be called.
class Signature {
using ExtraData =
@@ -104,6 +112,7 @@ class Signature {
llvm::CallingConv::ID CallingConv;
ExtraData::Kind ExtraDataKind; // packed with above
ExtraData ExtraDataStorage;
llvm::Optional<SignatureExpansionABIDetails> ABIDetails;
static_assert(ExtraData::union_is_trivially_copyable,
"not trivially copyable");
@@ -126,7 +135,8 @@ public:
/// IRGenModule::getSignature(CanSILFunctionType), which is what
/// clients should generally be using.
static Signature getUncached(IRGenModule &IGM, CanSILFunctionType formalType,
FunctionPointerKind kind);
FunctionPointerKind kind,
bool shouldComputeABIDetails = false);
/// Compute the signature of a coroutine's continuation function.
static Signature forCoroutineContinuation(IRGenModule &IGM,
@@ -194,6 +204,11 @@ public:
assert(isValid());
return Attributes;
}
const SignatureExpansionABIDetails &getABIDetails() {
assert(ABIDetails.hasValue());
return *ABIDetails;
}
};
} // end namespace irgen

View File

@@ -608,7 +608,7 @@ private:
}
Type getForeignResultType(AbstractFunctionDecl *AFD,
FunctionType *methodTy,
AnyFunctionType *methodTy,
Optional<ForeignAsyncConvention> asyncConvention,
Optional<ForeignErrorConvention> errorConvention) {
// A foreign error convention can affect the result type as seen in
@@ -950,7 +950,7 @@ private:
}
/// Print C or C++ trailing attributes for a function declaration.
void printFunctionClangAttributes(FuncDecl *FD, FunctionType *funcTy) {
void printFunctionClangAttributes(FuncDecl *FD, AnyFunctionType *funcTy) {
if (funcTy->getResult()->isUninhabited()) {
os << " SWIFT_NORETURN";
} else if (!funcTy->getResult()->isVoid() &&
@@ -1010,15 +1010,21 @@ private:
llvm::SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 2>
&params) {
for (auto param : ABIparams) {
if (param.role ==
IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self)
if (param.role == IRABIDetailsProvider::ABIAdditionalParam::
ABIParameterRole::GenericRequirementRole)
params.push_back({DeclAndTypeClangFunctionPrinter::AdditionalParam::
Role::GenericRequirement,
resultTy->getASTContext().getOpaquePointerType(),
/*isIndirect=*/false, param.genericRequirement});
else if (param.role ==
IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self)
params.push_back(
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Self,
resultTy->getASTContext().getOpaquePointerType(),
/*isIndirect=*/
isa<FuncDecl>(FD) ? cast<FuncDecl>(FD)->isMutating() : false});
if (param.role ==
IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Error)
else if (param.role == IRABIDetailsProvider::ABIAdditionalParam::
ABIParameterRole::Error)
params.push_back(
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Error,
resultTy->getASTContext().getOpaquePointerType()});
@@ -1034,12 +1040,15 @@ private:
FD->getForeignAsyncConvention();
Optional<ForeignErrorConvention> errorConvention =
FD->getForeignErrorConvention();
assert(!FD->getGenericSignature() &&
"top-level generic functions not supported here");
// FIXME (Alex): Make type adjustments for C++.
auto funcTy = givenFuncType
? *givenFuncType
: FD->getInterfaceType()->castTo<FunctionType>();
AnyFunctionType *funcTy;
if (givenFuncType || FD->getInterfaceType()->is<FunctionType>()) {
funcTy = givenFuncType ? *givenFuncType
: FD->getInterfaceType()->castTo<FunctionType>();
} else {
funcTy = FD->getInterfaceType()->castTo<GenericFunctionType>();
}
auto resultTy =
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
@@ -1061,7 +1070,8 @@ private:
/*isIndirect=*/
isa<FuncDecl>(FD) ? cast<FuncDecl>(FD)->isMutating() : false});
}
if (funcTy->isThrowing() && !ABIparams.empty())
// FIXME: Fix the method 'self' parameter.
if (!selfTypeDeclContext && !ABIparams.empty())
convertABIAdditionalParams(FD, resultTy, ABIparams, additionalParams);
funcPrinter.printFunctionSignature(
@@ -1098,13 +1108,10 @@ private:
FD->getForeignAsyncConvention();
Optional<ForeignErrorConvention> errorConvention =
FD->getForeignErrorConvention();
assert(!FD->getGenericSignature() &&
"top-level generic functions not supported here");
auto funcTy = FD->getInterfaceType()->castTo<FunctionType>();
auto funcTy = FD->getInterfaceType()->castTo<AnyFunctionType>();
auto resultTy =
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
os << "inline ";
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.prologueOS,
owningPrinter.typeMapping,
owningPrinter.interopContext);
@@ -1112,12 +1119,14 @@ private:
additionalParams;
auto ABIparams = owningPrinter.interopContext.getIrABIDetails()
.getFunctionABIAdditionalParams(FD);
if (funcTy->isThrowing() && !ABIparams.empty())
if (!ABIparams.empty())
convertABIAdditionalParams(FD, resultTy, ABIparams, additionalParams);
DeclAndTypeClangFunctionPrinter::FunctionSignatureModifiers modifiers;
modifiers.isInline = true;
funcPrinter.printFunctionSignature(
FD, FD->getName().getBaseIdentifier().get(), resultTy,
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CxxInlineThunk);
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CxxInlineThunk,
{}, modifiers);
// FIXME: Support throwing exceptions for Swift errors.
if (!funcTy->isThrowing())
os << " noexcept";
@@ -1126,7 +1135,7 @@ private:
os << " {\n";
funcPrinter.printCxxThunkBody(
funcABI.getSymbolName(), FD->getModuleContext(), resultTy,
FD->getParameters(), additionalParams, funcTy->isThrowing());
FD->getParameters(), additionalParams, funcTy->isThrowing(), funcTy);
os << "}\n";
}

View File

@@ -677,7 +677,8 @@ void swift::printModuleContentsAsCxx(
os << "#ifndef SWIFT_PRINTED_CORE\n";
os << "#define SWIFT_PRINTED_CORE\n";
printSwiftToClangCoreScaffold(interopContext, writer.getTypeMapping(), os);
printSwiftToClangCoreScaffold(interopContext, M.getASTContext(),
writer.getTypeMapping(), os);
os << "#endif\n";
// FIXME: refactor.

View File

@@ -322,6 +322,15 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
emitMacro("SWIFT_INDIRECT_RESULT", "__attribute__((swift_indirect_result))");
emitMacro("SWIFT_CONTEXT", "__attribute__((swift_context))");
emitMacro("SWIFT_ERROR_RESULT", "__attribute__((swift_error_result))");
if (ctx.getStdlibModule()->isStaticLibrary()) {
emitMacro("SWIFT_IMPORT_STDLIB_SYMBOL");
} else {
out << "#if defined(_WIN32)\n";
emitMacro("SWIFT_IMPORT_STDLIB_SYMBOL", "__declspec(dllimport)");
out << "#else\n";
emitMacro("SWIFT_IMPORT_STDLIB_SYMBOL");
out << "#endif\n";
}
// SWIFT_NOEXCEPT applies 'noexcept' in C++ mode only.
emitCxxConditional(
out, [&] { emitMacro("SWIFT_NOEXCEPT", "noexcept"); },

View File

@@ -18,6 +18,7 @@
#include "PrintClangValueType.h"
#include "SwiftToClangInteropContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/GenericParamList.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeVisitor.h"
@@ -217,6 +218,22 @@ public:
return;
}
void visitGenericTypeParamType(GenericTypeParamType *genericTpt,
Optional<OptionalTypeKind> optionalKind,
bool isInOutParam) {
// FIXME: handle optionalKind.
// FIXME: handle isInOutParam.
os << "const ";
if (languageMode == OutputLanguageMode::Cxx) {
// Pass a reference to a template type.
os << genericTpt->getName();
os << " &";
return;
}
// Pass an opaque param in C mode.
os << "void * _Nonnull";
}
void visitPart(Type Ty, Optional<OptionalTypeKind> optionalKind,
bool isInOutParam) {
TypeVisitor::visit(Ty, optionalKind, isInOutParam);
@@ -249,6 +266,25 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
const AbstractFunctionDecl *FD, StringRef name, Type resultTy,
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams,
FunctionSignatureModifiers modifiers) {
if (kind == FunctionSignatureKind::CxxInlineThunk && FD->isGeneric()) {
os << "template<";
llvm::interleaveComma(FD->getGenericParams()->getParams(), os,
[&](const GenericTypeParamDecl *genericParam) {
os << "class ";
ClangSyntaxPrinter(os).printBaseName(genericParam);
});
os << ">\n";
os << "requires ";
llvm::interleave(
FD->getGenericParams()->getParams(), os,
[&](const GenericTypeParamDecl *genericParam) {
os << "swift::isUsableInGenericContext<";
ClangSyntaxPrinter(os).printBaseName(genericParam);
os << ">";
},
" && ");
os << "\n";
}
auto emittedModule = FD->getModuleContext();
OutputLanguageMode outputLang = kind == FunctionSignatureKind::CFunctionProto
? OutputLanguageMode::ObjC
@@ -360,6 +396,11 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
} else if (param.role == AdditionalParam::Role::Error) {
os << "SWIFT_ERROR_RESULT ";
os << "void ** _error";
} else if (param.role == AdditionalParam::Role::GenericRequirement) {
os << "void * _Nonnull ";
if (param.genericRequirement->Protocol)
ClangSyntaxPrinter(os).printBaseName(
param.genericRequirement->Protocol);
}
});
}
@@ -378,6 +419,18 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
auto namePrinter = [&]() { ClangSyntaxPrinter(os).printIdentifier(name); };
if (!isKnownCxxType(type, typeMapping) &&
!hasKnownOptionalNullableCxxMapping(type)) {
if (type->getAs<ArchetypeType>() && type->getAs<ArchetypeType>()
->getInterfaceType()
->is<GenericTypeParamType>()) {
// FIXME: NEED to handle boxed resilient type.
// os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() <<
// "::getOpaquePointer(";
os << "reinterpret_cast<const void *>(&";
namePrinter();
os << ')';
return;
}
if (auto *decl = type->getNominalOrBoundGenericNominal()) {
if ((isa<StructDecl>(decl) || isa<EnumDecl>(decl))) {
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
@@ -407,7 +460,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
StringRef swiftSymbolName, const ModuleDecl *moduleContext, Type resultTy,
const ParameterList *params, ArrayRef<AdditionalParam> additionalParams,
bool hasThrows) {
bool hasThrows, const AnyFunctionType *funcType) {
if (hasThrows) {
os << " void* opaqueError = nullptr;\n";
os << " void* self = nullptr;\n";
@@ -444,18 +497,36 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
if (hasParams)
os << ", ";
interleaveComma(additionalParams, os, [&](const AdditionalParam &param) {
if (param.role == AdditionalParam::Role::Self && !hasThrows)
printCxxToCFunctionParameterUse(
param.type, "*this", moduleContext, /*isInOut=*/false,
/*isIndirect=*/param.isIndirect, param.role);
else if(param.role == AdditionalParam::Role::Self && hasThrows)
printCxxToCFunctionParameterUse(
param.type, "self", moduleContext, /*isInOut=*/false,
/*isIndirect=*/param.isIndirect, param.role);
else if(param.role == AdditionalParam::Role::Error && hasThrows)
printCxxToCFunctionParameterUse(
param.type, "&opaqueError", moduleContext, /*isInOut=*/false,
/*isIndirect=*/param.isIndirect, param.role);
if (param.role == AdditionalParam::Role::GenericRequirement) {
auto genericRequirement = *param.genericRequirement;
// FIXME: Add protocol requirement support.
assert(!genericRequirement.Protocol);
if (auto *gtpt = genericRequirement.TypeParameter
->getAs<GenericTypeParamType>()) {
assert(funcType);
auto *gft = dyn_cast<GenericFunctionType>(funcType);
if (gtpt->getDepth() == 0) {
os << "swift::getTypeMetadata<"
<< gft->getGenericParams()[gtpt->getIndex()]->getName()
<< ">()";
return;
}
}
os << "ERROR";
return;
}
if (param.role == AdditionalParam::Role::Self && !hasThrows)
printCxxToCFunctionParameterUse(
param.type, "*this", moduleContext, /*isInOut=*/false,
/*isIndirect=*/param.isIndirect, param.role);
else if (param.role == AdditionalParam::Role::Self && hasThrows)
printCxxToCFunctionParameterUse(
param.type, "self", moduleContext, /*isInOut=*/false,
/*isIndirect=*/param.isIndirect, param.role);
else if (param.role == AdditionalParam::Role::Error && hasThrows)
printCxxToCFunctionParameterUse(
param.type, "&opaqueError", moduleContext, /*isInOut=*/false,
/*isIndirect=*/param.isIndirect, param.role);
});
}

View File

@@ -14,6 +14,7 @@
#define SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
#include "OutputLanguageMode.h"
#include "swift/AST/GenericRequirement.h"
#include "swift/AST/Type.h"
#include "swift/Basic/LLVM.h"
#include "swift/ClangImporter/ClangImporter.h"
@@ -26,6 +27,7 @@ namespace swift {
class AbstractFunctionDecl;
class AccessorDecl;
class AnyFunctionType;
class FuncDecl;
class ModuleDecl;
class NominalTypeDecl;
@@ -55,12 +57,13 @@ public:
/// Information about any additional parameters.
struct AdditionalParam {
enum class Role { Self, Error };
enum class Role { GenericRequirement, Self, Error };
Role role;
Type type;
// Should self be passed indirectly?
bool isIndirect = false;
llvm::Optional<GenericRequirement> genericRequirement = None;
};
/// Optional modifiers that can be applied to function signature.
@@ -91,7 +94,8 @@ public:
const ModuleDecl *moduleContext, Type resultTy,
const ParameterList *params,
ArrayRef<AdditionalParam> additionalParams = {},
bool hasThrows = false);
bool hasThrows = false,
const AnyFunctionType *funcType = nullptr);
/// Print the Swift method as C++ method declaration/definition, including
/// constructors.

View File

@@ -18,6 +18,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/Type.h"
#include "swift/IRGen/IRABIDetailsProvider.h"
#include "swift/IRGen/Linking.h"
#include "llvm/ADT/STLExtras.h"
using namespace swift;
@@ -231,7 +232,61 @@ void printCxxNaiveException(raw_ostream &os) {
os << "};\n";
}
void printGenericTypeTraits(raw_ostream &os) {
os << "template<class T>\n";
os << "static inline const constexpr bool isUsableInGenericContext = "
"false;\n\n";
os << "template<class T> inline void * _Nonnull getTypeMetadata();\n\n";
}
void printPrimitiveGenericTypeTraits(raw_ostream &os, ASTContext &astContext,
PrimitiveTypeMapping &typeMapping,
bool isCForwardDefinition) {
Type supportedPrimitiveTypes[] = {
astContext.getBoolType(),
// Primitive integer, C integer and Int/UInt mappings.
astContext.getInt8Type(), astContext.getUInt8Type(),
astContext.getInt16Type(), astContext.getUInt16Type(),
astContext.getInt32Type(), astContext.getUInt32Type(),
astContext.getInt64Type(), astContext.getUInt64Type(),
// Primitive floating point type mappings.
astContext.getFloatType(), astContext.getDoubleType(),
// Pointer types.
// FIXME: support raw pointers?
astContext.getOpaquePointerType()};
for (Type type : llvm::makeArrayRef(supportedPrimitiveTypes)) {
auto typeInfo = *typeMapping.getKnownCxxTypeInfo(
type->getNominalOrBoundGenericNominal());
auto typeMetadataFunc = irgen::LinkEntity::forTypeMetadata(
type->getCanonicalType(), irgen::TypeMetadataAddress::AddressPoint);
std::string typeMetadataVarName = typeMetadataFunc.mangleAsString();
if (isCForwardDefinition) {
os << "// type metadata address for " << type.getString() << ".\n";
os << "SWIFT_IMPORT_STDLIB_SYMBOL extern size_t " << typeMetadataVarName
<< ";\n";
continue;
}
os << "template<>\n";
os << "static inline const constexpr bool isUsableInGenericContext<"
<< typeInfo.name << "> = true;\n\n";
os << "template<>\ninline void * _Nonnull getTypeMetadata<";
os << typeInfo.name << ">() {\n";
os << " return &" << cxx_synthesis::getCxxImplNamespaceName()
<< "::" << typeMetadataVarName << ";\n";
os << "}\n\n";
}
}
void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
ASTContext &astContext,
PrimitiveTypeMapping &typeMapping,
raw_ostream &os) {
ClangSyntaxPrinter printer(os);
@@ -242,6 +297,9 @@ void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
printTypeMetadataResponseType(ctx, typeMapping, os);
os << "\n";
printValueWitnessTable(os);
os << "\n";
printPrimitiveGenericTypeTraits(os, astContext, typeMapping,
/*isCForwardDefinition=*/true);
});
os << "\n";
printOpaqueAllocFee(os);
@@ -249,5 +307,13 @@ void swift::printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
printSwiftResilientStorageClass(os);
printCxxNaiveException(os);
});
os << "\n";
// C++ only supports inline variables from C++17.
// FIXME: silence the warning instead?
os << "#if __cplusplus > 201402L\n";
printGenericTypeTraits(os);
printPrimitiveGenericTypeTraits(os, astContext, typeMapping,
/*isCForwardDefinition=*/false);
os << "#endif\n";
});
}

View File

@@ -17,12 +17,14 @@
namespace swift {
class ASTContext;
class PrimitiveTypeMapping;
class SwiftToClangInteropContext;
/// Print out the core declarations required by C/C++ that are part of the core
/// Swift stdlib code.
void printSwiftToClangCoreScaffold(SwiftToClangInteropContext &ctx,
ASTContext &astContext,
PrimitiveTypeMapping &typeMapping,
llvm::raw_ostream &os);

View File

@@ -67,6 +67,31 @@
// CHECK-NEXT: #undef SWIFT_NOEXCEPT_FUNCTION_PTR
// CHECK-EMPTY:
// CHECK-EMPTY:
// CHECK-NEXT: // type metadata address for Bool.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $sSbN;
// CHECK-NEXT: // type metadata address for Int8.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss4Int8VN;
// CHECK-NEXT: // type metadata address for UInt8.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss5UInt8VN;
// CHECK-NEXT: // type metadata address for Int16.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss5Int16VN;
// CHECK-NEXT: // type metadata address for UInt16.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss6UInt16VN;
// CHECK-NEXT: // type metadata address for Int32.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss5Int32VN;
// CHECK-NEXT: // type metadata address for UInt32.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss6UInt32VN;
// CHECK-NEXT: // type metadata address for Int64.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss5Int64VN;
// CHECK-NEXT: // type metadata address for UInt64.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss6UInt64VN;
// CHECK-NEXT: // type metadata address for Float.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $sSfN;
// CHECK-NEXT: // type metadata address for Double.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $sSdN;
// CHECK-NEXT: // type metadata address for OpaquePointer.
// CHECK-NEXT: SWIFT_IMPORT_STDLIB_SYMBOL extern size_t $ss13OpaquePointerVN;
// CHECK-EMPTY:
// CHECK-NEXT: #ifdef __cplusplus
// CHECK-NEXT: }
// CHECK-NEXT: #endif
@@ -122,6 +147,110 @@
// CHECK-NEXT: } // namespace _impl
// CHECK-EMPTY:
// CHECK-EMPTY:
// CHECK-NEXT: #if __cplusplus > 201402L
// CHECK-NEXT: template<class T>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext = false;
// CHECK-EMPTY:
// CHECK-NEXT: template<class T> inline void * _Nonnull getTypeMetadata();
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<bool> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<bool>() {
// CHECK-NEXT: return &_impl::$sSbN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<int8_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<int8_t>() {
// CHECK-NEXT: return &_impl::$ss4Int8VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<uint8_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<uint8_t>() {
// CHECK-NEXT: return &_impl::$ss5UInt8VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<int16_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<int16_t>() {
// CHECK-NEXT: return &_impl::$ss5Int16VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<uint16_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<uint16_t>() {
// CHECK-NEXT: return &_impl::$ss6UInt16VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<int32_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<int32_t>() {
// CHECK-NEXT: return &_impl::$ss5Int32VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<uint32_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<uint32_t>() {
// CHECK-NEXT: return &_impl::$ss6UInt32VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<int64_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<int64_t>() {
// CHECK-NEXT: return &_impl::$ss5Int64VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<uint64_t> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<uint64_t>() {
// CHECK-NEXT: return &_impl::$ss6UInt64VN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<float> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<float>() {
// CHECK-NEXT: return &_impl::$sSfN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<double> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<double>() {
// CHECK-NEXT: return &_impl::$sSdN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<void *> = true;
// CHECK-EMPTY:
// CHECK-NEXT: template<>
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<void *>() {
// CHECK-NEXT: return &_impl::$ss13OpaquePointerVN;
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: #endif
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace swift
// CHECK-EMPTY:
// CHECK-NEXT: #endif

View File

@@ -0,0 +1,19 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %S/generic-function-in-cxx.swift -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
// RUN: %target-interop-build-clangxx -std=gnu++20 -c %s -I %t -o /dev/null -DUSE_TYPE=int
// RUN: not %target-interop-build-clangxx -std=gnu++20 -c %s -I %t -o /dev/null -DUSE_TYPE=CxxStruct
#include <cassert>
#include "functions.h"
struct CxxStruct { int x = 0; };
int main() {
using namespace Functions;
USE_TYPE value = {};
genericPrintFunction(value);
return 0;
}

View File

@@ -0,0 +1,112 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %S/generic-function-in-cxx.swift -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
// RUN: %target-interop-build-clangxx -std=gnu++20 -c %s -I %t -o %t/swift-functions-execution.o
// RUN: %target-interop-build-swift %S/generic-function-in-cxx.swift -o %t/swift-functions-execution -Xlinker %t/swift-functions-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain
// RUN: %target-codesign %t/swift-functions-execution
// RUN: %target-run %t/swift-functions-execution | %FileCheck %s
// REQUIRES: executable_test
#include <cassert>
#include "functions.h"
int main() {
using namespace Functions;
static_assert(noexcept(genericPrintFunctionTwoArg<int>(0, 0)), "noexcept function");
{
int i = 2;
genericPrintFunctionTwoArg(i, 3);
// CHECK: X: 2
// CHECK-NEXT: Y: 3
}
{
int8_t x = -1;
genericPrintFunction(x);
// CHECK-NEXT: Int8 value=-1
}
{
uint8_t x = 0xff;
genericPrintFunction(x);
// CHECK-NEXT: UInt8 value=255
}
{
int16_t x = -9856;
genericPrintFunction(x);
// CHECK-NEXT: Int16 value=-9856
}
{
uint16_t x = 3248;
genericPrintFunction(x);
// CHECK-NEXT: UInt16 value=3248
}
{
int32_t x = -0x12343;
genericPrintFunction(x);
// CHECK-NEXT: Int32 value=-74563
}
{
uint32_t x = 0xC0011334;
genericPrintFunction(x);
// CHECK-NEXT: UInt32 value=3221295924
}
{
int64_t x = -123456789123;
genericPrintFunction(x);
// CHECK-NEXT: Int64 value=-123456789123
}
{
uint64_t x = 0x12345678abcd1234;
genericPrintFunction(x);
// CHECK-NEXT: UInt64 value=1311768467750064692
}
{
float x = -54.0f;
genericPrintFunction(x);
// CHECK-NEXT: Float value=-54.0
}
{
double x = 1.25;
genericPrintFunction(x);
// CHECK-NEXT: Double value=1.25
}
{
bool x = true;
genericPrintFunction(x);
// CHECK-NEXT: Bool value=true
}
{
int i = 0;
void *x = &i;
genericPrintFunction(x);
// CHECK-NEXT: OpaquePointer value
}
{
int i = 55;
int j = 66;
bool x = false;
genericPrintFunctionMultiGeneric<int, bool>(-78, i, j, 45, x);
// CHECK-NEXT: Int32 value 1=55
// CHECK-NEXT: Int32 value 2=66
// CHECK-NEXT: Bool value 1=false
// CHECK-NEXT: other values=-78,45
}
return 0;
}

View File

@@ -0,0 +1,46 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
// RUN: %FileCheck %s < %t/functions.h
// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h)
public func genericPrintFunctionTwoArg<T>(_ x: T, _ y: Int) {
print("X:", x)
print("Y:", y)
}
public func genericPrintFunction<T>(_ x: T) {
print("\(T.self) value=\(x)")
}
public func genericPrintFunctionMultiGeneric<T1, T2>(_ x: Int, _ t1: T1, _ t1p: T1, _ y: Int, _ t2: T2) {
print("\(T1.self) value 1=\(t1)")
print("\(T1.self) value 2=\(t1p)")
print("\(T2.self) value 1=\(t2)")
print("other values=\(x),\(y)")
}
// CHECK: SWIFT_EXTERN void $s9Functions20genericPrintFunctionyyxlF(const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunction(_:)
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(ptrdiff_t x, const void * _Nonnull t1, const void * _Nonnull t1p, ptrdiff_t y, const void * _Nonnull t2, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionMultiGeneric(_:_:_:_:_:)
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions26genericPrintFunctionTwoArgyyx_SitlF(const void * _Nonnull x, ptrdiff_t y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionTwoArg(_:_:)
// CHECK: template<class T>
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
// CHECK-NEXT: inline void genericPrintFunction(const T & x) noexcept {
// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(reinterpret_cast<const void *>(&x), swift::getTypeMetadata<T>());
// CHECK-NEXT: }
// CHECK: template<class T1, class T2>
// CHECK-NEXT: requires swift::isUsableInGenericContext<T1> && swift::isUsableInGenericContext<T2>
// CHECK-NEXT: inline void genericPrintFunctionMultiGeneric(swift::Int x, const T1 & t1, const T1 & t1p, swift::Int y, const T2 & t2) noexcept {
// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, reinterpret_cast<const void *>(&t1), reinterpret_cast<const void *>(&t1p), y, reinterpret_cast<const void *>(&t2), swift::getTypeMetadata<T1>(), swift::getTypeMetadata<T2>());
// CHECK-NEXT: }
// CHECK: template<class T>
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
// CHECK-NEXT: inline void genericPrintFunctionTwoArg(const T & x, swift::Int y) noexcept {
// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(reinterpret_cast<const void *>(&x), y, swift::getTypeMetadata<T>());
// CHECK-NEXT: }

View File

@@ -33,6 +33,10 @@ config.substitutions.insert(0, ('%check-interop-cxx-header-in-clang\(([^)]+)\)',
r'%check-cxx-header-in-clang -std=c++17 -Wno-padded -Wno-c11-extensions -D_LIBCPP_CSTDLIB \1 && '
r'%check-cxx-header-in-clang -std=c++20 -Wno-padded -Wno-c11-extensions -D_LIBCPP_CSTDLIB \1')))
# Test parsing of the generated C++ header in different C++ language modes (with C++20 concepts support).
config.substitutions.insert(0, ('%check-generic-interop-cxx-header-in-clang\(([^)]+)\)',
SubstituteCaptures(r'%check-cxx-header-in-clang -std=c++20 -Wno-padded -Wno-c11-extensions -D_LIBCPP_CSTDLIB \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 -Wno-padded -Wno-c11-extensions \1 && '