Skip to content

Commit f7902a6

Browse files
committed
[cxx-interop] Emit C++ inline function thunks that with correct primitive types
1 parent 68fc606 commit f7902a6

11 files changed

+418
-40
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,7 @@ class DeclAndTypePrinter::Implementation
716716
/// Print the core function declaration for a given function with the given
717717
/// name.
718718
void printFunctionDeclAsCFunctionDecl(FuncDecl *FD, StringRef name,
719-
Type resultTy,
720-
bool printEmptyParamNames = false) {
719+
Type resultTy) {
721720
// The result type may be a partial function type we need to close
722721
// up later.
723722
PrintMultiPartType multiPart(*this);
@@ -737,12 +736,8 @@ class DeclAndTypePrinter::Implementation
737736
Type objTy;
738737
std::tie(objTy, kind) =
739738
getObjectTypeAndOptionality(param, param->getInterfaceType());
740-
std::string paramName =
741-
param->getName().empty() ? "" : param->getName().str().str();
742-
if (printEmptyParamNames && paramName.empty()) {
743-
llvm::raw_string_ostream os(paramName);
744-
os << "_" << index;
745-
}
739+
StringRef paramName =
740+
param->getName().empty() ? "" : param->getName().str();
746741
print(objTy, kind, paramName, IsFunctionParam);
747742
++index;
748743
});
@@ -868,9 +863,9 @@ class DeclAndTypePrinter::Implementation
868863
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
869864

870865
os << "inline ";
871-
printFunctionDeclAsCFunctionDecl(FD,
872-
FD->getName().getBaseIdentifier().get(),
873-
resultTy, /*printEmptyParamNames=*/true);
866+
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
867+
funcPrinter.printFunctionDeclAsCxxFunctionDecl(
868+
FD, FD->getName().getBaseIdentifier().get(), resultTy);
874869
// FIXME: Support throwing exceptions for Swift errors.
875870
os << " noexcept";
876871
printFunctionClangAttributes(FD, funcTy);
@@ -1998,7 +1993,7 @@ class DeclAndTypePrinter::Implementation
19981993
/// visitPart().
19991994
public:
20001995
void print(Type ty, Optional<OptionalTypeKind> optionalKind,
2001-
std::string name = "",
1996+
StringRef name = "",
20021997
IsFunctionParam_t isFuncParam = IsNotFunctionParam) {
20031998
PrettyStackTraceType trace(getASTContext(), "printing", ty);
20041999

lib/PrintAsClang/PrimitiveTypeMapping.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,20 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
2424
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
2525
CLANG_REPR, \
2626
Optional<StringRef>(CLANG_REPR), \
27+
Optional<StringRef>(CLANG_REPR), \
2728
NEEDS_NULLABILITY \
2829
}
2930
#define MAP_C(SWIFT_NAME, OBJC_REPR, C_REPR, NEEDS_NULLABILITY) \
3031
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
31-
OBJC_REPR, Optional<StringRef>(C_REPR), NEEDS_NULLABILITY}
32+
OBJC_REPR, \
33+
Optional<StringRef>(C_REPR), \
34+
Optional<StringRef>(C_REPR), \
35+
NEEDS_NULLABILITY \
36+
}
37+
#define MAP_CXX(SWIFT_NAME, OBJC_REPR, C_REPR, CXX_REPR, NEEDS_NULLABILITY) \
38+
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
39+
OBJC_REPR, Optional<StringRef>(C_REPR), Optional<StringRef>(CXX_REPR), \
40+
NEEDS_NULLABILITY}
3241

3342
MAP(CBool, "bool", false);
3443

@@ -66,8 +75,8 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
6675
MAP(Float32, "float", false);
6776
MAP(Float64, "double", false);
6877

69-
MAP_C(Int, "NSInteger", "ptrdiff_t", false);
70-
MAP_C(UInt, "NSUInteger", "size_t", false);
78+
MAP_CXX(Int, "NSInteger", "ptrdiff_t", "swift::Int", false);
79+
MAP_CXX(UInt, "NSUInteger", "size_t", "swift::UInt", false);
7180
MAP_C(Bool, "BOOL", "bool", false);
7281

7382
MAP(OpaquePointer, "void *", true);
@@ -76,33 +85,33 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
7685

7786
Identifier ID_ObjectiveC = ctx.Id_ObjectiveC;
7887
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier("ObjCBool")}] = {
79-
"BOOL", None, false};
88+
"BOOL", None, None, false};
8089
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier("Selector")}] = {
81-
"SEL", None, true};
90+
"SEL", None, None, true};
8291
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier(ctx.getSwiftName(
8392
KnownFoundationEntity::NSZone))}] = {
84-
"struct _NSZone *", None, true};
93+
"struct _NSZone *", None, None, true};
8594

