Skip to content

Commit 5c703b4

Browse files
committed
[interop][SwiftToCxx] support std::string -> Swift::String conversion in C++
1 parent 7c2ee16 commit 5c703b4

File tree

7 files changed

+68
-5
lines changed

7 files changed

+68
-5
lines changed

lib/PrintAsClang/ModuleContentsWriter.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,10 @@ EmittedClangHeaderDependencyInfo swift::printModuleContentsAsCxx(
776776
writer.write();
777777
info.dependsOnStandardLibrary = writer.isStdlibRequired();
778778
if (M.isStdlibModule()) {
779+
// Embed additional STL includes.
780+
os << "#ifndef SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY\n";
781+
os << "#include <string>\n";
782+
os << "#endif\n";
779783
// Embed an overlay for the standard library.
780784
ClangSyntaxPrinter(moduleOS).printIncludeForShimHeader(
781785
"_SwiftStdlibCxxOverlay.h");

lib/PrintAsClang/PrintClangValueType.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ void ClangValueTypePrinter::forwardDeclType(raw_ostream &os,
9595
}
9696

9797
static void addCppExtensionsToStdlibType(const NominalTypeDecl *typeDecl,
98+
raw_ostream &os,
9899
ClangSyntaxPrinter &printer,
99100
raw_ostream &cPrologueOS) {
100101
if (typeDecl == typeDecl->getASTContext().getStringDecl()) {
@@ -135,6 +136,9 @@ static void addCppExtensionsToStdlibType(const NominalTypeDecl *typeDecl,
135136
"$sSS10FoundationE36_"
136137
"unconditionallyBridgeFromObjectiveCySSSo8NSStringCSgFZ("
137138
"void * _Nullable) SWIFT_NOEXCEPT SWIFT_CALL;\n";
139+
cPrologueOS << "SWIFT_EXTERN swift_interop_stub_Swift_String "
140+
"$sSS7cStringSSSPys4Int8VG_tcfC("
141+
"const char * _Nonnull) SWIFT_NOEXCEPT SWIFT_CALL;\n";
138142
printer.printObjCBlock([](raw_ostream &os) {
139143
os << " ";
140144
ClangSyntaxPrinter(os).printInlineForThunk();
@@ -155,6 +159,14 @@ static void addCppExtensionsToStdlibType(const NominalTypeDecl *typeDecl,
155159
os << " return result;\n";
156160
os << " }\n";
157161
});
162+
os << "#ifndef SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY\n";
163+
ClangSyntaxPrinter(os).printInlineForThunk();
164+
os << "String(const std::string &str) noexcept {\n";
165+
os << " auto res = "
166+
"_impl::$sSS7cStringSSSPys4Int8VG_tcfC(str.c_str());\n";
167+
os << " memcpy(_getOpaquePointer(), &res, sizeof(res));\n";
168+
os << "}\n";
169+
os << "#endif\n";
158170
} else if (typeDecl == typeDecl->getASTContext().getOptionalDecl()) {
159171
// Add additional methods for the `Optional` declaration.
160172
printer.printDefine("SWIFT_CXX_INTEROP_OPTIONAL_MIXIN");
@@ -295,7 +307,7 @@ void ClangValueTypePrinter::printValueTypeDecl(
295307

296308
bodyPrinter();
297309
if (typeDecl->isStdlibDecl())
298-
addCppExtensionsToStdlibType(typeDecl, printer, cPrologueOS);
310+
addCppExtensionsToStdlibType(typeDecl, os, printer, cPrologueOS);
299311

300312
os << "private:\n";
301313

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -enable-experimental-cxx-interop -emit-clang-header-path %t/functions.h
33
// RUN: %FileCheck %s < %t/functions.h
44

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

77
// CHECK-LABEL: namespace Functions __attribute__((swift_private)) {
88

test/Interop/SwiftToCxx/stdlib/stdlib-dep-inline-in-cxx.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
// RUN: cat %t/stdlib.h %t/stdlib2.h > %t/two_includes.h
99

10-
// RUN: %check-interop-cxx-header-in-clang(%t/two_includes.h -Wno-unused-private-field -Wno-unused-function -Wno-shadow)
10+
// RUN: %check-interop-cxx-header-in-clang(-DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY %t/two_includes.h -Wno-unused-private-field -Wno-unused-function -Wno-shadow)
1111

1212
@_expose(Cxx)
1313
public func test() -> String {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -typecheck %t/print-string.swift -typecheck -module-name Stringer -enable-experimental-cxx-interop -emit-clang-header-path %t/Stringer.h
5+
6+
// RUN: %target-interop-build-clangxx -std=gnu++20 -c %t/string-conversions.cpp -I %t -o %t/swift-stdlib-execution.o
7+
// RUN: %target-build-swift %t/print-string.swift -o %t/swift-stdlib-execution -Xlinker %t/swift-stdlib-execution.o -module-name Stringer -Xfrontend -entry-point-function-name -Xfrontend swiftMain %target-cxx-lib
8+
// RUN: %target-codesign %t/swift-stdlib-execution
9+
// RUN: %target-run %t/swift-stdlib-execution | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
13+
//--- print-string.swift
14+
15+
@_expose(Cxx)
16+
public func printString(_ s: String) {
17+
print("'''\(s)'''")
18+
}
19+
20+
//--- string-conversions.cpp
21+
22+
#include <cassert>
23+
#include "Stringer.h"
24+
25+
int main() {
26+
using namespace Swift;
27+
using namespace Stringer;
28+
29+
{
30+
auto s = String("hello world");
31+
printString(s);
32+
}
33+
// CHECK: '''hello world'''
34+
35+
{
36+
std::string str = "test std::string";
37+
printString(str);
38+
}
39+
// CHECK-NEXT: '''test std::string'''
40+
return 0;
41+
}

test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-swift-frontend -parse-as-library %platform-module-dir/Swift.swiftmodule/%module-target-triple.swiftinterface -enable-library-evolution -disable-objc-attr-requires-foundation-module -typecheck -module-name Swift -parse-stdlib -enable-experimental-cxx-interop -emit-clang-header-path %t/Swift.h -experimental-skip-all-function-bodies
33
// RUN: %FileCheck %s < %t/Swift.h
44

5-
// RUN: %check-interop-cxx-header-in-clang(%t/Swift.h -Wno-unused-private-field -Wno-unused-function -Wno-shadow)
5+
// RUN: %check-interop-cxx-header-in-clang(%t/Swift.h -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY -Wno-unused-private-field -Wno-unused-function -Wno-shadow)
66

77
// FIXME: remove need for -Wno-shadow
88

@@ -87,6 +87,12 @@
8787
// CHECK-NEXT: }
8888
// CHECK-EMPTY:
8989
// CHECK-NEXT: #endif
90+
// CHECK-NEXT: #ifndef SWIFT_CXX_INTEROP_HIDE_STL_OVERLAY
91+
// CHECK-NEXT: inline __attribute__((always_inline)) String(const std::string &str) noexcept {
92+
// CHECK-NEXT: auto res = _impl::$sSS7cStringSSSPys4Int8VG_tcfC(str.c_str());
93+
// CHECK-NEXT: memcpy(_getOpaquePointer(), &res, sizeof(res));
94+
// CHECK-NEXT: }
95+
// CHECK-NEXT: #endif
9096
// CHECK-NEXT: private:
9197

9298
// CHECK: #if __has_include(<../../../swift/swiftToCxx/_SwiftStdlibCxxOverlay.h>)

test/Interop/SwiftToCxxToSwift/hide-swift-module-namespace-in-swift.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// RUN: %target-swift-frontend -typecheck %t/swiftMod.swift -typecheck -module-name SwiftMod -emit-clang-header-path %t/swiftMod2.h -I %t -enable-experimental-cxx-interop
1010

11-
// RUN: %check-interop-cxx-header-in-clang(%t/swiftMod2.h -Wno-error)
11+
// RUN: %check-interop-cxx-header-in-clang(%t/swiftMod2.h -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY -Wno-error)
1212

1313
// XFAIL: OS=linux-android, OS=linux-androideabi
1414

0 commit comments

Comments
 (0)