[interop][SwiftToCxx] emit instance property getters for structs

This commit is contained in:
Alex Lorenz
2022-06-14 15:32:11 -07:00
parent b04ae714f3
commit d7fd1233a9
13 changed files with 455 additions and 58 deletions

View File

@@ -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()) {

View File

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

View File

@@ -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"); },

View File

@@ -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 &param) {
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 &param) {
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";
}

View File

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

View File

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

View File

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

View File

@@ -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) { }

View File

@@ -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) {
}

View File

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

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

View File

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

View File

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