Skip to content

Commit bf224c7

Browse files
committed
[interop][SwiftToCxx] pass structs to generic functions
1 parent 7ecf84a commit bf224c7

File tree

6 files changed

+140
-42
lines changed

6 files changed

+140
-42
lines changed

lib/PrintAsClang/PrintClangClassType.cpp

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -94,47 +94,8 @@ void ClangClassTypePrinter::printClassTypeDecl(
9494
os << "};\n";
9595
});
9696

97-
// FIXME: avoid popping out of the module's namespace here.
98-
os << "} // end namespace \n\n";
99-
os << "namespace swift {\n";
100-
101-
os << "#pragma clang diagnostic push\n";
102-
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
103-
os << "template<>\n";
104-
os << "static inline const constexpr bool isUsableInGenericContext<";
105-
printer.printBaseName(typeDecl->getModuleContext());
106-
os << "::";
107-
printer.printBaseName(typeDecl);
108-
os << "> = true;\n";
109-
os << "#pragma clang diagnostic pop\n";
110-
111-
os << "template<>\n";
112-
os << "inline void * _Nonnull getTypeMetadata<";
113-
printer.printBaseName(typeDecl->getModuleContext());
114-
os << "::";
115-
printer.printBaseName(typeDecl);
116-
os << ">() {\n";
117-
os << " return ";
118-
printer.printBaseName(typeDecl->getModuleContext());
119-
os << "::" << cxx_synthesis::getCxxImplNamespaceName()
120-
<< "::" << typeMetadataFuncName << "(0)._0;\n";
121-
os << "}\n";
122-
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n";
123-
os << "template<>\n";
124-
os << "struct implClassFor<";
125-
printer.printBaseName(typeDecl->getModuleContext());
126-
os << "::";
127-
printer.printBaseName(typeDecl);
128-
os << "> { using type = ";
129-
printer.printBaseName(typeDecl->getModuleContext());
130-
os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
131-
printCxxImplClassName(os, typeDecl);
132-
os << "; };\n";
133-
os << "} // namespace\n";
134-
os << "} // namespace swift\n";
135-
os << "\nnamespace ";
136-
printer.printBaseName(typeDecl->getModuleContext());
137-
os << " {\n";
97+
ClangValueTypePrinter::printTypeGenericTraits(os, typeDecl,
98+
typeMetadataFuncName);
13899
}
139100

140101
void ClangClassTypePrinter::printClassTypeReturnScaffold(

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
281281

282282
if (!isOpaqueLayout)
283283
printCValueTypeStorageStruct(cPrologueOS, typeDecl, *typeSizeAlign);
284+
285+
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName);
284286
}
285287

286288
/// Print the name of the C stub struct for passing/returning a value type
@@ -456,3 +458,52 @@ void ClangValueTypePrinter::printValueTypeDirectReturnScaffold(
456458
os << ");\n";
457459
os << " });\n";
458460
}
461+
462+
void ClangValueTypePrinter::printTypeGenericTraits(
463+
raw_ostream &os, const NominalTypeDecl *typeDecl,
464+
StringRef typeMetadataFuncName) {
465+
ClangSyntaxPrinter printer(os);
466+
// FIXME: avoid popping out of the module's namespace here.
467+
os << "} // end namespace \n\n";
468+
os << "namespace swift {\n";
469+
470+
os << "#pragma clang diagnostic push\n";
471+
os << "#pragma clang diagnostic ignored \"-Wc++17-extensions\"\n";
472+
os << "template<>\n";
473+
os << "static inline const constexpr bool isUsableInGenericContext<";
474+
printer.printBaseName(typeDecl->getModuleContext());
475+
os << "::";
476+
printer.printBaseName(typeDecl);
477+
os << "> = true;\n";
478+
os << "#pragma clang diagnostic pop\n";
479+
480+
os << "template<>\n";
481+
os << "inline void * _Nonnull getTypeMetadata<";
482+
printer.printBaseName(typeDecl->getModuleContext());
483+
os << "::";
484+
printer.printBaseName(typeDecl);
485+
os << ">() {\n";
486+
os << " return ";
487+
printer.printBaseName(typeDecl->getModuleContext());
488+
os << "::" << cxx_synthesis::getCxxImplNamespaceName()
489+
<< "::" << typeMetadataFuncName << "(0)._0;\n";
490+
os << "}\n";
491+
if (isa<ClassDecl>(typeDecl)) {
492+
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << "{\n";
493+
os << "template<>\n";
494+
os << "struct implClassFor<";
495+
printer.printBaseName(typeDecl->getModuleContext());
496+
os << "::";
497+
printer.printBaseName(typeDecl);
498+
os << "> { using type = ";
499+
printer.printBaseName(typeDecl->getModuleContext());
500+
os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::";
501+
printCxxImplClassName(os, typeDecl);
502+
os << "; };\n";
503+
os << "} // namespace\n";
504+
}
505+
os << "} // namespace swift\n";
506+
os << "\nnamespace ";
507+
printer.printBaseName(typeDecl->getModuleContext());
508+
os << " {\n";
509+
}

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ class ClangValueTypePrinter {
9494
StringRef metadataVarName = "metadata",
9595
StringRef vwTableVarName = "vwTable");
9696

