Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -3379,6 +3379,21 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
str = std::move(buf).str();
}

if (auto *field = clang::dyn_cast<clang::FieldDecl>(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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't apply for rvalue cases

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}
}

if (isAddrOf()) {
bool is_reference_type = member->getType()->isReferenceType();
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(member)) {
Expand Down Expand Up @@ -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();
}

Expand Down
7 changes: 1 addition & 6 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
22 changes: 22 additions & 0 deletions tests/unit/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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;
}
21 changes: 21 additions & 0 deletions tests/unit/copy_ctor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
32 changes: 32 additions & 0 deletions tests/unit/out/refcount/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Route>) -> i32 {
if ((route.with(|__s| __s.path.first) % 2) != 0) {
return ({
Expand Down Expand Up @@ -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<Tally> = Rc::new(RefCell::new(Tally { calls: 0 }));
let ct: Value<Tally> = Rc::new(RefCell::new(Tally { calls: 0 }));
let rt: Ptr<Tally> = 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 {
Expand Down Expand Up @@ -168,4 +182,22 @@ impl RouteImpl for Ptr<Route> {
return old_cost;
}
}
pub trait TallyImpl {
fn SameNameBetweenConstAndNonConst_1(&self) -> i32;
fn SameNameBetweenConstAndNonConst_2(&self) -> i32;
}
impl TallyImpl for Ptr<Tally> {
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() {}
54 changes: 50 additions & 4 deletions tests/unit/out/refcount/copy_ctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Tracked>) -> 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<Tracked> = 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<Tracked>) {
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<Counted> = Rc::new(RefCell::new(Counted::new({ v })));
return Counted::copy_from({ c.as_pointer() });
}
Expand All @@ -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 });
Expand Down Expand Up @@ -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<Tracked> = Rc::new(RefCell::new(<Tracked>::default()));
let t2: Value<Tracked> = 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<Tracked> = Rc::new(RefCell::new(<Tracked>::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<Tracked>) -> Ptr<Tracked>;
}
impl TrackedImpl for Ptr<Tracked> {
fn copy_assign(&self, o: Ptr<Tracked>) -> Ptr<Tracked> {
field!(o, copied_from).with_mut(|__v| __v.prefix_inc());
return (*self).clone();
}
}
pub fn __cpp2rust_init_globals() {
let _ = copies_0.with(|_| ());
}
45 changes: 33 additions & 12 deletions tests/unit/out/unsafe/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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() {}
Loading
Loading