Skip to content

Commit 15eae42

Browse files
authored
Look through references for non-bool comparison operators (#510)
1 parent e65e265 commit 15eae42

7 files changed

Lines changed: 184 additions & 6 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4817,14 +4817,19 @@ std::string Converter::GetComparisonBool(const clang::FunctionDecl *op,
48174817
if (ret->isIntegerType()) {
48184818
return std::format("(({}) != 0)", call);
48194819
}
4820-
const auto *record = ret->getAsCXXRecordDecl();
4820+
bool returns_ref = ret->isReferenceType();
4821+
const auto *record = ret.getNonReferenceType()->getAsCXXRecordDecl();
48214822
assert(record && "unsupported comparison operator return type");
48224823
for (const auto *found : record->getVisibleConversionFunctions()) {
48234824
const auto *conversion = clang::dyn_cast<clang::CXXConversionDecl>(found);
48244825
if (conversion && conversion->getConversionType()->isBooleanType()) {
4825-
return std::format("{{ let __cmp = &{}; {}::{}({}) }}", call,
4826-
GetUFCSName(conversion), GetMethodName(conversion),
4827-
GetComparisonReceiver(conversion, record, "__cmp"));
4826+
auto receiver =
4827+
returns_ref
4828+
? GetComparisonReferenceReceiver(conversion, record, "__cmp")
4829+
: GetComparisonReceiver(conversion, record, "__cmp");
4830+
return std::format("{{ let __cmp = {}{}; {}::{}({}) }}",
4831+
returns_ref ? "" : "&", call, GetUFCSName(conversion),
4832+
GetMethodName(conversion), receiver);
48284833
}
48294834
}
48304835
assert(0 && "comparison operator result has no conversion to bool");
@@ -4837,6 +4842,13 @@ Converter::GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
48374842
return std::format("{} as *const {}", value, GetRecordName(decl));
48384843
}
48394844

4845+
std::string
4846+
Converter::GetComparisonReferenceReceiver(const clang::CXXMethodDecl *method,
4847+
const clang::CXXRecordDecl *decl,
4848+
std::string_view ptr) {
4849+
return GetComparisonReceiver(method, decl, std::format("&*{}", ptr));
4850+
}
4851+
48404852
std::string Converter::GetComparisonReceiver(const clang::CXXMethodDecl *method,
48414853
const clang::CXXRecordDecl *,
48424854
std::string_view lhs) {

‎cpp2rust/converter/converter.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,11 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
712712
GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
713713
std::string_view value);
714714

715+
virtual std::string
716+
GetComparisonReferenceReceiver(const clang::CXXMethodDecl *method,
717+
const clang::CXXRecordDecl *decl,
718+
std::string_view ptr);
719+
715720
virtual std::string GetComparisonReceiver(const clang::CXXMethodDecl *method,
716721
const clang::CXXRecordDecl *decl,
717722
std::string_view lhs);

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,13 @@ ConverterRefCount::GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
564564
return BoxValue(GetShallowCopy(decl, value)) + ".as_pointer()";
565565
}
566566

