Skip to content

Commit 8393f84

Browse files
authored
Use copy_from/move_from to translate copy/move ctor (#418)
If possible, use the `copy_from`/`move_from` idiomatic name instead of `S_pmutS_rv`. This is only possible when the copy/move constructor is unique (no other copy/move constructor exists) and when no other method in the class is called copy_from/move_from. Do the same for copy/move assignment: copy_assign and move_assign.
1 parent 7a349c9 commit 8393f84

47 files changed

Lines changed: 411 additions & 494 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎cpp2rust/converter/converter.cpp‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,10 @@ std::string Converter::GetMethodName(const clang::CXXMethodDecl *decl) {
10951095
if (clang::isa<clang::CXXDestructorDecl>(decl)) {
10961096
return kDestructorName;
10971097
}
1098+
if (const char *name = GetCopyOrMoveName(decl);
1099+
name && CanUseCopyOrMoveName(decl, name)) {
1100+
return name;
1101+
}
10981102
if (IsOverloadedMethod(decl)) {
10991103
return GetOverloadedFunctionName(decl);
11001104
}
@@ -1144,6 +1148,10 @@ std::string Converter::GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl) {
11441148

11451149
std::string Converter::GetCtorName(clang::CXXConstructorDecl *decl) {
11461150
if (decl->isCopyOrMoveConstructor()) {
1151+
if (const char *name = GetCopyOrMoveName(decl);
1152+
CanUseCopyOrMoveName(decl, name)) {
1153+
return name;
1154+
}
11471155
return GetOverloadedFunctionName(decl);
11481156
}
11491157
return GetNumberOfConvertingCtors(decl->getParent()) != 1
@@ -3342,7 +3350,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33423350
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(member);
33433351
method && IsOverloadedMethod(method)) {
33443352
StrCat(token::kDot);
3345-
StrCat(GetOverloadedFunctionName(method));
3353+
StrCat(GetMethodName(method));
33463354
} else if (!name_override.empty()) {
33473355
StrCat(token::kDot, name_override);
33483356
} else if (member->getDeclName().isIdentifier()) {

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,44 @@ bool IsOverloadedMethod(const clang::CXXMethodDecl *decl) {
286286
}) > 1;
287287
}
288288

289+
const char *GetCopyOrMoveName(const clang::CXXMethodDecl *method) {
290+
if (auto *ctor = clang::dyn_cast<clang::CXXConstructorDecl>(method)) {
291+
if (ctor->isCopyConstructor()) {
292+
return "copy_from";
293+
}
294+
if (ctor->isMoveConstructor()) {
295+
return "move_from";
296+
}
297+
return nullptr;
298+
}
299+
if (method->isCopyAssignmentOperator()) {
300+
return "copy_assign";
301+
}
302+
if (method->isMoveAssignmentOperator()) {
303+
return "move_assign";
304+
}
305+
return nullptr;
306+
}
307+
308+
bool CanUseCopyOrMoveName(const clang::CXXMethodDecl *decl,
309+
const std::string &name) {
310+
const auto *record = decl->getParent();
311+
bool is_unique_member =
312+
std::count_if(record->method_begin(), record->method_end(),
313+
[&name](const clang::CXXMethodDecl *method) {
314+
const char *method_name = GetCopyOrMoveName(method);
315+
return !method->isDeleted() && method_name &&
316+
method_name == name;
317+
}) == 1;
318+
bool is_unique_name =
319+
std::none_of(record->method_begin(), record->method_end(),
320+
[&name](const clang::CXXMethodDecl *method) {
321+
return method->getDeclName().isIdentifier() &&
322+
method->getName() == name;
323+
});
324+
return is_unique_member && is_unique_name;
325+
}
326+
289327
bool IsUserDefinedCopyConstructor(const clang::CXXConstructorDecl *ctor) {
290328
return ctor->isCopyConstructor() && ctor->isUserProvided() &&
291329
IsUserDefinedDecl(ctor);

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ void ForEachTemplateInstantiatedMethod(
7070

7171
bool IsOverloadedMethod(const clang::CXXMethodDecl *decl);
7272

73+
const char *GetCopyOrMoveName(const clang::CXXMethodDecl *method);
74+
75+
bool CanUseCopyOrMoveName(const clang::CXXMethodDecl *decl,
76+
const std::string &name);
77+
7378
bool IsUserDefinedCopyConstructor(const clang::CXXConstructorDecl *ctor);
7479

7580
bool IsConvertibleCopyOrMoveConstructor(const clang::CXXConstructorDecl *ctor);

‎docs/src/codegen/types/classes.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ behind pointers, is emitted at the end of the file as an empty
9090

9191
A constructor becomes an associated function named after the class. It opens
9292
with `let mut this = Self { ... }`, one field per member initializer, then runs
93-
the C++ body and returns `this`. Only implicit or defaulted copy and move
94-
constructors are supported: a user-defined one stops the translation, and the
95-
implicit copy is what the `Clone` impl represents.
93+
the C++ body and returns `this`. Copy and move constructors become `copy_from`
94+
and `move_from` (see [Naming](./naming.md)); the `Clone` impl calls `copy_from`
95+
when the copy constructor is user-defined.
9696

9797
Methods take `&self` when `const` and `&mut self` otherwise in the unsafe model.
9898
In the refcount model they always take `&self`, since mutation goes through the

‎docs/src/codegen/types/naming.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ name unless they are overloaded, in which case the parameter types are appended
2727
(`method_i32`, `method_i32_const`). `operator<` is emitted as `lt`; comparison
2828
operators additionally produce the corresponding trait impls (`PartialOrd`,
2929
`Ord`, `PartialEq`).
30+
31+
Copy and move constructors are named `copy_from` and `move_from`, and copy and
32+
move assignment operators `copy_assign` and `move_assign`, as long as the class
33+
has only one member of that kind and no method already uses the name; otherwise
34+
they get the overloaded form.

‎tests/multi-file/defaulted_move_cross_tu/out/refcount/defaulted_move_cross_tu.rs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl S {
2424
let this: Ptr<S> = __this.as_pointer();
2525
Rc::try_unwrap(__this).ok().unwrap().into_inner()
2626
}
27-
pub fn S_pmutS_rv(_a0: Ptr<S>) -> Self {
27+
pub fn move_from(_a0: Ptr<S>) -> Self {
2828
let __this: Value<S> = Rc::new(RefCell::new(Self {
2929
v: Rc::new(RefCell::new(std::mem::take(
3030
&mut (*(*_a0.upgrade().deref()).v.borrow_mut()),
@@ -84,18 +84,18 @@ fn main_0() -> i32 {
8484
pub fn shuffle_1(x: i32) -> i32 {
8585
let x: Value<i32> = Rc::new(RefCell::new(x));
8686
let a: Value<S> = Rc::new(RefCell::new(S::new({ (*x.borrow()) })));
87-
let b: Value<S> = Rc::new(RefCell::new(S::S_pmutS_rv({ a.as_pointer() })));
87+
let b: Value<S> = Rc::new(RefCell::new(S::move_from({ a.as_pointer() })));
8888
assert!((*(*a.borrow()).v.borrow()).is_empty());
8989
let c: Value<S> = Rc::new(RefCell::new(S::new({ 1 })));
90-
({ SImpl::operator_assign_pmutS_rv(&c.as_pointer(), b.as_pointer()) });
90+
({ SImpl::move_assign(&c.as_pointer(), b.as_pointer()) });
9191
assert!((*(*b.borrow()).v.borrow()).is_empty());
9292
return ({ sum_0(c.as_pointer()) });
9393
}
9494
pub trait SImpl {
95-
fn operator_assign_pmutS_rv(&self, _a0: Ptr<S>) -> Ptr<S>;
95+
fn move_assign(&self, _a0: Ptr<S>) -> Ptr<S>;
9696
}
9797
impl SImpl for Ptr<S> {
98-
fn operator_assign_pmutS_rv(&self, _a0: Ptr<S>) -> Ptr<S> {
98+
fn move_assign(&self, _a0: Ptr<S>) -> Ptr<S> {
9999
((*(*self).upgrade().deref()).v.as_pointer() as Ptr<Vec<i32>>).write(std::mem::take(
100100
&mut (*(*_a0.upgrade().deref()).v.borrow_mut()),
101101
));

‎tests/multi-file/defaulted_move_cross_tu/out/unsafe/defaulted_move_cross_tu.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ impl S {
2020
};
2121
this
2222
}
23-
pub unsafe fn S_pmutS_rv(_a0: *mut S) -> Self {
23+
pub unsafe fn move_from(_a0: *mut S) -> Self {
2424
let mut this = Self {
2525
v: std::mem::take(&mut (*_a0).v),
2626
n: std::array::from_fn::<_, 2, _>(|__i: usize| (*_a0).n[(__i)]),
2727
};
2828
this
2929
}
30-
pub unsafe fn operator_assign_pmutS_rv(&mut self, _a0: *mut S) -> *mut S {
30+
pub unsafe fn move_assign(&mut self, _a0: *mut S) -> *mut S {
3131
self.v = std::mem::take(&mut (*_a0).v);
3232
{
3333
if 8_usize != 0 {
@@ -67,10 +67,10 @@ unsafe fn main_0() -> i32 {
6767
}
6868
pub unsafe fn shuffle_1(mut x: i32) -> i32 {
6969
let mut a: S = S::new({ x });
70-
let mut b: S = S::S_pmutS_rv({ &mut a });
70+
let mut b: S = S::move_from({ &mut a });
7171
assert!(a.v.is_empty());
7272
let mut c: S = S::new({ 1 });
73-
(unsafe { S::operator_assign_pmutS_rv(&mut c, &mut b) });
73+
(unsafe { S::move_assign(&mut c, &mut b) });
7474
assert!(b.v.is_empty());
7575
return (unsafe { sum_0(&c) });
7676
}

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

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl Partial {
2525
let this: Ptr<Partial> = __this.as_pointer();
2626
Rc::try_unwrap(__this).ok().unwrap().into_inner()
2727
}
28-
pub fn Partial_pconstPartial(o: Ptr<Partial>) -> Self {
28+
pub fn copy_from(o: Ptr<Partial>) -> Self {
2929
let __this: Value<Partial> = Rc::new(RefCell::new(Self {
3030
v: Rc::new(RefCell::new((*(*o.upgrade().deref()).v.borrow()))),
3131
keep: Rc::new(RefCell::new((*(*o.upgrade().deref()).keep.borrow()))),
@@ -40,7 +40,7 @@ impl Clone for Partial {
4040
v: self.v.clone(),
4141
keep: self.keep.clone(),
4242
}));
43-
Partial::Partial_pconstPartial(__src.as_pointer())
43+
Partial::copy_from(__src.as_pointer())
4444
}
4545
}
4646
impl ByteRepr for Partial {
@@ -146,14 +146,10 @@ pub struct Holder {
146146
impl Clone for Holder {
147147
fn clone(&self) -> Self {
148148
let __this: Value<Holder> = Rc::new(RefCell::new(Self {
149-
p: Rc::new(RefCell::new(Partial::Partial_pconstPartial({
150-
self.p.as_pointer()
151-
}))),
149+
p: Rc::new(RefCell::new(Partial::copy_from({ self.p.as_pointer() }))),
152150
arr: Rc::new(RefCell::new(Box::new(std::array::from_fn::<_, 2, _>(
153151
|__i: usize| {
154-
Partial::Partial_pconstPartial({
155-
(self.arr.as_pointer() as Ptr<Partial>).offset(__i)
156-
})
152+
Partial::copy_from({ (self.arr.as_pointer() as Ptr<Partial>).offset(__i) })
157153
},
158154
)))),
159155
}));
@@ -196,38 +192,38 @@ fn main_0() -> i32 {
196192
let a: Value<Partial> = Rc::new(RefCell::new(Partial::new({ 1 }, { 100 })));
197193
let b: Value<Partial> = Rc::new(RefCell::new(Partial::new({ 2 }, { 200 })));
198194
let c: Value<Partial> = Rc::new(RefCell::new(Partial::new({ 3 }, { 300 })));
199-
({ PartialImpl::operator_assign(&a.as_pointer(), b.as_pointer()) });
195+
({ PartialImpl::copy_assign(&a.as_pointer(), b.as_pointer()) });
200196
assert!(((*(*a.borrow()).v.borrow()) == 2) && ((*(*a.borrow()).keep.borrow()) == 100));
201197
assert!((assigns_0.with(|rc| *rc.borrow()) == 1));
202198
({
203-
PartialImpl::operator_assign(
199+
PartialImpl::copy_assign(
204200
&c.as_pointer(),
205-
({ PartialImpl::operator_assign(&a.as_pointer(), b.as_pointer()) }),
201+
({ PartialImpl::copy_assign(&a.as_pointer(), b.as_pointer()) }),
206202
)
207203
});
208204
assert!(((*(*c.borrow()).v.borrow()) == 2) && ((*(*c.borrow()).keep.borrow()) == 300));
209205
assert!((assigns_0.with(|rc| *rc.borrow()) == 3));
210206
({
211207
let _o: Ptr<Partial> = a.as_pointer();
212-
PartialImpl::operator_assign(&a.as_pointer(), _o)
208+
PartialImpl::copy_assign(&a.as_pointer(), _o)
213209
});
214210
assert!((assigns_0.with(|rc| *rc.borrow()) == 3));
215211
({
216212
let _o: Value<Partial> = Rc::new(RefCell::new(Partial::new({ 9 }, { 900 })));
217-
PartialImpl::operator_assign(&a.as_pointer(), _o.as_pointer())
213+
PartialImpl::copy_assign(&a.as_pointer(), _o.as_pointer())
218214
});
219215
assert!(((*(*a.borrow()).v.borrow()) == 9) && ((*(*a.borrow()).keep.borrow()) == 100));
220216
assert!((assigns_0.with(|rc| *rc.borrow()) == 4));
221217
let ra: Ptr<Partial> = a.as_pointer();
222218
({
223219
let _o: Ptr<Partial> = c.as_pointer();
224-
PartialImpl::operator_assign(&ra, _o)
220+
PartialImpl::copy_assign(&ra, _o)
225221
});
226222
assert!(((*(*a.borrow()).v.borrow()) == 2));
227223
let pa: Value<Ptr<Partial>> = Rc::new(RefCell::new((a.as_pointer())));
228224
({
229225
let _o: Ptr<Partial> = b.as_pointer();
230-
PartialImpl::operator_assign(&(*pa.borrow()), _o)
226+
PartialImpl::copy_assign(&(*pa.borrow()), _o)
231227
});
232228
assert!(((*(*a.borrow()).v.borrow()) == 2));
233229
assert!((assigns_0.with(|rc| *rc.borrow()) == 6));
@@ -238,9 +234,9 @@ fn main_0() -> i32 {
238234
Partial::new({ 6 }, { 60 }),
239235
]))),
240236
}));
241-
({ PartialImpl::operator_assign(&(*h.borrow()).p.as_pointer(), b.as_pointer()) });
237+
({ PartialImpl::copy_assign(&(*h.borrow()).p.as_pointer(), b.as_pointer()) });
242238
({
243-
PartialImpl::operator_assign(
239+
PartialImpl::copy_assign(
244240
&((*h.borrow()).arr.as_pointer() as Ptr<Partial>).offset(1),
245241
c.as_pointer(),
246242
)
@@ -266,7 +262,7 @@ fn main_0() -> i32 {
266262
assert!(((*(*n2.borrow()).mark.borrow()) == 10));
267263
let r: Value<RefQualified> = Rc::new(RefCell::new(RefQualified::new()));
268264
let r1: Value<RefQualified> = Rc::new(RefCell::new(RefQualified::new()));
269-
({ RefQualifiedImpl::operator_assign(&r1.as_pointer(), r.as_pointer()) });
265+
({ RefQualifiedImpl::copy_assign(&r1.as_pointer(), r.as_pointer()) });
270266
assert!(((*(*r1.borrow()).mark.borrow()) == 1));
271267
return 0;
272268
}
@@ -287,10 +283,10 @@ impl NonConstAssignImpl for Ptr<NonConstAssign> {
287283
}
288284
}
289285
pub trait PartialImpl {
290-
fn operator_assign(&self, o: Ptr<Partial>) -> Ptr<Partial>;
286+
fn copy_assign(&self, o: Ptr<Partial>) -> Ptr<Partial>;
291287
}
292288
impl PartialImpl for Ptr<Partial> {
293-
fn operator_assign(&self, o: Ptr<Partial>) -> Ptr<Partial> {
289+
fn copy_assign(&self, o: Ptr<Partial>) -> Ptr<Partial> {
294290
if ((*self) == (o)) {
295291
return (*self).clone();
296292
}
@@ -301,10 +297,10 @@ impl PartialImpl for Ptr<Partial> {
301297
}
302298
}
303299
pub trait RefQualifiedImpl {
304-
fn operator_assign(&self, o: Ptr<RefQualified>) -> Ptr<RefQualified>;
300+
fn copy_assign(&self, o: Ptr<RefQualified>) -> Ptr<RefQualified>;
305301
}
306302
impl RefQualifiedImpl for Ptr<RefQualified> {
307-
fn operator_assign(&self, o: Ptr<RefQualified>) -> Ptr<RefQualified> {
303+
fn copy_assign(&self, o: Ptr<RefQualified>) -> Ptr<RefQualified> {
308304
let __rhs = ((*(*o.upgrade().deref()).mark.borrow()) + 1);
309305
(*(*(*self).upgrade().deref()).mark.borrow_mut()) = __rhs;
310306
return (*self).clone();

0 commit comments

Comments
 (0)