Skip to content

Commit 562e221

Browse files
authored
Merge pull request #59461 from hyp/eng/emit-instance-struct-methods
[interop][SwiftToCxx] emit non-mutating instance methods for structs
2 parents 702238c + f2b4a43 commit 562e221

File tree

5 files changed

+183
-18
lines changed

5 files changed

+183
-18
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ class DeclAndTypePrinter::Implementation
230230
os << (protocolMembersOptional ? "@optional\n" : "@required\n");
231231
}
232232
// Limit C++ decls for now.
233-
if (outputLang == OutputLanguageMode::Cxx && !isa<VarDecl>(VD))
233+
if (outputLang == OutputLanguageMode::Cxx &&
234+
!(isa<VarDecl>(VD) || isa<FuncDecl>(VD)))
234235
continue;
235236
ASTVisitor::visit(const_cast<ValueDecl*>(VD));
236237
}
@@ -534,6 +535,10 @@ class DeclAndTypePrinter::Implementation
534535
getForeignResultType(AFD, methodTy, asyncConvention, errorConvention);
535536

536537
if (outputLang == OutputLanguageMode::Cxx) {
538+
// FIXME: Support static methods.
539+
if (isClassMethod)
540+
return;
541+
assert(!AFD->isStatic());
537542
auto *typeDeclContext = cast<NominalTypeDecl>(AFD->getParent());
538543

539544
std::string cFuncDecl;
@@ -547,18 +552,33 @@ class DeclAndTypePrinter::Implementation
547552
DeclAndTypeClangFunctionPrinter declPrinter(os, owningPrinter.prologueOS,
548553
owningPrinter.typeMapping,
549554
owningPrinter.interopContext);
550-
declPrinter.printCxxPropertyAccessorMethod(
551-
typeDeclContext, AFD, funcABI.getSymbolName(), resultTy,
552-
/*isDefinition=*/false);
555+
if (auto *accessor = dyn_cast<AccessorDecl>(AFD)) {
556+
declPrinter.printCxxPropertyAccessorMethod(
557+
typeDeclContext, accessor, funcABI.getSymbolName(), resultTy,
558+
/*isDefinition=*/false);
559+
} else {
560+
declPrinter.printCxxMethod(typeDeclContext, AFD,
561+
funcABI.getSymbolName(), resultTy,
562+
/*isDefinition=*/false);
563+
}
553564

554565
llvm::raw_string_ostream defOS(outOfLineDefinitions);
555566
DeclAndTypeClangFunctionPrinter defPrinter(
556567
defOS, owningPrinter.prologueOS, owningPrinter.typeMapping,
557568
owningPrinter.interopContext);
558-
defPrinter.printCxxPropertyAccessorMethod(
559-
typeDeclContext, AFD, funcABI.getSymbolName(), resultTy,
560-
/*isDefinition=*/true);
561569

570+
if (auto *accessor = dyn_cast<AccessorDecl>(AFD)) {
571+
572+
defPrinter.printCxxPropertyAccessorMethod(
573+
typeDeclContext, accessor, funcABI.getSymbolName(), resultTy,
574+
/*isDefinition=*/true);
575+
} else {
576+
defPrinter.printCxxMethod(typeDeclContext, AFD, funcABI.getSymbolName(),
577+
resultTy, /*isDefinition=*/true);
578+
}
579+
580+
// FIXME: SWIFT_WARN_UNUSED_RESULT
581+
// FIXME: availability
562582
return;
563583
}
564584

@@ -1156,6 +1176,9 @@ class DeclAndTypePrinter::Implementation
11561176
return;
11571177
}
11581178

1179+
if (FD->getDeclContext()->isTypeContext())
1180+
return printAbstractFunctionAsMethod(FD, FD->isStatic());
1181+
11591182
// Emit the underlying C signature that matches the Swift ABI
11601183
// in the generated C++ implementation prologue for the module.
11611184
std::string cFuncDecl;

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,9 @@ class CFunctionSignatureTypePrinter
171171
} // end namespace
172172

173173
void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
174-
AbstractFunctionDecl *FD, StringRef name, Type resultTy,
175-
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams) {
174+
const AbstractFunctionDecl *FD, StringRef name, Type resultTy,
175+
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams,
176+
FunctionSignatureModifiers modifiers) {
176177
OutputLanguageMode outputLang = kind == FunctionSignatureKind::CFunctionProto
177178
? OutputLanguageMode::ObjC
178179
: OutputLanguageMode::Cxx;
@@ -213,7 +214,13 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
213214
os << "void";
214215
}
215216

216-
os << ' ' << name << '(';
217+
os << ' ';
218+
if (modifiers.qualifierContext) {
219+
// FIXME: Full qualifiers for nested types?
220+
ClangSyntaxPrinter(os).printBaseName(modifiers.qualifierContext);
221+
os << "::";
222+
}
223+
os << name << '(';
217224

218225
bool HasParams = false;
219226
// Indirect result is passed in as the first parameter.
@@ -367,16 +374,41 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
367374
os << ";\n";
368375
}
369376

