Skip to content

Commit 47e556e

Browse files
committed
[cxx-interop] Prevent usage in Swift of C++ copy constructor with default args
1 parent 8daf94c commit 47e556e

File tree

5 files changed

+52
-0
lines changed

5 files changed

+52
-0
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7851,6 +7851,14 @@ static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) {
78517851
return true;
78527852
}
78537853

7854+
static bool hasDefaultArgs(const clang::CXXConstructorDecl *ctor) {
7855+
if (ctor->param_empty()) {
7856+
return false;
7857+
}
7858+
auto lastParam = ctor->parameters().back();
7859+
return lastParam->hasDefaultArg();
7860+
}
7861+
78547862
/// Checks if a record provides the required value type lifetime operations
78557863
/// (copy and destroy).
78567864
static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) {
@@ -7867,6 +7875,7 @@ static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) {
78677875
// struct.
78687876
return llvm::any_of(decl->ctors(), [](clang::CXXConstructorDecl *ctor) {
78697877
return ctor->isCopyConstructor() && !ctor->isDeleted() &&
7878+
!hasDefaultArgs(ctor) &&
78707879
ctor->getAccess() == clang::AccessSpecifier::AS_public;
78717880
});
78727881
}

test/Interop/Cxx/class/Inputs/type-classification.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,16 @@ struct __attribute__((swift_attr("~Copyable"))) StructCopyableMovableAnnotatedNo
262262
~StructCopyableMovableAnnotatedNonCopyable() = default;
263263
};
264264

265+
struct HasCopyConstructorWithDefaultArgs {
266+
int value;
267+
HasCopyConstructorWithDefaultArgs(int value) : value(value) {}
268+
269+
HasCopyConstructorWithDefaultArgs(
270+
const HasCopyConstructorWithDefaultArgs &other, int value = 1)
271+
: value(other.value + value) {}
272+
273+
HasCopyConstructorWithDefaultArgs(HasCopyConstructorWithDefaultArgs &&) =
274+
default;
275+
};
276+
265277
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_TYPE_CLASSIFICATION_H

test/Interop/Cxx/class/type-classification-typechecker.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ func testAnnotated() {
2222
_ = v
2323
}
2424

25+
func testNonCopyable() {
26+
let x = HasCopyConstructorWithDefaultArgs(5)
27+
let v = copy x // expected-error {{'copy' cannot be applied to noncopyable types}}
28+
_ = v
29+
}
30+
2531
test()
2632
testField()
2733
testAnnotated()
34+
testNonCopyable()

test/Interop/Cxx/value-witness-table/Inputs/copy-constructors.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ struct HasNonTrivialDefaultCopyConstructor {
2323
const HasNonTrivialDefaultCopyConstructor &) = default;
2424
};
2525

26+
struct HasCopyConstructorWithDefaultArgs {
27+
int value;
28+
HasCopyConstructorWithDefaultArgs(int value) : value(value) {}
29+
30+
HasCopyConstructorWithDefaultArgs(
31+
const HasCopyConstructorWithDefaultArgs &other, int value = 1)
32+
: value(other.value + value) {}
33+
34+
HasCopyConstructorWithDefaultArgs(HasCopyConstructorWithDefaultArgs &&) =
35+
default;
36+
};
37+
2638
// Make sure that we don't crash on struct templates with copy-constructors.
2739
template <typename T> struct S {
2840
S(S const &) {}

test/Interop/Cxx/value-witness-table/copy-constructors-execution.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,16 @@ CXXCopyConstructorTestSuite.test("Default copy constructor, member with user-def
4848
expectTrue(result.0.box.numCopies + result.1.box.numCopies > 0)
4949
}
5050

51+
CXXCopyConstructorTestSuite.test("Copy constructor with default args") {
52+
@inline(never)
53+
54+
// When in the presence of a C++ copy constructor with default args, we make the type non-copyable
55+
let originalObj = HasCopyConstructorWithDefaultArgs(5)
56+
expectEqual(originalObj.value, 5)
57+
58+
// move originalObj
59+
let newObj = originalObj
60+
expectEqual(newObj.value, 5)
61+
}
62+
5163
runAllTests()

0 commit comments

Comments
 (0)