8695
mappedTypeNames[{ctx.Id_Darwin, ctx.getIdentifier("DarwinBoolean")}] = {
87-
"Boolean", None, false};
96+
"Boolean", None, None, false};
8897

8998
mappedTypeNames[{ctx.Id_CoreGraphics, ctx.Id_CGFloat}] = {"CGFloat", None,
90-
false};
99+
None, false};
91100

92101
mappedTypeNames[{ctx.Id_CoreFoundation, ctx.Id_CGFloat}] = {"CGFloat", None,
93-
false};
102+
None, false};
94103

95104
// Use typedefs we set up for SIMD vector types.
96105
#define MAP_SIMD_TYPE(BASENAME, _, __) \
106+
StringRef simd2##BASENAME = "swift_" #BASENAME "2"; \
97107
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "2")}] = { \
98-
"swift_" #BASENAME "2", Optional<StringRef>("swift_" #BASENAME "2"), \
99-
false}; \
108+
simd2##BASENAME, simd2##BASENAME, simd2##BASENAME, false}; \
109+
StringRef simd3##BASENAME = "swift_" #BASENAME "3"; \
100110
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "3")}] = { \
101-
"swift_" #BASENAME "3", Optional<StringRef>("swift_" #BASENAME "3"), \
102-
false}; \
111+
simd3##BASENAME, simd3##BASENAME, simd3##BASENAME, false}; \
112+
StringRef simd4##BASENAME = "swift_" #BASENAME "4"; \
103113
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "4")}] = { \
104-
"swift_" #BASENAME "4", Optional<StringRef>("swift_" #BASENAME "4"), \
105-
false};
114+
simd4##BASENAME, simd4##BASENAME, simd4##BASENAME, false};
106115
#include "swift/ClangImporter/SIMDMappedTypes.def"
107116
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
108117
"must add or remove special name mappings if max number of "
@@ -137,3 +146,12 @@ PrimitiveTypeMapping::getKnownCTypeInfo(const TypeDecl *typeDecl) {
137146
}
138147
return None;
139148
}
149+
150+
Optional<PrimitiveTypeMapping::CxxClangTypeInfo>
151+
PrimitiveTypeMapping::getKnownCxxTypeInfo(const TypeDecl *typeDecl) {
152+
if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl)) {
153+
if (typeInfo->cxxName)
154+
return CxxClangTypeInfo{*typeInfo->cxxName, typeInfo->canBeNullable};
155+
}
156+
return None;
157+
}

lib/PrintAsClang/PrimitiveTypeMapping.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ class PrimitiveTypeMapping {
4848
/// primitive type declaration, or \c None if no such type name exists.
4949
Optional<CClangTypeInfo> getKnownCTypeInfo(const TypeDecl *typeDecl);
5050

51+
struct CxxClangTypeInfo {
52+
StringRef name;
53+
bool canBeNullable;
54+
};
55+
56+
/// Returns the C++ type name and nullability for the given Swift
57+
/// primitive type declaration, or \c None if no such type name exists.
58+
Optional<CxxClangTypeInfo> getKnownCxxTypeInfo(const TypeDecl *typeDecl);
59+
5160
private:
5261
void initialize(ASTContext &ctx);
5362

@@ -56,6 +65,8 @@ class PrimitiveTypeMapping {
5665
StringRef objcName;
5766
// The C name of the Swift type.
5867
Optional<StringRef> cName;
68+
// The C++ name of the Swift type.
69+
Optional<StringRef> cxxName;
5970
bool canBeNullable;
6071
};
6172

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,15 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
304304
emitCxxConditional(
305305
out, [&] { emitMacro("SWIFT_NOEXCEPT", "noexcept"); },
306306
[&] { emitMacro("SWIFT_NOEXCEPT"); });
307+
emitCxxConditional(out, [&] {
308+
out << "#if !defined(SWIFT_CXX_INT_DEFINED)\n";
309+
out << "#define SWIFT_CXX_INT_DEFINED\n";
310+
out << "namespace swift {\n";
311+
out << "using Int = ptrdiff_t;\n";
312+
out << "using UInt = size_t;\n";
313+
out << "}\n";
314+
out << "#endif\n";
315+
});
307316
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
308317
"need to add SIMD typedefs here if max elements is increased");
309318
}

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "PrintClangFunction.h"
1414
#include "ClangSyntaxPrinter.h"
1515
#include "DeclAndTypePrinter.h"
16+
#include "OutputLanguageMode.h"
1617
#include "PrimitiveTypeMapping.h"
1718
#include "swift/AST/Decl.h"
1819
#include "swift/AST/ParameterList.h"
@@ -23,6 +24,22 @@
2324

