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
20 changes: 16 additions & 4 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4753,14 +4753,19 @@ std::string Converter::GetComparisonBool(const clang::FunctionDecl *op,
if (ret->isIntegerType()) {
return std::format("(({}) != 0)", call);
}
const auto *record = ret->getAsCXXRecordDecl();
bool returns_ref = ret->isReferenceType();
const auto *record = ret.getNonReferenceType()->getAsCXXRecordDecl();
assert(record && "unsupported comparison operator return type");
for (const auto *found : record->getVisibleConversionFunctions()) {
const auto *conversion = clang::dyn_cast<clang::CXXConversionDecl>(found);
if (conversion && conversion->getConversionType()->isBooleanType()) {
return std::format("{{ let __cmp = &{}; {}::{}({}) }}", call,
GetUFCSName(conversion), GetMethodName(conversion),
GetComparisonReceiver(conversion, record, "__cmp"));
auto receiver =
returns_ref
? GetComparisonReferenceReceiver(conversion, record, "__cmp")
: GetComparisonReceiver(conversion, record, "__cmp");
return std::format("{{ let __cmp = {}{}; {}::{}({}) }}",
returns_ref ? "" : "&", call, GetUFCSName(conversion),
GetMethodName(conversion), receiver);
}
}
assert(0 && "comparison operator result has no conversion to bool");
Expand All @@ -4773,6 +4778,13 @@ Converter::GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
return std::format("{} as *const {}", value, GetRecordName(decl));
}

std::string
Converter::GetComparisonReferenceReceiver(const clang::CXXMethodDecl *method,
const clang::CXXRecordDecl *decl,
std::string_view ptr) {
return GetComparisonReceiver(method, decl, std::format("&*{}", ptr));
}

std::string Converter::GetComparisonReceiver(const clang::CXXMethodDecl *method,
const clang::CXXRecordDecl *,
std::string_view lhs) {
Expand Down
5 changes: 5 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,11 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
std::string_view value);

virtual std::string
GetComparisonReferenceReceiver(const clang::CXXMethodDecl *method,
const clang::CXXRecordDecl *decl,
std::string_view ptr);

virtual std::string GetComparisonReceiver(const clang::CXXMethodDecl *method,
const clang::CXXRecordDecl *decl,
std::string_view lhs);
Expand Down
7 changes: 7 additions & 0 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,13 @@ ConverterRefCount::GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
return BoxValue(GetShallowCopy(decl, value)) + ".as_pointer()";
}

std::string
ConverterRefCount::GetComparisonReferenceReceiver(const clang::CXXMethodDecl *,
const clang::CXXRecordDecl *,
std::string_view ptr) {
return std::format("&{}", ptr);
}

