Skip to content

Commit 39d86bc

Browse files
committed
[interop][SwiftToCxx] the not yet implemented move constructor for Swift value types should lead to link error when a move is used in Swift, not runtime error
1 parent 16b1fe1 commit 39d86bc

12 files changed

+103
-16
lines changed

lib/PrintAsClang/PrintClangValueType.cpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,21 @@ void ClangValueTypePrinter::printValueTypeDecl(
308308

309309
// FIXME: implement the move constructor.
310310
os << " [[noreturn]] ";
311-
printer.printInlineForThunk();
311+
// NOTE: Do not apply attribute((used))
312+
// here to ensure the linker error isn't
313+
// forced, so just mark this an inline
314+
// helper function instead.
315+
printer.printInlineForHelperFunction();
312316
printer.printBaseName(typeDecl);
313317
os << "(";
314318
printer.printBaseName(typeDecl);
315-
os << " &&) noexcept { abort(); }\n";
319+
StringRef moveErrorMessage = "C++ does not support moving a Swift value yet";
320+
os << " &&) noexcept {\n "
321+
"swift::_impl::_fatalError_Cxx_move_of_Swift_value_type_not_supported_"
322+
"yet();\n swift::_impl::_swift_stdlib_reportFatalError(\"swift\", 5, "
323+
"\""
324+
<< moveErrorMessage << "\", " << moveErrorMessage.size()
325+
<< ", 0);\n abort();\n }\n";
316326

317327
bodyPrinter();
318328
if (typeDecl->isStdlibDecl())

lib/PrintAsClang/_SwiftCxxInteroperability.h

+15
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,21 @@ extern "C" void *_Nonnull swift_retain(void *_Nonnull) noexcept;
9393

9494
extern "C" void swift_release(void *_Nonnull) noexcept;
9595

96+
#pragma clang diagnostic push
97+
#pragma clang diagnostic ignored "-Wreserved-identifier"
98+
99+
extern "C" void _swift_stdlib_reportFatalError(const char *_Nonnull prefix,
100+
int prefixLength,
101+
const char *_Nonnull message,
102+
int messageLength,
103+
uint32_t flags) noexcept;
104+
105+
// A dummy symbol that forces a linker error when
106+
// C++ tries to invoke a move of a Swift value type.
107+
extern "C" void _fatalError_Cxx_move_of_Swift_value_type_not_supported_yet();
108+
109+
#pragma clang diagnostic pop
110+
96111
SWIFT_INLINE_THUNK void *_Nonnull opaqueAlloc(size_t size,
97112
size_t align) noexcept {
98113
#if defined(_WIN32)

test/Interop/SwiftToCxx/expose-attr/expose-swift-decls-to-cxx.swift

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public final class ExposedClass {
8383
// CHECK: class SWIFT_SYMBOL("{{.*}}") ExposedStruct final {
8484
// CHECK: class SWIFT_SYMBOL("{{.*}}") ExposedStruct2 final {
8585
// CHECK: ExposedStruct2(ExposedStruct2 &&)
86+
// CHECK: }
8687
// CHECK-NEXT: swift::Int getY() const SWIFT_SYMBOL("{{.*}}");
8788
// CHECK-NEXT: void setY(swift::Int value) SWIFT_SYMBOL("{{.*}}");
8889
// CHECK-NEXT: static SWIFT_INLINE_THUNK ExposedStruct2 init() SWIFT_SYMBOL("{{.*}}");

test/Interop/SwiftToCxx/initializers/init-in-cxx.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ public struct FirstSmallStruct {
3939

4040
// CHECK: class SWIFT_SYMBOL("s:4Init16FirstSmallStructV") FirstSmallStruct final {
4141
// CHECK-NEXT: public:
42-
// CHECK: SWIFT_INLINE_THUNK FirstSmallStruct(FirstSmallStruct &&)
42+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER FirstSmallStruct(FirstSmallStruct &&)
43+
// CHECK: }
4344
// CHECK-NEXT: SWIFT_INLINE_THUNK uint32_t getX() const SWIFT_SYMBOL("s:4Init16FirstSmallStructV1xs6UInt32Vvp");
4445
// CHECK-NEXT: static SWIFT_INLINE_THUNK FirstSmallStruct init() SWIFT_SYMBOL("s:4Init16FirstSmallStructVACycfc");
4546
// CHECK-NEXT: static SWIFT_INLINE_THUNK FirstSmallStruct init(swift::Int x) SWIFT_SYMBOL("s:4Init16FirstSmallStructVyACSicfc");

test/Interop/SwiftToCxx/methods/method-in-cxx.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ public final class PassStructInClassMethod {
9595
// CHECK-NEXT: static SWIFT_INLINE_THUNK LargeStruct staticFinalClassMethod(swift::Int x) SWIFT_SYMBOL("s:7Methods09ClassWithA0C011staticFinalB6Method1xAA11LargeStructVSi_tFZ");
9696

9797
// CHECK: class SWIFT_SYMBOL("s:7Methods11LargeStructV") LargeStruct final {
98-
// CHECK: SWIFT_INLINE_THUNK LargeStruct(LargeStruct &&)
98+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER LargeStruct(LargeStruct &&)
99+
// CHECK: }
99100
// CHECK-NEXT: SWIFT_INLINE_THUNK LargeStruct doubled() const SWIFT_SYMBOL("s:7Methods11LargeStructV7doubledACyF");
100101
// CHECK-NEXT: SWIFT_INLINE_THUNK void dump() const SWIFT_SYMBOL("s:7Methods11LargeStructV4dumpyyF");
101102
// CHECK-NEXT: SWIFT_INLINE_THUNK LargeStruct scaled(swift::Int x, swift::Int y) const SWIFT_SYMBOL("s:7Methods11LargeStructV6scaledyACSi_SitF");

test/Interop/SwiftToCxx/methods/mutating-method-in-cxx.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,16 @@ public struct SmallStruct {
5757
// CHECK: SWIFT_EXTERN void $s7Methods11SmallStructV6invertyyF(SWIFT_CONTEXT void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // invert()
5858

5959
// CHECK: class SWIFT_SYMBOL("s:7Methods11LargeStructV") LargeStruct final {
60-
// CHECK: SWIFT_INLINE_THUNK LargeStruct(LargeStruct &&)
60+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER LargeStruct(LargeStruct &&)
61+
// CHECK: }
6162
// CHECK-NEXT: SWIFT_INLINE_THUNK void dump() const SWIFT_SYMBOL("s:7Methods11LargeStructV4dumpyyF");
6263
// CHECK-NEXT: SWIFT_INLINE_THUNK void double_() SWIFT_SYMBOL("s:7Methods11LargeStructV6doubleyyF");
6364
// CHECK-NEXT: SWIFT_INLINE_THUNK LargeStruct scale(swift::Int x, swift::Int y) SWIFT_SYMBOL("s:7Methods11LargeStructV5scaleyACSi_SitF");
6465
// CHECK-NEXT: private
6566

6667
// CHECK: class SWIFT_SYMBOL("s:7Methods11SmallStructV") SmallStruct final {
67-
// CHECK: SWIFT_INLINE_THUNK SmallStruct(SmallStruct &&)
68+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER SmallStruct(SmallStruct &&)
69+
// CHECK: }
6870
// CHECK-NEXT: SWIFT_INLINE_THUNK void dump() const SWIFT_SYMBOL("s:7Methods11SmallStructV4dumpyyF");
6971
// CHECK-NEXT: SWIFT_INLINE_THUNK SmallStruct scale(float y) SWIFT_SYMBOL("s:7Methods11SmallStructV5scaleyACSfF");
7072
// CHECK-NEXT: SWIFT_INLINE_THUNK void invert() SWIFT_SYMBOL("s:7Methods11SmallStructV6invertyyF");

test/Interop/SwiftToCxx/properties/getter-in-cxx.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ public struct FirstSmallStruct {
1010

1111
// CHECK: class SWIFT_SYMBOL({{.*}}) FirstSmallStruct final {
1212
// CHECK: public:
13-
// CHECK: SWIFT_INLINE_THUNK FirstSmallStruct(FirstSmallStruct &&)
13+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER FirstSmallStruct(FirstSmallStruct &&)
14+
// CHECK: }
1415
// CHECK-NEXT: SWIFT_INLINE_THUNK uint32_t getX() const SWIFT_SYMBOL({{.*}});
1516
// CHECK-NEXT: private:
1617

@@ -36,7 +37,8 @@ public struct LargeStruct {
3637

3738
// CHECK: class SWIFT_SYMBOL({{.*}}) LargeStruct final {
3839
// CHECK: public:
39-
// CHECK: SWIFT_INLINE_THUNK LargeStruct(LargeStruct &&)
40+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER LargeStruct(LargeStruct &&)
41+
// CHECK: }
4042
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getX1() const SWIFT_SYMBOL({{.*}});
4143
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getX2() const SWIFT_SYMBOL({{.*}});
4244
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getX3() const SWIFT_SYMBOL({{.*}});
@@ -92,7 +94,8 @@ public struct SmallStructWithGetters {
9294

9395
// CHECK: class SWIFT_SYMBOL({{.*}}) SmallStructWithGetters final {
9496
// CHECK: public:
95-
// CHECK: SWIFT_INLINE_THUNK SmallStructWithGetters(SmallStructWithGetters &&)
97+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER SmallStructWithGetters(SmallStructWithGetters &&)
98+
// CHECK: }
9699
// CHECK-NEXT: SWIFT_INLINE_THUNK uint32_t getStoredInt() const SWIFT_SYMBOL({{.*}});
97100
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getComputedInt() const SWIFT_SYMBOL({{.*}});
98101
// CHECK-NEXT: SWIFT_INLINE_THUNK LargeStruct getLargeStruct() const SWIFT_SYMBOL({{.*}});

test/Interop/SwiftToCxx/properties/setter-in-cxx.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ public struct FirstSmallStruct {
1010

1111
// CHECK: class SWIFT_SYMBOL({{.*}}) FirstSmallStruct final {
1212
// CHECK: public:
13-
// CHECK: SWIFT_INLINE_THUNK FirstSmallStruct(FirstSmallStruct &&)
13+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER FirstSmallStruct(FirstSmallStruct &&)
14+
// CHECK: }
1415
// CHECK-NEXT: SWIFT_INLINE_THUNK uint32_t getX() const SWIFT_SYMBOL({{.*}});
1516
// CHECK-NEXT: SWIFT_INLINE_THUNK void setX(uint32_t value) SWIFT_SYMBOL({{.*}});
1617
// CHECK-NEXT: private:
@@ -31,7 +32,8 @@ public struct LargeStruct {
3132

3233
// CHECK: class SWIFT_SYMBOL({{.*}}) LargeStruct final {
3334
// CHECK: public:
34-
// CHECK: SWIFT_INLINE_THUNK LargeStruct(LargeStruct &&)
35+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER LargeStruct(LargeStruct &&)
36+
// CHECK: }
3537
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getX1() const SWIFT_SYMBOL({{.*}});
3638
// CHECK-NEXT: SWIFT_INLINE_THUNK void setX1(swift::Int value) SWIFT_SYMBOL({{.*}});
3739
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getX2() const SWIFT_SYMBOL({{.*}});
@@ -109,7 +111,8 @@ public struct SmallStructWithProps {
109111

110112
// CHECK: class SWIFT_SYMBOL({{.*}}) SmallStructWithProps final {
111113
// CHECK: public:
112-
// CHECK: SWIFT_INLINE_THUNK SmallStructWithProps(SmallStructWithProps &&)
114+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER SmallStructWithProps(SmallStructWithProps &&)
115+
// CHECK: }
113116
// CHECK-NEXT: SWIFT_INLINE_THUNK uint32_t getStoredInt() const SWIFT_SYMBOL({{.*}});
114117
// CHECK-NEXT: SWIFT_INLINE_THUNK void setStoredInt(uint32_t value) SWIFT_SYMBOL({{.*}});
115118
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int getComputedInt() const SWIFT_SYMBOL({{.*}});

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
// CHECK: }
7373
// CHECK-NEXT: SWIFT_INLINE_THUNK String(const String &other) noexcept {
7474
// CHECK: }
75-
// CHECK-NEXT: SWIFT_INLINE_THUNK String(String &&) noexcept { abort(); }
75+
// CHECK-NEXT: SWIFT_INLINE_PRIVATE_HELPER String(String &&) noexcept {
76+
// CHECK: }
7677
// CHECK-NEXT: static SWIFT_INLINE_THUNK String init() SWIFT_SYMBOL({{.*}});
7778
// CHECK: SWIFT_INLINE_THUNK void append(const String& other)
7879
// CHECK: SWIFT_INLINE_THUNK UTF8View getUtf8() const SWIFT_SYMBOL({{.*}});
@@ -107,7 +108,8 @@
107108
// CHECK-NEXT: private:
108109

109110
// CHECK: class SWIFT_SYMBOL({{.*}}) UTF8View final {
110-
// CHECK: SWIFT_INLINE_THUNK UTF8View(UTF8View &&) noexcept { abort(); }
111+
// CHECK: SWIFT_INLINE_PRIVATE_HELPER UTF8View(UTF8View &&) noexcept {
112+
// CHECK: }
111113
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index getStartIndex() const SWIFT_SYMBOL({{.*}});
112114
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index getEndIndex() const SWIFT_SYMBOL({{.*}});
113115
// CHECK: SWIFT_INLINE_THUNK swift::Optional<String_Index> indexOffsetByLimitedBy(const String_Index& i, swift::Int n, const String_Index& limit) const SWIFT_SYMBOL({{.*}});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/large-structs-pass-return-indirect-in-cxx.swift -typecheck -module-name Structs -clang-header-expose-decls=all-public -emit-clang-header-path %t/structs.h
4+
5+
// Link should fail by default when a move is
6+
// performed in C++.
7+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-structs-execution.o
8+
// RUN: not %target-interop-build-swift %S/large-structs-pass-return-indirect-in-cxx.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain 2>&1 | %FileCheck --check-prefix=LINK %s
9+
10+
// LINK: fatalError_Cxx_move_of_Swift_value_type_not_supported_yet
11+
12+
// Fallback to abort at runtime:
13+
14+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-structs-execution.o -DLINKS
15+
// RUN: %target-interop-build-swift %S/large-structs-pass-return-indirect-in-cxx.swift -o %t/swift-structs-execution -Xlinker %t/swift-structs-execution.o -module-name Structs -Xfrontend -entry-point-function-name -Xfrontend swiftMain 2>&1
16+
17+
// RUN: %target-codesign %t/swift-structs-execution
18+
// RUN: %target-run %t/swift-structs-execution 2>%t/output || true
19+
// RUN: cat %t/output | %FileCheck %s
20+
21+
// REQUIRES: executable_test
22+
23+
#include <assert.h>
24+
#include "structs.h"
25+
#include <memory>
26+
27+
#ifdef LINKS
28+
extern "C" void _fatalError_Cxx_move_of_Swift_value_type_not_supported_yet() {
29+
30+
}
31+
#endif
32+
33+
int main() {
34+
using namespace Structs;
35+
36+
auto x = returnNewStructSeveralI64(42);
37+
StructSeveralI64 x2 = std::move(x);
38+
return 0;
39+
}
40+
41+
// CHECK: C++ does not support moving a Swift value yet

test/Interop/SwiftToCxx/structs/struct-with-refcounted-member.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,9 @@ public func printBreak(_ x: Int) {
4747
// CHECK-NEXT: #endif
4848
// CHECK-NEXT: vwTable->initializeWithCopy(_getOpaquePointer(), const_cast<char *>(other._getOpaquePointer()), metadata._0);
4949
// CHECK-NEXT: }
50-
// CHECK-NEXT: SWIFT_INLINE_THUNK StructWithRefcountedMember(StructWithRefcountedMember &&) noexcept { abort(); }
50+
// CHECK-NEXT: SWIFT_INLINE_PRIVATE_HELPER StructWithRefcountedMember(StructWithRefcountedMember &&) noexcept {
51+
// CHECK-NEXT: swift::_impl::_fatalError_Cxx_move_of_Swift_value_type_not_supported_yet();
52+
// CHECK-NEXT: swift::_impl::_swift_stdlib_reportFatalError("swift", 5, "C++ does not support moving a Swift value yet", 45, 0);
53+
// CHECK-NEXT: abort();
54+
// CHECK-NEXT: }
5155
// CHECK-NEXT: private:

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@
3838
// CHECK: }
3939
// CHECK-NEXT: SWIFT_INLINE_THUNK StructWithIntField(const StructWithIntField &other) noexcept {
4040
// CHECK: }
41-
// CHECK-NEXT: noreturn]] SWIFT_INLINE_THUNK StructWithIntField(StructWithIntField &&) noexcept { abort(); }
41+
// CHECK-NEXT: noreturn]] SWIFT_INLINE_PRIVATE_HELPER StructWithIntField(StructWithIntField &&) noexcept {
42+
// CHECK-NEXT: swift::_impl::_fatalError_Cxx_move_of_Swift_value_type_not_supported_yet();
43+
// CHECK-NEXT: swift::_impl::_swift_stdlib_reportFatalError("swift", 5, "C++ does not support moving a Swift value yet", 45, 0);
44+
// CHECK-NEXT: abort();
45+
// CHECK-NEXT: }
4246
// CHECK-NEXT: private:
4347
// CHECK-NEXT: SWIFT_INLINE_THUNK StructWithIntField() noexcept {}
4448
// CHECK-NEXT: static SWIFT_INLINE_THUNK StructWithIntField _make() noexcept { return StructWithIntField(); }

0 commit comments

Comments
 (0)