Skip to content

Commit 8264141

Browse files
authored
Fix hoisted initialization outside goto_block (#239)
1 parent c443aa0 commit 8264141

5 files changed

Lines changed: 202 additions & 24 deletions

File tree

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -731,10 +731,10 @@ void ConverterRefCount::EmitHoistedInArmAssignment(clang::VarDecl *decl) {
731731
if (!decl->hasInit()) {
732732
return;
733733
}
734-
PushConversionKind push(*this, ConversionKind::Unboxed);
734+
PushConversionKind push(*this, ConversionKind::FullRefCount);
735735
StrCat(token::kStar, GetNamedDeclAsString(decl), ".borrow_mut()",
736736
token::kAssign);
737-
Convert(decl->getInit());
737+
StrCat(ConvertVarInitValue(decl->getType(), decl->getInit()));
738738
StrCat(token::kSemiColon);
739739
}
740740

@@ -1965,35 +1965,34 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
19651965
return attrs;
19661966
}
19671967

1968-
void ConverterRefCount::ConvertVarInit(clang::QualType qual_type,
1969-
clang::Expr *expr) {
1968+
std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type,
1969+
clang::Expr *expr) {
19701970
if (auto lambda = clang::dyn_cast<clang::LambdaExpr>(
19711971
expr->IgnoreUnlessSpelledInSource())) {
1972-
std::string str;
1973-
{
1974-
Buffer buf(*this);
1975-
PushConversionKind push(*this, ConversionKind::Unboxed);
1976-
if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) {
1977-
StrCat("FnPtr::new(");
1978-
VisitLambdaExpr(lambda);
1979-
StrCat(')');
1980-
} else {
1981-
VisitLambdaExpr(lambda);
1982-
}
1983-
str = std::move(buf).str();
1972+
Buffer buf(*this);
1973+
PushConversionKind push(*this, ConversionKind::Unboxed);
1974+
if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) {
1975+
StrCat("FnPtr::new(");
1976+
VisitLambdaExpr(lambda);
1977+
StrCat(')');
1978+
} else {
1979+
VisitLambdaExpr(lambda);
19841980
}
1985-
StrCat(BoxValue(std::move(str)));
1986-
return;
1981+
return std::move(buf).str();
19871982
}
19881983

1989-
bool is_ref = qual_type->isReferenceType();
1990-
PushConversionKind push(*this, ConversionKind::Unboxed, is_ref);
19911984
PushInitType init_type(*this, qual_type);
1992-
if (is_ref || qual_type->isFunctionPointerType()) {
1993-
StrCat(BoxValue(ConvertFreshPointer(expr)));
1994-
} else {
1995-
StrCat(BoxValue(ConvertFreshRValue(expr, qual_type)));
1985+
if (qual_type->isReferenceType() || qual_type->isFunctionPointerType()) {
1986+
return ConvertFreshPointer(expr);
19961987
}
1988+
return ConvertFreshRValue(expr, qual_type);
1989+
}
1990+
1991+
void ConverterRefCount::ConvertVarInit(clang::QualType qual_type,
1992+
clang::Expr *expr) {
1993+
bool is_ref = qual_type->isReferenceType();
1994+
PushConversionKind push(*this, ConversionKind::Unboxed, is_ref);
1995+
StrCat(BoxValue(ConvertVarInitValue(qual_type, expr)));
19971996
}
19981997

