Skip to content

Commit f89f64a

Browse files
committed
[interop][SwiftToCxx] add support for passing generic structs with concrete type params
1 parent 031b779 commit f89f64a

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
@@ -190,14 +190,14 @@ class CFunctionSignatureTypePrinter
190190
ClangRepresentation visitEnumType(EnumType *ET,
191191
Optional<OptionalTypeKind> optionalKind,
192192
bool isInOutParam) {
193-
return visitValueType(ET, ET->getNominalOrBoundGenericNominal(), ET,
193+
return visitValueType(ET, ET->getNominalOrBoundGenericNominal(),
194194
optionalKind, isInOutParam);
195195
}
196196

197197
ClangRepresentation visitStructType(StructType *ST,
198198
Optional<OptionalTypeKind> optionalKind,
199199
bool isInOutParam) {
200-
return visitValueType(ST, ST->getNominalOrBoundGenericNominal(), ST,
200+
return visitValueType(ST, ST->getNominalOrBoundGenericNominal(),
201201
optionalKind, isInOutParam);
202202
}
203203

@@ -218,12 +218,11 @@ class CFunctionSignatureTypePrinter
218218
return result;
219219
}
220220

221-
ClangRepresentation
222-
visitValueType(TypeBase *type, const NominalTypeDecl *decl, NominalType *NT,
223-
Optional<OptionalTypeKind> optionalKind, bool isInOutParam,
224-
ArrayRef<Type> genericArgs = {}) {
225-
if (NT)
226-
assert(isa<StructType>(NT) || isa<EnumType>(NT));
221+
ClangRepresentation visitValueType(TypeBase *type,
222+
const NominalTypeDecl *decl,
223+
Optional<OptionalTypeKind> optionalKind,
224+
bool isInOutParam,
225+
ArrayRef<Type> genericArgs = {}) {
227226
assert(isa<StructDecl>(decl) || isa<EnumDecl>(decl));
228227

229228
// Handle known type names.
@@ -234,16 +233,16 @@ class CFunctionSignatureTypePrinter
234233
// exposed.
235234
// FIXME: Handle optional structures.
236235
if (typeUseKind == FunctionSignatureTypeUse::ParamType) {
237-
if (languageMode != OutputLanguageMode::Cxx && !genericArgs.empty()) {
238-
// FIXME: what about concrete generic type.
236+
if (languageMode != OutputLanguageMode::Cxx && !genericArgs.empty() &&
237+
type->hasTypeParameter()) {
239238
if (!isInOutParam)
240239
os << "const ";
241240
os << "void * _Nonnull";
242241
return ClangRepresentation::representable;
243242
}
244243
if (languageMode != OutputLanguageMode::Cxx &&
245244
(decl->isResilient() ||
246-
(NT && interopContext.getIrABIDetails().shouldPassIndirectly(NT)))) {
245+
(interopContext.getIrABIDetails().shouldPassIndirectly(type)))) {
247246
if (modifiersDelegate.prefixIndirectlyPassedParamTypeInC)
248247
(*modifiersDelegate.prefixIndirectlyPassedParamTypeInC)(os);
249248
// FIXME: it would be nice to print out the C struct type here.
@@ -321,8 +320,8 @@ class CFunctionSignatureTypePrinter
321320
bool isInOutParam) {
322321
if (printIfKnownGenericStruct(BGT, optionalKind, isInOutParam))
323322
return ClangRepresentation::representable;
324-
return visitValueType(BGT, BGT->getDecl(), nullptr, optionalKind,
325-
isInOutParam, BGT->getGenericArgs());
323+
return visitValueType(BGT, BGT->getDecl(), optionalKind, isInOutParam,
324+
BGT->getGenericArgs());
326325
}
327326

328327
ClangRepresentation
@@ -597,11 +596,15 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
597596

598597
if (auto *decl = type->getNominalOrBoundGenericNominal()) {
599598
if ((isa<StructDecl>(decl) || isa<EnumDecl>(decl))) {
599+
ArrayRef<Type> genericArgs;
600+
// FIXME: Do we need to account for any sugar?
601+
if (const auto *bgt = type->getAs<BoundGenericType>())
602+
genericArgs = bgt->getGenericArgs();
600603
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
601604
.printParameterCxxToCUseScaffold(
602605
isIndirect || decl->isResilient() || isGenericType(type) ||
603606
interopContext.getIrABIDetails().shouldPassIndirectly(type),
604-
decl, moduleContext,
607+
decl, genericArgs, moduleContext,
605608
[&]() { printTypeImplTypeSpecifier(type, moduleContext); },
606609
namePrinter, isInOut,
607610
/*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";
@@ -450,15 +450,15 @@ printCStructStubForDirectPassing(raw_ostream &os, StringRef stubName, Type type,
450450
}
451451

452452
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
453-
bool isIndirect, const NominalTypeDecl *type,
453+
bool isIndirect, const NominalTypeDecl *type, ArrayRef<Type> genericArgs,
454454
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
455455
llvm::function_ref<void()> cxxParamPrinter, bool isInOut, bool isSelf) {
456456
// A Swift value type is passed to its underlying Swift function
457457
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
458458
if (!isIndirect && !isInOut) {
459459
os << cxx_synthesis::getCxxImplNamespaceName() << "::"
460460
<< "swift_interop_passDirect_";
461-
printCTypeName(os, type);
461+
printCTypeName(os, type, genericArgs);
462462
os << '(';
463463
}
464464
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)