mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
¶ms) {
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"); },
|
||||
|
||||
@@ -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 ¶m) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
112
test/Interop/SwiftToCxx/generics/generic-function-execution.cpp
Normal file
112
test/Interop/SwiftToCxx/generics/generic-function-execution.cpp
Normal 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;
|
||||
}
|
||||
@@ -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: }
|
||||
@@ -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 && '
|
||||
|
||||
Reference in New Issue
Block a user