std::string
ConverterRefCount::GetComparisonReceiver(const clang::CXXMethodDecl *,
const clang::CXXRecordDecl *decl,
Expand Down
4 changes: 4 additions & 0 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class ConverterRefCount final : public Converter {
std::string GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
std::string_view value) override;

std::string GetComparisonReferenceReceiver(const clang::CXXMethodDecl *method,
const clang::CXXRecordDecl *decl,
std::string_view ptr) override;

std::string GetComparisonReceiver(const clang::CXXMethodDecl *method,
const clang::CXXRecordDecl *decl,
std::string_view lhs) override;
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/operator_comparison_nonbool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ struct Boolish {
MyBool operator==(Boolish a, Boolish b) { return MyBool(a.v == b.v); }
MyBool operator<(Boolish a, Boolish b) { return MyBool(a.v < b.v); }

struct RefBool {
bool value;
explicit RefBool(bool v) : value(v) {}
RefBool(const RefBool &) = delete;
operator bool() const { return value; }
};

static RefBool ref_true{true};

struct RefInt {
int v;
RefBool &operator==(const RefInt &) const { return ref_true; }
};

int main() {
X a{1}, b{2}, c{1};
assert((a == c) == 2);
Expand Down Expand Up @@ -76,5 +90,10 @@ int main() {
Boolish bs[] = {{3}, {1}, {2}};
std::sort(bs, bs + 3);
assert(bs[0].v == 1 && bs[1].v == 2 && bs[2].v == 3);

RefInt ri1{1}, ri2{2};
assert(ri1 == ri2);
RefInt ris[] = {{1}, {2}};
assert(std::find(ris, ris + 2, ri2) == ris);
return 0;
}
81 changes: 80 additions & 1 deletion tests/unit/out/refcount/operator_comparison_nonbool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,40 @@ pub fn operator_eq_7(mut a: Boolish, mut b: Boolish) -> MyBool {
pub fn operator_lt_6(mut a: Boolish, mut b: Boolish) -> MyBool {
return MyBool::new({ (a.v < b.v) });
}
#[derive(Record, ByteRepr, FnPtrArg, Default)]
#[byte_size(1)]
pub struct RefBool {
#[offset(0)]
pub value: bool,
}
impl RefBool {
pub fn new(mut v: bool) -> Self {
Self { value: v }
}
}
thread_local!(
pub static ref_true_8: Value<RefBool> = Rc::new(RefCell::new(RefBool::new({ true })));
);
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
#[byte_size(4)]
pub struct RefInt {
#[offset(0)]
pub v: i32,
}
impl std::cmp::PartialEq for RefInt {
fn eq(&self, other: &Self) -> bool {
{
{
let __cmp = RefIntImpl::operator_eq(
&Rc::new(RefCell::new(RefInt { v: self.v.clone() })).as_pointer(),
Rc::new(RefCell::new(RefInt { v: other.v.clone() })).as_pointer(),
);
RefBoolImpl::to_bool(&__cmp)
}
}
}
}
impl std::cmp::Eq for RefInt {}
pub fn main() {
__cpp2rust_init_globals();
std::process::exit(main_0());
Expand Down Expand Up @@ -317,6 +351,33 @@ fn main_0() -> i32 {
(({ (*bs.borrow())[(0) as usize].v } == 1) && ({ (*bs.borrow())[(1) as usize].v } == 2))
&& ({ (*bs.borrow())[(2) as usize].v } == 3)
);
let ri1: Value<RefInt> = Rc::new(RefCell::new(RefInt { v: 1 }));
let ri2: Value<RefInt> = Rc::new(RefCell::new(RefInt { v: 2 }));
assert!(
({
RefBoolImpl::to_bool(
&({ RefIntImpl::operator_eq(&ri1.as_pointer(), ri2.as_pointer()) }),
)
})
);
let ris: Value<Box<[RefInt]>> =
Rc::new(RefCell::new(Box::new([RefInt { v: 1 }, RefInt { v: 2 }])));
assert!(
({
let count = ((ris.as_pointer() as Ptr<RefInt>)
.offset((2) as isize)
.get_offset()
- (ris.as_pointer() as Ptr<RefInt>).get_offset()) as usize;
(ris.as_pointer() as Ptr<RefInt>).offset(
(ris.as_pointer() as Ptr<RefInt>)
.clone()
.into_iter()
.take(count)
.position(|value_0| value_0.read() == (*ri2.borrow()))
.unwrap_or(count) as isize,
)
} == (ris.as_pointer() as Ptr<RefInt>))
);
return 0;
}
pub trait CustomImpl {
Expand Down Expand Up @@ -363,4 +424,22 @@ impl MyBoolImpl for Ptr<MyBool> {
return (*self).with(|__s| __s.value);
}
}
pub fn __cpp2rust_init_globals() {}
pub trait RefBoolImpl {
fn to_bool(&self) -> bool;
}
impl RefBoolImpl for Ptr<RefBool> {
fn to_bool(&self) -> bool {
return (*self).with(|__s| __s.value);
}
}
pub trait RefIntImpl {
fn operator_eq(&self, _a0: Ptr<RefInt>) -> Ptr<RefBool>;
}
impl RefIntImpl for Ptr<RefInt> {
fn operator_eq(&self, _a0: Ptr<RefInt>) -> Ptr<RefBool> {
return ref_true_8.with(|v| v.as_pointer());
}
}
pub fn __cpp2rust_init_globals() {
let _ = ref_true_8.with(|_| ());
}
54 changes: 53 additions & 1 deletion tests/unit/out/unsafe/operator_comparison_nonbool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,43 @@ pub unsafe fn operator_eq_7(mut a: Boolish, mut b: Boolish) -> MyBool {
pub unsafe fn operator_lt_6(mut a: Boolish, mut b: Boolish) -> MyBool {
return MyBool::new({ ((a.v) < (b.v)) });
}
#[repr(C)]
#[derive(FnPtrArg, Default)]
pub struct RefBool {
pub value: bool,
}
impl RefBool {
pub unsafe fn new(mut v: bool) -> Self {
let mut this = Self { value: v };
this
}
pub unsafe fn to_bool(&self) -> bool {
return self.value;
}
}
pub static mut ref_true_8: std::cell::LazyCell<RefBool> =
std::cell::LazyCell::new(|| unsafe { RefBool::new({ true }) });
#[repr(C)]
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
pub struct RefInt {
pub v: i32,
}
impl RefInt {
pub unsafe fn operator_eq(&self, _a0: *const RefInt) -> *mut RefBool {
return &mut (*std::cell::LazyCell::force_mut(&mut *&raw mut ref_true_8));
}
}
impl std::cmp::PartialEq for RefInt {
fn eq(&self, other: &Self) -> bool {
unsafe {
{
let __cmp = RefInt::operator_eq(self, other as *const RefInt);
RefBool::to_bool(&*__cmp)
}
}
}
}
impl std::cmp::Eq for RefInt {}
pub fn main() {
unsafe {
__cpp2rust_init_globals();
Expand Down Expand Up @@ -301,6 +338,21 @@ unsafe fn main_0() -> i32 {
(((bs[(0) as usize].v) == (1)) && ((bs[(1) as usize].v) == (2)))
&& ((bs[(2) as usize].v) == (3))
);
let mut ri1: RefInt = RefInt { v: 1 };
let mut ri2: RefInt = RefInt { v: 2 };
assert!((unsafe { RefBool::to_bool(&(*(unsafe { RefInt::operator_eq(&ri1, &ri2,) })),) }));
let mut ris: [RefInt; 2] = [RefInt { v: 1 }, RefInt { v: 2 }];
assert!(
(({
let mut it = ris.as_mut_ptr();
while it != ris.as_mut_ptr().offset((2) as isize) && *it != ri2 {
it = it.add(1);
}
it
}) == (ris.as_mut_ptr()))
);
return 0;
}
pub unsafe fn __cpp2rust_init_globals() {}
pub unsafe fn __cpp2rust_init_globals() {
std::cell::LazyCell::force(&*&raw const ref_true_8);
}
Loading