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
16 changes: 13 additions & 3 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ bool Converter::ConvertCXXMethodDecl(clang::CXXMethodDecl *decl) {
}

std::string Converter::GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl) {
return decl->isConst() ? "&self" : "&mut self";
return MethodNeedsMutableReceiver(decl) ? "&mut self" : "&self";
}

std::string Converter::GetCtorName(clang::CXXConstructorDecl *decl) {
Expand Down Expand Up @@ -3151,12 +3151,22 @@ void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow,
}
Buffer buf(*this);
PushExprKind push(*this, ExprKind::LValue);
StrCat(method->isConst() ? "&" : "&mut");
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 Expand Up @@ -4383,7 +4393,7 @@ std::string Converter::GetComparisonCall(const clang::FunctionDecl *op,
auto record = GetRecordName(decl);
auto arg = std::format("{} as *const {}", rhs, record);
if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(op)) {
auto recv = method->isConst()
auto recv = !MethodNeedsMutableReceiver(method)
? std::string(lhs)
: std::format("&mut *(&raw const *{}).cast_mut()", lhs);
return std::format("{}::{}({}, {})", GetUFCSName(method),
Expand Down
9 changes: 9 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,15 @@ bool IsRValueConvertingConstructor(const clang::CXXConstructorDecl *ctor) {
ctor->getParamDecl(0)->getType()->isRValueReferenceType();
}

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(); });
}

