Skip to content

Commit 70c3401

Browse files
authored
Don't use uninstantiated copy constructor (#477)
1 parent 370bf3d commit 70c3401

4 files changed

Lines changed: 100 additions & 11 deletions

File tree

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,11 @@ bool HasDefaultedCopyConstructor(const clang::RecordDecl *decl) {
508508
return true;
509509
}
510510
for (const auto *ctor : cxx->ctors()) {
511-
if (ctor->isCopyConstructor()) {
512-
return !ctor->isUserProvided() && !ctor->isDeleted();
511+
if (ctor->isCopyConstructor() && ctor->isUserProvided()) {
512+
return false;
513513
}
514514
}
515-
return !cxx->defaultedCopyConstructorIsDeleted();
515+
return HasCallableCopyConstructor(cxx);
516516
}
517517

518518
bool RecordHasOnlyReferenceFields(const clang::RecordDecl *decl) {
@@ -542,16 +542,21 @@ bool HasCallableCopyConstructor(const clang::RecordDecl *decl) {
542542
if (!cxx) {
543543
return true;
544544
}
545-
if (!cxx->hasUserDeclaredCopyConstructor()) {
546-
return !cxx->defaultedCopyConstructorIsDeleted();
545+
if (cxx->hasUserDeclaredCopyConstructor()) {
546+
return std::ranges::any_of(cxx->ctors(), [](const auto *ctor) {
547+
return ctor->isCopyConstructor() && !ctor->isDeleted() &&
548+
ctor->getDefinition();
549+
});
547550
}
548-
for (const auto *ctor : cxx->ctors()) {
549-
if (ctor->isCopyConstructor() && !ctor->isDeleted() &&
550-
ctor->getDefinition()) {
551-
return true;
552-
}
551+
if (cxx->defaultedCopyConstructorIsDeleted()) {
552+
return false;
553553
}
554-
return false;
554+
auto &ctx = cxx->getASTContext();
555+
return std::ranges::all_of(cxx->fields(), [&](const clang::FieldDecl *f) {
556+
auto *record = ctx.getBaseElementType(f->getType())->getAsCXXRecordDecl();
557+
return !record || !IsUserDefinedDecl(record) ||
558+
HasCallableCopyConstructor(record);
559+
});
555560
}
556561

557562
bool IsRValueConvertingConstructor(const clang::CXXConstructorDecl *ctor) {

‎tests/unit/copy_ctor.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ struct Holder {
2828
Counted arr[2];
2929
};
3030

31+
template <class T> struct Box {
32+
T val;
33+
Box(T v) : val(std::move(v)) {}
34+
Box(const Box &o) : val(o.val) {}
35+
Box(Box &&) = default;
36+
};
37+
38+
struct Owner {
39+
Box<int> box;
40+
};
41+
3142
static int by_value(Counted c) { return c.v; }
3243

3344
static Counted make(int v) {
@@ -74,6 +85,10 @@ int main() {
7485
assert(i1.v == 1 && i2.v == -1);
7586
assert(copies == 11);
7687

88+
Owner o{Box<int>(3)};
89+
Owner o2 = std::move(o);
90+
assert(o2.box.val == 3);
91+
7792
NonConst n;
7893
NonConst n1(n);
7994
const NonConst cn;

‎tests/unit/out/refcount/copy_ctor.rs‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,37 @@ impl Default for Holder {
111111
}
112112
}
113113
}
114+
#[derive(Record, ByteRepr, Default)]
115+
#[byte_size(4)]
116+
pub struct Box_int_ {
117+
#[offset(0)]
118+
pub val: i32,
119+
}
120+
impl Box_int_ {
121+
pub fn new(v: i32) -> Self {
122+
let v: Value<i32> = Rc::new(RefCell::new(v));
123+
Self { val: (*v.borrow()) }
124+
}
125+
pub fn move_from(_a0: Ptr<Box_int_>) -> Self {
126+
Self {
127+
val: { (*_a0.upgrade().deref()).val },
128+
}
129+
}
130+
}
131+
#[derive(Record, ByteRepr, Default)]
132+
#[byte_size(4)]
133+
pub struct Owner {
134+
#[offset(0)]
135+
#[byte_size(4)]
136+
pub box_: Box_int_,
137+
}
138+
impl Owner {
139+
pub fn move_from(_a0: Ptr<Owner>) -> Self {
140+
Self {
141+
box_: Box_int_::move_from({ field_ptr!(_a0, box_) }),
142+
}
143+
}
144+
}
114145
pub fn by_value_1(mut c: Counted) -> i32 {
115146
return c.v;
116147
}
@@ -176,6 +207,11 @@ fn main_0() -> i32 {
176207
let mut i2: Ignored = Ignored::copy_from({ i1.as_pointer() });
177208
assert!(({ (*i1.borrow()).v } == 1) && (i2.v == -1_i32));
178209
assert!((copies_0.with(|rc| *rc.borrow()) == 11));
210+
let o: Value<Owner> = Rc::new(RefCell::new(Owner {
211+
box_: Box_int_::new({ 3 }),
212+
}));
213+
let mut o2: Owner = Owner::move_from({ o.as_pointer() });
214+
assert!((o2.box_.val == 3));
179215
let n: Value<NonConst> = Rc::new(RefCell::new(NonConst::new()));
180216
let mut n1: NonConst = NonConst::new_1({ n.as_pointer() });
181217
let cn: Value<NonConst> = Rc::new(RefCell::new(NonConst::new()));

‎tests/unit/out/unsafe/copy_ctor.rs‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,34 @@ pub struct Holder {
8888
pub c: Counted,
8989
pub arr: [Counted; 2],
9090
}
91+
#[repr(C)]
92+
#[derive(Default)]
93+
pub struct Box_int_ {
94+
pub val: i32,
95+
}
96+
impl Box_int_ {
97+
pub unsafe fn new(mut v: i32) -> Self {
98+
let mut this = Self { val: v };
99+
this
100+
}
101+
pub unsafe fn move_from(_a0: *mut Box_int_) -> Self {
102+
let mut this = Self { val: (*_a0).val };
103+
this
104+
}
105+
}
106+
#[repr(C)]
107+
#[derive(Default)]
108+
pub struct Owner {
109+
pub box_: Box_int_,
110+
}
111+
impl Owner {
112+
pub unsafe fn move_from(_a0: *mut Owner) -> Self {
113+
let mut this = Self {
114+
box_: Box_int_::move_from({ &mut (*_a0).box_ }),
115+
};
116+
this
117+
}
118+
}
91119
pub unsafe fn by_value_1(mut c: Counted) -> i32 {
92120
return c.v;
93121
}
@@ -141,6 +169,11 @@ unsafe fn main_0() -> i32 {
141169
let mut i2: Ignored = Ignored::copy_from({ &i1 });
142170
assert!(((i1.v) == (1)) && ((i2.v) == (-1_i32)));
143171
assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (11)));
172+
let mut o: Owner = Owner {
173+
box_: Box_int_::new({ 3 }),
174+
};
175+
let mut o2: Owner = Owner::move_from({ &mut o });
176+
assert!(((o2.box_.val) == (3)));
144177
let mut n: NonConst = NonConst::new();
145178
let mut n1: NonConst = NonConst::new_1({ &mut n });
146179
let cn: NonConst = NonConst::new();

0 commit comments

Comments
 (0)