From 0a50db5dd472dedd955ae6f189567004620ccc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Sun, 5 Jul 2026 20:23:01 +0000 Subject: [PATCH 1/2] Add pre-commit tests --- tests/unit/compound_assign_ref.cpp | 13 ++++++++++++ .../unit/out/refcount/compound_assign_ref.rs | 19 ++++++++++++++++++ tests/unit/out/unsafe/compound_assign_ref.rs | 20 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 tests/unit/compound_assign_ref.cpp create mode 100644 tests/unit/out/refcount/compound_assign_ref.rs create mode 100644 tests/unit/out/unsafe/compound_assign_ref.rs diff --git a/tests/unit/compound_assign_ref.cpp b/tests/unit/compound_assign_ref.cpp new file mode 100644 index 00000000..59125dbb --- /dev/null +++ b/tests/unit/compound_assign_ref.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include + +int main() { + std::vector v; + v.push_back(10); + v.front() += 5; + assert(v.front() == 15); + return v.front(); +} diff --git a/tests/unit/out/refcount/compound_assign_ref.rs b/tests/unit/out/refcount/compound_assign_ref.rs new file mode 100644 index 00000000..cb18283c --- /dev/null +++ b/tests/unit/out/refcount/compound_assign_ref.rs @@ -0,0 +1,19 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let v: Value> = Rc::new(RefCell::new(Vec::new())); + (*v.borrow_mut()).push(10); + let rhs_0 = ((((v.as_pointer() as Ptr).read()) as i32) + 5) as i32; + (v.as_pointer() as Ptr).write(rhs_0); + assert!((((v.as_pointer() as Ptr).read()) == 15)); + return ((v.as_pointer() as Ptr).read()); +} diff --git a/tests/unit/out/unsafe/compound_assign_ref.rs b/tests/unit/out/unsafe/compound_assign_ref.rs new file mode 100644 index 00000000..1da5a005 --- /dev/null +++ b/tests/unit/out/unsafe/compound_assign_ref.rs @@ -0,0 +1,20 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut v: Vec = Vec::new(); + v.push(10); + ((v).first_mut().unwrap()) = ((((v).first_mut().unwrap()) as i32) + 5) as i32; + assert!(((*((v).first_mut().unwrap())) == (15))); + return (*((v).first_mut().unwrap())); +} From 890e2c2764a09c6c313891131c1a875f351ff88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Sun, 5 Jul 2026 20:38:18 +0000 Subject: [PATCH 2/2] Fix compound assignment type casts --- cpp2rust/converter/converter.cpp | 3 ++- cpp2rust/converter/models/converter_refcount.cpp | 11 ++++++++++- cpp2rust/converter/models/converter_refcount.h | 2 ++ tests/unit/out/refcount/auto.rs | 3 +-- tests/unit/out/refcount/compound_assign_ref.rs | 6 ++++-- tests/unit/out/refcount/foreach_mut.rs | 12 ++++++++---- tests/unit/out/refcount/unique_ptr_deref_ops.rs | 9 +++------ tests/unit/out/unsafe/auto.rs | 2 +- tests/unit/out/unsafe/compound_assign_ref.rs | 2 +- tests/unit/out/unsafe/foreach_mut.rs | 4 ++-- tests/unit/out/unsafe/unique_ptr_deref_ops.rs | 6 +++--- 11 files changed, 37 insertions(+), 23 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 65929016..37f474ad 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2274,7 +2274,8 @@ void Converter::ConvertBinaryOperator(clang::BinaryOperator *expr) { if (auto *cmpd_assign_op = llvm::dyn_cast(expr); expr->isCompoundAssignmentOp() && - lhs_type != cmpd_assign_op->getComputationResultType()) { + GetUnsafeTypeAsString(lhs_type) != + GetUnsafeTypeAsString(cmpd_assign_op->getComputationResultType())) { auto computation_result_type = cmpd_assign_op->getComputationResultType(); if (IsUnsignedArithOp(cmpd_assign_op)) { Convert(lhs); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index de3463c5..c7a2be2b 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -109,6 +109,14 @@ ConverterRefCount::PushUnboxedIfSimple::PushUnboxedIfSimple( : ConversionKind::FullRefCount); } +std::string +ConverterRefCount::GetSafeTypeAsString(clang::QualType qual_type) const { + std::string type_as_string; + ConverterRefCount converter(type_as_string, ctx_); + converter.Convert(qual_type); + return std::string(Trim(type_as_string)); +} + std::string ConverterRefCount::BoxType(std::string &&str) const { switch (getConversionKind()) { case ConversionKind::Unboxed: @@ -1362,7 +1370,8 @@ void ConverterRefCount::ConvertBinaryOperator(clang::BinaryOperator *expr) { std::string_view opcode_as_string = expr->getOpcodeStr(); if (auto *assign = llvm::dyn_cast(expr); - assign && lhs_type != assign->getComputationResultType()) { + assign && GetSafeTypeAsString(lhs_type) != + GetSafeTypeAsString(assign->getComputationResultType())) { auto computation_result_type = assign->getComputationResultType(); StrCat(keyword::kLet, "rhs_0", token::kAssign); if (IsUnsignedArithOp(assign)) { diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 819fa4ff..e58853e1 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -242,6 +242,8 @@ class ConverterRefCount final : public Converter { std::string ConvertPtrType(clang::QualType type); std::string ConvertPointeeType(clang::QualType ptr_type) override; + std::string GetSafeTypeAsString(clang::QualType qual_type) const; + /// The kind of conversion that should be performed. enum class ConversionKind : uint8_t { Unboxed, diff --git a/tests/unit/out/refcount/auto.rs b/tests/unit/out/refcount/auto.rs index cdeac07a..ded6317c 100644 --- a/tests/unit/out/refcount/auto.rs +++ b/tests/unit/out/refcount/auto.rs @@ -19,8 +19,7 @@ fn main_0() -> i32 { let sum: Value = Rc::new(RefCell::new(0)); 'loop_: for mut elem in v.as_pointer() as Ptr { let elem: Value = Rc::new(RefCell::new(elem.read().clone())); - let rhs_0 = (((*sum.borrow()) as i32) + (*elem.borrow())) as i32; - (*sum.borrow_mut()) = rhs_0; + (*sum.borrow_mut()) += (*elem.borrow()); } return (*sum.borrow()); } diff --git a/tests/unit/out/refcount/compound_assign_ref.rs b/tests/unit/out/refcount/compound_assign_ref.rs index cb18283c..de0dbe55 100644 --- a/tests/unit/out/refcount/compound_assign_ref.rs +++ b/tests/unit/out/refcount/compound_assign_ref.rs @@ -12,8 +12,10 @@ pub fn main() { fn main_0() -> i32 { let v: Value> = Rc::new(RefCell::new(Vec::new())); (*v.borrow_mut()).push(10); - let rhs_0 = ((((v.as_pointer() as Ptr).read()) as i32) + 5) as i32; - (v.as_pointer() as Ptr).write(rhs_0); + { + let _ptr = (v.as_pointer() as Ptr).clone(); + _ptr.write(_ptr.read() + 5) + }; assert!((((v.as_pointer() as Ptr).read()) == 15)); return ((v.as_pointer() as Ptr).read()); } diff --git a/tests/unit/out/refcount/foreach_mut.rs b/tests/unit/out/refcount/foreach_mut.rs index a96aa7bf..0a65f06e 100644 --- a/tests/unit/out/refcount/foreach_mut.rs +++ b/tests/unit/out/refcount/foreach_mut.rs @@ -24,8 +24,10 @@ fn main_0() -> i32 { (*sum.borrow_mut()) += (*x.borrow()); } 'loop_: for mut x in v1.as_pointer() as Ptr { - let rhs_0 = (((x.read()) as i32) + 10) as i32; - x.write(rhs_0); + { + let _ptr = x.clone(); + _ptr.write(_ptr.read() + 10) + }; } 'loop_: for mut x in v1.as_pointer() as Ptr { let __rhs = (x.read()); @@ -49,8 +51,10 @@ fn main_0() -> i32 { } 'loop_: for mut p in v2.as_pointer() as Ptr> { let p: Value> = Rc::new(RefCell::new(p.read().clone())); - let rhs_0 = ((((*p.borrow()).read()) as i32) + 5) as i32; - (*p.borrow()).write(rhs_0); + { + let _ptr = (*p.borrow()).clone(); + _ptr.write(_ptr.read() + 5) + }; } 'loop_: for mut p in v2.as_pointer() as Ptr> { let p: Value> = Rc::new(RefCell::new(p.read().clone())); diff --git a/tests/unit/out/refcount/unique_ptr_deref_ops.rs b/tests/unit/out/refcount/unique_ptr_deref_ops.rs index 128ad6ad..e311ab90 100644 --- a/tests/unit/out/refcount/unique_ptr_deref_ops.rs +++ b/tests/unit/out/refcount/unique_ptr_deref_ops.rs @@ -11,12 +11,9 @@ pub fn main() { } fn main_0() -> i32 { let p: Value>> = Rc::new(RefCell::new(Some(Rc::new(RefCell::new(10))))); - let rhs_0 = (((*(*p.borrow()).as_ref().unwrap().borrow()) as i32) + 5) as i32; - (*(*p.borrow_mut()).as_ref().unwrap().borrow_mut()) = rhs_0; - let rhs_0 = (((*(*p.borrow()).as_ref().unwrap().borrow()) as i32) - 3) as i32; - (*(*p.borrow_mut()).as_ref().unwrap().borrow_mut()) = rhs_0; - let rhs_0 = (((*(*p.borrow()).as_ref().unwrap().borrow()) as i32) * 2) as i32; - (*(*p.borrow_mut()).as_ref().unwrap().borrow_mut()) = rhs_0; + (*(*p.borrow_mut()).as_ref().unwrap().borrow_mut()) += 5; + (*(*p.borrow_mut()).as_ref().unwrap().borrow_mut()) -= 3; + (*(*p.borrow_mut()).as_ref().unwrap().borrow_mut()) *= 2; let q: Value>> = Rc::new(RefCell::new(Some(Rc::new(RefCell::new(1))))); let sum: Value = Rc::new(RefCell::new( ((*(*p.borrow()).as_ref().unwrap().borrow()) + (*(*q.borrow()).as_ref().unwrap().borrow())), diff --git a/tests/unit/out/unsafe/auto.rs b/tests/unit/out/unsafe/auto.rs index 9fe1ce28..5d206ab3 100644 --- a/tests/unit/out/unsafe/auto.rs +++ b/tests/unit/out/unsafe/auto.rs @@ -21,7 +21,7 @@ unsafe fn main_0() -> i32 { let mut sum: i32 = 0; 'loop_: for elem in 0..(v.len()) { let mut elem = v[elem].clone(); - sum = ((sum as i32) + elem) as i32; + sum += elem; } return sum; } diff --git a/tests/unit/out/unsafe/compound_assign_ref.rs b/tests/unit/out/unsafe/compound_assign_ref.rs index 1da5a005..9f7639ff 100644 --- a/tests/unit/out/unsafe/compound_assign_ref.rs +++ b/tests/unit/out/unsafe/compound_assign_ref.rs @@ -14,7 +14,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut v: Vec = Vec::new(); v.push(10); - ((v).first_mut().unwrap()) = ((((v).first_mut().unwrap()) as i32) + 5) as i32; + (*((v).first_mut().unwrap())) += 5; assert!(((*((v).first_mut().unwrap())) == (15))); return (*((v).first_mut().unwrap())); } diff --git a/tests/unit/out/unsafe/foreach_mut.rs b/tests/unit/out/unsafe/foreach_mut.rs index 41053eae..d3f3b73e 100644 --- a/tests/unit/out/unsafe/foreach_mut.rs +++ b/tests/unit/out/unsafe/foreach_mut.rs @@ -27,7 +27,7 @@ unsafe fn main_0() -> i32 { } 'loop_: for x in 0..(v1.len()) { let mut x = v1.as_mut_ptr().add(x); - (*x) = (((*x) as i32) + 10) as i32; + (*x) += 10; } 'loop_: for x in 0..(v1.len()) { let mut x = v1.as_ptr().add(x); @@ -47,7 +47,7 @@ unsafe fn main_0() -> i32 { } 'loop_: for p in 0..(v2.len()) { let mut p = v2[p].clone(); - (*p) = (((*p) as i32) + 5) as i32; + (*p) += 5; } 'loop_: for p in 0..(v2.len()) { let mut p = v2[p].clone(); diff --git a/tests/unit/out/unsafe/unique_ptr_deref_ops.rs b/tests/unit/out/unsafe/unique_ptr_deref_ops.rs index 295ac211..164ee079 100644 --- a/tests/unit/out/unsafe/unique_ptr_deref_ops.rs +++ b/tests/unit/out/unsafe/unique_ptr_deref_ops.rs @@ -13,9 +13,9 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut p: Option> = Some(Box::new(10)); - (*p.as_deref_mut().unwrap()) = (((*p.as_deref_mut().unwrap()) as i32) + 5) as i32; - (*p.as_deref_mut().unwrap()) = (((*p.as_deref_mut().unwrap()) as i32) - 3) as i32; - (*p.as_deref_mut().unwrap()) = (((*p.as_deref_mut().unwrap()) as i32) * 2) as i32; + (*p.as_deref_mut().unwrap()) += 5; + (*p.as_deref_mut().unwrap()) -= 3; + (*p.as_deref_mut().unwrap()) *= 2; let mut q: Option> = Some(Box::new(1)); let mut sum: i32 = ((*p.as_deref_mut().unwrap()) + (*q.as_deref_mut().unwrap())); return sum;