97+
static void printTypeGenericTraits(raw_ostream &os,
98+
const NominalTypeDecl *typeDecl,
99+
StringRef typeMetadataFuncName);
100+
97101
private:
98102
/// Prints out the C stub name used to pass/return value directly for the
99103
/// given value type.

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,41 @@ int main() {
156156
}
157157
// CHECK-NEXT: deinit TestClass
158158
// CHECK-NEXT: deinit TestClass
159+
160+
{
161+
auto x = createTestLargeStruct(0);
162+
genericPrintFunction(x);
163+
}
164+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 0, x2: 1, x3: -1, x4: 0, x5: 2, x6: -2)
165+
166+
{
167+
auto x = createTestLargeStruct(11);
168+
auto y = createTestLargeStruct(-9);
169+
genericPrintFunction(x);
170+
genericPrintFunction(y);
171+
genericSwap(x, y);
172+
genericPrintFunction(x);
173+
genericPrintFunction(y);
174+
}
175+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9)
176+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11)
177+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: -9, x2: -8, x3: -10, x4: -9, x5: -7, x6: -11)
178+
// CHECK-NEXT: TestLargeStruct value=TestLargeStruct(x1: 11, x2: 12, x3: 10, x4: 11, x5: 13, x6: 9)
179+
180+
{
181+
auto x = createTestSmallStruct(45);
182+
auto y = createTestSmallStruct(0xFed1);
183+
genericPrintFunction(x);
184+
genericPrintFunction(y);
185+
genericSwap(y, x);
186+
genericPrintFunction(x);
187+
genericPrintFunction(y);
188+
}
189+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45)
190+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
191+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
192+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 45)
193+
194+
// FIXME: return struct.
159195
return 0;
160196
}

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
33
// RUN: %FileCheck %s < %t/functions.h
44

5-
// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h)
5+
// RUN: %check-generic-interop-cxx-header-in-clang(%t/functions.h -Wno-unused-function)
66

77

88
public func genericPrintFunctionTwoArg<T>(_ x: T, _ y: Int) {
@@ -40,12 +40,41 @@ public class TestClass {
4040

4141
public func createTestClass() -> TestClass { return TestClass() }
4242

43+
public struct TestLargeStruct {
44+
var x1, x2, x3, x4, x5, x6: Int
45+
46+
init(_ x: Int) {
47+
x1 = x
48+
x2 = x+1
49+
x3 = x-1
50+
x4 = x
51+
x5 = x+2
52+
x6 = x-2
53+
}
54+
}
55+
56+
public func createTestLargeStruct(_ x: Int) -> TestLargeStruct {
57+
return TestLargeStruct(x)
58+
}
59+
60+
public struct TestSmallStruct {
61+
var x1: UInt32
62+
}
63+
64+
public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
65+
return TestSmallStruct(x1: x)
66+
}
67+
4368
// CHECK: SWIFT_EXTERN void $s9Functions20genericPrintFunctionyyxlF(const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunction(_:)
4469
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(ptrdiff_t x, const void * _Nonnull t1, const void * _Nonnull t1p, ptrdiff_t y, const void * _Nonnull t2, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionMultiGeneric(_:_:_:_:_:)
4570
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions26genericPrintFunctionTwoArgyyx_SitlF(const void * _Nonnull x, ptrdiff_t y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionTwoArg(_:_:)
4671
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions10genericRetyxxlF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericRet(_:)
4772
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions11genericSwapyyxz_xztlF(void * _Nonnull x, void * _Nonnull y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericSwap(_:_:)
4873

74+
// Skip templates in impl classes.
75+
// CHECK: _impl_TestSmallStruct
76+
// CHECK: template<class T>
77+
4978
// CHECK: template<class T>
5079
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
5180
// CHECK-NEXT: inline void genericPrintFunction(const T & x) noexcept {

test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,23 @@
6161
// CHECK-NEXT: };
6262
// CHECK-EMPTY:
6363
// CHECK-NEXT: }
64+
// CHECK-EMPTY:
65+
// CHECK-NEXT: } // end namespace
66+
// CHECK-EMPTY:
67+
// CHECK-NEXT: namespace swift {
68+
// CHECK-NEXT: #pragma clang diagnostic push
69+
// CHECK-NEXT: #pragma clang diagnostic ignored "-Wc++17-extensions"
70+
// CHECK-NEXT: template<>
71+
// CHECK-NEXT: static inline const constexpr bool isUsableInGenericContext<Structs::StructWithIntField> = true;
72+
// CHECK-NEXT: #pragma clang diagnostic pop
73+
// CHECK-NEXT: template<>
74+
// CHECK-NEXT: inline void * _Nonnull getTypeMetadata<Structs::StructWithIntField>() {
75+
// CHECK-NEXT: return Structs::_impl::$s7Structs18StructWithIntFieldVMa(0)._0;
76+
// CHECK-NEXT: }
77+
// CHECK-NEXT: } // namespace swift
78+
// CHECK-EMPTY:
79+
// CHECK-NEXT: namespace Structs {
80+
6481
public struct StructWithIntField {
6582
let field: Int64
6683
}

0 commit comments

Comments
 (0)