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
47 changes: 23 additions & 24 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,10 +723,10 @@ void ConverterRefCount::EmitHoistedInArmAssignment(clang::VarDecl *decl) {
if (!decl->hasInit()) {
return;
}
PushConversionKind push(*this, ConversionKind::Unboxed);
PushConversionKind push(*this, ConversionKind::FullRefCount);
StrCat(token::kStar, GetNamedDeclAsString(decl), ".borrow_mut()",
token::kAssign);
Convert(decl->getInit());
StrCat(ConvertVarInitValue(decl->getType(), decl->getInit()));
StrCat(token::kSemiColon);
}

Expand Down Expand Up @@ -1943,35 +1943,34 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
return attrs;
}

void ConverterRefCount::ConvertVarInit(clang::QualType qual_type,
clang::Expr *expr) {
std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type,
clang::Expr *expr) {
if (auto lambda = clang::dyn_cast<clang::LambdaExpr>(
expr->IgnoreUnlessSpelledInSource())) {
std::string str;
{
Buffer buf(*this);
PushConversionKind push(*this, ConversionKind::Unboxed);
if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) {
StrCat("FnPtr::new(");
VisitLambdaExpr(lambda);
StrCat(')');
} else {
VisitLambdaExpr(lambda);
}
str = std::move(buf).str();
Buffer buf(*this);
PushConversionKind push(*this, ConversionKind::Unboxed);
if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) {
StrCat("FnPtr::new(");
VisitLambdaExpr(lambda);
StrCat(')');
} else {
VisitLambdaExpr(lambda);
}
StrCat(BoxValue(std::move(str)));
return;
return std::move(buf).str();
}

bool is_ref = qual_type->isReferenceType();
PushConversionKind push(*this, ConversionKind::Unboxed, is_ref);
PushInitType init_type(*this, qual_type);
if (is_ref || qual_type->isFunctionPointerType()) {
StrCat(BoxValue(ConvertFreshPointer(expr)));
} else {
StrCat(BoxValue(ConvertFreshRValue(expr, qual_type)));
if (qual_type->isReferenceType() || qual_type->isFunctionPointerType()) {
return ConvertFreshPointer(expr);
}
return ConvertFreshRValue(expr, qual_type);
}

void ConverterRefCount::ConvertVarInit(clang::QualType qual_type,
clang::Expr *expr) {
bool is_ref = qual_type->isReferenceType();
PushConversionKind push(*this, ConversionKind::Unboxed, is_ref);
StrCat(BoxValue(ConvertVarInitValue(qual_type, expr)));
}

void ConverterRefCount::EmitSetOrAssign(clang::Expr *lhs,
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class ConverterRefCount final : public Converter {

void ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) override;

std::string ConvertVarInitValue(clang::QualType qual_type, clang::Expr *expr);

void ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs,
std::string_view assign_operator) override;

Expand Down
36 changes: 36 additions & 0 deletions tests/unit/goto_cleanup.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,48 @@ static int from_switch(int n) {
return ret;
}

struct wrapper {
int *item;
};

static int via_pointer(struct wrapper *w, int fail) {
int ret = 0;
int *item = w->item;
if (fail) {
ret = -1;
goto out;
}
ret = *item;
out:
return ret;
}

static int via_arrays(int fail) {
int ret = 0;
unsigned char remain[4] = {0};
char name[5] = "wxyz";
if (fail) {
ret = -1;
goto out;
}
remain[1] = 9;
ret = remain[0] + remain[1] + (name[0] == 'w') + (name[4] == '\0');
out:
return ret;
}

