Skip to content

Commit 02deef5

Browse files
committed
[interop][SwiftToCxx] add support for passing generic structs with concrete type params
1 parent e5a4879 commit 02deef5

File tree

5 files changed

+67
-21
lines changed

5 files changed

+67
-21
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,14 @@ class CFunctionSignatureTypePrinter
184184
ClangRepresentation visitEnumType(EnumType *ET,
185185
Optional<OptionalTypeKind> optionalKind,
186186
bool isInOutParam) {
187-
return visitValueType(ET, ET->getNominalOrBoundGenericNominal(), ET,
187+
return visitValueType(ET, ET->getNominalOrBoundGenericNominal(),
188188
optionalKind, isInOutParam);
189189
}
190190

191191
ClangRepresentation visitStructType(StructType *ST,
192192
Optional<OptionalTypeKind> optionalKind,
193193
bool isInOutParam) {
194-
return visitValueType(ST, ST->getNominalOrBoundGenericNominal(), ST,
194+
return visitValueType(ST, ST->getNominalOrBoundGenericNominal(),
195195
optionalKind, isInOutParam);
196196
}
197197

@@ -212,12 +212,11 @@ class CFunctionSignatureTypePrinter
212212
return result;
213213
}
214214

215-
ClangRepresentation
216-
visitValueType(TypeBase *type, const NominalTypeDecl *decl, NominalType *NT,
217-
Optional<OptionalTypeKind> optionalKind, bool isInOutParam,
218-
ArrayRef<Type> genericArgs = {}) {
219-
if (NT)
220-
assert(isa<StructType>(NT) || isa<EnumType>(NT));
215+
ClangRepresentation visitValueType(TypeBase *type,
216+
const NominalTypeDecl *decl,
217+
Optional<OptionalTypeKind> optionalKind,
218+
bool isInOutParam,
219+
ArrayRef<Type> genericArgs = {}) {
221220
assert(isa<StructDecl>(decl) || isa<EnumDecl>(decl));
222221

223222
// Handle known type names.
@@ -228,16 +227,16 @@ class CFunctionSignatureTypePrinter
228227
// exposed.
229228
// FIXME: Handle optional structures.
230229
if (typeUseKind == FunctionSignatureTypeUse::ParamType) {
231-
if (languageMode != OutputLanguageMode::Cxx && !genericArgs.empty()) {
232-
// FIXME: what about concrete generic type.
230+
if (languageMode != OutputLanguageMode::Cxx && !genericArgs.empty() &&
231+
type->hasTypeParameter()) {
233232
if (!isInOutParam)
234233
os << "const ";
235234
os << "void * _Nonnull";
236235
return ClangRepresentation::representable;
237236
}
238237
if (languageMode != OutputLanguageMode::Cxx &&
239238
(decl->isResilient() ||
240-
(NT && interopContext.getIrABIDetails().shouldPassIndirectly(NT)))) {
239+
(interopContext.getIrABIDetails().shouldPassIndirectly(type)))) {
241240
if (modifiersDelegate.prefixIndirectlyPassedParamTypeInC)
242241
(*modifiersDelegate.prefixIndirectlyPassedParamTypeInC)(os);
243242
// FIXME: it would be nice to print out the C struct type here.
@@ -315,8 +314,8 @@ class CFunctionSignatureTypePrinter
315314
bool isInOutParam) {
316315
if (printIfKnownGenericStruct(BGT, optionalKind, isInOutParam))
317316
return ClangRepresentation::representable;
318-
return visitValueType(BGT, BGT->getDecl(), nullptr, optionalKind,
319-
isInOutParam, BGT->getGenericArgs());
317+
return visitValueType(BGT, BGT->getDecl(), optionalKind, isInOutParam,
318+
BGT->getGenericArgs());
320319
}
321320

322321
ClangRepresentation
@@ -591,11 +590,15 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
591590

592591
if (auto *decl = type->getNominalOrBoundGenericNominal()) {
593592
if ((isa<StructDecl>(decl) || isa<EnumDecl>(decl))) {
593+
ArrayRef<Type> genericArgs;
594+
// FIXME: Do we need to account for any sugar?
595+
if (const auto *bgt = type->getAs<BoundGenericType>())
596+
genericArgs = bgt->getGenericArgs();
594597
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
595598
.printParameterCxxToCUseScaffold(
596599
isIndirect || decl->isResilient() || isGenericType(type) ||
597600
interopContext.getIrABIDetails().shouldPassIndirectly(type),
598-
decl, moduleContext,
601+
decl, genericArgs, moduleContext,
599602
[&]() { printTypeImplTypeSpecifier(type, moduleContext); },
600603
namePrinter, isInOut,
601604
/*isSelf=*/paramRole &&

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ using namespace swift;
2929

3030
/// Print out the C type name of a struct/enum declaration.
3131
static void printCTypeName(raw_ostream &os, const NominalTypeDecl *type,
32-
ArrayRef<Type> genericArgs = {}) {
32+
ArrayRef<Type> genericArgs) {
3333
ClangSyntaxPrinter printer(os);
3434
printer.printModuleNameCPrefix(*type->getParentModule());
3535
// FIXME: add nested type qualifiers to fully disambiguate the name.
@@ -85,7 +85,7 @@ static void
8585
printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
8686
IRABIDetailsProvider::SizeAndAlignment layout) {
8787
os << "struct ";
88-
printCTypeName(os, typeDecl);
88+
printCTypeName(os, typeDecl, /*genericArgs=*/{});
8989
os << " {\n";
9090
os << " _Alignas(" << layout.alignment << ") ";
9191
os << "char _storage[" << layout.size << "];\n";
@@ -467,15 +467,15 @@ printCStructStubForDirectPassing(raw_ostream &os, StringRef stubName, Type type,
467467
}
468468

469469
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
470-
bool isIndirect, const NominalTypeDecl *type,
470+
bool isIndirect, const NominalTypeDecl *type, ArrayRef<Type> genericArgs,
471471
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
472472
llvm::function_ref<void()> cxxParamPrinter, bool isInOut, bool isSelf) {
473473
// A Swift value type is passed to its underlying Swift function
474474
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
475475
if (!isIndirect && !isInOut) {
476476
os << cxx_synthesis::getCxxImplNamespaceName() << "::"
477477
<< "swift_interop_passDirect_";
478-
printCTypeName(os, type);
478+
printCTypeName(os, type, genericArgs);
479479
os << '(';
480480
}
481481
if (isSelf) {

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ClangValueTypePrinter {
4646
/// Print the use of a C++ struct/enum parameter value as it's passed to the
4747
/// underlying C function that represents the native Swift function.
4848
void printParameterCxxToCUseScaffold(
49-
bool isIndirect, const NominalTypeDecl *type,
49+
bool isIndirect, const NominalTypeDecl *type, ArrayRef<Type> genericArgs,
5050
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
5151
llvm::function_ref<void()> cxxParamPrinter, bool isInOut, bool isSelf);
5252

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ int main() {
3434
auto x = makeConcretePair(100000, 0x1fee7);
3535
takeGenericPair(x);
3636
// CHECK-NEXT: GenericPair<UInt32, UInt32>(x: 100000, y: 130791)
37+
takeConcretePair(x);
38+
// CHECK-NEXT: CONCRETE pair of UInt32: 100000 130791 ;
39+
auto xprime = passThroughConcretePair(x, 918);
40+
takeConcretePair(x);
41+
takeConcretePair(xprime);
42+
takeGenericPair(xprime);
43+
// CHECK-NEXT: CONCRETE pair of UInt32: 100000 130791 ;
44+
// CHECK-NEXT: CONCRETE pair of UInt32: 100000 918 ;
45+
// CHECK-NEXT: GenericPair<UInt32, UInt32>(x: 100000, y: 918)
46+
inoutConcretePair(77, x);
47+
takeConcretePair(x);
48+
// CHECK-NEXT: CONCRETE pair of UInt32: 77 130791 ;
3749
}
3850
return 0;
3951
}

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

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,30 @@ public func takeGenericPair<T, T1>(_ x: GenericPair<T, T1>) {
3030
print(x)
3131
}
3232

33+
public func takeConcretePair(_ x: GenericPair<UInt32, UInt32>) {
34+
print("CONCRETE pair of UInt32: ", x.x, x.y, ";")
35+
}
36+
3337
public func passThroughGenericPair<T1, T>(_ x: GenericPair<T1, T>, _ y: T) -> GenericPair<T1, T> {
3438
return GenericPair<T1, T>(x: x.x, y: y)
3539
}
3640

41+
public typealias ConcreteUint32Pair = GenericPair<UInt32, UInt32>
42+
43+
public func passThroughConcretePair(_ x: ConcreteUint32Pair, y: UInt32) -> ConcreteUint32Pair {
44+
return ConcreteUint32Pair(x: x.x, y: y)
45+
}
46+
3747
public func inoutGenericPair<T1, T>(_ x: inout GenericPair<T1, T>, _ y: T1) {
3848
x.x = y
3949
}
4050

41-
// CHECK: SWIFT_EXTERN void $s8Generics16inoutGenericPairyyAA0cD0Vyxq_Gz_xtr0_lF(void * _Nonnull x, const void * _Nonnull y, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // inoutGenericPair(_:_:)
51+
public func inoutConcretePair(_ x: UInt32, _ y: inout GenericPair<UInt32, UInt32>) {
52+
y.x = x
53+
}
54+
55+
// CHECK: SWIFT_EXTERN void $s8Generics17inoutConcretePairyys6UInt32V_AA07GenericD0VyA2DGztF(uint32_t x, char * _Nonnull y) SWIFT_NOEXCEPT SWIFT_CALL; // inoutConcretePair(_:_:)
56+
// CHECK-NEXT: SWIFT_EXTERN void $s8Generics16inoutGenericPairyyAA0cD0Vyxq_Gz_xtr0_lF(void * _Nonnull x, const void * _Nonnull y, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // inoutGenericPair(_:_:)
4257
// CHECK-NEXT: // Stub struct to be used to pass/return values to/from Swift functions.
4358
// CHECK-NEXT: struct swift_interop_stub_Generics_GenericPair_s6UInt32V_s6UInt32V {
4459
// CHECK-NEXT: uint64_t _1;
@@ -56,7 +71,9 @@ public func inoutGenericPair<T1, T>(_ x: inout GenericPair<T1, T>, _ y: T1) {
5671
// CHECK-EMPTY:
5772
// CHECK-NEXT: SWIFT_EXTERN struct swift_interop_stub_Generics_GenericPair_s6UInt32V_s6UInt32V $s8Generics16makeConcretePairyAA07GenericD0Vys6UInt32VAFGAF_AFtF(uint32_t x, uint32_t y) SWIFT_NOEXCEPT SWIFT_CALL; // makeConcretePair(_:_:)
5873
// CHECK-NEXT: SWIFT_EXTERN void $s8Generics15makeGenericPairyAA0cD0Vyxq_Gx_q_tr0_lF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, const void * _Nonnull y, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // makeGenericPair(_:_:)
74+
// CHECK-NEXT: SWIFT_EXTERN struct swift_interop_stub_Generics_GenericPair_s6UInt32V_s6UInt32V $s8Generics23passThroughConcretePair_1yAA07GenericE0Vys6UInt32VAGGAH_AGtF(struct swift_interop_stub_Generics_GenericPair_s6UInt32V_s6UInt32V x, uint32_t y) SWIFT_NOEXCEPT SWIFT_CALL; // passThroughConcretePair(_:y:)
5975
// CHECK-NEXT: SWIFT_EXTERN void $s8Generics22passThroughGenericPairyAA0dE0Vyxq_GAE_q_tr0_lF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, const void * _Nonnull y, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // passThroughGenericPair(_:_:)
76+
// CHECK-NEXT: SWIFT_EXTERN void $s8Generics16takeConcretePairyyAA07GenericD0Vys6UInt32VAFGF(struct swift_interop_stub_Generics_GenericPair_s6UInt32V_s6UInt32V x) SWIFT_NOEXCEPT SWIFT_CALL; // takeConcretePair(_:)
6077
// CHECK-NEXT: SWIFT_EXTERN void $s8Generics15takeGenericPairyyAA0cD0Vyxq_Gr0_lF(const void * _Nonnull x, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // takeGenericPair(_:)
6178

6279
// CHECK: template<class T_0_0, class T_0_1>
@@ -95,7 +112,11 @@ public func inoutGenericPair<T1, T>(_ x: inout GenericPair<T1, T>, _ y: T1) {
95112
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0> && swift::isUsableInGenericContext<T_0_1>
96113
// CHECK-NEXT: class GenericPair;
97114
// CHECK-EMPTY:
98-
// CHECK-NEXT: template<class T1, class T>
115+
// CHECK-NEXT: inline void inoutConcretePair(uint32_t x, GenericPair<uint32_t, uint32_t>& y) noexcept {
116+
// CHECK-NEXT: return _impl::$s8Generics17inoutConcretePairyys6UInt32V_AA07GenericD0VyA2DGztF(x, _impl::_impl_GenericPair<uint32_t, uint32_t>::getOpaquePointer(y));
117+
// CHECK-NEXT: }
118+
119+
// CHECK: template<class T1, class T>
99120
// CHECK-NEXT: requires swift::isUsableInGenericContext<T1> && swift::isUsableInGenericContext<T>
100121
// CHECK-NEXT: inline void inoutGenericPair(GenericPair<T1, T>& x, const T1 & y) noexcept {
101122
// CHECK-NEXT: return _impl::$s8Generics16inoutGenericPairyyAA0cD0Vyxq_Gz_xtr0_lF(_impl::_impl_GenericPair<T1, T>::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata<T1>(), swift::getTypeMetadata<T>());
@@ -109,6 +130,12 @@ public func inoutGenericPair<T1, T>(_ x: inout GenericPair<T1, T>, _ y: T1) {
109130
// CHECK-NEXT: });
110131
// CHECK-NEXT: }
111132

133+
// CHECK: inline GenericPair<uint32_t, uint32_t> passThroughConcretePair(const GenericPair<uint32_t, uint32_t>& x, uint32_t y) noexcept SWIFT_WARN_UNUSED_RESULT {
134+
// CHECK-NEXT: return _impl::_impl_GenericPair<uint32_t, uint32_t>::returnNewValue([&](char * _Nonnull result) {
135+
// CHECK-NEXT: _impl::swift_interop_returnDirect_Generics_GenericPair_s6UInt32V_s6UInt32V(result, _impl::$s8Generics23passThroughConcretePair_1yAA07GenericE0Vys6UInt32VAGGAH_AGtF(_impl::swift_interop_passDirect_Generics_GenericPair_s6UInt32V_s6UInt32V(_impl::_impl_GenericPair<uint32_t, uint32_t>::getOpaquePointer(x)), y));
136+
// CHECK-NEXT: });
137+
// CHECK-NEXT: }
138+
112139
// CHECK: template<class T1, class T>
113140
// CHECK-NEXT: requires swift::isUsableInGenericContext<T1> && swift::isUsableInGenericContext<T>
114141
// CHECK-NEXT: inline GenericPair<T1, T> passThroughGenericPair(const GenericPair<T1, T>& x, const T & y) noexcept SWIFT_WARN_UNUSED_RESULT {
@@ -117,6 +144,10 @@ public func inoutGenericPair<T1, T>(_ x: inout GenericPair<T1, T>, _ y: T1) {
117144
// CHECK-NEXT: });
118145
// CHECK-NEXT: }
119146

147+
// CHECK: inline void takeConcretePair(const GenericPair<uint32_t, uint32_t>& x) noexcept {
148+
// CHECK-NEXT: return _impl::$s8Generics16takeConcretePairyyAA07GenericD0Vys6UInt32VAFGF(_impl::swift_interop_passDirect_Generics_GenericPair_s6UInt32V_s6UInt32V(_impl::_impl_GenericPair<uint32_t, uint32_t>::getOpaquePointer(x)));
149+
// CHECK-NEXT: }
150+
120151
// CHECK: template<class T, class T1>
121152
// CHECK-NEXT: requires swift::isUsableInGenericContext<T> && swift::isUsableInGenericContext<T1>
122153
// CHECK-NEXT: inline void takeGenericPair(const GenericPair<T, T1>& x) noexcept {

0 commit comments

Comments
 (0)