Skip to content

Commit 7d6cdbc

Browse files
committed
[interop][SwiftToCxx] pass generic type to a function by value (non specialized generic though)
1 parent ebd8dea commit 7d6cdbc

File tree

7 files changed

+86
-39
lines changed

7 files changed

+86
-39
lines changed

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,11 @@ void ClangSyntaxPrinter::printGenericRequirementsInstantiantions(
265265
printGenericRequirementInstantiantion(requirement);
266266
});
267267
}
268+
269+
void ClangSyntaxPrinter::printPrimaryCxxTypeName(
270+
const NominalTypeDecl *type, const ModuleDecl *moduleContext) {
271+
printModuleNamespaceQualifiersIfNeeded(type->getModuleContext(),
272+
moduleContext);
273+
// FIXME: Print class qualifiers for nested class references.
274+
printBaseName(type);
275+
}

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ class ClangSyntaxPrinter {
139139
ArrayRef<GenericRequirement> requirements,
140140
LeadingTrivia leadingTrivia = LeadingTrivia::None);
141141

142+
// Print the C++ type name that corresponds to the primary user facing C++
143+
// class for the given nominal type.
144+
void printPrimaryCxxTypeName(const NominalTypeDecl *type,
145+
const ModuleDecl *moduleContext);
146+
142147
protected:
143148
raw_ostream &os;
144149
};

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,23 @@ class CFunctionSignatureTypePrinter
201201
optionalKind, isInOutParam);
202202
}
203203

