Skip to content

Commit ba2dcfb

Browse files
committed
[cxx-interop] support inout params as cxx references
1 parent 74d43a6 commit ba2dcfb

File tree

3 files changed

+297
-2
lines changed

3 files changed

+297
-2
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,16 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
102102
: OutputLanguageMode::Cxx;
103103
// FIXME: Might need a PrintMultiPartType here.
104104
auto print = [&, this](Type ty, Optional<OptionalTypeKind> optionalKind,
105-
StringRef name) {
105+
StringRef name, bool isInOutParam) {
106106
// FIXME: add support for noescape and PrintMultiPartType,
107107
// see DeclAndTypePrinter::print.
108108
CFunctionSignatureTypePrinter typePrinter(os, typeMapping, outputLang);
109109
typePrinter.visit(ty, optionalKind);
110110

111+
if (isInOutParam) {
112+
os << " &";
113+
}
114+
111115
if (!name.empty()) {
112116
os << ' ';
113117
ClangSyntaxPrinter(os).printIdentifier(name);
@@ -142,7 +146,7 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
142146
llvm::raw_string_ostream os(paramName);
143147
os << "_" << paramIndex;
144148
}
145-
print(objTy, argKind, paramName);
149+
print(objTy, argKind, paramName, param->isInOut());
146150
++paramIndex;
147151
});
148152
} else if (kind == FunctionSignatureKind::CFunctionProto) {
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
3+
// RUN: %FileCheck %s < %t/functions.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/functions.h)
6+
7+
// CHECK: inline void inOutBool(bool & x) noexcept {
8+
// CHECK-NEXT: return _impl::$s9Functions9inOutBoolyySbzF(x);
9+
// CHECK-NEXT: }
10+
11+
// CHECK: inline void inOutCBool(bool & x) noexcept {
12+
// CHECK-NEXT: return _impl::$s9Functions10inOutCBoolyySbzF(x);
13+
// CHECK-NEXT: }
14+
15+
// CHECK: inline void inOutCChar(char & x) noexcept {
16+
// CHECK-NEXT: return _impl::$s9Functions10inOutCCharyys4Int8VzF(x);
17+
// CHECK-NEXT: }
18+
19+
// CHECK: inline void inOutCChar16(char16_t & x) noexcept {
20+
// CHECK-NEXT: return _impl::$s9Functions12inOutCChar16yys6UInt16VzF(x);
21+
// CHECK-NEXT: }
22+
23+
// CHECK: inline void inOutCChar32(char32_t & x) noexcept {
24+
// CHECK-NEXT: return _impl::$s9Functions12inOutCChar32yys7UnicodeO6ScalarVzF(x);
25+
// CHECK-NEXT: }
26+
27+
// CHECK: inline void inOutCDouble(double & x) noexcept {
28+
// CHECK-NEXT: return _impl::$s9Functions12inOutCDoubleyySdzF(x);
29+
// CHECK-NEXT: }
30+
31+
// CHECK: inline void inOutCFloat(float & x) noexcept {
32+
// CHECK-NEXT: return _impl::$s9Functions11inOutCFloatyySfzF(x);
33+
// CHECK-NEXT: }
34+
35+
// CHECK: inline void inOutCInt(int & x) noexcept {
36+
// CHECK-NEXT: return _impl::$s9Functions9inOutCIntyys5Int32VzF(x);
37+
// CHECK-NEXT: }
38+
39+
// CHECK: inline void inOutCLongLong(long long & x) noexcept {
40+
// CHECK-NEXT: return _impl::$s9Functions14inOutCLongLongyys5Int64VzF(x);
41+
// CHECK-NEXT: }
42+
43+
// CHECK: inline void inOutCShort(short & x) noexcept {
44+
// CHECK-NEXT: return _impl::$s9Functions11inOutCShortyys5Int16VzF(x);
45+
// CHECK-NEXT: }
46+
47+
// CHECK: inline void inOutCSignedChar(signed char & x) noexcept {
48+
// CHECK-NEXT: return _impl::$s9Functions16inOutCSignedCharyys4Int8VzF(x);
49+
// CHECK-NEXT: }
50+
51+
// CHECK: inline void inOutCUnsignedChar(unsigned char & x) noexcept {
52+
// CHECK-NEXT: return _impl::$s9Functions18inOutCUnsignedCharyys5UInt8VzF(x);
53+
// CHECK-NEXT: }
54+
55+
// CHECK: inline void inOutCUnsignedInt(unsigned int & x) noexcept {
56+
// CHECK-NEXT: return _impl::$s9Functions17inOutCUnsignedIntyys6UInt32VzF(x);
57+
// CHECK-NEXT: }
58+
59+
// CHECK: inline void inOutCUnsignedLongLong(unsigned long long & x) noexcept {
60+
// CHECK-NEXT: return _impl::$s9Functions018inOutCUnsignedLongE0yys6UInt64VzF(x);
61+
// CHECK-NEXT: }
62+
63+
// CHECK: inline void inOutCUnsignedShort(unsigned short & x) noexcept {
64+
// CHECK-NEXT: return _impl::$s9Functions19inOutCUnsignedShortyys6UInt16VzF(x);
65+
// CHECK-NEXT: }
66+
67+
// CHECK: inline void inOutCWideChar(wchar_t & x) noexcept {
68+
// CHECK-NEXT: return _impl::$s9Functions14inOutCWideCharyys7UnicodeO6ScalarVzF(x);
69+
// CHECK-NEXT: }
70+
71+
// CHECK: inline void inOutDouble(double & x) noexcept {
72+
// CHECK-NEXT: return _impl::$s9Functions11inOutDoubleyySdzF(x);
73+
// CHECK-NEXT: }
74+
75+
// CHECK: inline void inOutFloat(float & x) noexcept {
76+
// CHECK-NEXT: return _impl::$s9Functions10inOutFloatyySfzF(x);
77+
// CHECK-NEXT: }
78+
79+
// CHECK: inline void inOutFloat32(float & x) noexcept {
80+
// CHECK-NEXT: return _impl::$s9Functions12inOutFloat32yySfzF(x);
81+
// CHECK-NEXT: }
82+
83+
// CHECK: inline void inOutFloat64(double & x) noexcept {
84+
// CHECK-NEXT: return _impl::$s9Functions12inOutFloat64yySdzF(x);
85+
// CHECK-NEXT: }
86+
87+
// CHECK: inline void inOutInt(swift::Int & x) noexcept {
88+
// CHECK-NEXT: return _impl::$s9Functions8inOutIntyySizF(x);
89+
// CHECK-NEXT: }
90+
91+
// CHECK: inline void inOutInt16(int16_t & x) noexcept {
92+
// CHECK-NEXT: return _impl::$s9Functions10inOutInt16yys0D0VzF(x);
93+
// CHECK-NEXT: }
94+
95+
// CHECK: inline void inOutInt32(int32_t & x) noexcept {
96+
// CHECK-NEXT: return _impl::$s9Functions10inOutInt32yys0D0VzF(x);
97+
// CHECK-NEXT: }
98+
99+
// CHECK: inline void inOutInt64(int64_t & x) noexcept {
100+
// CHECK-NEXT: return _impl::$s9Functions10inOutInt64yys0D0VzF(x);
101+
// CHECK-NEXT: }
102+
103+
// CHECK: inline void inOutInt8(int8_t & x) noexcept {
104+
// CHECK-NEXT: return _impl::$s9Functions9inOutInt8yys0D0VzF(x);
105+
// CHECK-NEXT: }
106+
107+
// CHECK: inline void inOutOpaquePointer(void * _Nonnull & x) noexcept {
108+
// CHECK-NEXT: return _impl::$s9Functions18inOutOpaquePointeryys0dE0VzF(x);
109+
// CHECK-NEXT: }
110+
111+
// CHECK: inline void inOutTwoInt(swift::Int & x, swift::Int & y) noexcept {
112+
// CHECK-NEXT: return _impl::$s9Functions11inOutTwoIntyySiz_SiztF(x, y);
113+
// CHECK-NEXT: }
114+
115+
// CHECK: inline void inOutTwoParam(bool & x, double & y) noexcept {
116+
// CHECK-NEXT: return _impl::$s9Functions13inOutTwoParamyySbz_SdztF(x, y);
117+
// CHECK-NEXT: }
118+
119+
// CHECK: inline void inOutUInt(swift::UInt & x) noexcept {
120+
// CHECK-NEXT: return _impl::$s9Functions9inOutUIntyySuzF(x);
121+
// CHECK-NEXT: }
122+
123+
// CHECK: inline void inOutUInt16(uint16_t & x) noexcept {
124+
// CHECK-NEXT: return _impl::$s9Functions11inOutUInt16yys0D0VzF(x);
125+
// CHECK-NEXT: }
126+
127+
// CHECK: inline void inOutUInt32(uint32_t & x) noexcept {
128+
// CHECK-NEXT: return _impl::$s9Functions11inOutUInt32yys0D0VzF(x);
129+
// CHECK-NEXT: }
130+
131+
// CHECK: inline void inOutUInt64(uint64_t & x) noexcept {
132+
// CHECK-NEXT: return _impl::$s9Functions11inOutUInt64yys0D0VzF(x);
133+
// CHECK-NEXT: }
134+
135+
// CHECK: inline void inOutUInt8(uint8_t & x) noexcept {
136+
// CHECK-NEXT: return _impl::$s9Functions10inOutUInt8yys0D0VzF(x);
137+
// CHECK-NEXT: }
138+
139+
// CHECK: inline void inOutUnsafeMutableRawPointer(void * _Nonnull & x) noexcept {
140+
// CHECK-NEXT: return _impl::$s9Functions28inOutUnsafeMutableRawPointeryySvzF(x);
141+
// CHECK-NEXT: }
142+
143+
// CHECK: inline void inOutUnsafeRawPointer(void const * _Nonnull & x) noexcept {
144+
// CHECK-NEXT: return _impl::$s9Functions21inOutUnsafeRawPointeryySVzF(x);
145+
// CHECK-NEXT: }
146+
147+
// CHECK: inline void roundTwoInOutUnsafeMutableRawPointer(void * _Nullable & x) noexcept {
148+
// CHECK-NEXT: return _impl::$s9Functions36roundTwoInOutUnsafeMutableRawPointeryySvSgzF(x);
149+
// CHECK-NEXT: }
150+
151+
public func inOutCBool(_ x: inout CBool) { x = CBool() }
152+
153+
public func inOutCChar(_ x: inout CChar) { x = CChar() }
154+
public func inOutCWideChar(_ x: inout CWideChar) { x = Unicode.Scalar(0) } // init() is not available
155+
public func inOutCChar16(_ x: inout CChar16) { x = CChar16() }
156+
public func inOutCChar32(_ x: inout CChar32) { x = Unicode.Scalar(0) } // init() is not available
157+
158+
// Don't test CLong as it's platform specific. See long-lp64 test instead.
159+
public func inOutCSignedChar(_ x: inout CSignedChar) { x = CSignedChar() }
160+
public func inOutCShort(_ x: inout CShort) { x = CShort() }
161+
public func inOutCInt(_ x: inout CInt) { x = CInt() }
162+
public func inOutCLongLong(_ x: inout CLongLong) { x = CLongLong() }
163+
164+
// Don't test CUnsignedLong as it's platform specific. See long-lp64 test instead.
165+
public func inOutCUnsignedChar(_ x: inout CUnsignedChar) { x = CUnsignedChar() }
166+
public func inOutCUnsignedShort(_ x: inout CUnsignedShort) { x = CUnsignedShort() }
167+
public func inOutCUnsignedInt(_ x: inout CUnsignedInt) { x = CUnsignedInt() }
168+
public func inOutCUnsignedLongLong(_ x: inout CUnsignedLongLong) { x = CUnsignedLongLong() }
169+
170+
public func inOutCFloat(_ x: inout CFloat) { x = CFloat() }
171+
public func inOutCDouble(_ x: inout CDouble) { x = CDouble() }
172+
173+
public func inOutInt8(_ x: inout Int8) { x = Int8() }
174+
public func inOutInt16(_ x: inout Int16) { x = Int16() }
175+
public func inOutInt32(_ x: inout Int32) { x = Int32() }
176+
public func inOutInt64(_ x: inout Int64) { x = Int64() }
177+
178+
public func inOutUInt8(_ x: inout UInt8) { x = UInt8() }
179+
public func inOutUInt16(_ x: inout UInt16) { x = UInt16() }
180+
public func inOutUInt32(_ x: inout UInt32) { x = UInt32() }
181+
public func inOutUInt64(_ x: inout UInt64) { x = UInt64() }
182+
183+
public func inOutFloat(_ x: inout Float) { x = Float() }
184+
public func inOutDouble(_ x: inout Double) { x = Double() }
185+
public func inOutFloat32(_ x: inout Float32) { x = Float32() }
186+
public func inOutFloat64(_ x: inout Float64) { x = Float64() }
187+
188+
public func inOutInt(_ x: inout Int) { x = Int() }
189+
public func inOutUInt(_ x: inout UInt) { x = UInt() }
190+
public func inOutBool(_ x: inout Bool) { x = Bool() }
191+
192+
public func inOutOpaquePointer(_ x: inout OpaquePointer) { x = OpaquePointer(UnsafeRawPointer(x)) }
193+
public func inOutUnsafeRawPointer(_ x: inout UnsafeRawPointer) { x = UnsafeRawPointer(x) }
194+
public func inOutUnsafeMutableRawPointer(_ x: inout UnsafeMutableRawPointer) { x = UnsafeMutableRawPointer(x) }
195+
196+
public func roundTwoInOutUnsafeMutableRawPointer(_ x: inout UnsafeMutableRawPointer?) { x = nil }
197+
198+
public func inOutTwoInt(_ x: inout Int, _ y: inout Int) {
199+
x += y
200+
y -= 2 * x
201+
}
202+
203+
public func inOutTwoParam(_ x: inout Bool, _ y: inout Double) {
204+
y = 3.14
205+
x = !x
206+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/swift-primitive-inout-functions-cxx-bridging.swift -typecheck -module-name Functions -clang-header-expose-public-decls -emit-clang-header-path %t/functions.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-functions-execution.o
6+
// RUN: %target-interop-build-swift %S/swift-primitive-inout-functions-cxx-bridging.swift -o %t/swift-functions-execution -Xlinker %t/swift-functions-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-functions-execution
9+
// RUN: %target-run %t/swift-functions-execution
10+
11+
// REQUIRES: executable_test
12+
13+
#include <cassert>
14+
#include "functions.h"
15+
16+
#define VERIFY_INOUT_VALUE(FUNC, TYPENAME, INITIAL_VALUE, EXPECT_VALUE) \
17+
do { \
18+
TYPENAME variable = INITIAL_VALUE; \
19+
FUNC(variable); \
20+
assert(variable == EXPECT_VALUE); \
21+
} while (false);
22+
23+
int main() {
24+
using namespace Functions;
25+
26+
// TODO: how to handle platform-dependent types?
27+
28+
VERIFY_INOUT_VALUE(inOutCBool, bool, true, false);
29+
VERIFY_INOUT_VALUE(inOutCChar, char, 'a', '\0');
30+
VERIFY_INOUT_VALUE(inOutCChar16, char16_t, u'a', u'\0');
31+
VERIFY_INOUT_VALUE(inOutCChar32, char32_t, U'a', U'\0');
32+
VERIFY_INOUT_VALUE(inOutCDouble, double, 1.0, 0.0);
33+
VERIFY_INOUT_VALUE(inOutCFloat, float, 1.0f, 0.0f);
34+
VERIFY_INOUT_VALUE(inOutCInt, int, 1, 0);
35+
VERIFY_INOUT_VALUE(inOutCLongLong, long long, 1LL, 0LL);
36+
VERIFY_INOUT_VALUE(inOutCShort, short, 1, 0);
37+
VERIFY_INOUT_VALUE(inOutCSignedChar, signed char, 1, 0);
38+
VERIFY_INOUT_VALUE(inOutCUnsignedChar, unsigned char, 1u, 0u);
39+
VERIFY_INOUT_VALUE(inOutCUnsignedInt, unsigned int, 1U, 0U);
40+
VERIFY_INOUT_VALUE(inOutCUnsignedLongLong, unsigned long long, 1ULL, 0ULL);
41+
VERIFY_INOUT_VALUE(inOutCUnsignedShort, unsigned short, 1u, 0u);
42+
VERIFY_INOUT_VALUE(inOutCWideChar, wchar_t, L'a', L'\0');
43+
44+
VERIFY_INOUT_VALUE(inOutBool, bool, true, false);
45+
46+
VERIFY_INOUT_VALUE(inOutDouble, double, 1.0, 0.0);
47+
VERIFY_INOUT_VALUE(inOutFloat, float, 1.0f, 0.0f);
48+
VERIFY_INOUT_VALUE(inOutFloat32, float, 1.0f, 0.0f);
49+
VERIFY_INOUT_VALUE(inOutFloat64, double, 1.0, 0.0);
50+
51+
VERIFY_INOUT_VALUE(inOutInt, swift::Int, swift::Int{1}, swift::Int{0});
52+
VERIFY_INOUT_VALUE(inOutInt16, int16_t, 1, 0);
53+
VERIFY_INOUT_VALUE(inOutInt32, int32_t, 1, 0);
54+
VERIFY_INOUT_VALUE(inOutInt64, int64_t, 1, 0);
55+
VERIFY_INOUT_VALUE(inOutInt8, int8_t, 1, 0);
56+
57+
VERIFY_INOUT_VALUE(inOutUInt, swift::UInt, swift::UInt{1u}, swift::UInt{0u});
58+
VERIFY_INOUT_VALUE(inOutUInt16, uint16_t, 1u, 0u);
59+
VERIFY_INOUT_VALUE(inOutUInt32, uint32_t, 1u, 0u);
60+
VERIFY_INOUT_VALUE(inOutUInt64, uint64_t, 1u, 0u);
61+
VERIFY_INOUT_VALUE(inOutUInt8, uint8_t, 1u, 0u);
62+
63+
{
64+
int x = 1;
65+
VERIFY_INOUT_VALUE(inOutOpaquePointer, void * _Nonnull, &x, &x);
66+
VERIFY_INOUT_VALUE(inOutUnsafeMutableRawPointer, void * _Nonnull, &x, &x);
67+
VERIFY_INOUT_VALUE(inOutUnsafeRawPointer, void const * _Nonnull, &x, &x);
68+
VERIFY_INOUT_VALUE(roundTwoInOutUnsafeMutableRawPointer, void * _Nullable, &x, nullptr);
69+
}
70+
71+
{
72+
swift::Int x{1}, y{2};
73+
inOutTwoInt(x, y);
74+
assert(x == swift::Int{3});
75+
assert(y == swift::Int{-4});
76+
}
77+
78+
{
79+
bool x = false;
80+
double y = 6.28;
81+
inOutTwoParam(x, y);
82+
assert(x);
83+
assert(y == 3.14);
84+
}
85+
}

0 commit comments

Comments
 (0)