diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index b63c7fcb3..bc4339dc9 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -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(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"); @@ -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) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 179207599..54baca96d 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -694,6 +694,11 @@ class Converter : public clang::RecursiveASTVisitor { 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); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 9a5f74873..67d51e208 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -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, diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index e76995a74..453af97ba 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -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; diff --git a/tests/unit/operator_comparison_nonbool.cpp b/tests/unit/operator_comparison_nonbool.cpp index 4b2861c05..4476efb41 100644 --- a/tests/unit/operator_comparison_nonbool.cpp +++ b/tests/unit/operator_comparison_nonbool.cpp @@ -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); @@ -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; } diff --git a/tests/unit/out/refcount/operator_comparison_nonbool.rs b/tests/unit/out/refcount/operator_comparison_nonbool.rs index bd227ef7b..cc87e5746 100644 --- a/tests/unit/out/refcount/operator_comparison_nonbool.rs +++ b/tests/unit/out/refcount/operator_comparison_nonbool.rs @@ -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 = 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()); @@ -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 = Rc::new(RefCell::new(RefInt { v: 1 })); + let ri2: Value = Rc::new(RefCell::new(RefInt { v: 2 })); + assert!( + ({ + RefBoolImpl::to_bool( + &({ RefIntImpl::operator_eq(&ri1.as_pointer(), ri2.as_pointer()) }), + ) + }) + ); + let ris: Value> = + Rc::new(RefCell::new(Box::new([RefInt { v: 1 }, RefInt { v: 2 }]))); + assert!( + ({ + let count = ((ris.as_pointer() as Ptr) + .offset((2) as isize) + .get_offset() + - (ris.as_pointer() as Ptr).get_offset()) as usize; + (ris.as_pointer() as Ptr).offset( + (ris.as_pointer() as Ptr) + .clone() + .into_iter() + .take(count) + .position(|value_0| value_0.read() == (*ri2.borrow())) + .unwrap_or(count) as isize, + ) + } == (ris.as_pointer() as Ptr)) + ); return 0; } pub trait CustomImpl { @@ -363,4 +424,22 @@ impl MyBoolImpl for Ptr { return (*self).with(|__s| __s.value); } } -pub fn __cpp2rust_init_globals() {} +pub trait RefBoolImpl { + fn to_bool(&self) -> bool; +} +impl RefBoolImpl for Ptr { + fn to_bool(&self) -> bool { + return (*self).with(|__s| __s.value); + } +} +pub trait RefIntImpl { + fn operator_eq(&self, _a0: Ptr) -> Ptr; +} +impl RefIntImpl for Ptr { + fn operator_eq(&self, _a0: Ptr) -> Ptr { + return ref_true_8.with(|v| v.as_pointer()); + } +} +pub fn __cpp2rust_init_globals() { + let _ = ref_true_8.with(|_| ()); +} diff --git a/tests/unit/out/unsafe/operator_comparison_nonbool.rs b/tests/unit/out/unsafe/operator_comparison_nonbool.rs index d4b9150e8..75f54f680 100644 --- a/tests/unit/out/unsafe/operator_comparison_nonbool.rs +++ b/tests/unit/out/unsafe/operator_comparison_nonbool.rs @@ -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 = + 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(); @@ -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); +}