diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index d4a591edc..6d125e8de 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3019,28 +3019,28 @@ bool Converter::ConvertIncAndDec(clang::UnaryOperator *expr) { auto *sub_expr = expr->getSubExpr(); switch (opcode) { case clang::UO_PostInc: { - PushExprKind push(*this, ExprKind::RValue); + PushExprKind push(*this, ExprKind::LValue); Convert(sub_expr); StrCat(".postfix_inc()"); SetFresh(); return true; } case clang::UO_PostDec: { - PushExprKind push(*this, ExprKind::RValue); + PushExprKind push(*this, ExprKind::LValue); Convert(sub_expr); StrCat(".postfix_dec()"); SetFresh(); return true; } case clang::UO_PreInc: { - PushExprKind push(*this, ExprKind::RValue); + PushExprKind push(*this, ExprKind::LValue); Convert(sub_expr); StrCat(".prefix_inc()"); SetFresh(); return true; } case clang::UO_PreDec: { - PushExprKind push(*this, ExprKind::RValue); + PushExprKind push(*this, ExprKind::LValue); Convert(sub_expr); StrCat(".prefix_dec()"); SetFresh(); @@ -3379,6 +3379,21 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { str = std::move(buf).str(); } + if (auto *field = clang::dyn_cast(member); + field && field->isMutable()) { + auto *base = expr->getBase(); + auto object_type = expr->isArrow() ? base->getType()->getPointeeType() + : base->getType().getNonReferenceType(); + if (!isRValue() && object_type.isConstQualified()) { + if (isAddrOf()) { + StrCat(std::format("(&raw const {}).cast_mut()", str)); + computed_expr_type_ = ComputedExprType::FreshPointer; + return false; + } + str = std::format("(*(&raw const {}).cast_mut())", str); + } + } + if (isAddrOf()) { bool is_reference_type = member->getType()->isReferenceType(); if (auto *method = clang::dyn_cast(member)) { @@ -3427,22 +3442,12 @@ void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, } Buffer buf(*this); PushExprKind push(*this, ExprKind::LValue); - auto object_type = is_arrow ? base->getType()->getPointeeType() - : base->getType().getNonReferenceType(); - bool cast_mut = - MethodNeedsMutableReceiver(method) && object_type.isConstQualified(); StrCat(MethodNeedsMutableReceiver(method) ? "&mut" : "&"); - if (cast_mut) { - StrCat("*(&raw const"); - } if (is_arrow) { ConvertArrow(base); } else { Convert(base); } - if (cast_mut) { - StrCat(").cast_mut()"); - } ufcs_receiver_ = std::move(buf).str(); } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index bb812cc8e..17090c8de 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -609,12 +609,7 @@ bool IsRValueConvertingConstructor(const clang::CXXConstructorDecl *ctor) { } bool MethodNeedsMutableReceiver(const clang::CXXMethodDecl *method) { - if (!method->isConst()) { - return true; - } - return std::any_of(method->getParent()->field_begin(), - method->getParent()->field_end(), - [](const clang::FieldDecl *f) { return f->isMutable(); }); + return !method->isConst(); } bool IsPassThroughConstructor(const clang::CXXConstructorDecl *ctor) { diff --git a/tests/unit/class.cpp b/tests/unit/class.cpp index 981d0c06c..1cf613891 100644 --- a/tests/unit/class.cpp +++ b/tests/unit/class.cpp @@ -51,6 +51,20 @@ struct Counter { } }; +struct Tally { + mutable int calls; + + int SameNameBetweenConstAndNonConst() { + calls += 1; + return 1; + } + + int SameNameBetweenConstAndNonConst() const { + calls += 10; + return 2; + } +}; + int RandomRoute(Route &route) { if (route.path.first % 2) { return route.path.SetFirst(route.path.SetSecond(10)); @@ -74,5 +88,13 @@ int main() { assert(c2 == c1); assert(c1.calls == 3); assert(c2.calls == 2); + Tally t{0}; + const Tally ct{0}; + const Tally &rt = t; + assert(t.SameNameBetweenConstAndNonConst() == 1); + assert(ct.SameNameBetweenConstAndNonConst() == 2); + assert(rt.SameNameBetweenConstAndNonConst() == 2); + assert(t.calls == 11); + assert(ct.calls == 10); return 0; } diff --git a/tests/unit/copy_ctor.cpp b/tests/unit/copy_ctor.cpp index c16058745..d0f59679f 100644 --- a/tests/unit/copy_ctor.cpp +++ b/tests/unit/copy_ctor.cpp @@ -47,6 +47,18 @@ struct OutOfLine { OutOfLine::OutOfLine(const OutOfLine &o) : v(o.v + 100) { ++copies; } +struct Tracked { + mutable int copied_from = 0; + Tracked() = default; + Tracked(const Tracked &o) { ++o.copied_from; } + Tracked &operator=(const Tracked &o) { + ++o.copied_from; + return *this; + } +}; + +static void touch(const Tracked *t) { ++t->copied_from; } + static int by_value(Counted c) { return c.v; } static Counted make(int v) { @@ -108,5 +120,14 @@ int main() { NonConst n2(cn); assert(n1.mark == 1); assert(n2.mark == 10); + + Tracked t1; + Tracked t2(t1); + t2 = t1; + assert(t1.copied_from == 2); + const Tracked ct; + Tracked t3(ct); + touch(&ct); + assert(ct.copied_from == 2); return 0; } diff --git a/tests/unit/out/refcount/class.rs b/tests/unit/out/refcount/class.rs index 7ec7d5cda..0c29a27ed 100644 --- a/tests/unit/out/refcount/class.rs +++ b/tests/unit/out/refcount/class.rs @@ -50,6 +50,12 @@ impl std::cmp::PartialEq for Counter { } } impl std::cmp::Eq for Counter {} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(4)] +pub struct Tally { + #[offset(0)] + pub calls: i32, +} pub fn RandomRoute_0(route: Ptr) -> i32 { if ((route.with(|__s| __s.path.first) % 2) != 0) { return ({ @@ -105,6 +111,14 @@ fn main_0() -> i32 { assert!(({ CounterImpl::operator_eq(&c2.as_pointer(), c1.as_pointer(),) })); assert!(({ (*c1.borrow()).calls } == 3)); assert!(({ (*c2.borrow()).calls } == 2)); + let t: Value = Rc::new(RefCell::new(Tally { calls: 0 })); + let ct: Value = Rc::new(RefCell::new(Tally { calls: 0 })); + let rt: Ptr = t.as_pointer(); + assert!((({ TallyImpl::SameNameBetweenConstAndNonConst_1(&t.as_pointer(),) }) == 1)); + assert!((({ TallyImpl::SameNameBetweenConstAndNonConst_2(&ct.as_pointer(),) }) == 2)); + assert!((({ TallyImpl::SameNameBetweenConstAndNonConst_2(&rt,) }) == 2)); + assert!(({ (*t.borrow()).calls } == 11)); + assert!(({ (*ct.borrow()).calls } == 10)); return 0; } pub trait CounterImpl { @@ -168,4 +182,22 @@ impl RouteImpl for Ptr { return old_cost; } } +pub trait TallyImpl { + fn SameNameBetweenConstAndNonConst_1(&self) -> i32; + fn SameNameBetweenConstAndNonConst_2(&self) -> i32; +} +impl TallyImpl for Ptr { + fn SameNameBetweenConstAndNonConst_1(&self) -> i32 { + { + field!((*self), calls).with_mut(|__v| *__v = *__v + 1) + }; + return 1; + } + fn SameNameBetweenConstAndNonConst_2(&self) -> i32 { + { + field!((*self), calls).with_mut(|__v| *__v = *__v + 10) + }; + return 2; + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/copy_ctor.rs b/tests/unit/out/refcount/copy_ctor.rs index 4c898ed84..5fe0d932a 100644 --- a/tests/unit/out/refcount/copy_ctor.rs +++ b/tests/unit/out/refcount/copy_ctor.rs @@ -175,10 +175,39 @@ impl Clone for OutOfLine { } } impl OutOfLine {} -pub fn by_value_1(mut c: Counted) -> i32 { +#[derive(Record, ByteRepr, VaArg, FnPtrArg)] +#[byte_size(4)] +pub struct Tracked { + #[offset(0)] + pub copied_from: i32, +} +impl Tracked { + pub fn copy_from(o: Ptr) -> Self { + let __this: Tracked = Self { copied_from: 0 }; + field!(o, copied_from).with_mut(|__v| __v.prefix_inc()); + __this + } +} +impl Clone for Tracked { + fn clone(&self) -> Self { + let __src: Value = Rc::new(RefCell::new(Tracked { + copied_from: self.copied_from.clone(), + })); + Tracked::copy_from(__src.as_pointer()) + } +} +impl Default for Tracked { + fn default() -> Self { + { Tracked { copied_from: 0 } } + } +} +pub fn touch_1(mut t: Ptr) { + field!(t, copied_from).with_mut(|__v| __v.prefix_inc()); +} +pub fn by_value_2(mut c: Counted) -> i32 { return c.v; } -pub fn make_2(mut v: i32) -> Counted { +pub fn make_3(mut v: i32) -> Counted { let c: Value = Rc::new(RefCell::new(Counted::new({ v }))); return Counted::copy_from({ c.as_pointer() }); } @@ -193,9 +222,9 @@ fn main_0() -> i32 { let mut d: Counted = Counted::copy_from({ a.as_pointer() }); assert!((copies_0.with(|rc| *rc.borrow()) == 3)); assert!(((b.v == 1) && (c.v == 1)) && (d.v == 1)); - assert!((({ by_value_1(Counted::copy_from({ a.as_pointer() },),) }) == 1)); + assert!((({ by_value_2(Counted::copy_from({ a.as_pointer() },),) }) == 1)); assert!((copies_0.with(|rc| *rc.borrow()) == 4)); - let mut e: Counted = ({ make_2(5) }); + let mut e: Counted = ({ make_3(5) }); assert!((e.v == 5)); assert!((copies_0.with(|rc| *rc.borrow()) == 5)); let mut f: Counted = Counted::new({ 6 }); @@ -255,8 +284,25 @@ fn main_0() -> i32 { let mut n2: NonConst = NonConst::new_2({ cn.as_pointer() }); assert!((n1.mark == 1)); assert!((n2.mark == 10)); + let t1: Value = Rc::new(RefCell::new(::default())); + let t2: Value = Rc::new(RefCell::new(Tracked::copy_from({ t1.as_pointer() }))); + ({ TrackedImpl::copy_assign(&t2.as_pointer(), t1.as_pointer()) }); + assert!(({ (*t1.borrow()).copied_from } == 2)); + let ct: Value = Rc::new(RefCell::new(::default())); + let mut t3: Tracked = Tracked::copy_from({ ct.as_pointer() }); + ({ touch_1((ct.as_pointer())) }); + assert!(({ (*ct.borrow()).copied_from } == 2)); return 0; } +pub trait TrackedImpl { + fn copy_assign(&self, o: Ptr) -> Ptr; +} +impl TrackedImpl for Ptr { + fn copy_assign(&self, o: Ptr) -> Ptr { + field!(o, copied_from).with_mut(|__v| __v.prefix_inc()); + return (*self).clone(); + } +} pub fn __cpp2rust_init_globals() { let _ = copies_0.with(|_| ()); } diff --git a/tests/unit/out/unsafe/class.rs b/tests/unit/out/unsafe/class.rs index 37f6a7a95..7e754eb5a 100644 --- a/tests/unit/out/unsafe/class.rs +++ b/tests/unit/out/unsafe/class.rs @@ -61,23 +61,36 @@ pub struct Counter { pub calls: i32, } impl Counter { - pub unsafe fn Get(&mut self) -> i32 { - self.calls.prefix_inc(); + pub unsafe fn Get(&self) -> i32 { + (*(&raw const self.calls).cast_mut()).prefix_inc(); return self.v; } - pub unsafe fn operator_eq(&mut self, o: *const Counter) -> bool { - self.calls.prefix_inc(); + pub unsafe fn operator_eq(&self, o: *const Counter) -> bool { + (*(&raw const self.calls).cast_mut()).prefix_inc(); return ((self.v) == ((*o).v)); } } impl std::cmp::PartialEq for Counter { fn eq(&self, other: &Self) -> bool { - unsafe { - Counter::operator_eq(&mut *(&raw const *self).cast_mut(), other as *const Counter) - } + unsafe { Counter::operator_eq(self, other as *const Counter) } } } impl std::cmp::Eq for Counter {} +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct Tally { + pub calls: i32, +} +impl Tally { + pub unsafe fn SameNameBetweenConstAndNonConst_1(&mut self) -> i32 { + self.calls += 1; + return 1; + } + pub unsafe fn SameNameBetweenConstAndNonConst_2(&self) -> i32 { + (*(&raw const self.calls).cast_mut()) += 10; + return 2; + } +} pub unsafe fn RandomRoute_0(route: *mut Route) -> i32 { if ((((*route).path.first) % (2)) != 0) { return (unsafe { @@ -128,13 +141,21 @@ unsafe fn main_0() -> i32 { let mut c1: Counter = Counter { v: 3, calls: 0 }; let c2: Counter = Counter { v: 3, calls: 0 }; let mut pc: *const Counter = (&mut c1 as *mut Counter).cast_const(); - assert!(((unsafe { Counter::Get(&mut *(&raw const c1).cast_mut(),) }) == (3))); - assert!(((unsafe { Counter::Get(&mut *(&raw const c2).cast_mut(),) }) == (3))); - assert!(((unsafe { Counter::Get(&mut *(&raw const (*pc)).cast_mut(),) }) == (3))); - assert!((unsafe { Counter::operator_eq(&mut *(&raw const c1).cast_mut(), &c2,) })); - assert!((unsafe { Counter::operator_eq(&mut *(&raw const c2).cast_mut(), &c1,) })); + assert!(((unsafe { Counter::Get(&c1,) }) == (3))); + assert!(((unsafe { Counter::Get(&c2,) }) == (3))); + assert!(((unsafe { Counter::Get(&(*pc),) }) == (3))); + assert!((unsafe { Counter::operator_eq(&c1, &c2,) })); + assert!((unsafe { Counter::operator_eq(&c2, &c1,) })); assert!(((c1.calls) == (3))); assert!(((c2.calls) == (2))); + let mut t: Tally = Tally { calls: 0 }; + let ct: Tally = Tally { calls: 0 }; + let rt: *const Tally = &t; + assert!(((unsafe { Tally::SameNameBetweenConstAndNonConst_1(&mut t,) }) == (1))); + assert!(((unsafe { Tally::SameNameBetweenConstAndNonConst_2(&ct,) }) == (2))); + assert!(((unsafe { Tally::SameNameBetweenConstAndNonConst_2(&(*rt),) }) == (2))); + assert!(((t.calls) == (11))); + assert!(((ct.calls) == (10))); return 0; } pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/copy_ctor.rs b/tests/unit/out/unsafe/copy_ctor.rs index 88b8c57c5..f6aaee237 100644 --- a/tests/unit/out/unsafe/copy_ctor.rs +++ b/tests/unit/out/unsafe/copy_ctor.rs @@ -141,10 +141,39 @@ impl Clone for OutOfLine { } } impl OutOfLine {} -pub unsafe fn by_value_1(mut c: Counted) -> i32 { +#[repr(C)] +#[derive(VaArg, FnPtrArg)] +pub struct Tracked { + pub copied_from: i32, +} +impl Tracked { + pub unsafe fn copy_from(o: *const Tracked) -> Self { + let mut this = Self { copied_from: 0 }; + (*(&raw const (*o).copied_from).cast_mut()).prefix_inc(); + this + } + pub unsafe fn copy_assign(&mut self, o: *const Tracked) -> *mut Tracked { + (*(&raw const (*o).copied_from).cast_mut()).prefix_inc(); + return &mut (*(self as *mut Tracked)); + } +} +impl Clone for Tracked { + fn clone(&self) -> Self { + unsafe { Tracked::copy_from(self as *const Tracked) } + } +} +impl Default for Tracked { + fn default() -> Self { + unsafe { Tracked { copied_from: 0 } } + } +} +pub unsafe fn touch_1(mut t: *const Tracked) { + (*(&raw const (*t).copied_from).cast_mut()).prefix_inc(); +} +pub unsafe fn by_value_2(mut c: Counted) -> i32 { return c.v; } -pub unsafe fn make_2(mut v: i32) -> Counted { +pub unsafe fn make_3(mut v: i32) -> Counted { let mut c: Counted = Counted::new({ v }); return Counted::copy_from({ &c }); } @@ -161,9 +190,9 @@ unsafe fn main_0() -> i32 { let mut d: Counted = Counted::copy_from({ &a }); assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (3))); assert!((((b.v) == (1)) && ((c.v) == (1))) && ((d.v) == (1))); - assert!(((unsafe { by_value_1(Counted::copy_from({ &a },),) }) == (1))); + assert!(((unsafe { by_value_2(Counted::copy_from({ &a },),) }) == (1))); assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (4))); - let mut e: Counted = (unsafe { make_2(5) }); + let mut e: Counted = (unsafe { make_3(5) }); assert!(((e.v) == (5))); assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut copies_0)) == (5))); let mut f: Counted = Counted::new({ 6 }); @@ -209,6 +238,14 @@ unsafe fn main_0() -> i32 { let mut n2: NonConst = NonConst::new_2({ &cn }); assert!(((n1.mark) == (1))); assert!(((n2.mark) == (10))); + let mut t1: Tracked = ::default(); + let mut t2: Tracked = Tracked::copy_from({ &t1 }); + (unsafe { Tracked::copy_assign(&mut t2, &t1) }); + assert!(((t1.copied_from) == (2))); + let ct: Tracked = ::default(); + let mut t3: Tracked = Tracked::copy_from({ &ct }); + (unsafe { touch_1((&ct as *const Tracked)) }); + assert!(((ct.copied_from) == (2))); return 0; } pub unsafe fn __cpp2rust_init_globals() {