Skip to content

Commit 74c444d

Browse files
committed
[cxx-interop] Emit function types as Swift closures in templated params
This is required to make the compiler distinguish between instantiations of `std::function`. Previously, when generating a Swift type name for a `std::function` instantiation, we would always emit `_` as the template parameter. If someone referenced two different instantiations of `std::function` in a Swift module, they would get mangled with the same name, triggering linker errors later. rdar://103979602
1 parent 7c63cd4 commit 74c444d

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

Diff for: lib/ClangImporter/ClangClassTemplateNamePrinter.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct TemplateInstantiationNamePrinter
5656
}
5757

5858
if (swiftType) {
59-
if (swiftType->is<NominalType>()) {
59+
if (swiftType->is<NominalType>() || swiftType->isVoid()) {
6060
return swiftType->getStringAsComponent();
6161
}
6262
}
@@ -113,6 +113,22 @@ struct TemplateInstantiationNamePrinter
113113

114114
return buffer.str().str();
115115
}
116+
117+
std::string VisitFunctionProtoType(const clang::FunctionProtoType *type) {
118+
llvm::SmallString<128> storage;
119+
llvm::raw_svector_ostream buffer(storage);
120+
121+
buffer << "((";
122+
llvm::interleaveComma(type->getParamTypes(), buffer,
123+
[&](const clang::QualType &paramType) {
124+
buffer << Visit(paramType.getTypePtr());
125+
});
126+
buffer << ") -> ";
127+
buffer << Visit(type->getReturnType().getTypePtr());
128+
buffer << ")";
129+
130+
return buffer.str().str();
131+
}
116132
};
117133

118134
std::string swift::importer::printClassTemplateSpecializationName(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_WITH_FUNCTION_ARGUMENT_H
2+
#define TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_WITH_FUNCTION_ARGUMENT_H
3+
4+
template <typename Fn>
5+
class function_wrapper;
6+
7+
template <typename Ret, typename... Params>
8+
class function_wrapper<Ret(Params...)> {
9+
Ret (*fn)(Params... params) = nullptr;
10+
};
11+
12+
typedef function_wrapper<bool(bool)> FuncBoolToBool;
13+
typedef function_wrapper<bool()> FuncVoidToBool;
14+
typedef function_wrapper<void(bool)> FuncBoolToVoid;
15+
typedef function_wrapper<void()> FuncVoidToVoid;
16+
typedef function_wrapper<int(int)> FuncIntToInt;
17+
typedef function_wrapper<int(int, int)> FuncIntIntToInt;
18+
typedef function_wrapper<void(int, int)> FuncIntIntToVoid;
19+
typedef function_wrapper<void(int, int, bool)> FuncIntIntBoolToVoid;
20+
21+
#endif // TEST_INTEROP_CXX_TEMPLATES_INPUTS_CLASS_TEMPLATE_WITH_FUNCTION_ARGUMENT_H

Diff for: test/Interop/Cxx/templates/Inputs/module.modulemap

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module ClassTemplateWithPrimitiveArgument {
88
requires cplusplus
99
}
1010

11+
module ClassTemplateWithFunctionParameter {
12+
header "class-template-with-function-parameter.h"
13+
requires cplusplus
14+
}
15+
1116
module ClassTemplateWithOutOfLineMember {
1217
header "class-template-with-static-out-of-line-member.h"
1318
requires cplusplus
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=ClassTemplateWithFunctionParameter -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
2+
// RUN: %target-swift-ide-test -print-module -module-to-print=ClassTemplateWithFunctionParameter -I %S/Inputs -source-filename=x -cxx-interoperability-mode=upcoming-swift | %FileCheck %s
3+
4+
// CHECK: @available(*, unavailable
5+
// CHECK: struct function_wrapper<Fn> {
6+
// CHECK: }
7+
8+
// CHECK: typealias FuncBoolToBool = function_wrapper<((CBool) -> CBool)>
9+
// CHECK: typealias FuncVoidToBool = function_wrapper<(() -> CBool)>
10+
// CHECK: typealias FuncBoolToVoid = function_wrapper<((CBool) -> Void)>
11+
// CHECK: typealias FuncVoidToVoid = function_wrapper<(() -> Void)>
12+
// CHECK: typealias FuncIntToInt = function_wrapper<((CInt) -> CInt)>
13+
// CHECK: typealias FuncIntIntToInt = function_wrapper<((CInt, CInt) -> CInt)>
14+
// CHECK: typealias FuncIntIntToVoid = function_wrapper<((CInt, CInt) -> Void)>
15+
// CHECK: typealias FuncIntIntBoolToVoid = function_wrapper<((CInt, CInt, CBool) -> Void)>

0 commit comments

Comments
 (0)