2425
using namespace swift;
2526

27+
namespace {
28+
29+
class ClangFunctionSignatureTypePrinter : private ClangSyntaxPrinter {
30+
public:
31+
ClangFunctionSignatureTypePrinter(raw_ostream &os) : ClangSyntaxPrinter(os) {}
32+
33+
void printIfSimpleType(StringRef name, bool canBeNullable,
34+
Optional<OptionalTypeKind> optionalKind) {
35+
os << name;
36+
if (canBeNullable)
37+
printNullability(optionalKind);
38+
}
39+
40+
void printVoidType() { os << "void"; }
41+
};
42+
2643
// Prints types in the C function signature that corresponds to the
2744
// native Swift function/method.
2845
class CFunctionSignatureTypePrinter
@@ -31,11 +48,22 @@ class CFunctionSignatureTypePrinter
3148
private ClangSyntaxPrinter {
3249
public:
3350
CFunctionSignatureTypePrinter(raw_ostream &os,
34-
PrimitiveTypeMapping &typeMapping)
35-
: ClangSyntaxPrinter(os), typeMapping(typeMapping) {}
51+
PrimitiveTypeMapping &typeMapping,
52+
OutputLanguageMode languageMode)
53+
: ClangSyntaxPrinter(os), typeMapping(typeMapping),
54+
languageMode(languageMode) {}
3655

3756
bool printIfKnownSimpleType(const TypeDecl *typeDecl,
3857
Optional<OptionalTypeKind> optionalKind) {
58+
if (languageMode == OutputLanguageMode::Cxx) {
59+
auto knownTypeInfo = typeMapping.getKnownCxxTypeInfo(typeDecl);
60+
if (!knownTypeInfo)
61+
return false;
62+
os << knownTypeInfo->name;
63+
if (knownTypeInfo->canBeNullable)
64+
printNullability(optionalKind);
65+
return true;
66+
}
3967
auto knownTypeInfo = typeMapping.getKnownCTypeInfo(typeDecl);
4068
if (!knownTypeInfo)
4169
return false;
@@ -83,16 +111,20 @@ class CFunctionSignatureTypePrinter
83111

84112
private:
85113
PrimitiveTypeMapping &typeMapping;
114+
OutputLanguageMode languageMode;
86115
};
87116

117+
} // end namespace
118+
88119
void DeclAndTypeClangFunctionPrinter::printFunctionDeclAsCFunctionDecl(
89120
FuncDecl *FD, StringRef name, Type resultTy) {
90121
// FIXME: Might need a PrintMultiPartType here.
91122
auto print = [this](Type ty, Optional<OptionalTypeKind> optionalKind,
92123
StringRef name) {
93124
// FIXME: add support for noescape and PrintMultiPartType,
94125
// see DeclAndTypePrinter::print.
95-
CFunctionSignatureTypePrinter typePrinter(os, typeMapping);
126+
CFunctionSignatureTypePrinter typePrinter(os, typeMapping,
127+
OutputLanguageMode::ObjC);
96128
typePrinter.visit(ty, optionalKind);
97129

98130
if (!name.empty()) {
@@ -106,7 +138,8 @@ void DeclAndTypeClangFunctionPrinter::printFunctionDeclAsCFunctionDecl(
106138
Type objTy;
107139
std::tie(objTy, kind) =
108140
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
109-
CFunctionSignatureTypePrinter typePrinter(os, typeMapping);
141+
CFunctionSignatureTypePrinter typePrinter(os, typeMapping,
142+
OutputLanguageMode::ObjC);
110143
typePrinter.visit(objTy, kind);
111144

112145
os << ' ' << name << '(';
@@ -128,3 +161,53 @@ void DeclAndTypeClangFunctionPrinter::printFunctionDeclAsCFunctionDecl(
128161
}
129162
os << ')';
130163
}
164+
165+
void DeclAndTypeClangFunctionPrinter::printFunctionDeclAsCxxFunctionDecl(
166+
FuncDecl *FD, StringRef name, Type resultTy) {
167+
// FIXME: Might need a PrintMultiPartType here.
168+
auto print = [this](Type ty, Optional<OptionalTypeKind> optionalKind,
169+
StringRef name) {
170+
// FIXME: add support for noescape and PrintMultiPartType,
171+
// see DeclAndTypePrinter::print.
172+
CFunctionSignatureTypePrinter typePrinter(os, typeMapping,
173+
OutputLanguageMode::Cxx);
174+
typePrinter.visit(ty, optionalKind);
175+
176+
if (!name.empty()) {
177+
os << ' ';
178+
ClangSyntaxPrinter(os).printIdentifier(name);
179+
}
180+
};
181+
182+
// Print out the return type.
183+
OptionalTypeKind kind;
184+
Type objTy;
185+
std::tie(objTy, kind) =
186+
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
187+
CFunctionSignatureTypePrinter typePrinter(os, typeMapping,
188+
OutputLanguageMode::Cxx);
189+
typePrinter.visit(objTy, kind);
190+
191+
os << ' ' << name << '(';
192+
193+
// Print out the parameter types.
194+
auto params = FD->getParameters();
195+
if (params->size()) {
196+
size_t paramIndex = 1;
197+
llvm::interleaveComma(*params, os, [&](const ParamDecl *param) {
198+
OptionalTypeKind kind;
199+
Type objTy;
200+
std::tie(objTy, kind) = DeclAndTypePrinter::getObjectTypeAndOptionality(
201+
param, param->getInterfaceType());
202+
std::string paramName =
203+
param->getName().empty() ? "" : param->getName().str().str();
204+
if (paramName.empty()) {
205+
llvm::raw_string_ostream os(paramName);
206+
os << "_" << paramIndex;
207+
}
208+
print(objTy, kind, paramName);
209+
++paramIndex;
210+
});
211+
}
212+
os << ')';
213+
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class DeclAndTypeClangFunctionPrinter {
3636
void printFunctionDeclAsCFunctionDecl(FuncDecl *FD, StringRef name,
3737
Type resultTy);
3838

39+
/// Print the inline C++ function thunk declaration that corresponds to the
40+
/// given Swift function declaration.
41+
void printFunctionDeclAsCxxFunctionDecl(FuncDecl *FD, StringRef name,
42+
Type resultTy);
43+
3944
private:
4045
raw_ostream &os;
4146
PrimitiveTypeMapping &typeMapping;

test/Interop/SwiftToCxx/functions/function-availability.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@
1616

1717
// CHECK: }
1818

19-
// CHECK: inline void alwaysDeprecated(void) noexcept SWIFT_DEPRECATED {
19+
// CHECK: inline void alwaysDeprecated() noexcept SWIFT_DEPRECATED {
2020
@available(*, deprecated)
2121
public func alwaysDeprecated() {}
2222

23-
// CHECK: inline void alwaysDeprecatedTwo(void) noexcept SWIFT_DEPRECATED_MSG("it should not be used")
23+
// CHECK: inline void alwaysDeprecatedTwo() noexcept SWIFT_DEPRECATED_MSG("it should not be used")
2424
@available(*, deprecated, message: "it should not be used")
2525
public func alwaysDeprecatedTwo() {}
2626

27-
// CHECK: inline void alwaysUnavailable(void) noexcept SWIFT_UNAVAILABLE
27+
// CHECK: inline void alwaysUnavailable() noexcept SWIFT_UNAVAILABLE
2828
@available(*, unavailable)
2929
public func alwaysUnavailable() {}
3030

31-
// CHECK: inline void alwaysUnavailableMessage(void) noexcept SWIFT_UNAVAILABLE_MSG("stuff happened")
31+
// CHECK: inline void alwaysUnavailableMessage() noexcept SWIFT_UNAVAILABLE_MSG("stuff happened")
3232
@available(*, unavailable, message: "stuff happened")
3333
public func alwaysUnavailableMessage() {}
3434

35-
// CHECK: inline void singlePlatAvailability(void) noexcept SWIFT_AVAILABILITY(macos,introduced=11)
35+
// CHECK: inline void singlePlatAvailability() noexcept SWIFT_AVAILABILITY(macos,introduced=11)
3636
@available(macOS 11, *)
3737
public func singlePlatAvailability() {}

test/Interop/SwiftToCxx/functions/swift-functions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ public func passTwoIntReturnIntNoArgLabelParamName(_ x2: CInt, _ y2: CInt) -> CI
4545

4646
public func passVoidReturnVoid() { print("passVoidReturnVoid") }
4747

48-
// CHECK: inline void passVoidReturnVoid(void) noexcept {
48+
// CHECK: inline void passVoidReturnVoid() noexcept {
4949
// CHECK: return _impl::$s9Functions014passVoidReturnC0yyF();
5050
// CHECK: }

0 commit comments

Comments
 (0)