bool IsPassThroughConstructor(const clang::CXXConstructorDecl *ctor) {
return !IsConvertibleCopyOrMoveConstructor(ctor) &&
(ctor->isCopyOrMoveConstructor() ||
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ bool IsRValueConvertingConstructor(const clang::CXXConstructorDecl *ctor);

bool IsPassThroughConstructor(const clang::CXXConstructorDecl *ctor);

bool MethodNeedsMutableReceiver(const clang::CXXMethodDecl *method);

bool IsConvertibleCXXRecordDecl(const clang::CXXRecordDecl *decl);

bool IsConvertibleCXXMethodDecl(const clang::CXXMethodDecl *decl);
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ struct Route {
}
};

struct Counter {
int v;
mutable int calls;

int Get() const {
++calls;
return v;
}

bool operator==(const Counter &o) const {
++calls;
return v == o.v;
}
};

int RandomRoute(Route &route) {
if (route.path.first % 2) {
return route.path.SetFirst(route.path.SetSecond(10));
Expand All @@ -49,5 +64,15 @@ int main() {
Route route2 = {{1, 0}, 10};
double old_cost = route1.SetCost(route2.SetCost(15));
assert(RandomRoute(route1) + RandomRoute(route2) + old_cost == 9);
Counter c1{3, 0};
const Counter c2{3, 0};
const Counter *pc = &c1;
assert(c1.Get() == 3);
assert(c2.Get() == 3);
assert(pc->Get() == 3);
assert(c1 == c2);
assert(c2 == c1);
assert(c1.calls == 3);
assert(c2.calls == 2);
return 0;
}
82 changes: 82 additions & 0 deletions tests/unit/out/refcount/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,55 @@ impl ByteRepr for Route {
}
}
}
#[derive(Default)]
pub struct Counter {
pub v: Value<i32>,
pub calls: Value<i32>,
}
impl std::cmp::PartialEq for Counter {
fn eq(&self, other: &Self) -> bool {
{
CounterImpl::operator_eq(
&Rc::new(RefCell::new(Counter {
v: self.v.clone(),
calls: self.calls.clone(),
}))
.as_pointer(),
Rc::new(RefCell::new(Counter {
v: other.v.clone(),
calls: other.calls.clone(),
}))
.as_pointer(),
)
}
}
}
impl std::cmp::Eq for Counter {}
impl Clone for Counter {
fn clone(&self) -> Self {
let __this: Value<Counter> = Rc::new(RefCell::new(Self {
v: Rc::new(RefCell::new((*self.v.borrow()))),
calls: Rc::new(RefCell::new((*self.calls.borrow()))),
}));
let this: Ptr<Counter> = __this.as_pointer();
Rc::try_unwrap(__this).ok().unwrap().into_inner()
}
}
impl ByteRepr for Counter {
fn byte_size() -> usize {
8
}
fn to_bytes(&self, buf: &mut [u8]) {
(*self.v.borrow()).to_bytes(&mut buf[0..4]);
(*self.calls.borrow()).to_bytes(&mut buf[4..8]);
}
fn from_bytes(buf: &[u8]) -> Self {
Self {
v: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
calls: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
}
}
}
pub fn RandomRoute_0(route: Ptr<Route>) -> i32 {
if (((*(*(*route.upgrade().deref()).path.borrow()).first.borrow()) % 2) != 0) {
return ({
Expand Down Expand Up @@ -115,8 +164,41 @@ fn main_0() -> i32 {
+ (*old_cost.borrow()))
== 9_f64)
);
let c1: Value<Counter> = Rc::new(RefCell::new(Counter {
v: Rc::new(RefCell::new(3)),
calls: Rc::new(RefCell::new(0)),
}));
let c2: Value<Counter> = Rc::new(RefCell::new(Counter {
v: Rc::new(RefCell::new(3)),
calls: Rc::new(RefCell::new(0)),
}));
let pc: Value<Ptr<Counter>> = Rc::new(RefCell::new((c1.as_pointer())));
assert!((({ CounterImpl::Get(&c1.as_pointer(),) }) == 3));
assert!((({ CounterImpl::Get(&c2.as_pointer(),) }) == 3));
assert!((({ CounterImpl::Get(&(*pc.borrow()),) }) == 3));
assert!(({ CounterImpl::operator_eq(&c1.as_pointer(), c2.as_pointer(),) }));
assert!(({ CounterImpl::operator_eq(&c2.as_pointer(), c1.as_pointer(),) }));
assert!(((*(*c1.borrow()).calls.borrow()) == 3));
assert!(((*(*c2.borrow()).calls.borrow()) == 2));
return 0;
}
pub trait CounterImpl {
fn Get(&self) -> i32;
fn operator_eq(&self, o: Ptr<Counter>) -> bool;
}
impl CounterImpl for Ptr<Counter> {
fn Get(&self) -> i32 {
(*(*(*self).upgrade().deref()).calls.borrow_mut()).prefix_inc();
return (*(*(*self).upgrade().deref()).v.borrow());
}
fn operator_eq(&self, o: Ptr<Counter>) -> bool {
(*(*(*self).upgrade().deref()).calls.borrow_mut()).prefix_inc();
return {
let _lhs = (*(*(*self).upgrade().deref()).v.borrow());
_lhs == (*(*o.upgrade().deref()).v.borrow())
};
}
}
pub trait PairImpl {
fn NOP(&self);
fn GetFirst(&self) -> i32;
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/out/unsafe/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,30 @@ impl Route {
return old_cost;
}
}
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct Counter {
pub v: i32,
pub calls: i32,
}
impl Counter {
pub unsafe fn Get(&mut self) -> i32 {
self.calls.prefix_inc();
return self.v;
}
pub unsafe fn operator_eq(&mut self, o: *const Counter) -> bool {
self.calls.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)
}
}
}
impl std::cmp::Eq for Counter {}
pub unsafe fn RandomRoute_0(route: *mut Route) -> i32 {
if ((((*route).path.first) % (2)) != 0) {
return (unsafe {
Expand Down Expand Up @@ -101,6 +125,16 @@ unsafe fn main_0() -> i32 {
+ (old_cost))
== (9_f64))
);
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!(((c1.calls) == (3)));
assert!(((c2.calls) == (2)));
return 0;
}
pub unsafe fn __cpp2rust_init_globals() {}
Loading