19991998
void ConverterRefCount::EmitSetOrAssign(clang::Expr *lhs,

cpp2rust/converter/models/converter_refcount.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class ConverterRefCount final : public Converter {
169169

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

172+
std::string ConvertVarInitValue(clang::QualType qual_type, clang::Expr *expr);
173+
172174
void ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs,
173175
std::string_view assign_operator) override;
174176

tests/unit/goto_cleanup.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,48 @@ static int from_switch(int n) {
4141
return ret;
4242
}
4343

44+
struct wrapper {
45+
int *item;
46+
};
47+
48+
static int via_pointer(struct wrapper *w, int fail) {
49+
int ret = 0;
50+
int *item = w->item;
51+
if (fail) {
52+
ret = -1;
53+
goto out;
54+
}
55+
ret = *item;
56+
out:
57+
return ret;
58+
}
59+
60+
static int via_arrays(int fail) {
61+
int ret = 0;
62+
unsigned char remain[4] = {0};
63+
char name[5] = "wxyz";
64+
if (fail) {
65+
ret = -1;
66+
goto out;
67+
}
68+
remain[1] = 9;
69+
ret = remain[0] + remain[1] + (name[0] == 'w') + (name[4] == '\0');
70+
out:
71+
return ret;
72+
}
73+
4474
int main(void) {
4575
assert(early(-1) == -1);
4676
assert(early(5) == 100);
4777
assert(from_loop(2) == 999);
4878
assert(from_loop(10) == 7);
4979
assert(from_switch(1) == 10);
5080
assert(from_switch(2) == 999);
81+
int value = 42;
82+
struct wrapper w = {&value};
83+
assert(via_pointer(&w, 0) == 42);
84+
assert(via_pointer(&w, 1) == -1);
85+
assert(via_arrays(0) == 11);
86+
assert(via_arrays(1) == -1);
5187
return 0;
5288
}

tests/unit/out/refcount/goto_cleanup.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,83 @@ pub fn from_switch_2(n: i32) -> i32 {
7777
});
7878
panic!("ub: non-void function does not return a value")
7979
}
80+
#[derive(Default)]
81+
pub struct wrapper {
82+
pub item: Value<Ptr<i32>>,
83+
}
84+
impl Clone for wrapper {
85+
fn clone(&self) -> Self {
86+
Self {
87+
item: Rc::new(RefCell::new((*self.item.borrow()).clone())),
88+
}
89+
}
90+
}
91+
impl ByteRepr for wrapper {
92+
fn byte_size() -> usize {
93+
8
94+
}
95+
fn to_bytes(&self, buf: &mut [u8]) {
96+
(*self.item.borrow()).to_bytes(&mut buf[0..8]);
97+
}
98+
fn from_bytes(buf: &[u8]) -> Self {
99+
Self {
100+
item: Rc::new(RefCell::new(<Ptr<i32>>::from_bytes(&buf[0..8]))),
101+
}
102+
}
103+
}
104+
pub fn via_pointer_3(w: Ptr<wrapper>, fail: i32) -> i32 {
105+
let w: Value<Ptr<wrapper>> = Rc::new(RefCell::new(w));
106+
let fail: Value<i32> = Rc::new(RefCell::new(fail));
107+
let ret: Value<i32> = <Value<i32>>::default();
108+
let item: Value<Ptr<i32>> = Rc::new(RefCell::new(Ptr::<i32>::null()));
109+
goto_block!({
110+
'__entry: {
111+
*ret.borrow_mut() = 0;
112+
*item.borrow_mut() = (*(*(*w.borrow()).upgrade().deref()).item.borrow()).clone();
113+
if ((*fail.borrow()) != 0) {
114+
(*ret.borrow_mut()) = -1_i32;
115+
goto!('out);
116+
}
117+
let __rhs = ((*item.borrow()).read());
118+
(*ret.borrow_mut()) = __rhs;
119+
}
120+
'out: {
121+
return (*ret.borrow());
122+
}
123+
});
124+
panic!("ub: non-void function does not return a value")
125+
}
126+
pub fn via_arrays_4(fail: i32) -> i32 {
127+
let fail: Value<i32> = Rc::new(RefCell::new(fail));
128+
let ret: Value<i32> = <Value<i32>>::default();
129+
let remain: Value<Box<[u8]>> = Rc::new(RefCell::new(
130+
(0..4).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
131+
));
132+
let name: Value<Box<[u8]>> = Rc::new(RefCell::new(
133+
(0..5).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
134+
));
135+
goto_block!({
136+
'__entry: {
137+
*ret.borrow_mut() = 0;
138+
*remain.borrow_mut() =
139+
Box::new([0_u8, <u8>::default(), <u8>::default(), <u8>::default()]);
140+
*name.borrow_mut() = Box::from(*b"wxyz\0");
141+
if ((*fail.borrow()) != 0) {
142+
(*ret.borrow_mut()) = -1_i32;
143+
goto!('out);
144+
}
145+
(*remain.borrow_mut())[(1) as usize] = 9_u8;
146+
(*ret.borrow_mut()) = (((((*remain.borrow())[(0) as usize] as i32)
147+
+ ((*remain.borrow())[(1) as usize] as i32))
148+
+ ((((*name.borrow())[(0) as usize] as i32) == ('w' as i32)) as i32))
149+
+ ((((*name.borrow())[(4) as usize] as i32) == ('\0' as i32)) as i32));
150+
}
151+
'out: {
152+
return (*ret.borrow());
153+
}
154+
});
155+
panic!("ub: non-void function does not return a value")
156+
}
80157
pub fn main() {
81158
std::process::exit(main_0());
82159
}
@@ -87,5 +164,13 @@ fn main_0() -> i32 {
87164
assert!((((({ from_loop_1(10,) }) == 7) as i32) != 0));
88165
assert!((((({ from_switch_2(1,) }) == 10) as i32) != 0));
89166
assert!((((({ from_switch_2(2,) }) == 999) as i32) != 0));
167+
let value: Value<i32> = Rc::new(RefCell::new(42));
168+
let w: Value<wrapper> = Rc::new(RefCell::new(wrapper {
169+
item: Rc::new(RefCell::new((value.as_pointer()))),
170+
}));
171+
assert!((((({ via_pointer_3((w.as_pointer()), 0,) }) == 42) as i32) != 0));
172+
assert!((((({ via_pointer_3((w.as_pointer()), 1,) }) == -1_i32) as i32) != 0));
173+
assert!((((({ via_arrays_4(0,) }) == 11) as i32) != 0));
174+
assert!((((({ via_arrays_4(1,) }) == -1_i32) as i32) != 0));
90175
return 0;
91176
}