567+
std::string
568+
ConverterRefCount::GetComparisonReferenceReceiver(const clang::CXXMethodDecl *,
569+
const clang::CXXRecordDecl *,
570+
std::string_view ptr) {
571+
return std::format("&{}", ptr);
572+
}
573+
567574
std::string
568575
ConverterRefCount::GetComparisonReceiver(const clang::CXXMethodDecl *,
569576
const clang::CXXRecordDecl *decl,

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class ConverterRefCount final : public Converter {
4747
std::string GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
4848
std::string_view value) override;
4949

50+
std::string GetComparisonReferenceReceiver(const clang::CXXMethodDecl *method,
51+
const clang::CXXRecordDecl *decl,
52+
std::string_view ptr) override;
53+
5054
std::string GetComparisonReceiver(const clang::CXXMethodDecl *method,
5155
const clang::CXXRecordDecl *decl,
5256
std::string_view lhs) override;

‎tests/unit/operator_comparison_nonbool.cpp‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ struct Boolish {
4242
MyBool operator==(Boolish a, Boolish b) { return MyBool(a.v == b.v); }
4343
MyBool operator<(Boolish a, Boolish b) { return MyBool(a.v < b.v); }
4444

45+
struct RefBool {
46+
bool value;
47+
explicit RefBool(bool v) : value(v) {}
48+
RefBool(const RefBool &) = delete;
49+
operator bool() const { return value; }
50+
};
51+
52+
static RefBool ref_true{true};
53+
54+
struct RefInt {
55+
int v;
56+
RefBool &operator==(const RefInt &) const { return ref_true; }
57+
};
58+
4559
int main() {
4660
X a{1}, b{2}, c{1};
4761
assert((a == c) == 2);
@@ -76,5 +90,10 @@ int main() {
7690
Boolish bs[] = {{3}, {1}, {2}};
7791
std::sort(bs, bs + 3);
7892
assert(bs[0].v == 1 && bs[1].v == 2 && bs[2].v == 3);
93+
94+
RefInt ri1{1}, ri2{2};
95+
assert(ri1 == ri2);
96+
RefInt ris[] = {{1}, {2}};
97+
assert(std::find(ris, ris + 2, ri2) == ris);
7998
return 0;
8099
}

‎tests/unit/out/refcount/operator_comparison_nonbool.rs‎

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,40 @@ pub fn operator_eq_7(mut a: Boolish, mut b: Boolish) -> MyBool {
182182
pub fn operator_lt_6(mut a: Boolish, mut b: Boolish) -> MyBool {
183183
return MyBool::new({ (a.v < b.v) });
184184
}
185+
#[derive(Record, ByteRepr, FnPtrArg, Default)]
186+
#[byte_size(1)]
187+
pub struct RefBool {
188+
#[offset(0)]
189+
pub value: bool,
190+
}
191+
impl RefBool {
192+
pub fn new(mut v: bool) -> Self {
193+
Self { value: v }
194+
}
195+
}
196+
thread_local!(
197+
pub static ref_true_8: Value<RefBool> = Rc::new(RefCell::new(RefBool::new({ true })));
198+
);
199+
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
200+
#[byte_size(4)]
201+
pub struct RefInt {
202+
#[offset(0)]
203+
pub v: i32,
204+
}
205+
impl std::cmp::PartialEq for RefInt {
206+
fn eq(&self, other: &Self) -> bool {
207+
{
208+
{
209+
let __cmp = RefIntImpl::operator_eq(
210+
&Rc::new(RefCell::new(RefInt { v: self.v.clone() })).as_pointer(),
211+
Rc::new(RefCell::new(RefInt { v: other.v.clone() })).as_pointer(),
212+
);
213+
RefBoolImpl::to_bool(&__cmp)
214+
}
215+
}
216+
}
217+
}
218+
impl std::cmp::Eq for RefInt {}
185219
pub fn main() {
186220
__cpp2rust_init_globals();
187221
std::process::exit(main_0());
@@ -317,6 +351,33 @@ fn main_0() -> i32 {
317351
(({ (*bs.borrow())[(0) as usize].v } == 1) && ({ (*bs.borrow())[(1) as usize].v } == 2))
318352
&& ({ (*bs.borrow())[(2) as usize].v } == 3)
319353
);
354+
let ri1: Value<RefInt> = Rc::new(RefCell::new(RefInt { v: 1 }));
355+
let ri2: Value<RefInt> = Rc::new(RefCell::new(RefInt { v: 2 }));
356+
assert!(
357+
({
358+
RefBoolImpl::to_bool(
359+
&({ RefIntImpl::operator_eq(&ri1.as_pointer(), ri2.as_pointer()) }),
360+
)
361+
})
362+
);
363+
let ris: Value<Box<[RefInt]>> =
364+
Rc::new(RefCell::new(Box::new([RefInt { v: 1 }, RefInt { v: 2 }])));
365+
assert!(
366+
({
367+
let count = ((ris.as_pointer() as Ptr<RefInt>)
368+
.offset((2) as isize)
369+
.get_offset()
370+
- (ris.as_pointer() as Ptr<RefInt>).get_offset()) as usize;
371+
(ris.as_pointer() as Ptr<RefInt>).offset(
372+
(ris.as_pointer() as Ptr<RefInt>)
373+
.clone()
374+
.into_iter()
375+
.take(count)
376+
.position(|value_0| value_0.read() == (*ri2.borrow()))
377+
.unwrap_or(count) as isize,
378+
)
379+
} == (ris.as_pointer() as Ptr<RefInt>))
380+
);
320381
return 0;
321382
}
322383
pub trait CustomImpl {
@@ -363,4 +424,22 @@ impl MyBoolImpl for Ptr<MyBool> {
363424
return (*self).with(|__s| __s.value);
364425
}
365426
}
366-
pub fn __cpp2rust_init_globals() {}
427+
pub trait RefBoolImpl {
428+
fn to_bool(&self) -> bool;
429+
}
430+
impl RefBoolImpl for Ptr<RefBool> {
431+
fn to_bool(&self) -> bool {
432+
return (*self).with(|__s| __s.value);
433+
}
434+
}
435+
pub trait RefIntImpl {
436+
fn operator_eq(&self, _a0: Ptr<RefInt>) -> Ptr<RefBool>;
437+
}
438+
impl RefIntImpl for Ptr<RefInt> {
439+
fn operator_eq(&self, _a0: Ptr<RefInt>) -> Ptr<RefBool> {
440+
return ref_true_8.with(|v| v.as_pointer());
441+
}
442+
}
443+
pub fn __cpp2rust_init_globals() {
444+
let _ = ref_true_8.with(|_| ());
445+
}

‎tests/unit/out/unsafe/operator_comparison_nonbool.rs‎

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,43 @@ pub unsafe fn operator_eq_7(mut a: Boolish, mut b: Boolish) -> MyBool {
172172
pub unsafe fn operator_lt_6(mut a: Boolish, mut b: Boolish) -> MyBool {
173173
return MyBool::new({ ((a.v) < (b.v)) });
174174
}
175+
#[repr(C)]
176+
#[derive(FnPtrArg, Default)]
177+
pub struct RefBool {
178+
pub value: bool,
179+
}
180+
impl RefBool {
181+
pub unsafe fn new(mut v: bool) -> Self {
182+
let mut this = Self { value: v };
183+
this
184+
}
185+
pub unsafe fn to_bool(&self) -> bool {
186+
return self.value;
187+
}
188+
}
189+
pub static mut ref_true_8: std::cell::LazyCell<RefBool> =
190+
std::cell::LazyCell::new(|| unsafe { RefBool::new({ true }) });
191+
#[repr(C)]
192+
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
193+
pub struct RefInt {
194+
pub v: i32,
195+
}
196+
impl RefInt {
197+
pub unsafe fn operator_eq(&self, _a0: *const RefInt) -> *mut RefBool {
198+
return &mut (*std::cell::LazyCell::force_mut(&mut *&raw mut ref_true_8));
199+
}
200+
}
201+
impl std::cmp::PartialEq for RefInt {
202+
fn eq(&self, other: &Self) -> bool {
203+
unsafe {
204+
{
205+
let __cmp = RefInt::operator_eq(self, other as *const RefInt);
206+
RefBool::to_bool(&*__cmp)
207+
}
208+
}
209+
}
210+
}
211+
impl std::cmp::Eq for RefInt {}
175212
pub fn main() {
176213
unsafe {
177214
__cpp2rust_init_globals();
@@ -301,6 +338,21 @@ unsafe fn main_0() -> i32 {
301338
(((bs[(0) as usize].v) == (1)) && ((bs[(1) as usize].v) == (2)))
302339
&& ((bs[(2) as usize].v) == (3))
303340
);
341+
let mut ri1: RefInt = RefInt { v: 1 };
342+
let mut ri2: RefInt = RefInt { v: 2 };
343+
assert!((unsafe { RefBool::to_bool(&(*(unsafe { RefInt::operator_eq(&ri1, &ri2,) })),) }));
344+
let mut ris: [RefInt; 2] = [RefInt { v: 1 }, RefInt { v: 2 }];
345+
assert!(
346+
(({
347+
let mut it = ris.as_mut_ptr();
348+
while it != ris.as_mut_ptr().offset((2) as isize) && *it != ri2 {
349+
it = it.add(1);
350+
}
351+
it
352+
}) == (ris.as_mut_ptr()))
353+
);
304354
return 0;
305355
}
306-
pub unsafe fn __cpp2rust_init_globals() {}
356+
pub unsafe fn __cpp2rust_init_globals() {
357+
std::cell::LazyCell::force(&*&raw const ref_true_8);
358+
}

0 commit comments

Comments
 (0)