204+
ClangRepresentation visitGenericArgs(ArrayRef<Type> genericArgs) {
205+
if (genericArgs.empty())
206+
return ClangRepresentation::representable;
207+
os << '<';
208+
llvm::SaveAndRestore<FunctionSignatureTypeUse> typeUseNormal(
209+
typeUseKind, FunctionSignatureTypeUse::TypeReference);
210+
decltype(modifiersDelegate) emptyModifiersDelegate;
211+
llvm::SaveAndRestore<decltype(modifiersDelegate)> modReset(
212+
modifiersDelegate, emptyModifiersDelegate);
213+
ClangRepresentation result = ClangRepresentation::representable;
214+
llvm::interleaveComma(genericArgs, os, [&](Type t) {
215+
result.merge(visitPart(t, None, false));
216+
});
217+
os << '>';
218+
return result;
219+
}
220+
204221
ClangRepresentation visitValueType(const NominalTypeDecl *decl,
205222
NominalType *NT,
206223
Optional<OptionalTypeKind> optionalKind,
@@ -218,6 +235,12 @@ class CFunctionSignatureTypePrinter
218235
// exposed.
219236
// FIXME: Handle optional structures.
220237
if (typeUseKind == FunctionSignatureTypeUse::ParamType) {
238+
if (languageMode != OutputLanguageMode::Cxx && !genericArgs.empty()) {
239+
// FIXME: what about concrete generic type.
240+
// FIXME: inout.
241+
os << "const void * _Nonnull";
242+
return ClangRepresentation::representable;
243+
}
221244
if (languageMode != OutputLanguageMode::Cxx &&
222245
(decl->isResilient() ||
223246
(NT && interopContext.getIrABIDetails().shouldPassIndirectly(NT)))) {
@@ -230,10 +253,18 @@ class CFunctionSignatureTypePrinter
230253
os << "const void * _Nonnull";
231254
}
232255

233-
} else {
256+
} else if (languageMode != OutputLanguageMode::Cxx) {
234257
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
235258
.printValueTypeParameterType(decl, languageMode, moduleContext,
236259
isInOutParam);
260+
} else {
261+
if (!isInOutParam) {
262+
os << "const ";
263+
}
264+
ClangSyntaxPrinter(os).printPrimaryCxxTypeName(decl, moduleContext);
265+
auto result = visitGenericArgs(genericArgs);
266+
os << '&';
267+
return result;
237268
}
238269
} else {
239270
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
@@ -244,20 +275,7 @@ class CFunctionSignatureTypePrinter
244275
ClangValueTypePrinter::TypeUseKind::CxxTypeName)
245276
: ClangValueTypePrinter::TypeUseKind::CxxTypeName,
246277
moduleContext);
247-
if (!genericArgs.empty()) {
248-
os << '<';
249-
llvm::SaveAndRestore<FunctionSignatureTypeUse> typeUseNormal(
250-
typeUseKind, FunctionSignatureTypeUse::TypeReference);
251-
decltype(modifiersDelegate) emptyModifiersDelegate;
252-
llvm::SaveAndRestore<decltype(modifiersDelegate)> modReset(
253-
modifiersDelegate, emptyModifiersDelegate);
254-
ClangRepresentation result = ClangRepresentation::representable;
255-
llvm::interleaveComma(genericArgs, os, [&](Type t) {
256-
result.merge(visitPart(t, None, false));
257-
});
258-
os << '>';
259-
return result;
260-
}
278+
return visitGenericArgs(genericArgs);
261279
}
262280
return ClangRepresentation::representable;
263281
}
@@ -538,9 +556,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
538556
auto namePrinter = [&]() { ClangSyntaxPrinter(os).printIdentifier(name); };
539557
if (!isKnownCxxType(type, typeMapping) &&
540558
!hasKnownOptionalNullableCxxMapping(type)) {
541-
if (type->getAs<ArchetypeType>() && type->getAs<ArchetypeType>()
542-
->getInterfaceType()
543-
->is<GenericTypeParamType>()) {
559+
if (type->is<GenericTypeParamType>()) {
544560
os << "swift::" << cxx_synthesis::getCxxImplNamespaceName()
545561
<< "::getOpaquePointer(";
546562
namePrinter();
@@ -558,9 +574,24 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
558574
if ((isa<StructDecl>(decl) || isa<EnumDecl>(decl))) {
559575
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
560576
.printParameterCxxToCUseScaffold(
561-
isIndirect || decl->isResilient() ||
577+
isIndirect || decl->isResilient() || isGenericType(type) ||
562578
interopContext.getIrABIDetails().shouldPassIndirectly(type),
563-
decl, moduleContext, namePrinter, isInOut,
579+
decl, moduleContext,
580+
[&]() {
581+
CFunctionSignatureTypePrinterModifierDelegate delegate;
582+
delegate.mapValueTypeUseKind = [](ClangValueTypePrinter::
583+
TypeUseKind kind) {
584+
return ClangValueTypePrinter::TypeUseKind::CxxImplTypeName;
585+
};
586+
CFunctionSignatureTypePrinter typePrinter(
587+
os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx,
588+
interopContext, delegate, moduleContext, declPrinter,
589+
FunctionSignatureTypeUse::TypeReference);
590+
auto result =
591+
typePrinter.visit(type, None, /*isInOut=*/false);
592+
assert(!result.isUnsupported());
593+
},
594+
namePrinter, isInOut,
564595
/*isSelf=*/paramRole &&
565596
*paramRole == AdditionalParam::Role::Self);
566597
return;
@@ -576,7 +607,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
576607

577608
void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
578609
const ParamDecl *param, StringRef name) {
579-
printCxxToCFunctionParameterUse(param->getType(), name,
610+
printCxxToCFunctionParameterUse(param->getInterfaceType(), name,
580611
param->getModuleContext(), param->isInOut());
581612
}
582613

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@ static void printCTypeName(raw_ostream &os, const NominalTypeDecl *type) {
3737
/// Print out the C++ type name of a struct/enum declaration.
3838
static void printCxxTypeName(raw_ostream &os, const NominalTypeDecl *type,
3939
const ModuleDecl *moduleContext) {
40-
// FIXME: Print class qualifiers for nested class references.
41-
ClangSyntaxPrinter printer(os);
42-
printer.printModuleNamespaceQualifiersIfNeeded(type->getModuleContext(),
43-
moduleContext);
44-
printer.printBaseName(type);
40+
ClangSyntaxPrinter(os).printPrimaryCxxTypeName(type, moduleContext);
4541
}
4642

4743
void ClangValueTypePrinter::printCxxImplClassName(raw_ostream &os,
@@ -490,8 +486,8 @@ void ClangValueTypePrinter::printValueTypeParameterType(
490486

491487
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
492488
bool isIndirect, const NominalTypeDecl *type,
493-
const ModuleDecl *moduleContext, llvm::function_ref<void()> cxxParamPrinter,
494-
bool isInOut, bool isSelf) {
489+
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
490+
llvm::function_ref<void()> cxxParamPrinter, bool isInOut, bool isSelf) {
495491
// A Swift value type is passed to its underlying Swift function
496492
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
497493
if (!isIndirect && !isInOut) {
@@ -503,10 +499,8 @@ void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
503499
if (isSelf) {
504500
os << "_getOpaquePointer()";
505501
} else {
506-
ClangSyntaxPrinter(os).printModuleNamespaceQualifiersIfNeeded(
507-
type->getModuleContext(), moduleContext);
508-
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
509-
printCxxImplClassName(os, type);
502+
// FIXME: can we propagate the _impl request here?
503+
typePrinter();
510504
os << "::getOpaquePointer(";
511505
cxxParamPrinter();
512506
os << ')';

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@ class ClangValueTypePrinter {
5151

5252
/// Print the use of a C++ struct/enum parameter value as it's passed to the
5353
/// underlying C function that represents the native Swift function.
54-
void
55-
printParameterCxxToCUseScaffold(bool isIndirect, const NominalTypeDecl *type,
56-
const ModuleDecl *moduleContext,
57-
llvm::function_ref<void()> cxxParamPrinter,
58-
bool isInOut, bool isSelf);
54+
void printParameterCxxToCUseScaffold(
55+
bool isIndirect, const NominalTypeDecl *type,
56+
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
57+
llvm::function_ref<void()> cxxParamPrinter, bool isInOut, bool isSelf);
5958

6059
enum class TypeUseKind {
6160
// The name of the C++ class that corresponds to the Swift value type (with

test/Interop/SwiftToCxx/generics/generic-struct-execution.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ int main() {
1919
using namespace Generics;
2020

2121
auto x = makeGenericPair<int, int>(11, 42);
22-
puts("no\n");
23-
// CHECK: no
22+
takeGenericPair(x);
23+
// CHECK: GenericPair<Int32, Int32>(x: 11, y: 42)
2424
return 0;
2525
}

test/Interop/SwiftToCxx/generics/generic-struct-in-cxx.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ public func makeGenericPair<T, T1>(_ x: T, _ y: T1) -> GenericPair<T, T1> {
1818
return GenericPair<T, T1>(x: x, y: y);
1919
}
2020

21+
public func takeGenericPair<T, T1>(_ x: GenericPair<T, T1>) {
22+
print(x)
23+
}
24+
2125
// CHECK: template<class T_0_0, class T_0_1>
2226
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0> && swift::isUsableInGenericContext<T_0_1>
2327
// CHECK-NEXT: class _impl_GenericPair;
@@ -60,3 +64,9 @@ public func makeGenericPair<T, T1>(_ x: T, _ y: T1) -> GenericPair<T, T1> {
6064
// CHECK-NEXT: _impl::$s8Generics15makeGenericPairyAA0cD0Vyxq_Gx_q_tr0_lF(result, swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata<T>(), swift::getTypeMetadata<T1>());
6165
// CHECK-NEXT: });
6266
// CHECK-NEXT: }
67+
68+
// CHECK: template<class T, class T1>
69+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T> && swift::isUsableInGenericContext<T1>
70+
// CHECK-NEXT: inline void takeGenericPair(const GenericPair<T, T1>& x) noexcept {
71+
// CHECK-NEXT: return _impl::$s8Generics15takeGenericPairyyAA0cD0Vyxq_Gr0_lF(_impl::_impl_GenericPair<T, T1>::getOpaquePointer(x), swift::getTypeMetadata<T>(), swift::getTypeMetadata<T1>());
72+
// CHECK-NEXT:}

0 commit comments

Comments
 (0)