Skip to content

Commit 7b0ccce

Browse files
committed
Fix double borrow in unsafe mode
1 parent 0720f6a commit 7b0ccce

4 files changed

Lines changed: 60 additions & 12 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3374,8 +3374,29 @@ 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);
33773379
PushExplicitAutoref autoref(*this, IsMutatingCall(expr));
3378-
ConvertArraySubscript(expr->getArg(0), expr->getArg(1), expr->getType());
3380+
// Rust borrows the container before computing the index, so an index that
3381+
// accesses the container is computed beforehand.
3382+
auto base_vars = GetAllVars(base);
3383+
if (!IsUniquePtr(base->getType()) &&
3384+
std::ranges::any_of(GetAllVars(idx), [&](const clang::ValueDecl *var) {
3385+
return base_vars.contains(var);
3386+
})) {
3387+
PushParen paren(*this);
3388+
StrCat(token::kStar);
3389+
PushBrace brace(*this);
3390+
StrCat("let __idx =", ConvertRValue(idx));
3391+
if (Mapper::Map(*this, idx->getType()) != "usize") {
3392+
StrCat(keyword::kAs, "usize");
3393+
}
3394+
StrCat(token::kSemiColon, IsMutatingCall(expr) ? "&mut" : "&");
3395+
Convert(base->IgnoreImplicit());
3396+
StrCat("[__idx]");
3397+
break;
3398+
}
3399+
ConvertArraySubscript(base, idx, expr->getType());
33793400
break;
33803401
}
33813402
case clang::OverloadedOperatorKind::OO_LessLess:

‎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)