mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[interop][SwiftToCxx] emit instance property getters for structs
This commit is contained in:
@@ -109,6 +109,8 @@ class DeclAndTypePrinter::Implementation
|
||||
|
||||
SmallVector<const FunctionType *, 4> openFunctionTypes;
|
||||
|
||||
std::string outOfLineDefinitions;
|
||||
|
||||
ASTContext &getASTContext() const {
|
||||
return owningPrinter.M.getASTContext();
|
||||
}
|
||||
@@ -211,6 +213,7 @@ private:
|
||||
template <bool AllowDelayed = false, typename R>
|
||||
void printMembers(R &&members) {
|
||||
bool protocolMembersOptional = false;
|
||||
assert(outOfLineDefinitions.empty());
|
||||
for (const Decl *member : members) {
|
||||
auto VD = dyn_cast<ValueDecl>(member);
|
||||
if (!VD || !shouldInclude(VD) || isa<TypeDecl>(VD))
|
||||
@@ -226,6 +229,9 @@ private:
|
||||
protocolMembersOptional = !protocolMembersOptional;
|
||||
os << (protocolMembersOptional ? "@optional\n" : "@required\n");
|
||||
}
|
||||
// Limit C++ decls for now.
|
||||
if (outputLang == OutputLanguageMode::Cxx && !isa<VarDecl>(VD))
|
||||
continue;
|
||||
ASTVisitor::visit(const_cast<ValueDecl*>(VD));
|
||||
}
|
||||
}
|
||||
@@ -336,7 +342,10 @@ private:
|
||||
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
|
||||
owningPrinter.typeMapping,
|
||||
owningPrinter.interopContext);
|
||||
printer.printValueTypeDecl(SD);
|
||||
printer.printValueTypeDecl(
|
||||
SD, /*bodyPrinter=*/[&]() { printMembers(SD->getMembers()); });
|
||||
os << outOfLineDefinitions;
|
||||
outOfLineDefinitions.clear();
|
||||
}
|
||||
|
||||
void visitExtensionDecl(ExtensionDecl *ED) {
|
||||
@@ -514,6 +523,45 @@ private:
|
||||
bool isClassMethod,
|
||||
bool isNSUIntegerSubscript = false) {
|
||||
printDocumentationComment(AFD);
|
||||
|
||||
Optional<ForeignAsyncConvention> asyncConvention =
|
||||
AFD->getForeignAsyncConvention();
|
||||
Optional<ForeignErrorConvention> errorConvention =
|
||||
AFD->getForeignErrorConvention();
|
||||
Type rawMethodTy = AFD->getMethodInterfaceType();
|
||||
auto methodTy = rawMethodTy->castTo<FunctionType>();
|
||||
auto resultTy =
|
||||
getForeignResultType(AFD, methodTy, asyncConvention, errorConvention);
|
||||
|
||||
if (outputLang == OutputLanguageMode::Cxx) {
|
||||
auto *typeDeclContext = cast<NominalTypeDecl>(AFD->getParent());
|
||||
|
||||
std::string cFuncDecl;
|
||||
llvm::raw_string_ostream cFuncPrologueOS(cFuncDecl);
|
||||
auto funcABI = Implementation(cFuncPrologueOS, owningPrinter, outputLang)
|
||||
.printSwiftABIFunctionSignatureAsCxxFunction(
|
||||
AFD, methodTy,
|
||||
/*selfTypeDeclContext=*/typeDeclContext);
|
||||
owningPrinter.prologueOS << cFuncPrologueOS.str();
|
||||
|
||||
DeclAndTypeClangFunctionPrinter declPrinter(os, owningPrinter.prologueOS,
|
||||
owningPrinter.typeMapping,
|
||||
owningPrinter.interopContext);
|
||||
declPrinter.printCxxPropertyAccessorMethod(
|
||||
typeDeclContext, AFD, funcABI.getSymbolName(), resultTy,
|
||||
/*isDefinition=*/false);
|
||||
|
||||
llvm::raw_string_ostream defOS(outOfLineDefinitions);
|
||||
DeclAndTypeClangFunctionPrinter defPrinter(
|
||||
defOS, owningPrinter.prologueOS, owningPrinter.typeMapping,
|
||||
owningPrinter.interopContext);
|
||||
defPrinter.printCxxPropertyAccessorMethod(
|
||||
typeDeclContext, AFD, funcABI.getSymbolName(), resultTy,
|
||||
/*isDefinition=*/true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isClassMethod)
|
||||
os << "+ (";
|
||||
else
|
||||
@@ -527,15 +575,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
Optional<ForeignAsyncConvention> asyncConvention
|
||||
= AFD->getForeignAsyncConvention();
|
||||
Optional<ForeignErrorConvention> errorConvention
|
||||
= AFD->getForeignErrorConvention();
|
||||
Type rawMethodTy = AFD->getMethodInterfaceType();
|
||||
auto methodTy = rawMethodTy->castTo<FunctionType>();
|
||||
auto resultTy = getForeignResultType(
|
||||
AFD, methodTy, asyncConvention, errorConvention);
|
||||
|
||||
// Constructors and methods returning DynamicSelf return
|
||||
// instancetype.
|
||||
if (isa<ConstructorDecl>(AFD) ||
|
||||
@@ -796,7 +835,8 @@ private:
|
||||
}
|
||||
|
||||
struct FuncionSwiftABIInformation {
|
||||
FuncionSwiftABIInformation(FuncDecl *FD, Mangle::ASTMangler &mangler) {
|
||||
FuncionSwiftABIInformation(AbstractFunctionDecl *FD,
|
||||
Mangle::ASTMangler &mangler) {
|
||||
isCDecl = FD->getAttrs().hasAttribute<CDeclAttr>();
|
||||
if (!isCDecl) {
|
||||
auto mangledName = mangler.mangleAnyDecl(FD, /*prefix=*/true);
|
||||
@@ -818,8 +858,9 @@ private:
|
||||
};
|
||||
|
||||
// Print out the extern C Swift ABI function signature.
|
||||
FuncionSwiftABIInformation
|
||||
printSwiftABIFunctionSignatureAsCxxFunction(FuncDecl *FD) {
|
||||
FuncionSwiftABIInformation printSwiftABIFunctionSignatureAsCxxFunction(
|
||||
AbstractFunctionDecl *FD, Optional<FunctionType *> givenFuncType = None,
|
||||
Optional<NominalTypeDecl *> selfTypeDeclContext = None) {
|
||||
assert(outputLang == OutputLanguageMode::Cxx);
|
||||
Optional<ForeignAsyncConvention> asyncConvention =
|
||||
FD->getForeignAsyncConvention();
|
||||
@@ -828,7 +869,9 @@ private:
|
||||
assert(!FD->getGenericSignature() &&
|
||||
"top-level generic functions not supported here");
|
||||
// FIXME (Alex): Make type adjustments for C++.
|
||||
auto funcTy = FD->getInterfaceType()->castTo<FunctionType>();
|
||||
auto funcTy = givenFuncType
|
||||
? *givenFuncType
|
||||
: FD->getInterfaceType()->castTo<FunctionType>();
|
||||
auto resultTy =
|
||||
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
|
||||
|
||||
@@ -840,9 +883,17 @@ private:
|
||||
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.prologueOS,
|
||||
owningPrinter.typeMapping,
|
||||
owningPrinter.interopContext);
|
||||
llvm::SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 1>
|
||||
additionalParams;
|
||||
if (selfTypeDeclContext) {
|
||||
additionalParams.push_back(
|
||||
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Self,
|
||||
(*selfTypeDeclContext)->getDeclaredType()});
|
||||
}
|
||||
funcPrinter.printFunctionSignature(
|
||||
FD, funcABI.getSymbolName(), resultTy,
|
||||
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CFunctionProto);
|
||||
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CFunctionProto,
|
||||
additionalParams);
|
||||
// Swift functions can't throw exceptions, we can only
|
||||
// throw them from C++ when emitting C++ inline thunks for the Swift
|
||||
// functions.
|
||||
@@ -1186,6 +1237,17 @@ private:
|
||||
assert(VD->getDeclContext()->isTypeContext() &&
|
||||
"cannot handle global variables right now");
|
||||
|
||||
if (outputLang == OutputLanguageMode::Cxx) {
|
||||
// FIXME: Documentation.
|
||||
// FIXME: availability.
|
||||
// FIXME: support static properties.
|
||||
if (VD->isStatic())
|
||||
return;
|
||||
auto *getter = VD->getOpaqueAccessor(AccessorKind::Get);
|
||||
printAbstractFunctionAsMethod(getter, /*isStatic=*/false);
|
||||
return;
|
||||
}
|
||||
|
||||
printDocumentationComment(VD);
|
||||
|
||||
if (VD->isStatic()) {
|
||||
|
||||
@@ -662,8 +662,9 @@ void swift::printModuleContentsAsCxx(
|
||||
std::string modulePrologueBuf;
|
||||
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
|
||||
|
||||
// FIXME: Use getRequiredAccess once @expose is supported.
|
||||
ModuleWriter writer(moduleOS, prologueOS, imports, M, interopContext,
|
||||
getRequiredAccess(M), OutputLanguageMode::Cxx);
|
||||
AccessLevel::Public, OutputLanguageMode::Cxx);
|
||||
writer.write();
|
||||
|
||||
os << "#ifndef SWIFT_PRINTED_CORE\n";
|
||||
|
||||
@@ -317,6 +317,7 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
|
||||
};
|
||||
emitMacro("SWIFT_CALL", "__attribute__((swiftcall))");
|
||||
emitMacro("SWIFT_INDIRECT_RESULT", "__attribute__((swift_indirect_result))");
|
||||
emitMacro("SWIFT_CONTEXT", "__attribute__((swift_context))");
|
||||
// SWIFT_NOEXCEPT applies 'noexcept' in C++ mode only.
|
||||
emitCxxConditional(
|
||||
out, [&] { emitMacro("SWIFT_NOEXCEPT", "noexcept"); },
|
||||
|
||||
@@ -59,6 +59,12 @@ bool isKnownCType(Type t, PrimitiveTypeMapping &typeMapping) {
|
||||
return isKnownType(t, typeMapping, OutputLanguageMode::ObjC);
|
||||
}
|
||||
|
||||
struct CFunctionSignatureTypePrinterModifierDelegate {
|
||||
/// Prefix the indirect value type param being printed in C mode.
|
||||
Optional<llvm::function_ref<void(raw_ostream &)>>
|
||||
prefixIndirectParamValueTypeInC = None;
|
||||
};
|
||||
|
||||
// Prints types in the C function signature that corresponds to the
|
||||
// native Swift function/method.
|
||||
class CFunctionSignatureTypePrinter
|
||||
@@ -66,15 +72,17 @@ class CFunctionSignatureTypePrinter
|
||||
Optional<OptionalTypeKind>, bool>,
|
||||
private ClangSyntaxPrinter {
|
||||
public:
|
||||
CFunctionSignatureTypePrinter(raw_ostream &os, raw_ostream &cPrologueOS,
|
||||
PrimitiveTypeMapping &typeMapping,
|
||||
OutputLanguageMode languageMode,
|
||||
CFunctionSignatureTypePrinter(
|
||||
raw_ostream &os, raw_ostream &cPrologueOS,
|
||||
PrimitiveTypeMapping &typeMapping, OutputLanguageMode languageMode,
|
||||
SwiftToClangInteropContext &interopContext,
|
||||
CFunctionSignatureTypePrinterModifierDelegate modifiersDelegate,
|
||||
FunctionSignatureTypeUse typeUseKind =
|
||||
FunctionSignatureTypeUse::ParamType)
|
||||
: ClangSyntaxPrinter(os), cPrologueOS(cPrologueOS),
|
||||
typeMapping(typeMapping), interopContext(interopContext),
|
||||
languageMode(languageMode), typeUseKind(typeUseKind) {}
|
||||
languageMode(languageMode), modifiersDelegate(modifiersDelegate),
|
||||
typeUseKind(typeUseKind) {}
|
||||
|
||||
bool printIfKnownSimpleType(const TypeDecl *typeDecl,
|
||||
Optional<OptionalTypeKind> optionalKind,
|
||||
@@ -128,6 +136,8 @@ public:
|
||||
if (typeUseKind == FunctionSignatureTypeUse::ParamType) {
|
||||
if (languageMode != OutputLanguageMode::Cxx &&
|
||||
interopContext.getIrABIDetails().shouldPassIndirectly(ST)) {
|
||||
if (modifiersDelegate.prefixIndirectParamValueTypeInC)
|
||||
(*modifiersDelegate.prefixIndirectParamValueTypeInC)(os);
|
||||
// FIXME: it would be nice to print out the C struct type here.
|
||||
if (isInOutParam) {
|
||||
os << "void * _Nonnull";
|
||||
@@ -154,23 +164,27 @@ private:
|
||||
PrimitiveTypeMapping &typeMapping;
|
||||
SwiftToClangInteropContext &interopContext;
|
||||
OutputLanguageMode languageMode;
|
||||
CFunctionSignatureTypePrinterModifierDelegate modifiersDelegate;
|
||||
FunctionSignatureTypeUse typeUseKind;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
FuncDecl *FD, StringRef name, Type resultTy, FunctionSignatureKind kind) {
|
||||
AbstractFunctionDecl *FD, StringRef name, Type resultTy,
|
||||
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams) {
|
||||
OutputLanguageMode outputLang = kind == FunctionSignatureKind::CFunctionProto
|
||||
? OutputLanguageMode::ObjC
|
||||
: OutputLanguageMode::Cxx;
|
||||
// FIXME: Might need a PrintMultiPartType here.
|
||||
auto print = [&, this](Type ty, Optional<OptionalTypeKind> optionalKind,
|
||||
StringRef name, bool isInOutParam) {
|
||||
auto print =
|
||||
[&, this](Type ty, Optional<OptionalTypeKind> optionalKind,
|
||||
StringRef name, bool isInOutParam,
|
||||
CFunctionSignatureTypePrinterModifierDelegate delegate = {}) {
|
||||
// FIXME: add support for noescape and PrintMultiPartType,
|
||||
// see DeclAndTypePrinter::print.
|
||||
CFunctionSignatureTypePrinter typePrinter(os, cPrologueOS, typeMapping,
|
||||
outputLang, interopContext);
|
||||
CFunctionSignatureTypePrinter typePrinter(
|
||||
os, cPrologueOS, typeMapping, outputLang, interopContext, delegate);
|
||||
typePrinter.visit(ty, optionalKind, isInOutParam);
|
||||
|
||||
if (!name.empty()) {
|
||||
@@ -191,6 +205,7 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
|
||||
CFunctionSignatureTypePrinter typePrinter(
|
||||
os, cPrologueOS, typeMapping, outputLang, interopContext,
|
||||
CFunctionSignatureTypePrinterModifierDelegate(),
|
||||
FunctionSignatureTypeUse::ReturnType);
|
||||
// Param for indirect return cannot be marked as inout
|
||||
typePrinter.visit(objTy, retKind, /*isInOutParam=*/false);
|
||||
@@ -213,6 +228,7 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
if (params->size()) {
|
||||
if (HasParams)
|
||||
os << ", ";
|
||||
HasParams = true;
|
||||
size_t paramIndex = 1;
|
||||
llvm::interleaveComma(*params, os, [&](const ParamDecl *param) {
|
||||
OptionalTypeKind argKind;
|
||||
@@ -231,7 +247,23 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
print(objTy, argKind, paramName, param->isInOut());
|
||||
++paramIndex;
|
||||
});
|
||||
} else if (kind == FunctionSignatureKind::CFunctionProto && !HasParams) {
|
||||
}
|
||||
if (additionalParams.size()) {
|
||||
assert(kind == FunctionSignatureKind::CFunctionProto);
|
||||
if (HasParams)
|
||||
os << ", ";
|
||||
HasParams = true;
|
||||
interleaveComma(additionalParams, os, [&](const AdditionalParam ¶m) {
|
||||
assert(param.role == AdditionalParam::Role::Self);
|
||||
CFunctionSignatureTypePrinterModifierDelegate delegate;
|
||||
delegate.prefixIndirectParamValueTypeInC = [](raw_ostream &os) {
|
||||
os << "SWIFT_CONTEXT ";
|
||||
};
|
||||
print(param.type, OptionalTypeKind::OTK_None, "_self", /*isInOut*/ false,
|
||||
delegate);
|
||||
});
|
||||
}
|
||||
if (kind == FunctionSignatureKind::CFunctionProto && !HasParams) {
|
||||
// Emit 'void' in an empty parameter list for C function declarations.
|
||||
os << "void";
|
||||
}
|
||||
@@ -239,27 +271,35 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
|
||||
}
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
|
||||
const ParamDecl *param, StringRef name) {
|
||||
Type type, StringRef name, bool isInOut,
|
||||
llvm::Optional<AdditionalParam::Role> paramRole) {
|
||||
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, param->isInOut());
|
||||
structDecl, namePrinter, isInOut,
|
||||
/*isSelf=*/paramRole &&
|
||||
*paramRole == AdditionalParam::Role::Self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Primitive types are passed directly without any conversions.
|
||||
if (param->isInOut()) {
|
||||
if (isInOut) {
|
||||
os << "&";
|
||||
}
|
||||
namePrinter();
|
||||
}
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
|
||||
const ParamDecl *param, StringRef name) {
|
||||
printCxxToCFunctionParameterUse(param->getType(), name, param->isInOut());
|
||||
}
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
|
||||
StringRef swiftSymbolName, Type resultTy, ParameterList *params) {
|
||||
StringRef swiftSymbolName, Type resultTy, const ParameterList *params,
|
||||
ArrayRef<AdditionalParam> additionalParams) {
|
||||
auto printCallToCFunc = [&](Optional<StringRef> additionalParam) {
|
||||
os << cxx_synthesis::getCxxImplNamespaceName() << "::" << swiftSymbolName
|
||||
<< '(';
|
||||
@@ -287,6 +327,16 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
|
||||
});
|
||||
}
|
||||
|
||||
if (additionalParams.size()) {
|
||||
if (hasParams)
|
||||
os << ", ";
|
||||
interleaveComma(additionalParams, os, [&](const AdditionalParam ¶m) {
|
||||
assert(param.role == AdditionalParam::Role::Self);
|
||||
printCxxToCFunctionParameterUse(param.type, "*this", /*isInOut=*/false,
|
||||
param.role);
|
||||
});
|
||||
}
|
||||
|
||||
os << ')';
|
||||
};
|
||||
|
||||
@@ -316,3 +366,47 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
|
||||
printCallToCFunc(/*additionalParam=*/None);
|
||||
os << ";\n";
|
||||
}
|
||||
|
||||
void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
|
||||
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
|
||||
StringRef swiftSymbolName, Type resultTy, bool isDefinition) {
|
||||
assert(FD->getParameters()->size() == 0);
|
||||
os << " inline ";
|
||||
|
||||
OptionalTypeKind retKind;
|
||||
Type objTy;
|
||||
std::tie(objTy, retKind) =
|
||||
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
|
||||
CFunctionSignatureTypePrinter typePrinter(
|
||||
os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx, interopContext,
|
||||
CFunctionSignatureTypePrinterModifierDelegate(),
|
||||
FunctionSignatureTypeUse::ReturnType);
|
||||
typePrinter.visit(objTy, retKind, /*isInOut=*/false);
|
||||
|
||||
ClangSyntaxPrinter printer(os);
|
||||
os << ' ';
|
||||
if (isDefinition) {
|
||||
// FIXME: Full qualifiers for nested types?
|
||||
printer.printBaseName(typeDeclContext);
|
||||
os << "::";
|
||||
}
|
||||
|
||||
StringRef name;
|
||||
auto accessor = cast<AccessorDecl>(FD);
|
||||
// For a getter or setter, go through the variable or subscript decl.
|
||||
name = accessor->getStorage()->getBaseIdentifier().str();
|
||||
|
||||
// FIXME: some names are remapped differently. (e.g. isX).
|
||||
os << "get" << char(std::toupper(name[0])) << name.drop_front();
|
||||
os << "() const";
|
||||
if (!isDefinition) {
|
||||
os << ";\n";
|
||||
return;
|
||||
}
|
||||
os << " {\n";
|
||||
// FIXME: should it be objTy for resultTy?
|
||||
printCxxThunkBody(swiftSymbolName, resultTy, FD->getParameters(),
|
||||
{AdditionalParam{AdditionalParam::Role::Self,
|
||||
typeDeclContext->getDeclaredType()}});
|
||||
os << " }\n";
|
||||
}
|
||||
|
||||
@@ -15,12 +15,16 @@
|
||||
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/Basic/LLVM.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace swift {
|
||||
|
||||
class AbstractFunctionDecl;
|
||||
class FuncDecl;
|
||||
class NominalTypeDecl;
|
||||
class ParamDecl;
|
||||
class ParameterList;
|
||||
class PrimitiveTypeMapping;
|
||||
@@ -45,10 +49,19 @@ public:
|
||||
CxxInlineThunk
|
||||
};
|
||||
|
||||
/// Information about any additional parameters.
|
||||
struct AdditionalParam {
|
||||
enum class Role { Self };
|
||||
|
||||
Role role;
|
||||
Type type;
|
||||
};
|
||||
|
||||
/// Print the C function declaration or the C++ function thunk that
|
||||
/// corresponds to the given function declaration.
|
||||
void printFunctionSignature(FuncDecl *FD, StringRef name, Type resultTy,
|
||||
FunctionSignatureKind kind);
|
||||
void printFunctionSignature(AbstractFunctionDecl *FD, StringRef name,
|
||||
Type resultTy, FunctionSignatureKind kind,
|
||||
ArrayRef<AdditionalParam> additionalParams = {});
|
||||
|
||||
/// Print the use of the C++ function thunk parameter as it's passed to the C
|
||||
/// function declaration.
|
||||
@@ -57,9 +70,20 @@ public:
|
||||
/// Print the body of the inline C++ function thunk that calls the underlying
|
||||
/// Swift function.
|
||||
void printCxxThunkBody(StringRef swiftSymbolName, Type resultTy,
|
||||
ParameterList *params);
|
||||
const ParameterList *params,
|
||||
ArrayRef<AdditionalParam> additionalParams = {});
|
||||
|
||||
/// Print the C++ getter/setter method signature.
|
||||
void printCxxPropertyAccessorMethod(const NominalTypeDecl *typeDeclContext,
|
||||
const AbstractFunctionDecl *FD,
|
||||
StringRef swiftSymbolName, Type resultTy,
|
||||
bool isDefinition);
|
||||
|
||||
private:
|
||||
void printCxxToCFunctionParameterUse(
|
||||
Type type, StringRef name, bool isInOut,
|
||||
llvm::Optional<AdditionalParam::Role> paramRole = None);
|
||||
|
||||
raw_ostream &os;
|
||||
raw_ostream &cPrologueOS;
|
||||
PrimitiveTypeMapping &typeMapping;
|
||||
|
||||
@@ -74,7 +74,8 @@ void printCTypeMetadataTypeFunction(raw_ostream &os,
|
||||
}
|
||||
|
||||
void ClangValueTypePrinter::printValueTypeDecl(
|
||||
const NominalTypeDecl *typeDecl) {
|
||||
const NominalTypeDecl *typeDecl,
|
||||
llvm::function_ref<void(void)> bodyPrinter) {
|
||||
auto typeSizeAlign =
|
||||
interopContext.getIrABIDetails().getTypeSizeAlignment(typeDecl);
|
||||
if (!typeSizeAlign) {
|
||||
@@ -148,7 +149,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
|
||||
printer.printBaseName(typeDecl);
|
||||
os << " &&) = default;\n";
|
||||
|
||||
// FIXME: Print the other members of the struct.
|
||||
bodyPrinter();
|
||||
|
||||
os << "private:\n";
|
||||
|
||||
// Print out private default constructor.
|
||||
@@ -311,7 +313,7 @@ void ClangValueTypePrinter::printValueTypeParameterType(
|
||||
|
||||
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
|
||||
bool isIndirect, const NominalTypeDecl *type,
|
||||
llvm::function_ref<void()> cxxParamPrinter, bool isInOut) {
|
||||
llvm::function_ref<void()> cxxParamPrinter, bool isInOut, bool isSelf) {
|
||||
// A Swift value type is passed to its underlying Swift function
|
||||
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
|
||||
if (!isIndirect && !isInOut) {
|
||||
@@ -320,11 +322,15 @@ void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
|
||||
printCTypeName(os, type);
|
||||
os << '(';
|
||||
}
|
||||
if (isSelf) {
|
||||
os << "_getOpaquePointer()";
|
||||
} else {
|
||||
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
|
||||
printCxxImplClassName(os, type);
|
||||
os << "::getOpaquePointer(";
|
||||
cxxParamPrinter();
|
||||
os << ')';
|
||||
}
|
||||
if (!isIndirect && !isInOut) {
|
||||
os << ')';
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "OutputLanguageMode.h"
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/Basic/LLVM.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace swift {
|
||||
@@ -37,7 +38,8 @@ public:
|
||||
|
||||
/// Print the C++ class definition that
|
||||
/// corresponds to the given structure or enum declaration.
|
||||
void printValueTypeDecl(const NominalTypeDecl *typeDecl);
|
||||
void printValueTypeDecl(const NominalTypeDecl *typeDecl,
|
||||
llvm::function_ref<void(void)> bodyPrinter);
|
||||
|
||||
/// Print the pararameter type that referes to a Swift struct type in C/C++.
|
||||
void printValueTypeParameterType(const NominalTypeDecl *type,
|
||||
@@ -49,7 +51,7 @@ public:
|
||||
void
|
||||
printParameterCxxToCUseScaffold(bool isIndirect, const NominalTypeDecl *type,
|
||||
llvm::function_ref<void()> cxxParamPrinter,
|
||||
bool isInOut);
|
||||
bool isInOut, bool isSelf);
|
||||
|
||||
/// Print the return type that refers to a Swift struct type in C/C++.
|
||||
void printValueTypeReturnType(const NominalTypeDecl *typeDecl,
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
// CHECK: SWIFT_EXTERN void $s9Functions19testKeywordArgument8registerySi_tF(ptrdiff_t register_) SWIFT_NOEXCEPT SWIFT_CALL;
|
||||
|
||||
func testKeywordArgument(register: Int) { }
|
||||
public func testKeywordArgument(register: Int) { }
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
// CHECK: inline void testKeywordArgument(swift::Int register_) noexcept
|
||||
// CHECK-NEXT: return _impl::$s9Functions19testKeywordArgument8registerySi_tF(register_);
|
||||
|
||||
func testKeywordArgument(register: Int) {
|
||||
public func testKeywordArgument(register: Int) {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// RUN: %target-swift-frontend %S/getter-in-cxx.swift -typecheck -module-name Properties -clang-header-expose-public-decls -emit-clang-header-path %t/properties.h
|
||||
|
||||
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-props-execution.o
|
||||
// RUN: %target-interop-build-swift %S/getter-in-cxx.swift -o %t/swift-props-execution -Xlinker %t/swift-props-execution.o -module-name Properties -Xfrontend -entry-point-function-name -Xfrontend swiftMain
|
||||
|
||||
// RUN: %target-codesign %t/swift-props-execution
|
||||
// RUN: %target-run %t/swift-props-execution | %FileCheck %s
|
||||
|
||||
// REQUIRES: executable_test
|
||||
|
||||
#include <assert.h>
|
||||
#include "properties.h"
|
||||
|
||||
int main() {
|
||||
using namespace Properties;
|
||||
|
||||
auto smallStructWithGetter = createSmallStructWithGetter();
|
||||
assert(smallStructWithGetter.getStoredInt() == 21);
|
||||
assert(smallStructWithGetter.getComputedInt() == 23);
|
||||
|
||||
auto largeStruct = smallStructWithGetter.getLargeStruct();
|
||||
assert(largeStruct.getX1() == 46);
|
||||
assert(largeStruct.getX2() == 1);
|
||||
assert(largeStruct.getX3() == 2);
|
||||
assert(largeStruct.getX4() == 3);
|
||||
assert(largeStruct.getX5() == 4);
|
||||
assert(largeStruct.getX6() == 5);
|
||||
|
||||
auto largeStruct2 = largeStruct.getAnotherLargeStruct();
|
||||
assert(largeStruct2.getX1() == 11);
|
||||
assert(largeStruct2.getX2() == 42);
|
||||
assert(largeStruct2.getX3() == -0xFFF);
|
||||
assert(largeStruct2.getX4() == 0xbad);
|
||||
assert(largeStruct2.getX5() == 5);
|
||||
assert(largeStruct2.getX6() == 0);
|
||||
|
||||
auto firstSmallStruct = largeStruct.getFirstSmallStruct();
|
||||
assert(firstSmallStruct.getX() == 65);
|
||||
|
||||
auto smallStruct2 = smallStructWithGetter.getSmallStruct();
|
||||
assert(smallStruct2.getStoredInt() == 0xFAE);
|
||||
assert(smallStruct2.getComputedInt() == (0xFAE + 2));
|
||||
|
||||
{
|
||||
StructWithRefCountStoredProp structWithRefCountStoredProp =
|
||||
createStructWithRefCountStoredProp();
|
||||
auto anotherOne = structWithRefCountStoredProp.getAnother();
|
||||
(void)anotherOne;
|
||||
}
|
||||
// CHECK: create RefCountedClass 0
|
||||
// CHECK-NEXT: create RefCountedClass 1
|
||||
// CHECK-NEXT: destroy RefCountedClass 1
|
||||
// CHECK-NEXT: destroy RefCountedClass 0
|
||||
return 0;
|
||||
}
|
||||
146
test/Interop/SwiftToCxx/properties/getter-in-cxx.swift
Normal file
146
test/Interop/SwiftToCxx/properties/getter-in-cxx.swift
Normal file
@@ -0,0 +1,146 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend %s -typecheck -module-name Properties -clang-header-expose-public-decls -emit-clang-header-path %t/properties.h
|
||||
// RUN: %FileCheck %s < %t/properties.h
|
||||
|
||||
// RUN: %check-interop-cxx-header-in-clang(%t/properties.h)
|
||||
|
||||
public struct FirstSmallStruct {
|
||||
public let x: UInt32
|
||||
}
|
||||
|
||||
// CHECK: class FirstSmallStruct final {
|
||||
// CHECK: public:
|
||||
// CHECK: inline FirstSmallStruct(FirstSmallStruct &&) = default;
|
||||
// CHECK-NEXT: inline uint32_t getX() const;
|
||||
// CHECK-NEXT: private:
|
||||
|
||||
// CHECK: inline uint32_t FirstSmallStruct::getX() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties16FirstSmallStructV1xs6UInt32Vvg(_impl::swift_interop_passDirect_Properties_FirstSmallStruct(_getOpaquePointer()));
|
||||
// CHECK-NEXT: }
|
||||
|
||||
public struct LargeStruct {
|
||||
public let x1, x2, x3, x4, x5, x6: Int
|
||||
|
||||
public var anotherLargeStruct: LargeStruct {
|
||||
return LargeStruct(x1: 11, x2: 42, x3: -0xFFF, x4: 0xbad, x5: 5, x6: 0)
|
||||
}
|
||||
|
||||
public var firstSmallStruct: FirstSmallStruct {
|
||||
return FirstSmallStruct(x: 65)
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: class LargeStruct final {
|
||||
// CHECK: public:
|
||||
// CHECK: inline LargeStruct(LargeStruct &&) = default;
|
||||
// CHECK-NEXT: inline swift::Int getX1() const;
|
||||
// CHECK-NEXT: inline swift::Int getX2() const;
|
||||
// CHECK-NEXT: inline swift::Int getX3() const;
|
||||
// CHECK-NEXT: inline swift::Int getX4() const;
|
||||
// CHECK-NEXT: inline swift::Int getX5() const;
|
||||
// CHECK-NEXT: inline swift::Int getX6() const;
|
||||
// CHECK-NEXT: inline LargeStruct getAnotherLargeStruct() const;
|
||||
// CHECK-NEXT: inline FirstSmallStruct getFirstSmallStruct() const;
|
||||
// CHECK-NEXT: private:
|
||||
|
||||
// CHECK: inline swift::Int LargeStruct::getX1() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x1Sivg(_getOpaquePointer());
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline swift::Int LargeStruct::getX2() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x2Sivg(_getOpaquePointer());
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline swift::Int LargeStruct::getX3() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x3Sivg(_getOpaquePointer());
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline swift::Int LargeStruct::getX4() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x4Sivg(_getOpaquePointer());
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline swift::Int LargeStruct::getX5() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x5Sivg(_getOpaquePointer());
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline swift::Int LargeStruct::getX6() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x6Sivg(_getOpaquePointer());
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline LargeStruct LargeStruct::getAnotherLargeStruct() const {
|
||||
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
|
||||
// CHECK-NEXT: _impl::$s10Properties11LargeStructV07anotherbC0ACvg(result, _getOpaquePointer());
|
||||
// CHECK-NEXT: });
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline FirstSmallStruct LargeStruct::getFirstSmallStruct() const {
|
||||
// CHECK-NEXT: return _impl::_impl_FirstSmallStruct::returnNewValue([&](char * _Nonnull result) {
|
||||
// CHECK-NEXT: _impl::swift_interop_returnDirect_Properties_FirstSmallStruct(result, _impl::$s10Properties11LargeStructV010firstSmallC0AA05FirsteC0Vvg(_getOpaquePointer()));
|
||||
// CHECK-NEXT: });
|
||||
// CHECK-NEXT: }
|
||||
|
||||
public struct SmallStructWithGetters {
|
||||
public let storedInt: UInt32
|
||||
public var computedInt: Int {
|
||||
return Int(storedInt) + 2
|
||||
}
|
||||
|
||||
public var largeStruct: LargeStruct {
|
||||
return LargeStruct(x1: computedInt * 2, x2: 1, x3: 2, x4: 3, x5: 4, x6: 5)
|
||||
}
|
||||
|
||||
public var smallStruct: SmallStructWithGetters {
|
||||
return SmallStructWithGetters(storedInt: 0xFAE);
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: class SmallStructWithGetters final {
|
||||
// CHECK: public:
|
||||
// CHECK: inline SmallStructWithGetters(SmallStructWithGetters &&) = default;
|
||||
// CHECK-NEXT: inline uint32_t getStoredInt() const;
|
||||
// CHECK-NEXT: inline swift::Int getComputedInt() const;
|
||||
// CHECK-NEXT: inline LargeStruct getLargeStruct() const;
|
||||
// CHECK-NEXT: inline SmallStructWithGetters getSmallStruct() const;
|
||||
// CHECK-NEXT: private:
|
||||
|
||||
// CHECK: inline uint32_t SmallStructWithGetters::getStoredInt() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties22SmallStructWithGettersV9storedInts6UInt32Vvg(_impl::swift_interop_passDirect_Properties_SmallStructWithGetters(_getOpaquePointer()));
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline swift::Int SmallStructWithGetters::getComputedInt() const {
|
||||
// CHECK-NEXT: return _impl::$s10Properties22SmallStructWithGettersV11computedIntSivg(_impl::swift_interop_passDirect_Properties_SmallStructWithGetters(_getOpaquePointer()));
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline LargeStruct SmallStructWithGetters::getLargeStruct() const {
|
||||
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
|
||||
// CHECK-NEXT: _impl::$s10Properties22SmallStructWithGettersV05largeC0AA05LargeC0Vvg(result, _impl::swift_interop_passDirect_Properties_SmallStructWithGetters(_getOpaquePointer()));
|
||||
// CHECK-NEXT: });
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: inline SmallStructWithGetters SmallStructWithGetters::getSmallStruct() const {
|
||||
// CHECK-NEXT: return _impl::_impl_SmallStructWithGetters::returnNewValue([&](char * _Nonnull result) {
|
||||
// CHECK-NEXT: _impl::swift_interop_returnDirect_Properties_SmallStructWithGetters(result, _impl::$s10Properties22SmallStructWithGettersV05smallC0ACvg(_impl::swift_interop_passDirect_Properties_SmallStructWithGetters(_getOpaquePointer())));
|
||||
// CHECK-NEXT: });
|
||||
// CHECK-NEXT: }
|
||||
|
||||
public func createSmallStructWithGetter() -> SmallStructWithGetters {
|
||||
return SmallStructWithGetters(storedInt: 21)
|
||||
}
|
||||
|
||||
private class RefCountedClass {
|
||||
let x: Int
|
||||
|
||||
init(x: Int) {
|
||||
self.x = x
|
||||
print("create RefCountedClass \(x)")
|
||||
}
|
||||
deinit {
|
||||
print("destroy RefCountedClass \(x)")
|
||||
}
|
||||
}
|
||||
|
||||
public struct StructWithRefCountStoredProp {
|
||||
private let storedRef: RefCountedClass
|
||||
|
||||
public init(x: Int) {
|
||||
storedRef = RefCountedClass(x: x)
|
||||
}
|
||||
|
||||
public var another: StructWithRefCountStoredProp {
|
||||
return StructWithRefCountStoredProp(x: 1)
|
||||
}
|
||||
}
|
||||
|
||||
public func createStructWithRefCountStoredProp() -> StructWithRefCountStoredProp {
|
||||
return StructWithRefCountStoredProp(x: 0)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// 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 -Wno-unused-private-field)
|
||||
// RUN: %check-interop-cxx-header-in-clang(%t/structs.h -Wno-unused-private-field -Wno-unused-function)
|
||||
|
||||
// CHECK: namespace Structs {
|
||||
// CHECK: namespace _impl {
|
||||
|
||||
@@ -73,6 +73,10 @@
|
||||
// CHECK-NEXT: # define IBSegueAction
|
||||
// CHECK-NEXT: #endif
|
||||
|
||||
// CHECK-LABEL: # define SWIFT_CALL __attribute__((swiftcall))
|
||||
// CHECK: # define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result))
|
||||
// CHECK: # define SWIFT_CONTEXT __attribute__((swift_context))
|
||||
|
||||
// CHECK-LABEL: #if defined(__OBJC__)
|
||||
// CHECK-NEXT: #if __has_feature(modules)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user