Skip to content

Commit 60266be

Browse files
committed
Fix double borrowing in unsafe mode
1 parent 0720f6a commit 60266be

5 files changed

Lines changed: 142 additions & 12 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3374,8 +3374,46 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) {
33743374
}
33753375
break;
33763376
case clang::OverloadedOperatorKind::OO_Subscript: {
3377+
auto *base = expr->getArg(0);
3378+
auto *idx = expr->getArg(1);
3379+
// Rust borrows the container before computing the index, so an index that
3380+
// reads the container, or that has side effects through anything the
3381+
// container is reached through, is computed beforehand.
3382+
std::unordered_set<const clang::ValueDecl *> base_vars;
3383+
auto *inner = base->IgnoreParenImpCasts();
3384+
if (idx->HasSideEffects(ctx_)) {
3385+
base_vars = GetAllVars(base);
3386+
} else if (auto *ref = clang::dyn_cast<clang::DeclRefExpr>(inner)) {
3387+
base_vars.insert(ref->getDecl());
3388+
} else if (auto *member = clang::dyn_cast<clang::MemberExpr>(inner)) {
3389+
base_vars.insert(member->getMemberDecl());
3390+
} else {
3391+
base_vars = GetAllVars(base);
3392+
}
3393+
if (!IsUniquePtr(base->getType()) &&
3394+
std::ranges::any_of(GetAllVars(idx), [&](const clang::ValueDecl *var) {
3395+
return base_vars.contains(var);
3396+
})) {
3397+
std::string idx_str;
3398+
{
3399+
PushExplicitAutoref no_autoref(*this, std::nullopt);
3400+
idx_str = ConvertRValue(idx);
3401+
}
3402+
PushParen paren(*this);
3403+
StrCat(token::kStar);
3404+
PushBrace brace(*this);
3405+
StrCat("let __idx =", idx_str);
3406+
if (Mapper::Map(*this, idx->getType()) != "usize") {
3407+
StrCat(keyword::kAs, "usize");
3408+
}
3409+
StrCat(token::kSemiColon, IsMutatingCall(expr) ? "&mut" : "&");
3410+
PushExplicitAutoref autoref(*this, IsMutatingCall(expr));
3411+
Convert(base->IgnoreImplicit());
3412+
StrCat("[__idx]");
3413+
break;
3414+
}
33773415
PushExplicitAutoref autoref(*this, IsMutatingCall(expr));
3378-
ConvertArraySubscript(expr->getArg(0), expr->getArg(1), expr->getType());
3416+
ConvertArraySubscript(base, idx, expr->getType());
33793417
break;
33803418
}
33813419
case clang::OverloadedOperatorKind::OO_LessLess:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub static mut next_0: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 0 });
10+
pub unsafe fn bump_1(mut v: *mut Vec<i32>, mut x: i32) -> i32 {
11+
(&mut (*v))[(0_usize)] += x;
12+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut next_0)).postfix_inc();
13+
}
14+
pub fn main() {
15+
unsafe {
16+
__cpp2rust_init_globals();
17+
std::process::exit(main_0() as i32);
18+
}
19+
}
20+
unsafe fn main_0() -> i32 {
21+
let mut v: Vec<i32> = vec![1; 4_usize as usize];
22+
let mut items: Vec<u32> = (0..(3_usize) as usize)
23+
.map(|_| <u32>::default())
24+
.collect::<Vec<_>>();
25+
let mut i: u32 = 0_u32;
26+
'loop_: while ((i as usize) < (items.len())) {
27+
items[(i as usize)] = (i).wrapping_mul(2_u32);
28+
i.prefix_inc();
29+
}
30+
items[(1_usize)] = (items[(1_usize)]).wrapping_add(5_u32);
31+
items[(2_usize)].postfix_inc();
32+
assert!(
33+
(((items[(0_usize)]) == (0_u32)) && ((items[(1_usize)]) == (7_u32)))
34+
&& ((items[(2_usize)]) == (5_u32))
35+
);
36+
(*{
37+
let __idx = (v[(0_usize)] as usize);
38+
&mut v[__idx]
39+
}) = 3;
40+
(*{
41+
let __idx = (v[(1_usize)] as usize);
42+
&mut v[__idx]
43+
}) = ((v[(1_usize)]) + (4));
44+
assert!(((v[(1_usize)]) == (3)) && ((v[(3_usize)]) == (7)));
45+
let mut p: *mut i32 = (&mut v[(0_usize)] as *mut i32);
46+
v[((*p) as usize)] = 9;
47+
assert!(((v[(1_usize)]) == (9)));
48+
(*{
49+
let __idx = ((unsafe { bump_1((&mut v as *mut Vec<i32>), 10) }) as usize);
50+
&mut v[__idx]
51+
}) = 2;
52+
assert!(((v[(0_usize)]) == (2)));
53+
assert!(
54+
((unsafe {
55+
let _v: *mut Vec<i32> = (&mut v as *mut Vec<i32>);
56+
let _x: i32 = v[(2_usize)];
57+
bump_1(_v, _x)
58+
}) == (1))
59+
&& ((v[(0_usize)]) == (3))
60+
);
61+
return 0;
62+
}
63+
pub unsafe fn __cpp2rust_init_globals() {
64+
std::cell::LazyCell::force(&*&raw const next_0);
65+
}

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

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::io::{Read, Seek, Write};
77
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
88
use std::rc::Rc;
99
#[repr(C)]
10-
#[derive(Copy, Clone, Default)]
10+
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
1111
pub struct Point {
1212
pub x: i32,
1313
pub y: i32,
@@ -18,13 +18,16 @@ impl Point {
1818
}
1919
}
2020
#[repr(C)]
21-
#[derive(Clone, Default)]
21+
#[derive(Clone, VaArg, FnPtrArg, Default)]
2222
pub struct Holder {
2323
pub values: Vec<i32>,
2424
pub points: Vec<Point>,
2525
}
2626
pub unsafe fn push_and_index_0(v: *mut Vec<i32>) -> i32 {
27-
(*v).push(42);
27+
{
28+
let __a1 = 42;
29+
(*v).push(__a1)
30+
};
2831
return (((*v).len() as i32) - (1));
2932
}
3033
pub unsafe fn sum_ref_1(v: *const Vec<i32>) -> i32 {
@@ -52,12 +55,25 @@ unsafe fn main_0() -> i32 {
5255
v[(0_usize)] = v[(1_usize)];
5356
assert!(((v[(0_usize)]) == (7)));
5457
v[(1_usize)] = 0;
55-
assert!(((v[(v[(1_usize)] as usize)]) == (7)));
58+
assert!(
59+
((*{
60+
let __idx = (v[(1_usize)] as usize);
61+
&mut v[__idx]
62+
}) == (7))
63+
);
5664
let mut i: i32 = 0;
5765
v[(i.postfix_inc() as usize)] = 3;
5866
assert!(((i) == (1)) && ((v[(0_usize)]) == (3)));
59-
assert!(((v[((unsafe { push_and_index_0(&mut v,) }) as usize)]) == (42)));
60-
v[((unsafe { push_and_index_0(&mut v) }) as usize)] = 5;
67+
assert!(
68+
((*{
69+
let __idx = ((unsafe { push_and_index_0(&mut v) }) as usize);
70+
&mut v[__idx]
71+
}) == (42))
72+
);
73+
(*{
74+
let __idx = ((unsafe { push_and_index_0(&mut v) }) as usize);
75+
&mut v[__idx]
76+
}) = 5;
6177
assert!(((v.len()) == (5_usize)) && ((v[(4_usize)]) == (5)));
6278
let mut p: *mut i32 = (&mut v[(2_usize)] as *mut i32);
6379
(*p) = 9;
@@ -69,7 +85,10 @@ unsafe fn main_0() -> i32 {
6985
h.values.resize_with(__a0, || <i32>::default())
7086
};
7187
h.values[(1_usize)] = 6;
72-
h.points.push(Point { x: 1, y: 2 });
88+
{
89+
let __a1 = Point { x: 1, y: 2 };
90+
h.points.push(__a1)
91+
};
7392
h.points[(0_usize)].y = 5;
7493
assert!(((h.values[(1_usize)]) == (6)));
7594
assert!(((unsafe { Point::sum(&h.points[(0_usize)],) }) == (6)));
@@ -80,9 +99,20 @@ unsafe fn main_0() -> i32 {
8099
let mut q: Point = h.points[(0_usize)];
81100
q.x = 0;
82101
assert!(((h.points[(0_usize)].x) == (7)));
83-
let mut grid: Vec<Vec<i32>> = vec![vec![0; 3_usize as usize]; 2_usize as usize];
102+
let mut grid: Vec<Vec<i32>> = Vec::new();
103+
{
104+
let __a1 = vec![0; 3_usize as usize];
105+
grid.push(__a1)
106+
};
107+
{
108+
let __a1 = vec![0; 3_usize as usize];
109+
grid.push(__a1)
110+
};
84111
grid[(1_usize)][(2_usize)] = 8;
85112
assert!(((grid[(1_usize)][(2_usize)]) == (8)) && ((grid[(0_usize)][(2_usize)]) == (0)));
113+
grid[(0_usize)][(1_usize)] = grid[(1_usize)][(2_usize)];
114+
grid[(1_usize)][(0_usize)] += grid[(0_usize)][(1_usize)];
115+
assert!(((grid[(0_usize)][(1_usize)]) == (8)) && ((grid[(1_usize)][(0_usize)]) == (8)));
86116
let mut a: Vec<i32> = vec![4, 5, 6];
87117
a[(1_usize)] = ((a[(0_usize)]) + (a[(2_usize)]));
88118
assert!(((a[(1_usize)]) == (10)));

‎tests/unit/vector_subscript_borrow.cpp‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// no-compile: unsafe
21
#include <cassert>
32
#include <vector>
43

‎tests/unit/vector_subscript_direct.cpp‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// The unsafe model cannot express v[push_and_index(v)] without two borrows.
2-
// no-compile: unsafe
31
#include <array>
42
#include <cassert>
53
#include <vector>

0 commit comments

Comments
 (0)