int main(void) {
assert(early(-1) == -1);
assert(early(5) == 100);
assert(from_loop(2) == 999);
assert(from_loop(10) == 7);
assert(from_switch(1) == 10);
assert(from_switch(2) == 999);
int value = 42;
struct wrapper w = {&value};
assert(via_pointer(&w, 0) == 42);
assert(via_pointer(&w, 1) == -1);
assert(via_arrays(0) == 11);
assert(via_arrays(1) == -1);
return 0;
}
85 changes: 85 additions & 0 deletions tests/unit/out/refcount/goto_cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,83 @@ pub fn from_switch_2(n: i32) -> i32 {
});
panic!("ub: non-void function does not return a value")
}
#[derive(Default)]
pub struct wrapper {
pub item: Value<Ptr<i32>>,
}
impl Clone for wrapper {
fn clone(&self) -> Self {
Self {
item: Rc::new(RefCell::new((*self.item.borrow()).clone())),
}
}
}
impl ByteRepr for wrapper {
fn byte_size() -> usize {
8
}
fn to_bytes(&self, buf: &mut [u8]) {
(*self.item.borrow()).to_bytes(&mut buf[0..8]);
}
fn from_bytes(buf: &[u8]) -> Self {
Self {
item: Rc::new(RefCell::new(<Ptr<i32>>::from_bytes(&buf[0..8]))),
}
}
}
pub fn via_pointer_3(w: Ptr<wrapper>, fail: i32) -> i32 {
let w: Value<Ptr<wrapper>> = Rc::new(RefCell::new(w));
let fail: Value<i32> = Rc::new(RefCell::new(fail));
let ret: Value<i32> = <Value<i32>>::default();
let item: Value<Ptr<i32>> = Rc::new(RefCell::new(Ptr::<i32>::null()));
goto_block!({
'__entry: {
*ret.borrow_mut() = 0;
*item.borrow_mut() = (*(*(*w.borrow()).upgrade().deref()).item.borrow()).clone();
if ((*fail.borrow()) != 0) {
(*ret.borrow_mut()) = -1_i32;
goto!('out);
}
let __rhs = ((*item.borrow()).read());
(*ret.borrow_mut()) = __rhs;
}
'out: {
return (*ret.borrow());
}
});
panic!("ub: non-void function does not return a value")
}
pub fn via_arrays_4(fail: i32) -> i32 {
let fail: Value<i32> = Rc::new(RefCell::new(fail));
let ret: Value<i32> = <Value<i32>>::default();
let remain: Value<Box<[u8]>> = Rc::new(RefCell::new(
(0..4).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
));
let name: Value<Box<[u8]>> = Rc::new(RefCell::new(
(0..5).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
));
goto_block!({
'__entry: {
*ret.borrow_mut() = 0;
*remain.borrow_mut() =
Box::new([0_u8, <u8>::default(), <u8>::default(), <u8>::default()]);
*name.borrow_mut() = Box::from(*b"wxyz\0");
if ((*fail.borrow()) != 0) {
(*ret.borrow_mut()) = -1_i32;
goto!('out);
}
(*remain.borrow_mut())[(1) as usize] = 9_u8;
(*ret.borrow_mut()) = (((((*remain.borrow())[(0) as usize] as i32)
+ ((*remain.borrow())[(1) as usize] as i32))
+ ((((*name.borrow())[(0) as usize] as i32) == ('w' as i32)) as i32))
+ ((((*name.borrow())[(4) as usize] as i32) == ('\0' as i32)) as i32));
}
'out: {
return (*ret.borrow());
}
});
panic!("ub: non-void function does not return a value")
}
pub fn main() {
std::process::exit(main_0());
}
Expand All @@ -87,5 +164,13 @@ fn main_0() -> i32 {
assert!((((({ from_loop_1(10,) }) == 7) as i32) != 0));
assert!((((({ from_switch_2(1,) }) == 10) as i32) != 0));
assert!((((({ from_switch_2(2,) }) == 999) as i32) != 0));
let value: Value<i32> = Rc::new(RefCell::new(42));
let w: Value<wrapper> = Rc::new(RefCell::new(wrapper {
item: Rc::new(RefCell::new((value.as_pointer()))),
}));
assert!((((({ via_pointer_3((w.as_pointer()), 0,) }) == 42) as i32) != 0));
assert!((((({ via_pointer_3((w.as_pointer()), 1,) }) == -1_i32) as i32) != 0));
assert!((((({ via_arrays_4(0,) }) == 11) as i32) != 0));
assert!((((({ via_arrays_4(1,) }) == -1_i32) as i32) != 0));
return 0;
}
56 changes: 56 additions & 0 deletions tests/unit/out/unsafe/goto_cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,54 @@ pub unsafe fn from_switch_2(mut n: i32) -> i32 {
});
panic!("ub: non-void function does not return a value")
}
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct wrapper {
pub item: *mut i32,
}
pub unsafe fn via_pointer_3(mut w: *mut wrapper, mut fail: i32) -> i32 {
let mut ret: i32 = 0_i32;
let mut item: *mut i32 = std::ptr::null_mut();
goto_block!({
'__entry: {
ret = 0;
item = (*w).item;
if (fail != 0) {
ret = -1_i32;
goto!('out);
}
ret = (*item);
}
'out: {
return ret;
}
});
panic!("ub: non-void function does not return a value")
}
pub unsafe fn via_arrays_4(mut fail: i32) -> i32 {
let mut ret: i32 = 0_i32;
let mut remain: [u8; 4] = [0_u8; 4];
let mut name: [libc::c_char; 5] = [(0 as libc::c_char); 5];
goto_block!({
'__entry: {
ret = 0;
remain = [0_u8, 0_u8, 0_u8, 0_u8];
name = std::mem::transmute(*b"wxyz\0");
if (fail != 0) {
ret = -1_i32;
goto!('out);
}
remain[(1) as usize] = 9_u8;
ret = ((((remain[(0) as usize] as i32) + (remain[(1) as usize] as i32))
+ (((name[(0) as usize] as i32) == ('w' as i32)) as i32))
+ (((name[(4) as usize] as i32) == ('\0' as i32)) as i32));
}
'out: {
return ret;
}
});
panic!("ub: non-void function does not return a value")
}
pub fn main() {
unsafe {
std::process::exit(main_0() as i32);
Expand All @@ -85,5 +133,13 @@ unsafe fn main_0() -> i32 {
assert!(((((unsafe { from_loop_1(10,) }) == (7)) as i32) != 0));
assert!(((((unsafe { from_switch_2(1,) }) == (10)) as i32) != 0));
assert!(((((unsafe { from_switch_2(2,) }) == (999)) as i32) != 0));
let mut value: i32 = 42;
let mut w: wrapper = wrapper {
item: (&mut value as *mut i32),
};
assert!(((((unsafe { via_pointer_3((&mut w as *mut wrapper), 0,) }) == (42)) as i32) != 0));
assert!(((((unsafe { via_pointer_3((&mut w as *mut wrapper), 1,) }) == (-1_i32)) as i32) != 0));
assert!(((((unsafe { via_arrays_4(0,) }) == (11)) as i32) != 0));
assert!(((((unsafe { via_arrays_4(1,) }) == (-1_i32)) as i32) != 0));
return 0;
}
Loading