370-
void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
377+
void DeclAndTypeClangFunctionPrinter::printCxxMethod(
371378
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
372379
StringRef swiftSymbolName, Type resultTy, bool isDefinition) {
373-
assert(FD->getParameters()->size() == 0);
380+
os << " inline ";
381+
// FIXME: Full qualifier.
382+
FunctionSignatureModifiers modifiers;
383+
if (isDefinition)
384+
modifiers.qualifierContext = typeDeclContext;
385+
printFunctionSignature(FD, FD->getName().getBaseIdentifier().get(), resultTy,
386+
FunctionSignatureKind::CxxInlineThunk, {}, modifiers);
387+
388+
// FIXME: Add support for mutating methods.
389+
os << " const";
390+
if (!isDefinition) {
391+
os << ";\n";
392+
return;
393+
}
394+
os << " {\n";
395+
// FIXME: should it be objTy for resultTy?
396+
printCxxThunkBody(swiftSymbolName, resultTy, FD->getParameters(),
397+
{AdditionalParam{AdditionalParam::Role::Self,
398+
typeDeclContext->getDeclaredType()}});
399+
os << " }\n";
400+
}
401+
402+
void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
403+
const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor,
404+
StringRef swiftSymbolName, Type resultTy, bool isDefinition) {
405+
assert(accessor->getParameters()->size() == 0);
374406
os << " inline ";
375407

376408
OptionalTypeKind retKind;
377409
Type objTy;
378410
std::tie(objTy, retKind) =
379-
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
411+
DeclAndTypePrinter::getObjectTypeAndOptionality(accessor, resultTy);
380412
CFunctionSignatureTypePrinter typePrinter(
381413
os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx, interopContext,
382414
CFunctionSignatureTypePrinterModifierDelegate(),
@@ -392,7 +424,6 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
392424
}
393425

394426
StringRef name;
395-
auto accessor = cast<AccessorDecl>(FD);
396427
// For a getter or setter, go through the variable or subscript decl.
397428
name = accessor->getStorage()->getBaseIdentifier().str();
398429

@@ -405,7 +436,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
405436
}
406437
os << " {\n";
407438
// FIXME: should it be objTy for resultTy?
408-
printCxxThunkBody(swiftSymbolName, resultTy, FD->getParameters(),
439+
printCxxThunkBody(swiftSymbolName, resultTy, accessor->getParameters(),
409440
{AdditionalParam{AdditionalParam::Role::Self,
410441
typeDeclContext->getDeclaredType()}});
411442
os << " }\n";

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
namespace swift {
2424

2525
class AbstractFunctionDecl;
26+
class AccessorDecl;
2627
class FuncDecl;
2728
class NominalTypeDecl;
2829
class ParamDecl;
@@ -57,11 +58,20 @@ class DeclAndTypeClangFunctionPrinter {
5758
Type type;
5859
};
5960

61+
/// Optional modifiers that can be applied to function signature.
62+
struct FunctionSignatureModifiers {
63+
/// Additional qualifier to add before the function's name.
64+
const NominalTypeDecl *qualifierContext;
65+
66+
FunctionSignatureModifiers() : qualifierContext(nullptr) {}
67+
};
68+
6069
/// Print the C function declaration or the C++ function thunk that
6170
/// corresponds to the given function declaration.
62-
void printFunctionSignature(AbstractFunctionDecl *FD, StringRef name,
71+
void printFunctionSignature(const AbstractFunctionDecl *FD, StringRef name,
6372
Type resultTy, FunctionSignatureKind kind,
64-
ArrayRef<AdditionalParam> additionalParams = {});
73+
ArrayRef<AdditionalParam> additionalParams = {},
74+
FunctionSignatureModifiers modifiers = {});
6575

6676
/// Print the use of the C++ function thunk parameter as it's passed to the C
6777
/// function declaration.
@@ -73,9 +83,14 @@ class DeclAndTypeClangFunctionPrinter {
7383
const ParameterList *params,
7484
ArrayRef<AdditionalParam> additionalParams = {});
7585

86+
/// Print the Swift method as C++ method declaration/definition.
87+
void printCxxMethod(const NominalTypeDecl *typeDeclContext,
88+
const AbstractFunctionDecl *FD, StringRef swiftSymbolName,
89+
Type resultTy, bool isDefinition);
90+
7691
/// Print the C++ getter/setter method signature.
7792
void printCxxPropertyAccessorMethod(const NominalTypeDecl *typeDeclContext,
78-
const AbstractFunctionDecl *FD,
93+
const AccessorDecl *accessor,
7994
StringRef swiftSymbolName, Type resultTy,
8095
bool isDefinition);
8196

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/method-in-cxx.swift -typecheck -module-name Methods -clang-header-expose-public-decls -emit-clang-header-path %t/methods.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-methods-execution.o
6+
// RUN: %target-interop-build-swift %S/method-in-cxx.swift -o %t/swift-methods-execution -Xlinker %t/swift-methods-execution.o -module-name Methods -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-methods-execution
9+
// RUN: %target-run %t/swift-methods-execution | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
13+
#include <assert.h>
14+
#include "methods.h"
15+
16+
int main() {
17+
using namespace Methods;
18+
19+
auto largeStruct = createLargeStruct();
20+
largeStruct.dump();
21+
// CHECK: -1, 2, -100, 42, 67, -10101
22+
23+
LargeStruct largeStructDoubled = largeStruct.doubled();
24+
largeStructDoubled.dump();
25+
// CHECK-NEXT: -2, 4, -200, 84, 134, -20202
26+
27+
auto largeStructScaled = largeStruct.scaled(2, -4);
28+
largeStructScaled.dump();
29+
// CHECK-NEXT: -2, -8, -200, -168, 134, 40404
30+
31+
auto largeStructAdded = largeStructDoubled.added(largeStruct);
32+
largeStructAdded.dump();
33+
// CHECK-NEXT: -3, 6, -300, 126, 201, -30303
34+
return 0;
35+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Methods -clang-header-expose-public-decls -emit-clang-header-path %t/methods.h
3+
// RUN: %FileCheck %s < %t/methods.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/methods.h)
6+
7+
public struct LargeStruct {
8+
let x1, x2, x3, x4, x5, x6: Int
9+
10+
public func doubled() -> LargeStruct {
11+
return LargeStruct(x1: x1 * 2, x2: x2 * 2, x3: x3 * 2, x4: x4 * 2, x5: x5 * 2, x6: x6 * 2)
12+
}
13+
14+
public func dump() {
15+
print("\(x1), \(x2), \(x3), \(x4), \(x5), \(x6)")
16+
}
17+
18+
public func scaled(_ x: Int, _ y: Int) -> LargeStruct {
19+
return LargeStruct(x1: x1 * x, x2: x2 * y, x3: x3 * x, x4: x4 * y, x5: x5 * x, x6: x6 * y)
20+
}
21+
22+
public func added(_ x: LargeStruct) -> LargeStruct {
23+
return LargeStruct(x1: x1 + x.x1, x2: x2 + x.x2, x3: x3 + x.x3, x4: x4 + x.x4, x5: x5 + x.x5, x6: x6 + x.x6)
24+
}
25+
}
26+
27+
// CHECK: SWIFT_EXTERN void $s7Methods11LargeStructV7doubledACyF(SWIFT_INDIRECT_RESULT void * _Nonnull, SWIFT_CONTEXT const void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // doubled()
28+
// CHECK: SWIFT_EXTERN void $s7Methods11LargeStructV4dumpyyF(SWIFT_CONTEXT const void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // dump()
29+
// CHECK: SWIFT_EXTERN void $s7Methods11LargeStructV6scaledyACSi_SitF(SWIFT_INDIRECT_RESULT void * _Nonnull, ptrdiff_t x, ptrdiff_t y, SWIFT_CONTEXT const void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // scaled(_:_:)
30+
// CHECK: SWIFT_EXTERN void $s7Methods11LargeStructV5addedyA2CF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, SWIFT_CONTEXT const void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // added(_:)
31+
32+
// CHECK: class LargeStruct final {
33+
// CHECK: inline LargeStruct(LargeStruct &&) = default;
34+
// CHECK-NEXT: inline LargeStruct doubled() const;
35+
// CHECK-NEXT: inline void dump() const;
36+
// CHECK-NEXT: inline LargeStruct scaled(swift::Int x, swift::Int y) const;
37+
// CHECK-NEXT: inline LargeStruct added(const LargeStruct& x) const;
38+
// CHECK-NEXT: private
39+
40+
// CHECK: inline LargeStruct LargeStruct::doubled() const {
41+
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
42+
// CHECK-NEXT: _impl::$s7Methods11LargeStructV7doubledACyF(result, _getOpaquePointer());
43+
// CHECK-NEXT: });
44+
// CHECK-NEXT: }
45+
// CHECK-NEXT: inline void LargeStruct::dump() const {
46+
// CHECK-NEXT: return _impl::$s7Methods11LargeStructV4dumpyyF(_getOpaquePointer());
47+
// CHECK-NEXT: }
48+
// CHECK-NEXT: inline LargeStruct LargeStruct::scaled(swift::Int x, swift::Int y) const {
49+
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
50+
// CHECK-NEXT: _impl::$s7Methods11LargeStructV6scaledyACSi_SitF(result, x, y, _getOpaquePointer());
51+
// CHECK-NEXT: });
52+
// CHECK-NEXT: }
53+
// CHECK-NEXT: inline LargeStruct LargeStruct::added(const LargeStruct& x) const {
54+
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
55+
// CHECK-NEXT: _impl::$s7Methods11LargeStructV5addedyA2CF(result, _impl::_impl_LargeStruct::getOpaquePointer(x), _getOpaquePointer());
56+
// CHECK-NEXT: });
57+
// CHECK-NEXT: }
58+
59+
public func createLargeStruct() -> LargeStruct {
60+
return LargeStruct(x1: -1, x2: 2, x3: -100, x4: 42, x5: 67, x6: -10101)
61+
}

0 commit comments

Comments
 (0)