Skip to content

Commit c3cd993

Browse files
committed
[cxx-interop] Implicitly defined move constructors
1 parent 94949f3 commit c3cd993

File tree

5 files changed

+82
-33
lines changed

5 files changed

+82
-33
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3105,14 +3105,13 @@ namespace {
31053105
// instantiate its copy constructor.
31063106
bool isExplicitlyNonCopyable = hasNonCopyableAttr(decl);
31073107

3108-
clang::CXXConstructorDecl *moveCtor = nullptr;
31093108
clang::CXXConstructorDecl *defaultCtor = nullptr;
31103109
if (decl->needsImplicitCopyConstructor() && !isExplicitlyNonCopyable) {
31113110
clangSema.DeclareImplicitCopyConstructor(
31123111
const_cast<clang::CXXRecordDecl *>(decl));
31133112
}
31143113
if (decl->needsImplicitMoveConstructor()) {
3115-
moveCtor = clangSema.DeclareImplicitMoveConstructor(
3114+
clangSema.DeclareImplicitMoveConstructor(
31163115
const_cast<clang::CXXRecordDecl *>(decl));
31173116
}
31183117
if (decl->needsImplicitDefaultConstructor()) {
@@ -3129,20 +3128,13 @@ namespace {
31293128
// Note: we use "doesThisDeclarationHaveABody" here because
31303129
// that's what "DefineImplicitCopyConstructor" checks.
31313130
!declCtor->doesThisDeclarationHaveABody()) {
3132-
if (declCtor->isMoveConstructor()) {
3133-
if (!moveCtor)
3134-
moveCtor = declCtor;
3135-
} else if (declCtor->isDefaultConstructor()) {
3131+
if (declCtor->isDefaultConstructor()) {
31363132
if (!defaultCtor)
31373133
defaultCtor = declCtor;
31383134
}
31393135
}
31403136
}
31413137
}
3142-
if (moveCtor && !decl->isAnonymousStructOrUnion()) {
3143-
clangSema.DefineImplicitMoveConstructor(clang::SourceLocation(),
3144-
moveCtor);
3145-
}
31463138
if (defaultCtor) {
31473139
clangSema.DefineImplicitDefaultConstructor(clang::SourceLocation(),
31483140
defaultCtor);
@@ -3151,7 +3143,8 @@ namespace {
31513143
if (decl->needsImplicitDestructor()) {
31523144
auto dtor = clangSema.DeclareImplicitDestructor(
31533145
const_cast<clang::CXXRecordDecl *>(decl));
3154-
clangSema.DefineImplicitDestructor(clang::SourceLocation(), dtor);
3146+
if (!dtor->isDeleted() && !dtor->isIneligibleOrNotSelected())
3147+
clangSema.DefineImplicitDestructor(clang::SourceLocation(), dtor);
31553148
}
31563149
}
31573150

lib/IRGen/GenStruct.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ namespace {
611611
/*invocation subs*/ SubstitutionMap(), IGF.IGM.Context);
612612
}
613613

614-
void emitCopyWithCopyConstructor(
614+
void emitCopyWithCopyOrMoveConstructor(
615615
IRGenFunction &IGF, SILType T,
616616
const clang::CXXConstructorDecl *copyConstructor, llvm::Value *src,
617617
llvm::Value *dest) const {
@@ -625,12 +625,21 @@ namespace {
625625
if (copyConstructor->isDefaulted() &&
626626
copyConstructor->getAccess() == clang::AS_public &&
627627
!copyConstructor->isDeleted() &&
628+
!copyConstructor->isIneligibleOrNotSelected() &&
628629
// Note: we use "doesThisDeclarationHaveABody" here because
629630
// that's what "DefineImplicitCopyConstructor" checks.
630631
!copyConstructor->doesThisDeclarationHaveABody()) {
631-
importer->getClangSema().DefineImplicitCopyConstructor(
632-
clang::SourceLocation(),
633-
const_cast<clang::CXXConstructorDecl *>(copyConstructor));
632+
assert(!copyConstructor->getParent()->isAnonymousStructOrUnion() &&
633+
"Cannot do codegen of special member functions of anonymous "
634+
"structs/unions");
635+
if (copyConstructor->isCopyConstructor())
636+
importer->getClangSema().DefineImplicitCopyConstructor(
637+
clang::SourceLocation(),
638+
const_cast<clang::CXXConstructorDecl *>(copyConstructor));
639+
else
640+
importer->getClangSema().DefineImplicitMoveConstructor(
641+
clang::SourceLocation(),
642+
const_cast<clang::CXXConstructorDecl *>(copyConstructor));
634643
}
635644

636645
auto &diagEngine = importer->getClangSema().getDiagnostics();
@@ -812,9 +821,9 @@ namespace {
812821
Address srcAddr, SILType T,
813822
bool isOutlined) const override {
814823
if (auto copyConstructor = findCopyConstructor()) {
815-
emitCopyWithCopyConstructor(IGF, T, copyConstructor,
816-
srcAddr.getAddress(),
817-
destAddr.getAddress());
824+
emitCopyWithCopyOrMoveConstructor(IGF, T, copyConstructor,
825+
srcAddr.getAddress(),
826+
destAddr.getAddress());
818827
return;
819828
}
820829
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
@@ -827,9 +836,9 @@ namespace {
827836
SILType T, bool isOutlined) const override {
828837
if (auto copyConstructor = findCopyConstructor()) {
829838
destroy(IGF, destAddr, T, isOutlined);
830-
emitCopyWithCopyConstructor(IGF, T, copyConstructor,
831-
srcAddr.getAddress(),
832-
destAddr.getAddress());
839+
emitCopyWithCopyOrMoveConstructor(IGF, T, copyConstructor,
840+
srcAddr.getAddress(),
841+
destAddr.getAddress());
833842
return;
834843
}
835844
StructTypeInfoBase<AddressOnlyCXXClangRecordTypeInfo, FixedTypeInfo,
@@ -841,17 +850,15 @@ namespace {
841850
SILType T, bool isOutlined,
842851
bool zeroizeIfSensitive) const override {
843852
if (auto moveConstructor = findMoveConstructor()) {
844-
emitCopyWithCopyConstructor(IGF, T, moveConstructor,
845-
src.getAddress(),
846-
dest.getAddress());
853+
emitCopyWithCopyOrMoveConstructor(IGF, T, moveConstructor,
854+
src.getAddress(), dest.getAddress());
847855
destroy(IGF, src, T, isOutlined);
848856
return;
849857
}
850858

851859
if (auto copyConstructor = findCopyConstructor()) {
852-
emitCopyWithCopyConstructor(IGF, T, copyConstructor,
853-
src.getAddress(),
854-
dest.getAddress());
860+
emitCopyWithCopyOrMoveConstructor(IGF, T, copyConstructor,
861+
src.getAddress(), dest.getAddress());
855862
destroy(IGF, src, T, isOutlined);
856863
return;
857864
}
@@ -865,18 +872,16 @@ namespace {
865872
bool isOutlined) const override {
866873
if (auto moveConstructor = findMoveConstructor()) {
867874
destroy(IGF, dest, T, isOutlined);
868-
emitCopyWithCopyConstructor(IGF, T, moveConstructor,
869-
src.getAddress(),
870-
dest.getAddress());
875+
emitCopyWithCopyOrMoveConstructor(IGF, T, moveConstructor,
876+
src.getAddress(), dest.getAddress());
871877
destroy(IGF, src, T, isOutlined);
872878
return;
873879
}
874880

875881
if (auto copyConstructor = findCopyConstructor()) {
876882
destroy(IGF, dest, T, isOutlined);
877-
emitCopyWithCopyConstructor(IGF, T, copyConstructor,
878-
src.getAddress(),
879-
dest.getAddress());
883+
emitCopyWithCopyOrMoveConstructor(IGF, T, copyConstructor,
884+
src.getAddress(), dest.getAddress());
880885
destroy(IGF, src, T, isOutlined);
881886
return;
882887
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,9 @@ module CustomSmartPtr {
9999
requires cplusplus
100100
export *
101101
}
102+
103+
module StdExpected {
104+
header "std-expected.h"
105+
requires cplusplus
106+
export *
107+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef TEST_INTEROP_CXX_STDLIB_INPUTS_STD_UNIQUE_PTR_H
2+
#define TEST_INTEROP_CXX_STDLIB_INPUTS_STD_UNIQUE_PTR_H
3+
4+
#include <memory>
5+
#include <expected>
6+
7+
using NonCopyableExpected = std::expected<std::unique_ptr<bool>, int>;
8+
9+
template<typename T>
10+
class UniqueRef {
11+
public:
12+
std::unique_ptr<T> _field;
13+
};
14+
15+
struct Decoder {};
16+
enum Error {
17+
DoomA,
18+
DoomB
19+
};
20+
21+
using DecoderOrError = std::expected<UniqueRef<Decoder>, Error>;
22+
23+
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_UNIQUE_PTR_H
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: not %target-swift-frontend %s -typecheck -I %S/Inputs -cxx-interoperability-mode=default -Xcc -std=c++23 -diagnostic-style llvm 2>&1 | %FileCheck %s
2+
3+
// TODO <expected> not yet supported with libstdc++
4+
// XFAIL: OS=linux-gnu
5+
6+
// https://github.com/apple/swift/issues/70226
7+
// UNSUPPORTED: OS=windows-msvc
8+
9+
import StdExpected
10+
import CxxStdlib
11+
12+
func takeCopyable<T: Copyable>(_ x: T) {}
13+
14+
let nonCopExpected = NonCopyableExpected()
15+
takeCopyable(nonCopExpected)
16+
// CHECK: error: global function 'takeCopyable' requires that 'NonCopyableExpected' (aka {{.*}}) conform to 'Copyable'
17+
18+
let doe = DecoderOrError()
19+
takeCopyable(doe)
20+
// CHECK: error: global function 'takeCopyable' requires that 'DecoderOrError' (aka {{.*}}) conform to 'Copyable'
21+
22+
// CHECK-NOT: error

0 commit comments

Comments
 (0)