tests/unit/out/unsafe/goto_cleanup.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,54 @@ pub unsafe fn from_switch_2(mut n: i32) -> i32 {
7373
});
7474
panic!("ub: non-void function does not return a value")
7575
}
76+
#[repr(C)]
77+
#[derive(Copy, Clone, Default)]
78+
pub struct wrapper {
79+
pub item: *mut i32,
80+
}
81+
pub unsafe fn via_pointer_3(mut w: *mut wrapper, mut fail: i32) -> i32 {
82+
let mut ret: i32 = 0_i32;
83+
let mut item: *mut i32 = std::ptr::null_mut();
84+
goto_block!({
85+
'__entry: {
86+
ret = 0;
87+
item = (*w).item;
88+
if (fail != 0) {
89+
ret = -1_i32;
90+
goto!('out);
91+
}
92+
ret = (*item);
93+
}
94+
'out: {
95+
return ret;
96+
}
97+
});
98+
panic!("ub: non-void function does not return a value")
99+
}
100+
pub unsafe fn via_arrays_4(mut fail: i32) -> i32 {
101+
let mut ret: i32 = 0_i32;
102+
let mut remain: [u8; 4] = [0_u8; 4];
103+
let mut name: [libc::c_char; 5] = [(0 as libc::c_char); 5];
104+
goto_block!({
105+
'__entry: {
106+
ret = 0;
107+
remain = [0_u8, 0_u8, 0_u8, 0_u8];
108+
name = std::mem::transmute(*b"wxyz\0");
109+
if (fail != 0) {
110+
ret = -1_i32;
111+
goto!('out);
112+
}
113+
remain[(1) as usize] = 9_u8;
114+
ret = ((((remain[(0) as usize] as i32) + (remain[(1) as usize] as i32))
115+
+ (((name[(0) as usize] as i32) == ('w' as i32)) as i32))
116+
+ (((name[(4) as usize] as i32) == ('\0' as i32)) as i32));
117+
}
118+
'out: {
119+
return ret;
120+
}
121+
});
122+
panic!("ub: non-void function does not return a value")
123+
}
76124
pub fn main() {
77125
unsafe {
78126
std::process::exit(main_0() as i32);
@@ -85,5 +133,13 @@ unsafe fn main_0() -> i32 {
85133
assert!(((((unsafe { from_loop_1(10,) }) == (7)) as i32) != 0));
86134
assert!(((((unsafe { from_switch_2(1,) }) == (10)) as i32) != 0));
87135
assert!(((((unsafe { from_switch_2(2,) }) == (999)) as i32) != 0));
136+
let mut value: i32 = 42;
137+
let mut w: wrapper = wrapper {
138+
item: (&mut value as *mut i32),
139+
};
140+
assert!(((((unsafe { via_pointer_3((&mut w as *mut wrapper), 0,) }) == (42)) as i32) != 0));
141+
assert!(((((unsafe { via_pointer_3((&mut w as *mut wrapper), 1,) }) == (-1_i32)) as i32) != 0));
142+
assert!(((((unsafe { via_arrays_4(0,) }) == (11)) as i32) != 0));
143+
assert!(((((unsafe { via_arrays_4(1,) }) == (-1_i32)) as i32) != 0));
88144
return 0;
89145
}

0 commit comments

Comments
 (0)