Skip to content

Commit d594f47

Browse files
committed
[cxx-interop] Check for unsafe types of default arguments consistently
If the C++ type of a function parameter defines a custom copy constructor, assume that it is safe to use from Swift. This matches the heuristic that we use to detect if a C++ method is safe based on the return type. rdar://121391798
1 parent 443489f commit d594f47

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2540,7 +2540,8 @@ bool ClangImporter::Implementation::isDefaultArgSafeToImport(
25402540
// default expression, since we cannot guarantee the lifetime of the
25412541
// pointee value.
25422542
if (auto paramRecordDecl = param->getType()->getAsCXXRecordDecl()) {
2543-
if (isViewType(paramRecordDecl))
2543+
if (isViewType(paramRecordDecl) &&
2544+
!paramRecordDecl->hasUserDeclaredCopyConstructor())
25442545
return false;
25452546
}
25462547
// If the parameter is a const reference, check if the expression

test/Interop/Cxx/stdlib/Inputs/module.modulemap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ module StdSet {
2222
export *
2323
}
2424

25+
module StdString {
26+
header "std-string.h"
27+
requires cplusplus
28+
export *
29+
}
30+
2531
module StdPair {
2632
header "std-pair.h"
2733
requires cplusplus
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <string>
2+
3+
struct HasMethodThatReturnsString {
4+
int value = 111;
5+
std::string getString() const { return std::to_string(value); }
6+
};
7+
8+
inline std::string takesStringWithDefaultArg(std::string s = "abc") { return s; }

test/Interop/Cxx/stdlib/use-std-string.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop)
2-
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift)
2+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -D USE_CUSTOM_STRING_API)
3+
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -D SUPPORTS_DEFAULT_ARGUMENTS -D USE_CUSTOM_STRING_API)
34
//
45
// REQUIRES: executable_test
56

67
import StdlibUnittest
78
import CxxStdlib
9+
#if USE_CUSTOM_STRING_API
10+
import StdString
11+
#endif
812

913
var StdStringTestSuite = TestSuite("StdString")
1014

@@ -392,4 +396,30 @@ StdStringTestSuite.test("std::string from C string") {
392396
expectEqual(str, std.string("abc"))
393397
}
394398

399+
#if USE_CUSTOM_STRING_API
400+
StdStringTestSuite.test("get from a method") {
401+
let box = HasMethodThatReturnsString()
402+
let str = box.getString()
403+
expectEqual(str.size(), 3)
404+
expectEqual(str, std.string("111"))
405+
}
406+
407+
StdStringTestSuite.test("pass as an argument") {
408+
let s = std.string("a")
409+
let res = takesStringWithDefaultArg(s)
410+
expectEqual(res.size(), 1)
411+
expectEqual(res[0], 97)
412+
}
413+
414+
#if SUPPORTS_DEFAULT_ARGUMENTS
415+
StdStringTestSuite.test("pass as a default argument") {
416+
let res = takesStringWithDefaultArg()
417+
expectEqual(res.size(), 3)
418+
expectEqual(res[0], 97)
419+
expectEqual(res[1], 98)
420+
expectEqual(res[2], 99)
421+
}
422+
#endif
423+
#endif
424+
395425
runAllTests()

0 commit comments

Comments
 (0)